summaryrefslogtreecommitdiff
path: root/chromium/third_party/catapult
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/third_party/catapult
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/catapult')
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/AUTHORS.txt43
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/COPYING.txt26
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/NEWS.txt1066
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/PKG-INFO20
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/README.chromium11
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/README.txt63
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/TODO.txt31
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/__init__.py406
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/__init__.py321
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_html5lib.py285
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_htmlparser.py258
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_lxml.py233
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/dammit.py829
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/diagnose.py204
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/element.py1611
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/bs4/testing.py592
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/doc/Makefile130
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/6.1.jpgbin0 -> 22619 bytes
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/conf.py256
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/index.rst3049
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstrate_parser_differences.py95
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstration_markup.txt34
-rw-r--r--chromium/third_party/catapult/third_party/beautifulsoup4/setup.py29
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/.travis.yml37
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/AUTHORS.rst43
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/CHANGES.rst217
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/CONTRIBUTING.rst60
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/LICENSE20
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/MANIFEST.in6
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/README.chromium11
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/README.rst157
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/debug-info.py37
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/Makefile177
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/changes.rst3
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/conf.py280
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.filters.rst59
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.rst77
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst19
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst43
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst59
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/index.rst21
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/license.rst4
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/make.bat242
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/modules.rst7
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/doc/movingparts.rst209
-rwxr-xr-xchromium/third_party/catapult/third_party/html5lib-python/flake8-run.sh14
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/__init__.py25
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/constants.py3102
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/__init__.py0
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/_base.py12
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py20
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py65
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/lint.py90
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py205
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py12
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py38
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/html5parser.py2724
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/ihatexml.py285
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/inputstream.py903
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/sanitizer.py296
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py16
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py317
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/tokenizer.py1731
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py0
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py44
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py76
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py377
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py227
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py337
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py369
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py147
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py200
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py43
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py136
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py69
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py201
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py63
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/__init__.py12
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/_base.py37
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/datrie.py44
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/py.py67
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/html5lib/utils.py103
-rwxr-xr-xchromium/third_party/catapult/third_party/html5lib-python/parse.py241
-rwxr-xr-xchromium/third_party/catapult/third_party/html5lib-python/requirements-install.sh16
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-2.6.txt5
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-cpython.txt5
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/requirements-optional.txt13
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/requirements-test.txt5
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/requirements.txt1
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/setup.py58
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/tox.ini30
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/utils/entities.py88
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/utils/iana_parse.py24
-rw-r--r--chromium/third_party/catapult/third_party/html5lib-python/utils/spider.py122
-rw-r--r--chromium/third_party/catapult/third_party/polymer/.bowerrc3
-rw-r--r--chromium/third_party/catapult/third_party/polymer/LICENSE.polymer27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/README.chromium26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/bower.json24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/.bower.json (renamed from chromium/third_party/catapult/tracing/third_party/components/core-component-page/.bower.json)10
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/README.md9
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/bowager-logo.png (renamed from chromium/third_party/catapult/tracing/third_party/components/core-component-page/bowager-logo.png)bin5165 -> 5165 bytes
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/bower.json (renamed from chromium/third_party/catapult/tracing/third_party/components/core-component-page/bower.json)4
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/core-component-page.html1
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/demo.html (renamed from chromium/third_party/catapult/tracing/third_party/components/core-component-page/demo.html)0
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-component-page/index.html (renamed from chromium/third_party/catapult/tracing/third_party/components/core-component-page/index.html)0
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/.bower.json18
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/README.md7
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/bower.json8
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/core-media-query.html87
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/demo.html44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-media-query/index.html22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/README.md4
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/bower.json13
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.css104
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.html217
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/demo.html211
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/index.html23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/core-tooltip/metadata.html20
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/font-roboto/.bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/font-roboto/README.md1
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/font-roboto/bower.json22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/font-roboto/roboto.html11
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/README.md49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/index.html38
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/x-announces.html50
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/index.html28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/iron-a11y-announcer.html125
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.bower.json43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/README.md58
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/x-key-aware.html104
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html492
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.bower.json48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/README.md44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/bower.json39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/demo/index.html111
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/hero.svg33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/iron-autogrow-textarea.html353
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.github/ISSUE_TEMPLATE.md33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/README.md22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/bower.json32
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/index.html48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/simple-button.html71
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/index.html27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-button-state.html228
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-control-state.html110
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.bower.json43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.travis.yml22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/README.md25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/bower.json34
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/index.html39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/simple-checkbox.html64
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/iron-checked-element-behavior.html120
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.bower.json43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/README.md58
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/bower.json34
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/demo/index.html104
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-collapse/hero.svg23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/index.html31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-collapse/iron-collapse.html285
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.bower.json48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/README.md46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/bower.json39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/grow-height-animation.html36
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/index.html160
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/x-select.html80
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown-scroll-manager.html233
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown.html275
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/README.md57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html166
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html594
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/README.md55
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-flex-layout.html311
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-shadow-flex-layout.html307
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/demo/index.html396
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout-classes.html431
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout.html399
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.travis.yml22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/README.md23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/index.html67
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-element.html27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-form.html53
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/iron-form-element-behavior.html86
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/.bower.json45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/README.md92
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/bower.json35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/async.html62
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/index.html48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/location.pngbin0 -> 324 bytes
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-icon/hero.svg19
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/index.html26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icon/iron-icon.html207
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/.bower.json47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/README.md44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/av-icons.html88
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/bower.json38
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/communication-icons.html64
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/demo/index.html132
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/device-icons.html94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/editor-icons.html76
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/hardware-icons.html63
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-icons/hero.svg35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/image-icons.html169
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/index.html25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/iron-icons.html338
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/maps-icons.html76
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/notification-icons.html66
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/places-icons.html33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-icons/social-icons.html40
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.bower.json43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.travis.yml28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/README.md50
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/index.html70
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/svg-sample-icons.html81
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/index.html26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/iron-iconset-svg.html194
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/.github/ISSUE_TEMPLATE.md33
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/.travis.yml23
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/CONTRIBUTING.md77
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/README.md86
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/bower.json33
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/demo/index.html266
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/loading.pngbin0 -> 2183 bytes
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/demo/polymer.svg175
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/index.html24
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-image/iron-image.html403
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/.bower.json44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/README.md59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/bower.json35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/demo/index.html87
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-input/hero.svg19
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-input/iron-input.html306
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.bower.json46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/README.md30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/bower.json37
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/index.html114
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menu.html52
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menubar.html56
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menu-behavior.html334
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menubar-behavior.html81
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/.bower.json39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/.travis.yml28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/README.md93
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/bower.json29
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/demo/index.html46
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-meta/hero.svg33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/index.html27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-meta/iron-meta.html333
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.bower.json47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.github/ISSUE_TEMPLATE.md33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/README.md71
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/bower.json37
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/index.html179
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/simple-overlay.html49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-backdrop.html168
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html628
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-manager.html398
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/.bower.json39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/README.md24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/bower.json29
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/demo/index.html79
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/iron-range-behavior.html121
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/.bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/README.md36
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/index.html29
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/src/x-app.html114
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/index.html25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/iron-resizable-behavior.html195
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/.bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/.github/ISSUE_TEMPLATE.md33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/CONTRIBUTING.md77
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-selector/README.md91
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-selector/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/demo/index.html101
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/iron-selector/index.html28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-multi-selectable.html154
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selectable.html388
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selection.html119
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selector.html87
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/.bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/README.md42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/cats-only.html46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/index.html71
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/validatable-input.html46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/iron-validatable-behavior.html149
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/.bower.json61
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/README.md306
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/cascaded-animation.html95
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-in-animation.html49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-out-animation.html49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/hero-animation.html83
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/opaque-animation.html46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/reverse-ripple-animation.html87
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/ripple-animation.html93
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-down-animation.html65
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-up-animation.html65
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-down-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-bottom-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-left-animation.html60
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-right-animation.html60
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-top-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-left-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-right-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-up-animation.html59
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/transform-animation.html70
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/bower.json52
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/index.html166
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-card.html94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-cards-list.html75
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/declarative/index.html132
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/index.html70
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-animatable.html68
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-dialog.html94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/animated-dropdown.html90
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/index.html54
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/animated-grid.html164
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/fullsize-page-with-card.html122
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/index.html64
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/index.html45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/full-view.html118
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/index.html35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-demo.html102
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-view.html124
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/animated-grid.html146
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/full-page.html82
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/index.html48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/animated-grid.html167
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/fullsize-page-with-card.html120
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/index.html63
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/reprojected-pages.html45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/shared-styles.html47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/circles-page.html107
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/index.html70
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/squares-page.html100
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/guides/neon-animation.md314
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable-behavior.html150
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable.html57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animated-pages.html224
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-behavior.html86
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-runner-behavior.html116
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation.html18
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animations.html29
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animatable-behavior.html43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animation-behavior.html72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/neon-animation/web-animations.html (renamed from chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.html)7
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.bower.json51
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/README.md44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/index.html57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-button.html72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-radio-button.html119
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/index.html26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-button-behavior.html103
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-checked-element-behavior.html61
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-inky-focus-behavior.html55
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-ripple-behavior.html130
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/.bower.json50
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/README.md94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/demo/index.html138
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/index.html26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-button/paper-button.html178
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/.travis.yml23
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/CONTRIBUTING.md77
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/README.md65
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/cafe.pngbin0 -> 256315 bytes
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/donuts.pngbin0 -> 395250 bytes
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/house.pngbin0 -> 376570 bytes
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/demo/index.html323
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/travel.pngbin0 -> 364923 bytes
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/trip.pngbin0 -> 283091 bytes
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/index.html28
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-card/paper-card.html226
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.bower.json49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/README.md54
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/bower.json40
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/index.html102
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/simple-dialog.html39
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/hero.svg51
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-behavior.html140
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-common.css57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-shared-styles.html83
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.bower.json47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/README.md74
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/bower.json38
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/demo/index.html199
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-dialog/hero.svg58
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dialog/paper-dialog.html122
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.bower.json57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/README.md149
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/bower.json48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/demo/index.html295
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-icons.html17
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-light.html576
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-shared-styles.html79
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu.html382
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/README.md4
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/bower.json16
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/demo.html83
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/index.html22
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/metadata.html36
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-fab/paper-fab.html180
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.bower.json50
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/README.md81
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/bower.json40
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/index.html103
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/paper-icon-button-light.html57
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/index.html23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button-light.html91
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button.html176
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/.bower.json60
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/README.md254
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/all-imports.html12
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/bower.json51
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/index.html155
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-input.html96
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-validator.html27
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-input/hero.svg19
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/index.html28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-addon-behavior.html47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-behavior.html541
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-char-counter.html99
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-container.html621
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-error.html94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input.html162
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-textarea.html138
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/.bower.json52
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/README.md163
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/all-imports.html13
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/bower.json43
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/demo/index.html191
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-icon-item.html86
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-behavior.html36
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-body.html83
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-shared-styles.html70
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item.html111
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-listbox/README.md5
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-listbox/bower.json38
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-listbox/demo/index.html93
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-listbox/hero.svg35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-listbox/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-listbox/paper-listbox.html96
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/.bower.json44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/README.md35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/bower.json35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/demo/index.html84
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material-shared-styles.html42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material.html78
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.bower.json55
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/README.md69
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/bower.json46
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/demo/index.html203
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-menu-button/hero.svg39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button-animations.html109
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button.html407
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/.bower.json48
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/CONTRIBUTING.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/README.md113
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/bower.json39
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/demo/index.html150
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-menu/hero.svg35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu-shared-styles.html47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu.html102
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-submenu.html231
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/.bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/README.md94
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/bower.json32
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/demo/index.html122
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-progress/hero.svg21
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/index.html28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-progress/paper-progress.html341
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.bower.json45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/README.md90
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/bower.json35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/demo/index.html415
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-ripple/hero.svg30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/index.html27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-ripple/paper-ripple.html758
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.bower.json47
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.travis.yml23
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/README.md93
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/bower.json38
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/demo/index.html97
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-spinner/hero.svg27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/index.html30
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-behavior.html87
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-lite.html71
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-styles.html341
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner.html91
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/.bower.json42
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/README.md49
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/bower.json33
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/global.html96
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow-layout.html302
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow.html52
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/typography.html169
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/color.html333
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/default-theme.html72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo-pages.html72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo.css25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo/index.html339
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/index.html24
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles-classes.html14
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles.html44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/shadow.html71
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-styles/typography.html169
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/.bower.json45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/README.md72
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/bower.json35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo.html63
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo/index.html96
-rwxr-xr-xchromium/third_party/catapult/third_party/polymer/components/paper-toast/hero.svg20
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/index.html26
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/metadata.html20
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.css80
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.html323
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.bower.json45
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.travis.yml25
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/CONTRIBUTING.md77
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/README.md62
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/bower.json36
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/index.html133
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/test-button.html37
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/index.html28
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html372
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/.bower.json44
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/LICENSE.txt27
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/bower.json34
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/build.log473
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-micro.html715
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-mini.html2164
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/polymer/polymer.html5226
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/.bower.json41
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/COPYING202
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/History.md203
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/README.md172
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/bower.json31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js17
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js.map1
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js17
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js.map1
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.html50
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js17
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js.map1
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/.bower.json (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/.bower.json)14
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.js (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.js)348
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.min.js11
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.js (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.js)352
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.min.js11
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/README.md (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/README.md)35
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.js (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.js)274
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.min.js14
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/bower.json (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/bower.json)4
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/build.log31
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/package.json (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/package.json)2
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.js (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.js)686
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.min.js12
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.js (renamed from chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.js)1184
-rw-r--r--chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.min.js16
-rw-r--r--chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py5
-rw-r--r--chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py52
-rw-r--r--chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module_unittest.py45
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/compare_samples54
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/generate_about_tracing_contents4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/html2trace10
-rw-r--r--chromium/third_party/catapult/tracing/bin/index.html8
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/map_traces14
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/merge_traces3
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/run_dev_server_tests6
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/run_metric55
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/run_py_tests11
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/run_tests8
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/run_vinn_tests4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/slim_trace16
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/strip_memory_infra_trace13
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/symbolize_trace54
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/trace2html4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/update_gypi4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/validate_all_metrics4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/vulcanize_trace_viewer4
-rwxr-xr-xchromium/third_party/catapult/tracing/bin/why_imported4
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/core-component-page/README.md6
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/core-component-page/core-component-page.html37
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/.bower.json32
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/README.chromium16
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/README.md21
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/bower.json23
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/build.log26
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/layout.html286
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.js11857
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.min.js14
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.min.js11
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.min.js11
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.min.js13
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/build.log31
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.min.js11
-rw-r--r--chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.min.js14
-rw-r--r--chromium/third_party/catapult/tracing/trace_viewer.gypi58
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/color.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/color_scheme.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/color_scheme_test.html33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/event.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/event_target.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/extension_registry.html11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/extension_registry_basic.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/extension_registry_type_based.html36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/iteration_helpers.html55
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/iteration_helpers_test.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/math.html36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/quad.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/range.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/range_test.html19
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/range_utils.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/rect.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/running_statistics.html157
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/running_statistics_test.html48
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/settings.html64
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator_test.html55
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/sorted_array_utils.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/statistics.html244
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/statistics_test.html170
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/time_display_modes.html (renamed from chromium/third_party/catapult/tracing/tracing/value/time_display_mode.html)8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unit.html (renamed from chromium/third_party/catapult/tracing/tracing/value/unit.html)94
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unit_scale.html (renamed from chromium/third_party/catapult/tracing/tracing/value/unit_scale.html)37
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unit_test.html (renamed from chromium/third_party/catapult/tracing/tracing/value/unit_test.html)25
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/html_test_results.html77
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/interactive_test_runner.html95
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/suite_loader.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/test_case.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/test_runner.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/test_suite.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/unittest/text_test_results.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/utils.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/utils_test.html3
-rw-r--r--chromium/third_party/catapult/tracing/tracing/base/xhr.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/core/test_utils.html22
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor.html69
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor_test.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/blame_context_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/frame_tree_node.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/render_frame.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/top_level.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/display_item_list.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_impl.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/picture.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/region.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/render_pass.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/tile.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/util.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver.html75
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver_test.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test_data.js2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome/layout_tree.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/chrome_config.html1
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/android/event_log_importer.html24
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer.html63
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer_test.html19
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/ddms_importer.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer.html54
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer_test.html23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/etw/eventtrace_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/etw/process_parser.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/etw/thread_parser.html39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer.html42
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer_test.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/android_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser.html152
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html57
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer.html116
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser.html182
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser_test.html85
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/power_parser.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/trace_code_map.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer.html236
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/v8/codemap.html17
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/v8/log_reader.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/v8/splaytree.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer.html98
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice_test.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/system_stats/system_stats_snapshot.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/tquery/filter.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/v8/v8_gc_stats_thread_slice.html49
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/v8/v8_thread_slice.html46
-rw-r--r--chromium/third_party/catapult/tracing/tracing/extras/v8_config.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/empty_importer.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/find_input_expectations.html643
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/import.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/proto_expectation.html45
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/user_expectation_verifier.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/importer/user_model_builder_test.html784
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric.html199
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric_test.html202
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/buildbot_output_for_compare_samples_test.txt187
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/compare_samples.py55
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_cmdline.html253
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_unittest.py225
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric.html87
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric_test.html121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/discover_cmdline.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/discover_unittest.py6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function.html82
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function_test.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/metric_registry_test.html45
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/metric_runner.py31
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/sample_metric.html35
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric.html22
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric_test.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric.html89
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric_test.html123
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric.html78
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric_test.html56
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric.html423
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric_test.html235
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric_test.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric.html437
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric_test.html338
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric.html39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric_test.html113
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric.html749
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric_test.html1586
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric.html290
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric_test.html377
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric.html85
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric_test.html70
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/system_health_metrics.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/utils.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric.html59
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric_test.html35
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric.html90
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric_test.html60
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric.html269
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html283
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html233
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html85
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/utils_test.html31
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/v8/v8_metrics.html3
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/valueset_output_for_compare_samples_test.json1
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/alert.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/async_slice.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager.html173
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager_test.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/container_memory_dump.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/container_memory_dump_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/counter.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/counter_sample.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/counter_sample_test.html33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/counter_series.html1
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/counter_test.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/cpu.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/cpu_slice.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/cpu_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/event.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/event_registry.html31
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/event_set.html174
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/event_set_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/flow_event.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/frame.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/global_memory_dump.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/global_memory_dump_test.html57
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/android_app.html77
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/android_model_helper_test.html67
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/android_surface_flinger.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_browser_helper.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_gpu_helper.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper.html28
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper_test.html22
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper.html107
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper_test.html156
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/instant_event.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/location.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump_test.html48
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/memory_dump_test_utils.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/model.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/model_stats.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/model_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/object_collection.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/object_collection_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/object_instance.html25
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/object_snapshot.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/object_snapshot_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/power_sample.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/power_sample_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/power_series.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/power_series_test.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/process.html1
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/process_memory_dump.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/process_memory_dump_test.html121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/process_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/sample.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/slice.html50
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/slice_group.html89
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/slice_group_test.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/slice_test.html22
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/stack_frame.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/thread.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/thread_slice.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/thread_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/thread_time_slice.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/time_to_object_instance_map.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/timed_event.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/timed_event_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/animation_expectation.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/idle_expectation.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/load_expectation.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/response_expectation.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/startup_expectation.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/user_expectation.html52
-rw-r--r--chromium/third_party/catapult/tracing/tracing/model/user_model/user_model.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/__init__.py3
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/cloud_storage.py71
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/corpus_driver.py9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/corpus_driver_cmdline.py23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/failure.html47
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/failure.py53
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/failure_test.html46
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/failure_unittest.py56
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/file_handle.html109
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/file_handle.py100
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/function_handle.html178
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/function_handle.py139
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/function_handle_test.html122
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/function_handle_unittest.py86
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/gtest_progress_reporter.py88
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/job.html49
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/job.py36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/json_output_formatter.py20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/local_directory_corpus_driver.py68
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_runner.py105
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.html63
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.py135
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_cmdline.html91
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_unittest.py208
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_traces.py67
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/map_traces_handler.py14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/mre_result.html61
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/mre_result.py48
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/mre_result_test.html30
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/mre_result_unittest.py46
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/output_formatter.py19
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/progress_reporter.py27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results_cmdline.html70
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/run_and_convert_errors_to_failures.html31
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue.py121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue_unittest.py33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/results2_template.html3
-rw-r--r--chromium/third_party/catapult/tracing/tracing/results_renderer.py40
-rw-r--r--chromium/third_party/catapult/tracing/tracing/results_renderer_unittest.py79
-rw-r--r--chromium/third_party/catapult/tracing/tracing/tests.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/trace2html.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html263
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html227
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html238
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html298
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html70
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html556
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html30
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html42
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html211
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html60
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html276
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html498
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html260
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html149
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html106
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html44
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html109
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html66
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html185
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html35
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html76
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html333
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html171
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html127
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html533
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html45
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html87
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html59
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html144
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html430
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html131
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html41
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html77
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html232
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html59
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html66
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html475
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html124
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html65
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html82
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html128
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html452
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html30
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html108
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html3
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html64
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html72
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html146
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html174
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html75
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html128
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html49
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html174
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html103
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html71
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html209
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html236
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/base.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html345
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html226
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html178
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html80
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html248
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html295
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html17
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/d3.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html28
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html74
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html75
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html280
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html12
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html176
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html24
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html24
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/file.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html443
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/heading.html191
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html452
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html77
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html81
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html42
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html181
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html29
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html40
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html58
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html42
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html58
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html64
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html73
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html108
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html223
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html45
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html47
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html607
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html381
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/table.html2408
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html675
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/ui.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/utils.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html19
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html24
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html26
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html133
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html49
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html61
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html110
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html68
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html124
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html20
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html47
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html344
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/layout_tree_sub_view.html (renamed from chromium/third_party/catapult/tracing/tracing/ui/analysis/layout_tree_sub_view.html)39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html184
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html263
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html38
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html266
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html129
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html548
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html768
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html28
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html18
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html556
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html45
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html44
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html79
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html230
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html181
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html96
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html15
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/find_control.html193
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/find_controller.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html59
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html234
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html21
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html64
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html32
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html317
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html40
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html1955
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html751
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html41
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html35
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html25
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html22
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html81
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html21
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html227
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html98
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html31
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html14
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html91
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html9
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html7
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html8
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html103
-rw-r--r--chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/__init__.py192
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/breakdown.html96
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/composition.html33
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic.html36
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map.html74
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map_test.html48
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/event_ref.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/generic.html27
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/iteration_info.html187
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set.html118
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set_test.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown.html136
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown_test.html83
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_map.html112
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_set.html95
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/scalar.html43
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/diagnostics/value_ref.html23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/histogram.html1002
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/histogram_test.html508
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/numeric.html648
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/numeric_test.html390
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span_test.html2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span.html139
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span_test.html55
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table.html72
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table_test.html13
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_span.html5
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/generic_diagnostic_span.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/generic_table_view.html10
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span.html451
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span_test.html41
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/iteration_info_span.html121
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit_test.html4
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span.html23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span_test.html11
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span_test.html6
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span_test.html16
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller.html197
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller_test.html311
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span.html39
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span_test.html23
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table_test.html30
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span.html671
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span_test.html868
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table.html1038
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table_test.html581
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view.html226
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view_test.html30
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/value.html232
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/value_set.html274
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/value_set_test.html132
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/value_test.html92
-rw-r--r--chromium/third_party/catapult/tracing/tracing/value/value_unittest.py52
-rw-r--r--chromium/third_party/catapult/tracing/tracing_build/check_common.py2
-rw-r--r--chromium/third_party/catapult/tracing/tracing_build/html2trace.py34
-rw-r--r--chromium/third_party/catapult/tracing/tracing_build/merge_traces.py60
-rw-r--r--chromium/third_party/catapult/tracing/tracing_build/slim_trace.py112
-rwxr-xr-xchromium/third_party/catapult/tracing/tracing_build/strip_memory_infra_trace.py100
-rw-r--r--chromium/third_party/catapult/tracing/tracing_build/trace2html.py4
-rw-r--r--chromium/third_party/catapult/tracing/tracing_project.py5
1333 files changed, 117984 insertions, 32838 deletions
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/AUTHORS.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/AUTHORS.txt
new file mode 100644
index 00000000000..8c113de6cf0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/AUTHORS.txt
@@ -0,0 +1,43 @@
+Behold, mortal, the origins of Beautiful Soup...
+================================================
+
+Leonard Richardson is the primary programmer.
+
+Aaron DeVore is awesome.
+
+Mark Pilgrim provided the encoding detection code that forms the base
+of UnicodeDammit.
+
+Thomas Kluyver and Ezio Melotti finished the work of getting Beautiful
+Soup 4 working under Python 3.
+
+Simon Willison wrote soupselect, which was used to make Beautiful Soup
+support CSS selectors.
+
+Sam Ruby helped with a lot of edge cases.
+
+Jonathan Ellis was awarded the prestigous Beau Potage D'Or for his
+work in solving the nestable tags conundrum.
+
+An incomplete list of people have contributed patches to Beautiful
+Soup:
+
+ Istvan Albert, Andrew Lin, Anthony Baxter, Andrew Boyko, Tony Chang,
+ Zephyr Fang, Fuzzy, Roman Gaufman, Yoni Gilad, Richie Hindle, Peteris
+ Krumins, Kent Johnson, Ben Last, Robert Leftwich, Staffan Malmgren,
+ Ksenia Marasanova, JP Moins, Adam Monsen, John Nagle, "Jon", Ed
+ Oskiewicz, Greg Phillips, Giles Radford, Arthur Rudolph, Marko
+ Samastur, Jouni Seppänen, Alexander Schmolck, Andy Theyers, Glyn
+ Webster, Paul Wright, Danny Yoo
+
+An incomplete list of people who made suggestions or found bugs or
+found ways to break Beautiful Soup:
+
+ Hanno Böck, Matteo Bertini, Chris Curvey, Simon Cusack, Bruce Eckel,
+ Matt Ernst, Michael Foord, Tom Harris, Bill de hOra, Donald Howes,
+ Matt Patterson, Scott Roberts, Steve Strassmann, Mike Williams,
+ warchild at redho dot com, Sami Kuisma, Carlos Rocha, Bob Hutchison,
+ Joren Mc, Michal Migurski, John Kleven, Tim Heaney, Tripp Lilley, Ed
+ Summers, Dennis Sutch, Chris Smith, Aaron Sweep^W Swartz, Stuart
+ Turner, Greg Edwards, Kevin J Kalupson, Nikos Kouremenos, Artur de
+ Sousa Rocha, Yichun Wei, Per Vognsen
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/COPYING.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/COPYING.txt
new file mode 100644
index 00000000000..d668d13f041
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/COPYING.txt
@@ -0,0 +1,26 @@
+Beautiful Soup is made available under the MIT license:
+
+ Copyright (c) 2004-2012 Leonard Richardson
+
+ 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, DAMMIT.
+
+Beautiful Soup incorporates code from the html5lib library, which is
+also made available under the MIT license.
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/NEWS.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/NEWS.txt
new file mode 100644
index 00000000000..88a60a2458f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/NEWS.txt
@@ -0,0 +1,1066 @@
+= 4.3.2 (20131002) =
+
+* Fixed a bug in which short Unicode input was improperly encoded to
+ ASCII when checking whether or not it was the name of a file on
+ disk. [bug=1227016]
+
+* Fixed a crash when a short input contains data not valid in
+ filenames. [bug=1232604]
+
+* Fixed a bug that caused Unicode data put into UnicodeDammit to
+ return None instead of the original data. [bug=1214983]
+
+* Combined two tests to stop a spurious test failure when tests are
+ run by nosetests. [bug=1212445]
+
+= 4.3.1 (20130815) =
+
+* Fixed yet another problem with the html5lib tree builder, caused by
+ html5lib's tendency to rearrange the tree during
+ parsing. [bug=1189267]
+
+* Fixed a bug that caused the optimized version of find_all() to
+ return nothing. [bug=1212655]
+
+= 4.3.0 (20130812) =
+
+* Instead of converting incoming data to Unicode and feeding it to the
+ lxml tree builder in chunks, Beautiful Soup now makes successive
+ guesses at the encoding of the incoming data, and tells lxml to
+ parse the data as that encoding. Giving lxml more control over the
+ parsing process improves performance and avoids a number of bugs and
+ issues with the lxml parser which had previously required elaborate
+ workarounds:
+
+ - An issue in which lxml refuses to parse Unicode strings on some
+ systems. [bug=1180527]
+
+ - A returning bug that truncated documents longer than a (very
+ small) size. [bug=963880]
+
+ - A returning bug in which extra spaces were added to a document if
+ the document defined a charset other than UTF-8. [bug=972466]
+
+ This required a major overhaul of the tree builder architecture. If
+ you wrote your own tree builder and didn't tell me, you'll need to
+ modify your prepare_markup() method.
+
+* The UnicodeDammit code that makes guesses at encodings has been
+ split into its own class, EncodingDetector. A lot of apparently
+ redundant code has been removed from Unicode, Dammit, and some
+ undocumented features have also been removed.
+
+* Beautiful Soup will issue a warning if instead of markup you pass it
+ a URL or the name of a file on disk (a common beginner's mistake).
+
+* A number of optimizations improve the performance of the lxml tree
+ builder by about 33%, the html.parser tree builder by about 20%, and
+ the html5lib tree builder by about 15%.
+
+* All find_all calls should now return a ResultSet object. Patch by
+ Aaron DeVore. [bug=1194034]
+
+= 4.2.1 (20130531) =
+
+* The default XML formatter will now replace ampersands even if they
+ appear to be part of entities. That is, "&lt;" will become
+ "&amp;lt;". The old code was left over from Beautiful Soup 3, which
+ didn't always turn entities into Unicode characters.
+
+ If you really want the old behavior (maybe because you add new
+ strings to the tree, those strings include entities, and you want
+ the formatter to leave them alone on output), it can be found in
+ EntitySubstitution.substitute_xml_containing_entities(). [bug=1182183]
+
+* Gave new_string() the ability to create subclasses of
+ NavigableString. [bug=1181986]
+
+* Fixed another bug by which the html5lib tree builder could create a
+ disconnected tree. [bug=1182089]
+
+* The .previous_element of a BeautifulSoup object is now always None,
+ not the last element to be parsed. [bug=1182089]
+
+* Fixed test failures when lxml is not installed. [bug=1181589]
+
+* html5lib now supports Python 3. Fixed some Python 2-specific
+ code in the html5lib test suite. [bug=1181624]
+
+* The html.parser treebuilder can now handle numeric attributes in
+ text when the hexidecimal name of the attribute starts with a
+ capital X. Patch by Tim Shirley. [bug=1186242]
+
+= 4.2.0 (20130514) =
+
+* The Tag.select() method now supports a much wider variety of CSS
+ selectors.
+
+ - Added support for the adjacent sibling combinator (+) and the
+ general sibling combinator (~). Tests by "liquider". [bug=1082144]
+
+ - The combinators (>, +, and ~) can now combine with any supported
+ selector, not just one that selects based on tag name.
+
+ - Added limited support for the "nth-of-type" pseudo-class. Code
+ by Sven Slootweg. [bug=1109952]
+
+* The BeautifulSoup class is now aliased to "_s" and "_soup", making
+ it quicker to type the import statement in an interactive session:
+
+ from bs4 import _s
+ or
+ from bs4 import _soup
+
+ The alias may change in the future, so don't use this in code you're
+ going to run more than once.
+
+* Added the 'diagnose' submodule, which includes several useful
+ functions for reporting problems and doing tech support.
+
+ - diagnose(data) tries the given markup on every installed parser,
+ reporting exceptions and displaying successes. If a parser is not
+ installed, diagnose() mentions this fact.
+
+ - lxml_trace(data, html=True) runs the given markup through lxml's
+ XML parser or HTML parser, and prints out the parser events as
+ they happen. This helps you quickly determine whether a given
+ problem occurs in lxml code or Beautiful Soup code.
+
+ - htmlparser_trace(data) is the same thing, but for Python's
+ built-in HTMLParser class.
+
+* In an HTML document, the contents of a <script> or <style> tag will
+ no longer undergo entity substitution by default. XML documents work
+ the same way they did before. [bug=1085953]
+
+* Methods like get_text() and properties like .strings now only give
+ you strings that are visible in the document--no comments or
+ processing commands. [bug=1050164]
+
+* The prettify() method now leaves the contents of <pre> tags
+ alone. [bug=1095654]
+
+* Fix a bug in the html5lib treebuilder which sometimes created
+ disconnected trees. [bug=1039527]
+
+* Fix a bug in the lxml treebuilder which crashed when a tag included
+ an attribute from the predefined "xml:" namespace. [bug=1065617]
+
+* Fix a bug by which keyword arguments to find_parent() were not
+ being passed on. [bug=1126734]
+
+* Stop a crash when unwisely messing with a tag that's been
+ decomposed. [bug=1097699]
+
+* Now that lxml's segfault on invalid doctype has been fixed, fixed a
+ corresponding problem on the Beautiful Soup end that was previously
+ invisible. [bug=984936]
+
+* Fixed an exception when an overspecified CSS selector didn't match
+ anything. Code by Stefaan Lippens. [bug=1168167]
+
+= 4.1.3 (20120820) =
+
+* Skipped a test under Python 2.6 and Python 3.1 to avoid a spurious
+ test failure caused by the lousy HTMLParser in those
+ versions. [bug=1038503]
+
+* Raise a more specific error (FeatureNotFound) when a requested
+ parser or parser feature is not installed. Raise NotImplementedError
+ instead of ValueError when the user calls insert_before() or
+ insert_after() on the BeautifulSoup object itself. Patch by Aaron
+ Devore. [bug=1038301]
+
+= 4.1.2 (20120817) =
+
+* As per PEP-8, allow searching by CSS class using the 'class_'
+ keyword argument. [bug=1037624]
+
+* Display namespace prefixes for namespaced attribute names, instead of
+ the fully-qualified names given by the lxml parser. [bug=1037597]
+
+* Fixed a crash on encoding when an attribute name contained
+ non-ASCII characters.
+
+* When sniffing encodings, if the cchardet library is installed,
+ Beautiful Soup uses it instead of chardet. cchardet is much
+ faster. [bug=1020748]
+
+* Use logging.warning() instead of warning.warn() to notify the user
+ that characters were replaced with REPLACEMENT
+ CHARACTER. [bug=1013862]
+
+= 4.1.1 (20120703) =
+
+* Fixed an html5lib tree builder crash which happened when html5lib
+ moved a tag with a multivalued attribute from one part of the tree
+ to another. [bug=1019603]
+
+* Correctly display closing tags with an XML namespace declared. Patch
+ by Andreas Kostyrka. [bug=1019635]
+
+* Fixed a typo that made parsing significantly slower than it should
+ have been, and also waited too long to close tags with XML
+ namespaces. [bug=1020268]
+
+* get_text() now returns an empty Unicode string if there is no text,
+ rather than an empty bytestring. [bug=1020387]
+
+= 4.1.0 (20120529) =
+
+* Added experimental support for fixing Windows-1252 characters
+ embedded in UTF-8 documents. (UnicodeDammit.detwingle())
+
+* Fixed the handling of &quot; with the built-in parser. [bug=993871]
+
+* Comments, processing instructions, document type declarations, and
+ markup declarations are now treated as preformatted strings, the way
+ CData blocks are. [bug=1001025]
+
+* Fixed a bug with the lxml treebuilder that prevented the user from
+ adding attributes to a tag that didn't originally have
+ attributes. [bug=1002378] Thanks to Oliver Beattie for the patch.
+
+* Fixed some edge-case bugs having to do with inserting an element
+ into a tag it's already inside, and replacing one of a tag's
+ children with another. [bug=997529]
+
+* Added the ability to search for attribute values specified in UTF-8. [bug=1003974]
+
+ This caused a major refactoring of the search code. All the tests
+ pass, but it's possible that some searches will behave differently.
+
+= 4.0.5 (20120427) =
+
+* Added a new method, wrap(), which wraps an element in a tag.
+
+* Renamed replace_with_children() to unwrap(), which is easier to
+ understand and also the jQuery name of the function.
+
+* Made encoding substitution in <meta> tags completely transparent (no
+ more %SOUP-ENCODING%).
+
+* Fixed a bug in decoding data that contained a byte-order mark, such
+ as data encoded in UTF-16LE. [bug=988980]
+
+* Fixed a bug that made the HTMLParser treebuilder generate XML
+ definitions ending with two question marks instead of
+ one. [bug=984258]
+
+* Upon document generation, CData objects are no longer run through
+ the formatter. [bug=988905]
+
+* The test suite now passes when lxml is not installed, whether or not
+ html5lib is installed. [bug=987004]
+
+* Print a warning on HTMLParseErrors to let people know they should
+ install a better parser library.
+
+= 4.0.4 (20120416) =
+
+* Fixed a bug that sometimes created disconnected trees.
+
+* Fixed a bug with the string setter that moved a string around the
+ tree instead of copying it. [bug=983050]
+
+* Attribute values are now run through the provided output formatter.
+ Previously they were always run through the 'minimal' formatter. In
+ the future I may make it possible to specify different formatters
+ for attribute values and strings, but for now, consistent behavior
+ is better than inconsistent behavior. [bug=980237]
+
+* Added the missing renderContents method from Beautiful Soup 3. Also
+ added an encode_contents() method to go along with decode_contents().
+
+* Give a more useful error when the user tries to run the Python 2
+ version of BS under Python 3.
+
+* UnicodeDammit can now convert Microsoft smart quotes to ASCII with
+ UnicodeDammit(markup, smart_quotes_to="ascii").
+
+= 4.0.3 (20120403) =
+
+* Fixed a typo that caused some versions of Python 3 to convert the
+ Beautiful Soup codebase incorrectly.
+
+* Got rid of the 4.0.2 workaround for HTML documents--it was
+ unnecessary and the workaround was triggering a (possibly different,
+ but related) bug in lxml. [bug=972466]
+
+= 4.0.2 (20120326) =
+
+* Worked around a possible bug in lxml that prevents non-tiny XML
+ documents from being parsed. [bug=963880, bug=963936]
+
+* Fixed a bug where specifying `text` while also searching for a tag
+ only worked if `text` wanted an exact string match. [bug=955942]
+
+= 4.0.1 (20120314) =
+
+* This is the first official release of Beautiful Soup 4. There is no
+ 4.0.0 release, to eliminate any possibility that packaging software
+ might treat "4.0.0" as being an earlier version than "4.0.0b10".
+
+* Brought BS up to date with the latest release of soupselect, adding
+ CSS selector support for direct descendant matches and multiple CSS
+ class matches.
+
+= 4.0.0b10 (20120302) =
+
+* Added support for simple CSS selectors, taken from the soupselect project.
+
+* Fixed a crash when using html5lib. [bug=943246]
+
+* In HTML5-style <meta charset="foo"> tags, the value of the "charset"
+ attribute is now replaced with the appropriate encoding on
+ output. [bug=942714]
+
+* Fixed a bug that caused calling a tag to sometimes call find_all()
+ with the wrong arguments. [bug=944426]
+
+* For backwards compatibility, brought back the BeautifulStoneSoup
+ class as a deprecated wrapper around BeautifulSoup.
+
+= 4.0.0b9 (20120228) =
+
+* Fixed the string representation of DOCTYPEs that have both a public
+ ID and a system ID.
+
+* Fixed the generated XML declaration.
+
+* Renamed Tag.nsprefix to Tag.prefix, for consistency with
+ NamespacedAttribute.
+
+* Fixed a test failure that occured on Python 3.x when chardet was
+ installed.
+
+* Made prettify() return Unicode by default, so it will look nice on
+ Python 3 when passed into print().
+
+= 4.0.0b8 (20120224) =
+
+* All tree builders now preserve namespace information in the
+ documents they parse. If you use the html5lib parser or lxml's XML
+ parser, you can access the namespace URL for a tag as tag.namespace.
+
+ However, there is no special support for namespace-oriented
+ searching or tree manipulation. When you search the tree, you need
+ to use namespace prefixes exactly as they're used in the original
+ document.
+
+* The string representation of a DOCTYPE always ends in a newline.
+
+* Issue a warning if the user tries to use a SoupStrainer in
+ conjunction with the html5lib tree builder, which doesn't support
+ them.
+
+= 4.0.0b7 (20120223) =
+
+* Upon decoding to string, any characters that can't be represented in
+ your chosen encoding will be converted into numeric XML entity
+ references.
+
+* Issue a warning if characters were replaced with REPLACEMENT
+ CHARACTER during Unicode conversion.
+
+* Restored compatibility with Python 2.6.
+
+* The install process no longer installs docs or auxillary text files.
+
+* It's now possible to deepcopy a BeautifulSoup object created with
+ Python's built-in HTML parser.
+
+* About 100 unit tests that "test" the behavior of various parsers on
+ invalid markup have been removed. Legitimate changes to those
+ parsers caused these tests to fail, indicating that perhaps
+ Beautiful Soup should not test the behavior of foreign
+ libraries.
+
+ The problematic unit tests have been reformulated as informational
+ comparisons generated by the script
+ scripts/demonstrate_parser_differences.py.
+
+ This makes Beautiful Soup compatible with html5lib version 0.95 and
+ future versions of HTMLParser.
+
+= 4.0.0b6 (20120216) =
+
+* Multi-valued attributes like "class" always have a list of values,
+ even if there's only one value in the list.
+
+* Added a number of multi-valued attributes defined in HTML5.
+
+* Stopped generating a space before the slash that closes an
+ empty-element tag. This may come back if I add a special XHTML mode
+ (http://www.w3.org/TR/xhtml1/#C_2), but right now it's pretty
+ useless.
+
+* Passing text along with tag-specific arguments to a find* method:
+
+ find("a", text="Click here")
+
+ will find tags that contain the given text as their
+ .string. Previously, the tag-specific arguments were ignored and
+ only strings were searched.
+
+* Fixed a bug that caused the html5lib tree builder to build a
+ partially disconnected tree. Generally cleaned up the html5lib tree
+ builder.
+
+* If you restrict a multi-valued attribute like "class" to a string
+ that contains spaces, Beautiful Soup will only consider it a match
+ if the values correspond to that specific string.
+
+= 4.0.0b5 (20120209) =
+
+* Rationalized Beautiful Soup's treatment of CSS class. A tag
+ belonging to multiple CSS classes is treated as having a list of
+ values for the 'class' attribute. Searching for a CSS class will
+ match *any* of the CSS classes.
+
+ This actually affects all attributes that the HTML standard defines
+ as taking multiple values (class, rel, rev, archive, accept-charset,
+ and headers), but 'class' is by far the most common. [bug=41034]
+
+* If you pass anything other than a dictionary as the second argument
+ to one of the find* methods, it'll assume you want to use that
+ object to search against a tag's CSS classes. Previously this only
+ worked if you passed in a string.
+
+* Fixed a bug that caused a crash when you passed a dictionary as an
+ attribute value (possibly because you mistyped "attrs"). [bug=842419]
+
+* Unicode, Dammit now detects the encoding in HTML 5-style <meta> tags
+ like <meta charset="utf-8" />. [bug=837268]
+
+* If Unicode, Dammit can't figure out a consistent encoding for a
+ page, it will try each of its guesses again, with errors="replace"
+ instead of errors="strict". This may mean that some data gets
+ replaced with REPLACEMENT CHARACTER, but at least most of it will
+ get turned into Unicode. [bug=754903]
+
+* Patched over a bug in html5lib (?) that was crashing Beautiful Soup
+ on certain kinds of markup. [bug=838800]
+
+* Fixed a bug that wrecked the tree if you replaced an element with an
+ empty string. [bug=728697]
+
+* Improved Unicode, Dammit's behavior when you give it Unicode to
+ begin with.
+
+= 4.0.0b4 (20120208) =
+
+* Added BeautifulSoup.new_string() to go along with BeautifulSoup.new_tag()
+
+* BeautifulSoup.new_tag() will follow the rules of whatever
+ tree-builder was used to create the original BeautifulSoup object. A
+ new <p> tag will look like "<p />" if the soup object was created to
+ parse XML, but it will look like "<p></p>" if the soup object was
+ created to parse HTML.
+
+* We pass in strict=False to html.parser on Python 3, greatly
+ improving html.parser's ability to handle bad HTML.
+
+* We also monkeypatch a serious bug in html.parser that made
+ strict=False disastrous on Python 3.2.2.
+
+* Replaced the "substitute_html_entities" argument with the
+ more general "formatter" argument.
+
+* Bare ampersands and angle brackets are always converted to XML
+ entities unless the user prevents it.
+
+* Added PageElement.insert_before() and PageElement.insert_after(),
+ which let you put an element into the parse tree with respect to
+ some other element.
+
+* Raise an exception when the user tries to do something nonsensical
+ like insert a tag into itself.
+
+
+= 4.0.0b3 (20120203) =
+
+Beautiful Soup 4 is a nearly-complete rewrite that removes Beautiful
+Soup's custom HTML parser in favor of a system that lets you write a
+little glue code and plug in any HTML or XML parser you want.
+
+Beautiful Soup 4.0 comes with glue code for four parsers:
+
+ * Python's standard HTMLParser (html.parser in Python 3)
+ * lxml's HTML and XML parsers
+ * html5lib's HTML parser
+
+HTMLParser is the default, but I recommend you install lxml if you
+can.
+
+For complete documentation, see the Sphinx documentation in
+bs4/doc/source/. What follows is a summary of the changes from
+Beautiful Soup 3.
+
+=== The module name has changed ===
+
+Previously you imported the BeautifulSoup class from a module also
+called BeautifulSoup. To save keystrokes and make it clear which
+version of the API is in use, the module is now called 'bs4':
+
+ >>> from bs4 import BeautifulSoup
+
+=== It works with Python 3 ===
+
+Beautiful Soup 3.1.0 worked with Python 3, but the parser it used was
+so bad that it barely worked at all. Beautiful Soup 4 works with
+Python 3, and since its parser is pluggable, you don't sacrifice
+quality.
+
+Special thanks to Thomas Kluyver and Ezio Melotti for getting Python 3
+support to the finish line. Ezio Melotti is also to thank for greatly
+improving the HTML parser that comes with Python 3.2.
+
+=== CDATA sections are normal text, if they're understood at all. ===
+
+Currently, the lxml and html5lib HTML parsers ignore CDATA sections in
+markup:
+
+ <p><![CDATA[foo]]></p> => <p></p>
+
+A future version of html5lib will turn CDATA sections into text nodes,
+but only within tags like <svg> and <math>:
+
+ <svg><![CDATA[foo]]></svg> => <p>foo</p>
+
+The default XML parser (which uses lxml behind the scenes) turns CDATA
+sections into ordinary text elements:
+
+ <p><![CDATA[foo]]></p> => <p>foo</p>
+
+In theory it's possible to preserve the CDATA sections when using the
+XML parser, but I don't see how to get it to work in practice.
+
+=== Miscellaneous other stuff ===
+
+If the BeautifulSoup instance has .is_xml set to True, an appropriate
+XML declaration will be emitted when the tree is transformed into a
+string:
+
+ <?xml version="1.0" encoding="utf-8">
+ <markup>
+ ...
+ </markup>
+
+The ['lxml', 'xml'] tree builder sets .is_xml to True; the other tree
+builders set it to False. If you want to parse XHTML with an HTML
+parser, you can set it manually.
+
+
+= 3.2.0 =
+
+The 3.1 series wasn't very useful, so I renamed the 3.0 series to 3.2
+to make it obvious which one you should use.
+
+= 3.1.0 =
+
+A hybrid version that supports 2.4 and can be automatically converted
+to run under Python 3.0. There are three backwards-incompatible
+changes you should be aware of, but no new features or deliberate
+behavior changes.
+
+1. str() may no longer do what you want. This is because the meaning
+of str() inverts between Python 2 and 3; in Python 2 it gives you a
+byte string, in Python 3 it gives you a Unicode string.
+
+The effect of this is that you can't pass an encoding to .__str__
+anymore. Use encode() to get a string and decode() to get Unicode, and
+you'll be ready (well, readier) for Python 3.
+
+2. Beautiful Soup is now based on HTMLParser rather than SGMLParser,
+which is gone in Python 3. There's some bad HTML that SGMLParser
+handled but HTMLParser doesn't, usually to do with attribute values
+that aren't closed or have brackets inside them:
+
+ <a href="foo</a>, </a><a href="bar">baz</a>
+ <a b="<a>">', '<a b="&lt;a&gt;"></a><a>"></a>
+
+A later version of Beautiful Soup will allow you to plug in different
+parsers to make tradeoffs between speed and the ability to handle bad
+HTML.
+
+3. In Python 3 (but not Python 2), HTMLParser converts entities within
+attributes to the corresponding Unicode characters. In Python 2 it's
+possible to parse this string and leave the &eacute; intact.
+
+ <a href="http://crummy.com?sacr&eacute;&bleu">
+
+In Python 3, the &eacute; is always converted to \xe9 during
+parsing.
+
+
+= 3.0.7a =
+
+Added an import that makes BS work in Python 2.3.
+
+
+= 3.0.7 =
+
+Fixed a UnicodeDecodeError when unpickling documents that contain
+non-ASCII characters.
+
+Fixed a TypeError that occured in some circumstances when a tag
+contained no text.
+
+Jump through hoops to avoid the use of chardet, which can be extremely
+slow in some circumstances. UTF-8 documents should never trigger the
+use of chardet.
+
+Whitespace is preserved inside <pre> and <textarea> tags that contain
+nothing but whitespace.
+
+Beautiful Soup can now parse a doctype that's scoped to an XML namespace.
+
+
+= 3.0.6 =
+
+Got rid of a very old debug line that prevented chardet from working.
+
+Added a Tag.decompose() method that completely disconnects a tree or a
+subset of a tree, breaking it up into bite-sized pieces that are
+easy for the garbage collecter to collect.
+
+Tag.extract() now returns the tag that was extracted.
+
+Tag.findNext() now does something with the keyword arguments you pass
+it instead of dropping them on the floor.
+
+Fixed a Unicode conversion bug.
+
+Fixed a bug that garbled some <meta> tags when rewriting them.
+
+
+= 3.0.5 =
+
+Soup objects can now be pickled, and copied with copy.deepcopy.
+
+Tag.append now works properly on existing BS objects. (It wasn't
+originally intended for outside use, but it can be now.) (Giles
+Radford)
+
+Passing in a nonexistent encoding will no longer crash the parser on
+Python 2.4 (John Nagle).
+
+Fixed an underlying bug in SGMLParser that thinks ASCII has 255
+characters instead of 127 (John Nagle).
+
+Entities are converted more consistently to Unicode characters.
+
+Entity references in attribute values are now converted to Unicode
+characters when appropriate. Numeric entities are always converted,
+because SGMLParser always converts them outside of attribute values.
+
+ALL_ENTITIES happens to just be the XHTML entities, so I renamed it to
+XHTML_ENTITIES.
+
+The regular expression for bare ampersands was too loose. In some
+cases ampersands were not being escaped. (Sam Ruby?)
+
+Non-breaking spaces and other special Unicode space characters are no
+longer folded to ASCII spaces. (Robert Leftwich)
+
+Information inside a TEXTAREA tag is now parsed literally, not as HTML
+tags. TEXTAREA now works exactly the same way as SCRIPT. (Zephyr Fang)
+
+= 3.0.4 =
+
+Fixed a bug that crashed Unicode conversion in some cases.
+
+Fixed a bug that prevented UnicodeDammit from being used as a
+general-purpose data scrubber.
+
+Fixed some unit test failures when running against Python 2.5.
+
+When considering whether to convert smart quotes, UnicodeDammit now
+looks at the original encoding in a case-insensitive way.
+
+= 3.0.3 (20060606) =
+
+Beautiful Soup is now usable as a way to clean up invalid XML/HTML (be
+sure to pass in an appropriate value for convertEntities, or XML/HTML
+entities might stick around that aren't valid in HTML/XML). The result
+may not validate, but it should be good enough to not choke a
+real-world XML parser. Specifically, the output of a properly
+constructed soup object should always be valid as part of an XML
+document, but parts may be missing if they were missing in the
+original. As always, if the input is valid XML, the output will also
+be valid.
+
+= 3.0.2 (20060602) =
+
+Previously, Beautiful Soup correctly handled attribute values that
+contained embedded quotes (sometimes by escaping), but not other kinds
+of XML character. Now, it correctly handles or escapes all special XML
+characters in attribute values.
+
+I aliased methods to the 2.x names (fetch, find, findText, etc.) for
+backwards compatibility purposes. Those names are deprecated and if I
+ever do a 4.0 I will remove them. I will, I tell you!
+
+Fixed a bug where the findAll method wasn't passing along any keyword
+arguments.
+
+When run from the command line, Beautiful Soup now acts as an HTML
+pretty-printer, not an XML pretty-printer.
+
+= 3.0.1 (20060530) =
+
+Reintroduced the "fetch by CSS class" shortcut. I thought keyword
+arguments would replace it, but they don't. You can't call soup('a',
+class='foo') because class is a Python keyword.
+
+If Beautiful Soup encounters a meta tag that declares the encoding,
+but a SoupStrainer tells it not to parse that tag, Beautiful Soup will
+no longer try to rewrite the meta tag to mention the new
+encoding. Basically, this makes SoupStrainers work in real-world
+applications instead of crashing the parser.
+
+= 3.0.0 "Who would not give all else for two p" (20060528) =
+
+This release is not backward-compatible with previous releases. If
+you've got code written with a previous version of the library, go
+ahead and keep using it, unless one of the features mentioned here
+really makes your life easier. Since the library is self-contained,
+you can include an old copy of the library in your old applications,
+and use the new version for everything else.
+
+The documentation has been rewritten and greatly expanded with many
+more examples.
+
+Beautiful Soup autodetects the encoding of a document (or uses the one
+you specify), and converts it from its native encoding to
+Unicode. Internally, it only deals with Unicode strings. When you
+print out the document, it converts to UTF-8 (or another encoding you
+specify). [Doc reference]
+
+It's now easy to make large-scale changes to the parse tree without
+screwing up the navigation members. The methods are extract,
+replaceWith, and insert. [Doc reference. See also Improving Memory
+Usage with extract]
+
+Passing True in as an attribute value gives you tags that have any
+value for that attribute. You don't have to create a regular
+expression. Passing None for an attribute value gives you tags that
+don't have that attribute at all.
+
+Tag objects now know whether or not they're self-closing. This avoids
+the problem where Beautiful Soup thought that tags like <BR /> were
+self-closing even in XML documents. You can customize the self-closing
+tags for a parser object by passing them in as a list of
+selfClosingTags: you don't have to subclass anymore.
+
+There's a new built-in parser, MinimalSoup, which has most of
+BeautifulSoup's HTML-specific rules, but no tag nesting rules. [Doc
+reference]
+
+You can use a SoupStrainer to tell Beautiful Soup to parse only part
+of a document. This saves time and memory, often making Beautiful Soup
+about as fast as a custom-built SGMLParser subclass. [Doc reference,
+SoupStrainer reference]
+
+You can (usually) use keyword arguments instead of passing a
+dictionary of attributes to a search method. That is, you can replace
+soup(args={"id" : "5"}) with soup(id="5"). You can still use args if
+(for instance) you need to find an attribute whose name clashes with
+the name of an argument to findAll. [Doc reference: **kwargs attrs]
+
+The method names have changed to the better method names used in
+Rubyful Soup. Instead of find methods and fetch methods, there are
+only find methods. Instead of a scheme where you can't remember which
+method finds one element and which one finds them all, we have find
+and findAll. In general, if the method name mentions All or a plural
+noun (eg. findNextSiblings), then it finds many elements
+method. Otherwise, it only finds one element. [Doc reference]
+
+Some of the argument names have been renamed for clarity. For instance
+avoidParserProblems is now parserMassage.
+
+Beautiful Soup no longer implements a feed method. You need to pass a
+string or a filehandle into the soup constructor, not with feed after
+the soup has been created. There is still a feed method, but it's the
+feed method implemented by SGMLParser and calling it will bypass
+Beautiful Soup and cause problems.
+
+The NavigableText class has been renamed to NavigableString. There is
+no NavigableUnicodeString anymore, because every string inside a
+Beautiful Soup parse tree is a Unicode string.
+
+findText and fetchText are gone. Just pass a text argument into find
+or findAll.
+
+Null was more trouble than it was worth, so I got rid of it. Anything
+that used to return Null now returns None.
+
+Special XML constructs like comments and CDATA now have their own
+NavigableString subclasses, instead of being treated as oddly-formed
+data. If you parse a document that contains CDATA and write it back
+out, the CDATA will still be there.
+
+When you're parsing a document, you can get Beautiful Soup to convert
+XML or HTML entities into the corresponding Unicode characters. [Doc
+reference]
+
+= 2.1.1 (20050918) =
+
+Fixed a serious performance bug in BeautifulStoneSoup which was
+causing parsing to be incredibly slow.
+
+Corrected several entities that were previously being incorrectly
+translated from Microsoft smart-quote-like characters.
+
+Fixed a bug that was breaking text fetch.
+
+Fixed a bug that crashed the parser when text chunks that look like
+HTML tag names showed up within a SCRIPT tag.
+
+THEAD, TBODY, and TFOOT tags are now nestable within TABLE
+tags. Nested tables should parse more sensibly now.
+
+BASE is now considered a self-closing tag.
+
+= 2.1.0 "Game, or any other dish?" (20050504) =
+
+Added a wide variety of new search methods which, given a starting
+point inside the tree, follow a particular navigation member (like
+nextSibling) over and over again, looking for Tag and NavigableText
+objects that match certain criteria. The new methods are findNext,
+fetchNext, findPrevious, fetchPrevious, findNextSibling,
+fetchNextSiblings, findPreviousSibling, fetchPreviousSiblings,
+findParent, and fetchParents. All of these use the same basic code
+used by first and fetch, so you can pass your weird ways of matching
+things into these methods.
+
+The fetch method and its derivatives now accept a limit argument.
+
+You can now pass keyword arguments when calling a Tag object as though
+it were a method.
+
+Fixed a bug that caused all hand-created tags to share a single set of
+attributes.
+
+= 2.0.3 (20050501) =
+
+Fixed Python 2.2 support for iterators.
+
+Fixed a bug that gave the wrong representation to tags within quote
+tags like <script>.
+
+Took some code from Mark Pilgrim that treats CDATA declarations as
+data instead of ignoring them.
+
+Beautiful Soup's setup.py will now do an install even if the unit
+tests fail. It won't build a source distribution if the unit tests
+fail, so I can't release a new version unless they pass.
+
+= 2.0.2 (20050416) =
+
+Added the unit tests in a separate module, and packaged it with
+distutils.
+
+Fixed a bug that sometimes caused renderContents() to return a Unicode
+string even if there was no Unicode in the original string.
+
+Added the done() method, which closes all of the parser's open
+tags. It gets called automatically when you pass in some text to the
+constructor of a parser class; otherwise you must call it yourself.
+
+Reinstated some backwards compatibility with 1.x versions: referencing
+the string member of a NavigableText object returns the NavigableText
+object instead of throwing an error.
+
+= 2.0.1 (20050412) =
+
+Fixed a bug that caused bad results when you tried to reference a tag
+name shorter than 3 characters as a member of a Tag, eg. tag.table.td.
+
+Made sure all Tags have the 'hidden' attribute so that an attempt to
+access tag.hidden doesn't spawn an attempt to find a tag named
+'hidden'.
+
+Fixed a bug in the comparison operator.
+
+= 2.0.0 "Who cares for fish?" (20050410)
+
+Beautiful Soup version 1 was very useful but also pretty stupid. I
+originally wrote it without noticing any of the problems inherent in
+trying to build a parse tree out of ambiguous HTML tags. This version
+solves all of those problems to my satisfaction. It also adds many new
+clever things to make up for the removal of the stupid things.
+
+== Parsing ==
+
+The parser logic has been greatly improved, and the BeautifulSoup
+class should much more reliably yield a parse tree that looks like
+what the page author intended. For a particular class of odd edge
+cases that now causes problems, there is a new class,
+ICantBelieveItsBeautifulSoup.
+
+By default, Beautiful Soup now performs some cleanup operations on
+text before parsing it. This is to avoid common problems with bad
+definitions and self-closing tags that crash SGMLParser. You can
+provide your own set of cleanup operations, or turn it off
+altogether. The cleanup operations include fixing self-closing tags
+that don't close, and replacing Microsoft smart quotes and similar
+characters with their HTML entity equivalents.
+
+You can now get a pretty-print version of parsed HTML to get a visual
+picture of how Beautiful Soup parses it, with the Tag.prettify()
+method.
+
+== Strings and Unicode ==
+
+There are separate NavigableText subclasses for ASCII and Unicode
+strings. These classes directly subclass the corresponding base data
+types. This means you can treat NavigableText objects as strings
+instead of having to call methods on them to get the strings.
+
+str() on a Tag always returns a string, and unicode() always returns
+Unicode. Previously it was inconsistent.
+
+== Tree traversal ==
+
+In a first() or fetch() call, the tag name or the desired value of an
+attribute can now be any of the following:
+
+ * A string (matches that specific tag or that specific attribute value)
+ * A list of strings (matches any tag or attribute value in the list)
+ * A compiled regular expression object (matches any tag or attribute
+ value that matches the regular expression)
+ * A callable object that takes the Tag object or attribute value as a
+ string. It returns None/false/empty string if the given string
+ doesn't match, and any other value if it does.
+
+This is much easier to use than SQL-style wildcards (see, regular
+expressions are good for something). Because of this, I took out
+SQL-style wildcards. I'll put them back if someone complains, but
+their removal simplifies the code a lot.
+
+You can use fetch() and first() to search for text in the parse tree,
+not just tags. There are new alias methods fetchText() and firstText()
+designed for this purpose. As with searching for tags, you can pass in
+a string, a regular expression object, or a method to match your text.
+
+If you pass in something besides a map to the attrs argument of
+fetch() or first(), Beautiful Soup will assume you want to match that
+thing against the "class" attribute. When you're scraping
+well-structured HTML, this makes your code a lot cleaner.
+
+1.x and 2.x both let you call a Tag object as a shorthand for
+fetch(). For instance, foo("bar") is a shorthand for
+foo.fetch("bar"). In 2.x, you can also access a specially-named member
+of a Tag object as a shorthand for first(). For instance, foo.barTag
+is a shorthand for foo.first("bar"). By chaining these shortcuts you
+traverse a tree in very little code: for header in
+soup.bodyTag.pTag.tableTag('th'):
+
+If an element relationship (like parent or next) doesn't apply to a
+tag, it'll now show up Null instead of None. first() will also return
+Null if you ask it for a nonexistent tag. Null is an object that's
+just like None, except you can do whatever you want to it and it'll
+give you Null instead of throwing an error.
+
+This lets you do tree traversals like soup.htmlTag.headTag.titleTag
+without having to worry if the intermediate stages are actually
+there. Previously, if there was no 'head' tag in the document, headTag
+in that instance would have been None, and accessing its 'titleTag'
+member would have thrown an AttributeError. Now, you can get what you
+want when it exists, and get Null when it doesn't, without having to
+do a lot of conditionals checking to see if every stage is None.
+
+There are two new relations between page elements: previousSibling and
+nextSibling. They reference the previous and next element at the same
+level of the parse tree. For instance, if you have HTML like this:
+
+ <p><ul><li>Foo<br /><li>Bar</ul>
+
+The first 'li' tag has a previousSibling of Null and its nextSibling
+is the second 'li' tag. The second 'li' tag has a nextSibling of Null
+and its previousSibling is the first 'li' tag. The previousSibling of
+the 'ul' tag is the first 'p' tag. The nextSibling of 'Foo' is the
+'br' tag.
+
+I took out the ability to use fetch() to find tags that have a
+specific list of contents. See, I can't even explain it well. It was
+really difficult to use, I never used it, and I don't think anyone
+else ever used it. To the extent anyone did, they can probably use
+fetchText() instead. If it turns out someone needs it I'll think of
+another solution.
+
+== Tree manipulation ==
+
+You can add new attributes to a tag, and delete attributes from a
+tag. In 1.x you could only change a tag's existing attributes.
+
+== Porting Considerations ==
+
+There are three changes in 2.0 that break old code:
+
+In the post-1.2 release you could pass in a function into fetch(). The
+function took a string, the tag name. In 2.0, the function takes the
+actual Tag object.
+
+It's no longer to pass in SQL-style wildcards to fetch(). Use a
+regular expression instead.
+
+The different parsing algorithm means the parse tree may not be shaped
+like you expect. This will only actually affect you if your code uses
+one of the affected parts. I haven't run into this problem yet while
+porting my code.
+
+= Between 1.2 and 2.0 =
+
+This is the release to get if you want Python 1.5 compatibility.
+
+The desired value of an attribute can now be any of the following:
+
+ * A string
+ * A string with SQL-style wildcards
+ * A compiled RE object
+ * A callable that returns None/false/empty string if the given value
+ doesn't match, and any other value otherwise.
+
+This is much easier to use than SQL-style wildcards (see, regular
+expressions are good for something). Because of this, I no longer
+recommend you use SQL-style wildcards. They may go away in a future
+release to clean up the code.
+
+Made Beautiful Soup handle processing instructions as text instead of
+ignoring them.
+
+Applied patch from Richie Hindle (richie at entrian dot com) that
+makes tag.string a shorthand for tag.contents[0].string when the tag
+has only one string-owning child.
+
+Added still more nestable tags. The nestable tags thing won't work in
+a lot of cases and needs to be rethought.
+
+Fixed an edge case where searching for "%foo" would match any string
+shorter than "foo".
+
+= 1.2 "Who for such dainties would not stoop?" (20040708) =
+
+Applied patch from Ben Last (ben at benlast dot com) that made
+Tag.renderContents() correctly handle Unicode.
+
+Made BeautifulStoneSoup even dumber by making it not implicitly close
+a tag when another tag of the same type is encountered; only when an
+actual closing tag is encountered. This change courtesy of Fuzzy (mike
+at pcblokes dot com). BeautifulSoup still works as before.
+
+= 1.1 "Swimming in a hot tureen" =
+
+Added more 'nestable' tags. Changed popping semantics so that when a
+nestable tag is encountered, tags are popped up to the previously
+encountered nestable tag (of whatever kind). I will revert this if
+enough people complain, but it should make more people's lives easier
+than harder. This enhancement was suggested by Anthony Baxter (anthony
+at interlink dot com dot au).
+
+= 1.0 "So rich and green" (20040420) =
+
+Initial release.
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/PKG-INFO b/chromium/third_party/catapult/third_party/beautifulsoup4/PKG-INFO
new file mode 100644
index 00000000000..c9fbab8f8a4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/PKG-INFO
@@ -0,0 +1,20 @@
+Metadata-Version: 1.1
+Name: beautifulsoup4
+Version: 4.3.2
+Summary: UNKNOWN
+Home-page: http://www.crummy.com/software/BeautifulSoup/bs4/
+Author: Leonard Richardson
+Author-email: leonardr@segfault.org
+License: MIT
+Download-URL: http://www.crummy.com/software/BeautifulSoup/bs4/download/
+Description: Beautiful Soup sits atop an HTML or XML parser, providing Pythonic idioms for iterating, searching, and modifying the parse tree.
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Text Processing :: Markup :: HTML
+Classifier: Topic :: Text Processing :: Markup :: XML
+Classifier: Topic :: Text Processing :: Markup :: SGML
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/README.chromium b/chromium/third_party/catapult/third_party/beautifulsoup4/README.chromium
new file mode 100644
index 00000000000..0cb5289417f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/README.chromium
@@ -0,0 +1,11 @@
+Name: BeautifulSoup
+Short Name: bs4
+URL: http://www.crummy.com/software/BeautifulSoup/
+Version: 4.3.2
+License: MIT
+
+Description:
+Beautiful Soup is a library for HTML parsing.
+It's included in catapult because webtest depends on it.
+
+Local Modifications: None
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/README.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/README.txt
new file mode 100644
index 00000000000..305c51e05e3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/README.txt
@@ -0,0 +1,63 @@
+= Introduction =
+
+ >>> from bs4 import BeautifulSoup
+ >>> soup = BeautifulSoup("<p>Some<b>bad<i>HTML")
+ >>> print soup.prettify()
+ <html>
+ <body>
+ <p>
+ Some
+ <b>
+ bad
+ <i>
+ HTML
+ </i>
+ </b>
+ </p>
+ </body>
+ </html>
+ >>> soup.find(text="bad")
+ u'bad'
+
+ >>> soup.i
+ <i>HTML</i>
+
+ >>> soup = BeautifulSoup("<tag1>Some<tag2/>bad<tag3>XML", "xml")
+ >>> print soup.prettify()
+ <?xml version="1.0" encoding="utf-8">
+ <tag1>
+ Some
+ <tag2 />
+ bad
+ <tag3>
+ XML
+ </tag3>
+ </tag1>
+
+= Full documentation =
+
+The bs4/doc/ directory contains full documentation in Sphinx
+format. Run "make html" in that directory to create HTML
+documentation.
+
+= Running the unit tests =
+
+Beautiful Soup supports unit test discovery from the project root directory:
+
+ $ nosetests
+
+ $ python -m unittest discover -s bs4 # Python 2.7 and up
+
+If you checked out the source tree, you should see a script in the
+home directory called test-all-versions. This script will run the unit
+tests under Python 2.7, then create a temporary Python 3 conversion of
+the source and run the unit tests again under Python 3.
+
+= Links =
+
+Homepage: http://www.crummy.com/software/BeautifulSoup/bs4/
+Documentation: http://www.crummy.com/software/BeautifulSoup/bs4/doc/
+ http://readthedocs.org/docs/beautiful-soup-4/
+Discussion group: http://groups.google.com/group/beautifulsoup/
+Development: https://code.launchpad.net/beautifulsoup/
+Bug tracker: https://bugs.launchpad.net/beautifulsoup/
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/TODO.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/TODO.txt
new file mode 100644
index 00000000000..e26d6264dac
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/TODO.txt
@@ -0,0 +1,31 @@
+Additions
+---------
+
+More of the jQuery API: nextUntil?
+
+Optimizations
+-------------
+
+The html5lib tree builder doesn't use the standard tree-building API,
+which worries me and has resulted in a number of bugs.
+
+markup_attr_map can be optimized since it's always a map now.
+
+Upon encountering UTF-16LE data or some other uncommon serialization
+of Unicode, UnicodeDammit will convert the data to Unicode, then
+encode it at UTF-8. This is wasteful because it will just get decoded
+back to Unicode.
+
+CDATA
+-----
+
+The elementtree XMLParser has a strip_cdata argument that, when set to
+False, should allow Beautiful Soup to preserve CDATA sections instead
+of treating them as text. Except it doesn't. (This argument is also
+present for HTMLParser, and also does nothing there.)
+
+Currently, htm5lib converts CDATA sections into comments. An
+as-yet-unreleased version of html5lib changes the parser's handling of
+CDATA sections to allow CDATA sections in tags like <svg> and
+<math>. The HTML5TreeBuilder will need to be updated to create CData
+objects instead of Comment objects in this situation.
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/__init__.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/__init__.py
new file mode 100644
index 00000000000..7ba34269af7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/__init__.py
@@ -0,0 +1,406 @@
+"""Beautiful Soup
+Elixir and Tonic
+"The Screen-Scraper's Friend"
+http://www.crummy.com/software/BeautifulSoup/
+
+Beautiful Soup uses a pluggable XML or HTML parser to parse a
+(possibly invalid) document into a tree representation. Beautiful Soup
+provides provides methods and Pythonic idioms that make it easy to
+navigate, search, and modify the parse tree.
+
+Beautiful Soup works with Python 2.6 and up. It works better if lxml
+and/or html5lib is installed.
+
+For more than you ever wanted to know about Beautiful Soup, see the
+documentation:
+http://www.crummy.com/software/BeautifulSoup/bs4/doc/
+"""
+
+__author__ = "Leonard Richardson (leonardr@segfault.org)"
+__version__ = "4.3.2"
+__copyright__ = "Copyright (c) 2004-2013 Leonard Richardson"
+__license__ = "MIT"
+
+__all__ = ['BeautifulSoup']
+
+import os
+import re
+import warnings
+
+from .builder import builder_registry, ParserRejectedMarkup
+from .dammit import UnicodeDammit
+from .element import (
+ CData,
+ Comment,
+ DEFAULT_OUTPUT_ENCODING,
+ Declaration,
+ Doctype,
+ NavigableString,
+ PageElement,
+ ProcessingInstruction,
+ ResultSet,
+ SoupStrainer,
+ Tag,
+ )
+
+# The very first thing we do is give a useful error if someone is
+# running this code under Python 3 without converting it.
+syntax_error = u'You are trying to run the Python 2 version of Beautiful Soup under Python 3. This will not work. You need to convert the code, either by installing it (`python setup.py install`) or by running 2to3 (`2to3 -w bs4`).'
+
+class BeautifulSoup(Tag):
+ """
+ This class defines the basic interface called by the tree builders.
+
+ These methods will be called by the parser:
+ reset()
+ feed(markup)
+
+ The tree builder may call these methods from its feed() implementation:
+ handle_starttag(name, attrs) # See note about return value
+ handle_endtag(name)
+ handle_data(data) # Appends to the current data node
+ endData(containerClass=NavigableString) # Ends the current data node
+
+ No matter how complicated the underlying parser is, you should be
+ able to build a tree using 'start tag' events, 'end tag' events,
+ 'data' events, and "done with data" events.
+
+ If you encounter an empty-element tag (aka a self-closing tag,
+ like HTML's <br> tag), call handle_starttag and then
+ handle_endtag.
+ """
+ ROOT_TAG_NAME = u'[document]'
+
+ # If the end-user gives no indication which tree builder they
+ # want, look for one with these features.
+ DEFAULT_BUILDER_FEATURES = ['html', 'fast']
+
+ ASCII_SPACES = '\x20\x0a\x09\x0c\x0d'
+
+ def __init__(self, markup="", features=None, builder=None,
+ parse_only=None, from_encoding=None, **kwargs):
+ """The Soup object is initialized as the 'root tag', and the
+ provided markup (which can be a string or a file-like object)
+ is fed into the underlying parser."""
+
+ if 'convertEntities' in kwargs:
+ warnings.warn(
+ "BS4 does not respect the convertEntities argument to the "
+ "BeautifulSoup constructor. Entities are always converted "
+ "to Unicode characters.")
+
+ if 'markupMassage' in kwargs:
+ del kwargs['markupMassage']
+ warnings.warn(
+ "BS4 does not respect the markupMassage argument to the "
+ "BeautifulSoup constructor. The tree builder is responsible "
+ "for any necessary markup massage.")
+
+ if 'smartQuotesTo' in kwargs:
+ del kwargs['smartQuotesTo']
+ warnings.warn(
+ "BS4 does not respect the smartQuotesTo argument to the "
+ "BeautifulSoup constructor. Smart quotes are always converted "
+ "to Unicode characters.")
+
+ if 'selfClosingTags' in kwargs:
+ del kwargs['selfClosingTags']
+ warnings.warn(
+ "BS4 does not respect the selfClosingTags argument to the "
+ "BeautifulSoup constructor. The tree builder is responsible "
+ "for understanding self-closing tags.")
+
+ if 'isHTML' in kwargs:
+ del kwargs['isHTML']
+ warnings.warn(
+ "BS4 does not respect the isHTML argument to the "
+ "BeautifulSoup constructor. You can pass in features='html' "
+ "or features='xml' to get a builder capable of handling "
+ "one or the other.")
+
+ def deprecated_argument(old_name, new_name):
+ if old_name in kwargs:
+ warnings.warn(
+ 'The "%s" argument to the BeautifulSoup constructor '
+ 'has been renamed to "%s."' % (old_name, new_name))
+ value = kwargs[old_name]
+ del kwargs[old_name]
+ return value
+ return None
+
+ parse_only = parse_only or deprecated_argument(
+ "parseOnlyThese", "parse_only")
+
+ from_encoding = from_encoding or deprecated_argument(
+ "fromEncoding", "from_encoding")
+
+ if len(kwargs) > 0:
+ arg = kwargs.keys().pop()
+ raise TypeError(
+ "__init__() got an unexpected keyword argument '%s'" % arg)
+
+ if builder is None:
+ if isinstance(features, basestring):
+ features = [features]
+ if features is None or len(features) == 0:
+ features = self.DEFAULT_BUILDER_FEATURES
+ builder_class = builder_registry.lookup(*features)
+ if builder_class is None:
+ raise FeatureNotFound(
+ "Couldn't find a tree builder with the features you "
+ "requested: %s. Do you need to install a parser library?"
+ % ",".join(features))
+ builder = builder_class()
+ self.builder = builder
+ self.is_xml = builder.is_xml
+ self.builder.soup = self
+
+ self.parse_only = parse_only
+
+ if hasattr(markup, 'read'): # It's a file-type object.
+ markup = markup.read()
+ elif len(markup) <= 256:
+ # Print out warnings for a couple beginner problems
+ # involving passing non-markup to Beautiful Soup.
+ # Beautiful Soup will still parse the input as markup,
+ # just in case that's what the user really wants.
+ if (isinstance(markup, unicode)
+ and not os.path.supports_unicode_filenames):
+ possible_filename = markup.encode("utf8")
+ else:
+ possible_filename = markup
+ is_file = False
+ try:
+ is_file = os.path.exists(possible_filename)
+ except Exception, e:
+ # This is almost certainly a problem involving
+ # characters not valid in filenames on this
+ # system. Just let it go.
+ pass
+ if is_file:
+ warnings.warn(
+ '"%s" looks like a filename, not markup. You should probably open this file and pass the filehandle into Beautiful Soup.' % markup)
+ if markup[:5] == "http:" or markup[:6] == "https:":
+ # TODO: This is ugly but I couldn't get it to work in
+ # Python 3 otherwise.
+ if ((isinstance(markup, bytes) and not b' ' in markup)
+ or (isinstance(markup, unicode) and not u' ' in markup)):
+ warnings.warn(
+ '"%s" looks like a URL. Beautiful Soup is not an HTTP client. You should probably use an HTTP client to get the document behind the URL, and feed that document to Beautiful Soup.' % markup)
+
+ for (self.markup, self.original_encoding, self.declared_html_encoding,
+ self.contains_replacement_characters) in (
+ self.builder.prepare_markup(markup, from_encoding)):
+ self.reset()
+ try:
+ self._feed()
+ break
+ except ParserRejectedMarkup:
+ pass
+
+ # Clear out the markup and remove the builder's circular
+ # reference to this object.
+ self.markup = None
+ self.builder.soup = None
+
+ def _feed(self):
+ # Convert the document to Unicode.
+ self.builder.reset()
+
+ self.builder.feed(self.markup)
+ # Close out any unfinished strings and close all the open tags.
+ self.endData()
+ while self.currentTag.name != self.ROOT_TAG_NAME:
+ self.popTag()
+
+ def reset(self):
+ Tag.__init__(self, self, self.builder, self.ROOT_TAG_NAME)
+ self.hidden = 1
+ self.builder.reset()
+ self.current_data = []
+ self.currentTag = None
+ self.tagStack = []
+ self.preserve_whitespace_tag_stack = []
+ self.pushTag(self)
+
+ def new_tag(self, name, namespace=None, nsprefix=None, **attrs):
+ """Create a new tag associated with this soup."""
+ return Tag(None, self.builder, name, namespace, nsprefix, attrs)
+
+ def new_string(self, s, subclass=NavigableString):
+ """Create a new NavigableString associated with this soup."""
+ navigable = subclass(s)
+ navigable.setup()
+ return navigable
+
+ def insert_before(self, successor):
+ raise NotImplementedError("BeautifulSoup objects don't support insert_before().")
+
+ def insert_after(self, successor):
+ raise NotImplementedError("BeautifulSoup objects don't support insert_after().")
+
+ def popTag(self):
+ tag = self.tagStack.pop()
+ if self.preserve_whitespace_tag_stack and tag == self.preserve_whitespace_tag_stack[-1]:
+ self.preserve_whitespace_tag_stack.pop()
+ #print "Pop", tag.name
+ if self.tagStack:
+ self.currentTag = self.tagStack[-1]
+ return self.currentTag
+
+ def pushTag(self, tag):
+ #print "Push", tag.name
+ if self.currentTag:
+ self.currentTag.contents.append(tag)
+ self.tagStack.append(tag)
+ self.currentTag = self.tagStack[-1]
+ if tag.name in self.builder.preserve_whitespace_tags:
+ self.preserve_whitespace_tag_stack.append(tag)
+
+ def endData(self, containerClass=NavigableString):
+ if self.current_data:
+ current_data = u''.join(self.current_data)
+ # If whitespace is not preserved, and this string contains
+ # nothing but ASCII spaces, replace it with a single space
+ # or newline.
+ if not self.preserve_whitespace_tag_stack:
+ strippable = True
+ for i in current_data:
+ if i not in self.ASCII_SPACES:
+ strippable = False
+ break
+ if strippable:
+ if '\n' in current_data:
+ current_data = '\n'
+ else:
+ current_data = ' '
+
+ # Reset the data collector.
+ self.current_data = []
+
+ # Should we add this string to the tree at all?
+ if self.parse_only and len(self.tagStack) <= 1 and \
+ (not self.parse_only.text or \
+ not self.parse_only.search(current_data)):
+ return
+
+ o = containerClass(current_data)
+ self.object_was_parsed(o)
+
+ def object_was_parsed(self, o, parent=None, most_recent_element=None):
+ """Add an object to the parse tree."""
+ parent = parent or self.currentTag
+ most_recent_element = most_recent_element or self._most_recent_element
+ o.setup(parent, most_recent_element)
+
+ if most_recent_element is not None:
+ most_recent_element.next_element = o
+ self._most_recent_element = o
+ parent.contents.append(o)
+
+ def _popToTag(self, name, nsprefix=None, inclusivePop=True):
+ """Pops the tag stack up to and including the most recent
+ instance of the given tag. If inclusivePop is false, pops the tag
+ stack up to but *not* including the most recent instqance of
+ the given tag."""
+ #print "Popping to %s" % name
+ if name == self.ROOT_TAG_NAME:
+ # The BeautifulSoup object itself can never be popped.
+ return
+
+ most_recently_popped = None
+
+ stack_size = len(self.tagStack)
+ for i in range(stack_size - 1, 0, -1):
+ t = self.tagStack[i]
+ if (name == t.name and nsprefix == t.prefix):
+ if inclusivePop:
+ most_recently_popped = self.popTag()
+ break
+ most_recently_popped = self.popTag()
+
+ return most_recently_popped
+
+ def handle_starttag(self, name, namespace, nsprefix, attrs):
+ """Push a start tag on to the stack.
+
+ If this method returns None, the tag was rejected by the
+ SoupStrainer. You should proceed as if the tag had not occured
+ in the document. For instance, if this was a self-closing tag,
+ don't call handle_endtag.
+ """
+
+ # print "Start tag %s: %s" % (name, attrs)
+ self.endData()
+
+ if (self.parse_only and len(self.tagStack) <= 1
+ and (self.parse_only.text
+ or not self.parse_only.search_tag(name, attrs))):
+ return None
+
+ tag = Tag(self, self.builder, name, namespace, nsprefix, attrs,
+ self.currentTag, self._most_recent_element)
+ if tag is None:
+ return tag
+ if self._most_recent_element:
+ self._most_recent_element.next_element = tag
+ self._most_recent_element = tag
+ self.pushTag(tag)
+ return tag
+
+ def handle_endtag(self, name, nsprefix=None):
+ #print "End tag: " + name
+ self.endData()
+ self._popToTag(name, nsprefix)
+
+ def handle_data(self, data):
+ self.current_data.append(data)
+
+ def decode(self, pretty_print=False,
+ eventual_encoding=DEFAULT_OUTPUT_ENCODING,
+ formatter="minimal"):
+ """Returns a string or Unicode representation of this document.
+ To get Unicode, pass None for encoding."""
+
+ if self.is_xml:
+ # Print the XML declaration
+ encoding_part = ''
+ if eventual_encoding != None:
+ encoding_part = ' encoding="%s"' % eventual_encoding
+ prefix = u'<?xml version="1.0"%s?>\n' % encoding_part
+ else:
+ prefix = u''
+ if not pretty_print:
+ indent_level = None
+ else:
+ indent_level = 0
+ return prefix + super(BeautifulSoup, self).decode(
+ indent_level, eventual_encoding, formatter)
+
+# Alias to make it easier to type import: 'from bs4 import _soup'
+_s = BeautifulSoup
+_soup = BeautifulSoup
+
+class BeautifulStoneSoup(BeautifulSoup):
+ """Deprecated interface to an XML parser."""
+
+ def __init__(self, *args, **kwargs):
+ kwargs['features'] = 'xml'
+ warnings.warn(
+ 'The BeautifulStoneSoup class is deprecated. Instead of using '
+ 'it, pass features="xml" into the BeautifulSoup constructor.')
+ super(BeautifulStoneSoup, self).__init__(*args, **kwargs)
+
+
+class StopParsing(Exception):
+ pass
+
+class FeatureNotFound(ValueError):
+ pass
+
+
+#By default, act as an HTML pretty-printer.
+if __name__ == '__main__':
+ import sys
+ soup = BeautifulSoup(sys.stdin)
+ print soup.prettify()
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/__init__.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/__init__.py
new file mode 100644
index 00000000000..740f5f29cd7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/__init__.py
@@ -0,0 +1,321 @@
+from collections import defaultdict
+import itertools
+import sys
+from bs4.element import (
+ CharsetMetaAttributeValue,
+ ContentMetaAttributeValue,
+ whitespace_re
+ )
+
+__all__ = [
+ 'HTMLTreeBuilder',
+ 'SAXTreeBuilder',
+ 'TreeBuilder',
+ 'TreeBuilderRegistry',
+ ]
+
+# Some useful features for a TreeBuilder to have.
+FAST = 'fast'
+PERMISSIVE = 'permissive'
+STRICT = 'strict'
+XML = 'xml'
+HTML = 'html'
+HTML_5 = 'html5'
+
+
+class TreeBuilderRegistry(object):
+
+ def __init__(self):
+ self.builders_for_feature = defaultdict(list)
+ self.builders = []
+
+ def register(self, treebuilder_class):
+ """Register a treebuilder based on its advertised features."""
+ for feature in treebuilder_class.features:
+ self.builders_for_feature[feature].insert(0, treebuilder_class)
+ self.builders.insert(0, treebuilder_class)
+
+ def lookup(self, *features):
+ if len(self.builders) == 0:
+ # There are no builders at all.
+ return None
+
+ if len(features) == 0:
+ # They didn't ask for any features. Give them the most
+ # recently registered builder.
+ return self.builders[0]
+
+ # Go down the list of features in order, and eliminate any builders
+ # that don't match every feature.
+ features = list(features)
+ features.reverse()
+ candidates = None
+ candidate_set = None
+ while len(features) > 0:
+ feature = features.pop()
+ we_have_the_feature = self.builders_for_feature.get(feature, [])
+ if len(we_have_the_feature) > 0:
+ if candidates is None:
+ candidates = we_have_the_feature
+ candidate_set = set(candidates)
+ else:
+ # Eliminate any candidates that don't have this feature.
+ candidate_set = candidate_set.intersection(
+ set(we_have_the_feature))
+
+ # The only valid candidates are the ones in candidate_set.
+ # Go through the original list of candidates and pick the first one
+ # that's in candidate_set.
+ if candidate_set is None:
+ return None
+ for candidate in candidates:
+ if candidate in candidate_set:
+ return candidate
+ return None
+
+# The BeautifulSoup class will take feature lists from developers and use them
+# to look up builders in this registry.
+builder_registry = TreeBuilderRegistry()
+
+class TreeBuilder(object):
+ """Turn a document into a Beautiful Soup object tree."""
+
+ features = []
+
+ is_xml = False
+ preserve_whitespace_tags = set()
+ empty_element_tags = None # A tag will be considered an empty-element
+ # tag when and only when it has no contents.
+
+ # A value for these tag/attribute combinations is a space- or
+ # comma-separated list of CDATA, rather than a single CDATA.
+ cdata_list_attributes = {}
+
+
+ def __init__(self):
+ self.soup = None
+
+ def reset(self):
+ pass
+
+ def can_be_empty_element(self, tag_name):
+ """Might a tag with this name be an empty-element tag?
+
+ The final markup may or may not actually present this tag as
+ self-closing.
+
+ For instance: an HTMLBuilder does not consider a <p> tag to be
+ an empty-element tag (it's not in
+ HTMLBuilder.empty_element_tags). This means an empty <p> tag
+ will be presented as "<p></p>", not "<p />".
+
+ The default implementation has no opinion about which tags are
+ empty-element tags, so a tag will be presented as an
+ empty-element tag if and only if it has no contents.
+ "<foo></foo>" will become "<foo />", and "<foo>bar</foo>" will
+ be left alone.
+ """
+ if self.empty_element_tags is None:
+ return True
+ return tag_name in self.empty_element_tags
+
+ def feed(self, markup):
+ raise NotImplementedError()
+
+ def prepare_markup(self, markup, user_specified_encoding=None,
+ document_declared_encoding=None):
+ return markup, None, None, False
+
+ def test_fragment_to_document(self, fragment):
+ """Wrap an HTML fragment to make it look like a document.
+
+ Different parsers do this differently. For instance, lxml
+ introduces an empty <head> tag, and html5lib
+ doesn't. Abstracting this away lets us write simple tests
+ which run HTML fragments through the parser and compare the
+ results against other HTML fragments.
+
+ This method should not be used outside of tests.
+ """
+ return fragment
+
+ def set_up_substitutions(self, tag):
+ return False
+
+ def _replace_cdata_list_attribute_values(self, tag_name, attrs):
+ """Replaces class="foo bar" with class=["foo", "bar"]
+
+ Modifies its input in place.
+ """
+ if not attrs:
+ return attrs
+ if self.cdata_list_attributes:
+ universal = self.cdata_list_attributes.get('*', [])
+ tag_specific = self.cdata_list_attributes.get(
+ tag_name.lower(), None)
+ for attr in attrs.keys():
+ if attr in universal or (tag_specific and attr in tag_specific):
+ # We have a "class"-type attribute whose string
+ # value is a whitespace-separated list of
+ # values. Split it into a list.
+ value = attrs[attr]
+ if isinstance(value, basestring):
+ values = whitespace_re.split(value)
+ else:
+ # html5lib sometimes calls setAttributes twice
+ # for the same tag when rearranging the parse
+ # tree. On the second call the attribute value
+ # here is already a list. If this happens,
+ # leave the value alone rather than trying to
+ # split it again.
+ values = value
+ attrs[attr] = values
+ return attrs
+
+class SAXTreeBuilder(TreeBuilder):
+ """A Beautiful Soup treebuilder that listens for SAX events."""
+
+ def feed(self, markup):
+ raise NotImplementedError()
+
+ def close(self):
+ pass
+
+ def startElement(self, name, attrs):
+ attrs = dict((key[1], value) for key, value in list(attrs.items()))
+ #print "Start %s, %r" % (name, attrs)
+ self.soup.handle_starttag(name, attrs)
+
+ def endElement(self, name):
+ #print "End %s" % name
+ self.soup.handle_endtag(name)
+
+ def startElementNS(self, nsTuple, nodeName, attrs):
+ # Throw away (ns, nodeName) for now.
+ self.startElement(nodeName, attrs)
+
+ def endElementNS(self, nsTuple, nodeName):
+ # Throw away (ns, nodeName) for now.
+ self.endElement(nodeName)
+ #handler.endElementNS((ns, node.nodeName), node.nodeName)
+
+ def startPrefixMapping(self, prefix, nodeValue):
+ # Ignore the prefix for now.
+ pass
+
+ def endPrefixMapping(self, prefix):
+ # Ignore the prefix for now.
+ # handler.endPrefixMapping(prefix)
+ pass
+
+ def characters(self, content):
+ self.soup.handle_data(content)
+
+ def startDocument(self):
+ pass
+
+ def endDocument(self):
+ pass
+
+
+class HTMLTreeBuilder(TreeBuilder):
+ """This TreeBuilder knows facts about HTML.
+
+ Such as which tags are empty-element tags.
+ """
+
+ preserve_whitespace_tags = set(['pre', 'textarea'])
+ empty_element_tags = set(['br' , 'hr', 'input', 'img', 'meta',
+ 'spacer', 'link', 'frame', 'base'])
+
+ # The HTML standard defines these attributes as containing a
+ # space-separated list of values, not a single value. That is,
+ # class="foo bar" means that the 'class' attribute has two values,
+ # 'foo' and 'bar', not the single value 'foo bar'. When we
+ # encounter one of these attributes, we will parse its value into
+ # a list of values if possible. Upon output, the list will be
+ # converted back into a string.
+ cdata_list_attributes = {
+ "*" : ['class', 'accesskey', 'dropzone'],
+ "a" : ['rel', 'rev'],
+ "link" : ['rel', 'rev'],
+ "td" : ["headers"],
+ "th" : ["headers"],
+ "td" : ["headers"],
+ "form" : ["accept-charset"],
+ "object" : ["archive"],
+
+ # These are HTML5 specific, as are *.accesskey and *.dropzone above.
+ "area" : ["rel"],
+ "icon" : ["sizes"],
+ "iframe" : ["sandbox"],
+ "output" : ["for"],
+ }
+
+ def set_up_substitutions(self, tag):
+ # We are only interested in <meta> tags
+ if tag.name != 'meta':
+ return False
+
+ http_equiv = tag.get('http-equiv')
+ content = tag.get('content')
+ charset = tag.get('charset')
+
+ # We are interested in <meta> tags that say what encoding the
+ # document was originally in. This means HTML 5-style <meta>
+ # tags that provide the "charset" attribute. It also means
+ # HTML 4-style <meta> tags that provide the "content"
+ # attribute and have "http-equiv" set to "content-type".
+ #
+ # In both cases we will replace the value of the appropriate
+ # attribute with a standin object that can take on any
+ # encoding.
+ meta_encoding = None
+ if charset is not None:
+ # HTML 5 style:
+ # <meta charset="utf8">
+ meta_encoding = charset
+ tag['charset'] = CharsetMetaAttributeValue(charset)
+
+ elif (content is not None and http_equiv is not None
+ and http_equiv.lower() == 'content-type'):
+ # HTML 4 style:
+ # <meta http-equiv="content-type" content="text/html; charset=utf8">
+ tag['content'] = ContentMetaAttributeValue(content)
+
+ return (meta_encoding is not None)
+
+def register_treebuilders_from(module):
+ """Copy TreeBuilders from the given module into this module."""
+ # I'm fairly sure this is not the best way to do this.
+ this_module = sys.modules['bs4.builder']
+ for name in module.__all__:
+ obj = getattr(module, name)
+
+ if issubclass(obj, TreeBuilder):
+ setattr(this_module, name, obj)
+ this_module.__all__.append(name)
+ # Register the builder while we're at it.
+ this_module.builder_registry.register(obj)
+
+class ParserRejectedMarkup(Exception):
+ pass
+
+# Builders are registered in reverse order of priority, so that custom
+# builder registrations will take precedence. In general, we want lxml
+# to take precedence over html5lib, because it's faster. And we only
+# want to use HTMLParser as a last result.
+from . import _htmlparser
+register_treebuilders_from(_htmlparser)
+try:
+ from . import _html5lib
+ register_treebuilders_from(_html5lib)
+except ImportError:
+ # They don't have html5lib installed.
+ pass
+try:
+ from . import _lxml
+ register_treebuilders_from(_lxml)
+except ImportError:
+ # They don't have lxml installed.
+ pass
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_html5lib.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_html5lib.py
new file mode 100644
index 00000000000..7de36ae75e4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_html5lib.py
@@ -0,0 +1,285 @@
+__all__ = [
+ 'HTML5TreeBuilder',
+ ]
+
+import warnings
+from bs4.builder import (
+ PERMISSIVE,
+ HTML,
+ HTML_5,
+ HTMLTreeBuilder,
+ )
+from bs4.element import NamespacedAttribute
+import html5lib
+from html5lib.constants import namespaces
+from bs4.element import (
+ Comment,
+ Doctype,
+ NavigableString,
+ Tag,
+ )
+
+class HTML5TreeBuilder(HTMLTreeBuilder):
+ """Use html5lib to build a tree."""
+
+ features = ['html5lib', PERMISSIVE, HTML_5, HTML]
+
+ def prepare_markup(self, markup, user_specified_encoding):
+ # Store the user-specified encoding for use later on.
+ self.user_specified_encoding = user_specified_encoding
+ yield (markup, None, None, False)
+
+ # These methods are defined by Beautiful Soup.
+ def feed(self, markup):
+ if self.soup.parse_only is not None:
+ warnings.warn("You provided a value for parse_only, but the html5lib tree builder doesn't support parse_only. The entire document will be parsed.")
+ parser = html5lib.HTMLParser(tree=self.create_treebuilder)
+ doc = parser.parse(markup, encoding=self.user_specified_encoding)
+
+ # Set the character encoding detected by the tokenizer.
+ if isinstance(markup, unicode):
+ # We need to special-case this because html5lib sets
+ # charEncoding to UTF-8 if it gets Unicode input.
+ doc.original_encoding = None
+ else:
+ doc.original_encoding = parser.tokenizer.stream.charEncoding[0]
+
+ def create_treebuilder(self, namespaceHTMLElements):
+ self.underlying_builder = TreeBuilderForHtml5lib(
+ self.soup, namespaceHTMLElements)
+ return self.underlying_builder
+
+ def test_fragment_to_document(self, fragment):
+ """See `TreeBuilder`."""
+ return u'<html><head></head><body>%s</body></html>' % fragment
+
+
+class TreeBuilderForHtml5lib(html5lib.treebuilders._base.TreeBuilder):
+
+ def __init__(self, soup, namespaceHTMLElements):
+ self.soup = soup
+ super(TreeBuilderForHtml5lib, self).__init__(namespaceHTMLElements)
+
+ def documentClass(self):
+ self.soup.reset()
+ return Element(self.soup, self.soup, None)
+
+ def insertDoctype(self, token):
+ name = token["name"]
+ publicId = token["publicId"]
+ systemId = token["systemId"]
+
+ doctype = Doctype.for_name_and_ids(name, publicId, systemId)
+ self.soup.object_was_parsed(doctype)
+
+ def elementClass(self, name, namespace):
+ tag = self.soup.new_tag(name, namespace)
+ return Element(tag, self.soup, namespace)
+
+ def commentClass(self, data):
+ return TextNode(Comment(data), self.soup)
+
+ def fragmentClass(self):
+ self.soup = BeautifulSoup("")
+ self.soup.name = "[document_fragment]"
+ return Element(self.soup, self.soup, None)
+
+ def appendChild(self, node):
+ # XXX This code is not covered by the BS4 tests.
+ self.soup.append(node.element)
+
+ def getDocument(self):
+ return self.soup
+
+ def getFragment(self):
+ return html5lib.treebuilders._base.TreeBuilder.getFragment(self).element
+
+class AttrList(object):
+ def __init__(self, element):
+ self.element = element
+ self.attrs = dict(self.element.attrs)
+ def __iter__(self):
+ return list(self.attrs.items()).__iter__()
+ def __setitem__(self, name, value):
+ "set attr", name, value
+ self.element[name] = value
+ def items(self):
+ return list(self.attrs.items())
+ def keys(self):
+ return list(self.attrs.keys())
+ def __len__(self):
+ return len(self.attrs)
+ def __getitem__(self, name):
+ return self.attrs[name]
+ def __contains__(self, name):
+ return name in list(self.attrs.keys())
+
+
+class Element(html5lib.treebuilders._base.Node):
+ def __init__(self, element, soup, namespace):
+ html5lib.treebuilders._base.Node.__init__(self, element.name)
+ self.element = element
+ self.soup = soup
+ self.namespace = namespace
+
+ def appendChild(self, node):
+ string_child = child = None
+ if isinstance(node, basestring):
+ # Some other piece of code decided to pass in a string
+ # instead of creating a TextElement object to contain the
+ # string.
+ string_child = child = node
+ elif isinstance(node, Tag):
+ # Some other piece of code decided to pass in a Tag
+ # instead of creating an Element object to contain the
+ # Tag.
+ child = node
+ elif node.element.__class__ == NavigableString:
+ string_child = child = node.element
+ else:
+ child = node.element
+
+ if not isinstance(child, basestring) and child.parent is not None:
+ node.element.extract()
+
+ if (string_child and self.element.contents
+ and self.element.contents[-1].__class__ == NavigableString):
+ # We are appending a string onto another string.
+ # TODO This has O(n^2) performance, for input like
+ # "a</a>a</a>a</a>..."
+ old_element = self.element.contents[-1]
+ new_element = self.soup.new_string(old_element + string_child)
+ old_element.replace_with(new_element)
+ self.soup._most_recent_element = new_element
+ else:
+ if isinstance(node, basestring):
+ # Create a brand new NavigableString from this string.
+ child = self.soup.new_string(node)
+
+ # Tell Beautiful Soup to act as if it parsed this element
+ # immediately after the parent's last descendant. (Or
+ # immediately after the parent, if it has no children.)
+ if self.element.contents:
+ most_recent_element = self.element._last_descendant(False)
+ else:
+ most_recent_element = self.element
+
+ self.soup.object_was_parsed(
+ child, parent=self.element,
+ most_recent_element=most_recent_element)
+
+ def getAttributes(self):
+ return AttrList(self.element)
+
+ def setAttributes(self, attributes):
+ if attributes is not None and len(attributes) > 0:
+
+ converted_attributes = []
+ for name, value in list(attributes.items()):
+ if isinstance(name, tuple):
+ new_name = NamespacedAttribute(*name)
+ del attributes[name]
+ attributes[new_name] = value
+
+ self.soup.builder._replace_cdata_list_attribute_values(
+ self.name, attributes)
+ for name, value in attributes.items():
+ self.element[name] = value
+
+ # The attributes may contain variables that need substitution.
+ # Call set_up_substitutions manually.
+ #
+ # The Tag constructor called this method when the Tag was created,
+ # but we just set/changed the attributes, so call it again.
+ self.soup.builder.set_up_substitutions(self.element)
+ attributes = property(getAttributes, setAttributes)
+
+ def insertText(self, data, insertBefore=None):
+ if insertBefore:
+ text = TextNode(self.soup.new_string(data), self.soup)
+ self.insertBefore(data, insertBefore)
+ else:
+ self.appendChild(data)
+
+ def insertBefore(self, node, refNode):
+ index = self.element.index(refNode.element)
+ if (node.element.__class__ == NavigableString and self.element.contents
+ and self.element.contents[index-1].__class__ == NavigableString):
+ # (See comments in appendChild)
+ old_node = self.element.contents[index-1]
+ new_str = self.soup.new_string(old_node + node.element)
+ old_node.replace_with(new_str)
+ else:
+ self.element.insert(index, node.element)
+ node.parent = self
+
+ def removeChild(self, node):
+ node.element.extract()
+
+ def reparentChildren(self, new_parent):
+ """Move all of this tag's children into another tag."""
+ element = self.element
+ new_parent_element = new_parent.element
+ # Determine what this tag's next_element will be once all the children
+ # are removed.
+ final_next_element = element.next_sibling
+
+ new_parents_last_descendant = new_parent_element._last_descendant(False, False)
+ if len(new_parent_element.contents) > 0:
+ # The new parent already contains children. We will be
+ # appending this tag's children to the end.
+ new_parents_last_child = new_parent_element.contents[-1]
+ new_parents_last_descendant_next_element = new_parents_last_descendant.next_element
+ else:
+ # The new parent contains no children.
+ new_parents_last_child = None
+ new_parents_last_descendant_next_element = new_parent_element.next_element
+
+ to_append = element.contents
+ append_after = new_parent.element.contents
+ if len(to_append) > 0:
+ # Set the first child's previous_element and previous_sibling
+ # to elements within the new parent
+ first_child = to_append[0]
+ first_child.previous_element = new_parents_last_descendant
+ first_child.previous_sibling = new_parents_last_child
+
+ # Fix the last child's next_element and next_sibling
+ last_child = to_append[-1]
+ last_child.next_element = new_parents_last_descendant_next_element
+ last_child.next_sibling = None
+
+ for child in to_append:
+ child.parent = new_parent_element
+ new_parent_element.contents.append(child)
+
+ # Now that this element has no children, change its .next_element.
+ element.contents = []
+ element.next_element = final_next_element
+
+ def cloneNode(self):
+ tag = self.soup.new_tag(self.element.name, self.namespace)
+ node = Element(tag, self.soup, self.namespace)
+ for key,value in self.attributes:
+ node.attributes[key] = value
+ return node
+
+ def hasContent(self):
+ return self.element.contents
+
+ def getNameTuple(self):
+ if self.namespace == None:
+ return namespaces["html"], self.name
+ else:
+ return self.namespace, self.name
+
+ nameTuple = property(getNameTuple)
+
+class TextNode(Element):
+ def __init__(self, element, soup):
+ html5lib.treebuilders._base.Node.__init__(self, None)
+ self.element = element
+ self.soup = soup
+
+ def cloneNode(self):
+ raise NotImplementedError
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_htmlparser.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_htmlparser.py
new file mode 100644
index 00000000000..ca8d8b892bf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_htmlparser.py
@@ -0,0 +1,258 @@
+"""Use the HTMLParser library to parse HTML files that aren't too bad."""
+
+__all__ = [
+ 'HTMLParserTreeBuilder',
+ ]
+
+from HTMLParser import (
+ HTMLParser,
+ HTMLParseError,
+ )
+import sys
+import warnings
+
+# Starting in Python 3.2, the HTMLParser constructor takes a 'strict'
+# argument, which we'd like to set to False. Unfortunately,
+# http://bugs.python.org/issue13273 makes strict=True a better bet
+# before Python 3.2.3.
+#
+# At the end of this file, we monkeypatch HTMLParser so that
+# strict=True works well on Python 3.2.2.
+major, minor, release = sys.version_info[:3]
+CONSTRUCTOR_TAKES_STRICT = (
+ major > 3
+ or (major == 3 and minor > 2)
+ or (major == 3 and minor == 2 and release >= 3))
+
+from bs4.element import (
+ CData,
+ Comment,
+ Declaration,
+ Doctype,
+ ProcessingInstruction,
+ )
+from bs4.dammit import EntitySubstitution, UnicodeDammit
+
+from bs4.builder import (
+ HTML,
+ HTMLTreeBuilder,
+ STRICT,
+ )
+
+
+HTMLPARSER = 'html.parser'
+
+class BeautifulSoupHTMLParser(HTMLParser):
+ def handle_starttag(self, name, attrs):
+ # XXX namespace
+ attr_dict = {}
+ for key, value in attrs:
+ # Change None attribute values to the empty string
+ # for consistency with the other tree builders.
+ if value is None:
+ value = ''
+ attr_dict[key] = value
+ attrvalue = '""'
+ self.soup.handle_starttag(name, None, None, attr_dict)
+
+ def handle_endtag(self, name):
+ self.soup.handle_endtag(name)
+
+ def handle_data(self, data):
+ self.soup.handle_data(data)
+
+ def handle_charref(self, name):
+ # XXX workaround for a bug in HTMLParser. Remove this once
+ # it's fixed.
+ if name.startswith('x'):
+ real_name = int(name.lstrip('x'), 16)
+ elif name.startswith('X'):
+ real_name = int(name.lstrip('X'), 16)
+ else:
+ real_name = int(name)
+
+ try:
+ data = unichr(real_name)
+ except (ValueError, OverflowError), e:
+ data = u"\N{REPLACEMENT CHARACTER}"
+
+ self.handle_data(data)
+
+ def handle_entityref(self, name):
+ character = EntitySubstitution.HTML_ENTITY_TO_CHARACTER.get(name)
+ if character is not None:
+ data = character
+ else:
+ data = "&%s;" % name
+ self.handle_data(data)
+
+ def handle_comment(self, data):
+ self.soup.endData()
+ self.soup.handle_data(data)
+ self.soup.endData(Comment)
+
+ def handle_decl(self, data):
+ self.soup.endData()
+ if data.startswith("DOCTYPE "):
+ data = data[len("DOCTYPE "):]
+ elif data == 'DOCTYPE':
+ # i.e. "<!DOCTYPE>"
+ data = ''
+ self.soup.handle_data(data)
+ self.soup.endData(Doctype)
+
+ def unknown_decl(self, data):
+ if data.upper().startswith('CDATA['):
+ cls = CData
+ data = data[len('CDATA['):]
+ else:
+ cls = Declaration
+ self.soup.endData()
+ self.soup.handle_data(data)
+ self.soup.endData(cls)
+
+ def handle_pi(self, data):
+ self.soup.endData()
+ if data.endswith("?") and data.lower().startswith("xml"):
+ # "An XHTML processing instruction using the trailing '?'
+ # will cause the '?' to be included in data." - HTMLParser
+ # docs.
+ #
+ # Strip the question mark so we don't end up with two
+ # question marks.
+ data = data[:-1]
+ self.soup.handle_data(data)
+ self.soup.endData(ProcessingInstruction)
+
+
+class HTMLParserTreeBuilder(HTMLTreeBuilder):
+
+ is_xml = False
+ features = [HTML, STRICT, HTMLPARSER]
+
+ def __init__(self, *args, **kwargs):
+ if CONSTRUCTOR_TAKES_STRICT:
+ kwargs['strict'] = False
+ self.parser_args = (args, kwargs)
+
+ def prepare_markup(self, markup, user_specified_encoding=None,
+ document_declared_encoding=None):
+ """
+ :return: A 4-tuple (markup, original encoding, encoding
+ declared within markup, whether any characters had to be
+ replaced with REPLACEMENT CHARACTER).
+ """
+ if isinstance(markup, unicode):
+ yield (markup, None, None, False)
+ return
+
+ try_encodings = [user_specified_encoding, document_declared_encoding]
+ dammit = UnicodeDammit(markup, try_encodings, is_html=True)
+ yield (dammit.markup, dammit.original_encoding,
+ dammit.declared_html_encoding,
+ dammit.contains_replacement_characters)
+
+ def feed(self, markup):
+ args, kwargs = self.parser_args
+ parser = BeautifulSoupHTMLParser(*args, **kwargs)
+ parser.soup = self.soup
+ try:
+ parser.feed(markup)
+ except HTMLParseError, e:
+ warnings.warn(RuntimeWarning(
+ "Python's built-in HTMLParser cannot parse the given document. This is not a bug in Beautiful Soup. The best solution is to install an external parser (lxml or html5lib), and use Beautiful Soup with that parser. See http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser for help."))
+ raise e
+
+# Patch 3.2 versions of HTMLParser earlier than 3.2.3 to use some
+# 3.2.3 code. This ensures they don't treat markup like <p></p> as a
+# string.
+#
+# XXX This code can be removed once most Python 3 users are on 3.2.3.
+if major == 3 and minor == 2 and not CONSTRUCTOR_TAKES_STRICT:
+ import re
+ attrfind_tolerant = re.compile(
+ r'\s*((?<=[\'"\s])[^\s/>][^\s/=>]*)(\s*=+\s*'
+ r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?')
+ HTMLParserTreeBuilder.attrfind_tolerant = attrfind_tolerant
+
+ locatestarttagend = re.compile(r"""
+ <[a-zA-Z][-.a-zA-Z0-9:_]* # tag name
+ (?:\s+ # whitespace before attribute name
+ (?:[a-zA-Z_][-.:a-zA-Z0-9_]* # attribute name
+ (?:\s*=\s* # value indicator
+ (?:'[^']*' # LITA-enclosed value
+ |\"[^\"]*\" # LIT-enclosed value
+ |[^'\">\s]+ # bare value
+ )
+ )?
+ )
+ )*
+ \s* # trailing whitespace
+""", re.VERBOSE)
+ BeautifulSoupHTMLParser.locatestarttagend = locatestarttagend
+
+ from html.parser import tagfind, attrfind
+
+ def parse_starttag(self, i):
+ self.__starttag_text = None
+ endpos = self.check_for_whole_start_tag(i)
+ if endpos < 0:
+ return endpos
+ rawdata = self.rawdata
+ self.__starttag_text = rawdata[i:endpos]
+
+ # Now parse the data between i+1 and j into a tag and attrs
+ attrs = []
+ match = tagfind.match(rawdata, i+1)
+ assert match, 'unexpected call to parse_starttag()'
+ k = match.end()
+ self.lasttag = tag = rawdata[i+1:k].lower()
+ while k < endpos:
+ if self.strict:
+ m = attrfind.match(rawdata, k)
+ else:
+ m = attrfind_tolerant.match(rawdata, k)
+ if not m:
+ break
+ attrname, rest, attrvalue = m.group(1, 2, 3)
+ if not rest:
+ attrvalue = None
+ elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]:
+ attrvalue = attrvalue[1:-1]
+ if attrvalue:
+ attrvalue = self.unescape(attrvalue)
+ attrs.append((attrname.lower(), attrvalue))
+ k = m.end()
+
+ end = rawdata[k:endpos].strip()
+ if end not in (">", "/>"):
+ lineno, offset = self.getpos()
+ if "\n" in self.__starttag_text:
+ lineno = lineno + self.__starttag_text.count("\n")
+ offset = len(self.__starttag_text) \
+ - self.__starttag_text.rfind("\n")
+ else:
+ offset = offset + len(self.__starttag_text)
+ if self.strict:
+ self.error("junk characters in start tag: %r"
+ % (rawdata[k:endpos][:20],))
+ self.handle_data(rawdata[i:endpos])
+ return endpos
+ if end.endswith('/>'):
+ # XHTML-style empty tag: <span attr="value" />
+ self.handle_startendtag(tag, attrs)
+ else:
+ self.handle_starttag(tag, attrs)
+ if tag in self.CDATA_CONTENT_ELEMENTS:
+ self.set_cdata_mode(tag)
+ return endpos
+
+ def set_cdata_mode(self, elem):
+ self.cdata_elem = elem.lower()
+ self.interesting = re.compile(r'</\s*%s\s*>' % self.cdata_elem, re.I)
+
+ BeautifulSoupHTMLParser.parse_starttag = parse_starttag
+ BeautifulSoupHTMLParser.set_cdata_mode = set_cdata_mode
+
+ CONSTRUCTOR_TAKES_STRICT = True
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_lxml.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_lxml.py
new file mode 100644
index 00000000000..fa5d49875ea
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/builder/_lxml.py
@@ -0,0 +1,233 @@
+__all__ = [
+ 'LXMLTreeBuilderForXML',
+ 'LXMLTreeBuilder',
+ ]
+
+from io import BytesIO
+from StringIO import StringIO
+import collections
+from lxml import etree
+from bs4.element import Comment, Doctype, NamespacedAttribute
+from bs4.builder import (
+ FAST,
+ HTML,
+ HTMLTreeBuilder,
+ PERMISSIVE,
+ ParserRejectedMarkup,
+ TreeBuilder,
+ XML)
+from bs4.dammit import EncodingDetector
+
+LXML = 'lxml'
+
+class LXMLTreeBuilderForXML(TreeBuilder):
+ DEFAULT_PARSER_CLASS = etree.XMLParser
+
+ is_xml = True
+
+ # Well, it's permissive by XML parser standards.
+ features = [LXML, XML, FAST, PERMISSIVE]
+
+ CHUNK_SIZE = 512
+
+ # This namespace mapping is specified in the XML Namespace
+ # standard.
+ DEFAULT_NSMAPS = {'http://www.w3.org/XML/1998/namespace' : "xml"}
+
+ def default_parser(self, encoding):
+ # This can either return a parser object or a class, which
+ # will be instantiated with default arguments.
+ if self._default_parser is not None:
+ return self._default_parser
+ return etree.XMLParser(
+ target=self, strip_cdata=False, recover=True, encoding=encoding)
+
+ def parser_for(self, encoding):
+ # Use the default parser.
+ parser = self.default_parser(encoding)
+
+ if isinstance(parser, collections.Callable):
+ # Instantiate the parser with default arguments
+ parser = parser(target=self, strip_cdata=False, encoding=encoding)
+ return parser
+
+ def __init__(self, parser=None, empty_element_tags=None):
+ # TODO: Issue a warning if parser is present but not a
+ # callable, since that means there's no way to create new
+ # parsers for different encodings.
+ self._default_parser = parser
+ if empty_element_tags is not None:
+ self.empty_element_tags = set(empty_element_tags)
+ self.soup = None
+ self.nsmaps = [self.DEFAULT_NSMAPS]
+
+ def _getNsTag(self, tag):
+ # Split the namespace URL out of a fully-qualified lxml tag
+ # name. Copied from lxml's src/lxml/sax.py.
+ if tag[0] == '{':
+ return tuple(tag[1:].split('}', 1))
+ else:
+ return (None, tag)
+
+ def prepare_markup(self, markup, user_specified_encoding=None,
+ document_declared_encoding=None):
+ """
+ :yield: A series of 4-tuples.
+ (markup, encoding, declared encoding,
+ has undergone character replacement)
+
+ Each 4-tuple represents a strategy for parsing the document.
+ """
+ if isinstance(markup, unicode):
+ # We were given Unicode. Maybe lxml can parse Unicode on
+ # this system?
+ yield markup, None, document_declared_encoding, False
+
+ if isinstance(markup, unicode):
+ # No, apparently not. Convert the Unicode to UTF-8 and
+ # tell lxml to parse it as UTF-8.
+ yield (markup.encode("utf8"), "utf8",
+ document_declared_encoding, False)
+
+ # Instead of using UnicodeDammit to convert the bytestring to
+ # Unicode using different encodings, use EncodingDetector to
+ # iterate over the encodings, and tell lxml to try to parse
+ # the document as each one in turn.
+ is_html = not self.is_xml
+ try_encodings = [user_specified_encoding, document_declared_encoding]
+ detector = EncodingDetector(markup, try_encodings, is_html)
+ for encoding in detector.encodings:
+ yield (detector.markup, encoding, document_declared_encoding, False)
+
+ def feed(self, markup):
+ if isinstance(markup, bytes):
+ markup = BytesIO(markup)
+ elif isinstance(markup, unicode):
+ markup = StringIO(markup)
+
+ # Call feed() at least once, even if the markup is empty,
+ # or the parser won't be initialized.
+ data = markup.read(self.CHUNK_SIZE)
+ try:
+ self.parser = self.parser_for(self.soup.original_encoding)
+ self.parser.feed(data)
+ while len(data) != 0:
+ # Now call feed() on the rest of the data, chunk by chunk.
+ data = markup.read(self.CHUNK_SIZE)
+ if len(data) != 0:
+ self.parser.feed(data)
+ self.parser.close()
+ except (UnicodeDecodeError, LookupError, etree.ParserError), e:
+ raise ParserRejectedMarkup(str(e))
+
+ def close(self):
+ self.nsmaps = [self.DEFAULT_NSMAPS]
+
+ def start(self, name, attrs, nsmap={}):
+ # Make sure attrs is a mutable dict--lxml may send an immutable dictproxy.
+ attrs = dict(attrs)
+ nsprefix = None
+ # Invert each namespace map as it comes in.
+ if len(self.nsmaps) > 1:
+ # There are no new namespaces for this tag, but
+ # non-default namespaces are in play, so we need a
+ # separate tag stack to know when they end.
+ self.nsmaps.append(None)
+ elif len(nsmap) > 0:
+ # A new namespace mapping has come into play.
+ inverted_nsmap = dict((value, key) for key, value in nsmap.items())
+ self.nsmaps.append(inverted_nsmap)
+ # Also treat the namespace mapping as a set of attributes on the
+ # tag, so we can recreate it later.
+ attrs = attrs.copy()
+ for prefix, namespace in nsmap.items():
+ attribute = NamespacedAttribute(
+ "xmlns", prefix, "http://www.w3.org/2000/xmlns/")
+ attrs[attribute] = namespace
+
+ # Namespaces are in play. Find any attributes that came in
+ # from lxml with namespaces attached to their names, and
+ # turn then into NamespacedAttribute objects.
+ new_attrs = {}
+ for attr, value in attrs.items():
+ namespace, attr = self._getNsTag(attr)
+ if namespace is None:
+ new_attrs[attr] = value
+ else:
+ nsprefix = self._prefix_for_namespace(namespace)
+ attr = NamespacedAttribute(nsprefix, attr, namespace)
+ new_attrs[attr] = value
+ attrs = new_attrs
+
+ namespace, name = self._getNsTag(name)
+ nsprefix = self._prefix_for_namespace(namespace)
+ self.soup.handle_starttag(name, namespace, nsprefix, attrs)
+
+ def _prefix_for_namespace(self, namespace):
+ """Find the currently active prefix for the given namespace."""
+ if namespace is None:
+ return None
+ for inverted_nsmap in reversed(self.nsmaps):
+ if inverted_nsmap is not None and namespace in inverted_nsmap:
+ return inverted_nsmap[namespace]
+ return None
+
+ def end(self, name):
+ self.soup.endData()
+ completed_tag = self.soup.tagStack[-1]
+ namespace, name = self._getNsTag(name)
+ nsprefix = None
+ if namespace is not None:
+ for inverted_nsmap in reversed(self.nsmaps):
+ if inverted_nsmap is not None and namespace in inverted_nsmap:
+ nsprefix = inverted_nsmap[namespace]
+ break
+ self.soup.handle_endtag(name, nsprefix)
+ if len(self.nsmaps) > 1:
+ # This tag, or one of its parents, introduced a namespace
+ # mapping, so pop it off the stack.
+ self.nsmaps.pop()
+
+ def pi(self, target, data):
+ pass
+
+ def data(self, content):
+ self.soup.handle_data(content)
+
+ def doctype(self, name, pubid, system):
+ self.soup.endData()
+ doctype = Doctype.for_name_and_ids(name, pubid, system)
+ self.soup.object_was_parsed(doctype)
+
+ def comment(self, content):
+ "Handle comments as Comment objects."
+ self.soup.endData()
+ self.soup.handle_data(content)
+ self.soup.endData(Comment)
+
+ def test_fragment_to_document(self, fragment):
+ """See `TreeBuilder`."""
+ return u'<?xml version="1.0" encoding="utf-8"?>\n%s' % fragment
+
+
+class LXMLTreeBuilder(HTMLTreeBuilder, LXMLTreeBuilderForXML):
+
+ features = [LXML, HTML, FAST, PERMISSIVE]
+ is_xml = False
+
+ def default_parser(self, encoding):
+ return etree.HTMLParser
+
+ def feed(self, markup):
+ encoding = self.soup.original_encoding
+ try:
+ self.parser = self.parser_for(encoding)
+ self.parser.feed(markup)
+ self.parser.close()
+ except (UnicodeDecodeError, LookupError, etree.ParserError), e:
+ raise ParserRejectedMarkup(str(e))
+
+
+ def test_fragment_to_document(self, fragment):
+ """See `TreeBuilder`."""
+ return u'<html><body>%s</body></html>' % fragment
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/dammit.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/dammit.py
new file mode 100644
index 00000000000..59640b7ce3a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/dammit.py
@@ -0,0 +1,829 @@
+# -*- coding: utf-8 -*-
+"""Beautiful Soup bonus library: Unicode, Dammit
+
+This library converts a bytestream to Unicode through any means
+necessary. It is heavily based on code from Mark Pilgrim's Universal
+Feed Parser. It works best on XML and XML, but it does not rewrite the
+XML or HTML to reflect a new encoding; that's the tree builder's job.
+"""
+
+import codecs
+from htmlentitydefs import codepoint2name
+import re
+import logging
+import string
+
+# Import a library to autodetect character encodings.
+chardet_type = None
+try:
+ # First try the fast C implementation.
+ # PyPI package: cchardet
+ import cchardet
+ def chardet_dammit(s):
+ return cchardet.detect(s)['encoding']
+except ImportError:
+ try:
+ # Fall back to the pure Python implementation
+ # Debian package: python-chardet
+ # PyPI package: chardet
+ import chardet
+ def chardet_dammit(s):
+ return chardet.detect(s)['encoding']
+ #import chardet.constants
+ #chardet.constants._debug = 1
+ except ImportError:
+ # No chardet available.
+ def chardet_dammit(s):
+ return None
+
+# Available from http://cjkpython.i18n.org/.
+try:
+ import iconv_codec
+except ImportError:
+ pass
+
+xml_encoding_re = re.compile(
+ '^<\?.*encoding=[\'"](.*?)[\'"].*\?>'.encode(), re.I)
+html_meta_re = re.compile(
+ '<\s*meta[^>]+charset\s*=\s*["\']?([^>]*?)[ /;\'">]'.encode(), re.I)
+
+class EntitySubstitution(object):
+
+ """Substitute XML or HTML entities for the corresponding characters."""
+
+ def _populate_class_variables():
+ lookup = {}
+ reverse_lookup = {}
+ characters_for_re = []
+ for codepoint, name in list(codepoint2name.items()):
+ character = unichr(codepoint)
+ if codepoint != 34:
+ # There's no point in turning the quotation mark into
+ # &quot;, unless it happens within an attribute value, which
+ # is handled elsewhere.
+ characters_for_re.append(character)
+ lookup[character] = name
+ # But we do want to turn &quot; into the quotation mark.
+ reverse_lookup[name] = character
+ re_definition = "[%s]" % "".join(characters_for_re)
+ return lookup, reverse_lookup, re.compile(re_definition)
+ (CHARACTER_TO_HTML_ENTITY, HTML_ENTITY_TO_CHARACTER,
+ CHARACTER_TO_HTML_ENTITY_RE) = _populate_class_variables()
+
+ CHARACTER_TO_XML_ENTITY = {
+ "'": "apos",
+ '"': "quot",
+ "&": "amp",
+ "<": "lt",
+ ">": "gt",
+ }
+
+ BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
+ "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
+ ")")
+
+ AMPERSAND_OR_BRACKET = re.compile("([<>&])")
+
+ @classmethod
+ def _substitute_html_entity(cls, matchobj):
+ entity = cls.CHARACTER_TO_HTML_ENTITY.get(matchobj.group(0))
+ return "&%s;" % entity
+
+ @classmethod
+ def _substitute_xml_entity(cls, matchobj):
+ """Used with a regular expression to substitute the
+ appropriate XML entity for an XML special character."""
+ entity = cls.CHARACTER_TO_XML_ENTITY[matchobj.group(0)]
+ return "&%s;" % entity
+
+ @classmethod
+ def quoted_attribute_value(self, value):
+ """Make a value into a quoted XML attribute, possibly escaping it.
+
+ Most strings will be quoted using double quotes.
+
+ Bob's Bar -> "Bob's Bar"
+
+ If a string contains double quotes, it will be quoted using
+ single quotes.
+
+ Welcome to "my bar" -> 'Welcome to "my bar"'
+
+ If a string contains both single and double quotes, the
+ double quotes will be escaped, and the string will be quoted
+ using double quotes.
+
+ Welcome to "Bob's Bar" -> "Welcome to &quot;Bob's bar&quot;
+ """
+ quote_with = '"'
+ if '"' in value:
+ if "'" in value:
+ # The string contains both single and double
+ # quotes. Turn the double quotes into
+ # entities. We quote the double quotes rather than
+ # the single quotes because the entity name is
+ # "&quot;" whether this is HTML or XML. If we
+ # quoted the single quotes, we'd have to decide
+ # between &apos; and &squot;.
+ replace_with = "&quot;"
+ value = value.replace('"', replace_with)
+ else:
+ # There are double quotes but no single quotes.
+ # We can use single quotes to quote the attribute.
+ quote_with = "'"
+ return quote_with + value + quote_with
+
+ @classmethod
+ def substitute_xml(cls, value, make_quoted_attribute=False):
+ """Substitute XML entities for special XML characters.
+
+ :param value: A string to be substituted. The less-than sign
+ will become &lt;, the greater-than sign will become &gt;,
+ and any ampersands will become &amp;. If you want ampersands
+ that appear to be part of an entity definition to be left
+ alone, use substitute_xml_containing_entities() instead.
+
+ :param make_quoted_attribute: If True, then the string will be
+ quoted, as befits an attribute value.
+ """
+ # Escape angle brackets and ampersands.
+ value = cls.AMPERSAND_OR_BRACKET.sub(
+ cls._substitute_xml_entity, value)
+
+ if make_quoted_attribute:
+ value = cls.quoted_attribute_value(value)
+ return value
+
+ @classmethod
+ def substitute_xml_containing_entities(
+ cls, value, make_quoted_attribute=False):
+ """Substitute XML entities for special XML characters.
+
+ :param value: A string to be substituted. The less-than sign will
+ become &lt;, the greater-than sign will become &gt;, and any
+ ampersands that are not part of an entity defition will
+ become &amp;.
+
+ :param make_quoted_attribute: If True, then the string will be
+ quoted, as befits an attribute value.
+ """
+ # Escape angle brackets, and ampersands that aren't part of
+ # entities.
+ value = cls.BARE_AMPERSAND_OR_BRACKET.sub(
+ cls._substitute_xml_entity, value)
+
+ if make_quoted_attribute:
+ value = cls.quoted_attribute_value(value)
+ return value
+
+ @classmethod
+ def substitute_html(cls, s):
+ """Replace certain Unicode characters with named HTML entities.
+
+ This differs from data.encode(encoding, 'xmlcharrefreplace')
+ in that the goal is to make the result more readable (to those
+ with ASCII displays) rather than to recover from
+ errors. There's absolutely nothing wrong with a UTF-8 string
+ containg a LATIN SMALL LETTER E WITH ACUTE, but replacing that
+ character with "&eacute;" will make it more readable to some
+ people.
+ """
+ return cls.CHARACTER_TO_HTML_ENTITY_RE.sub(
+ cls._substitute_html_entity, s)
+
+
+class EncodingDetector:
+ """Suggests a number of possible encodings for a bytestring.
+
+ Order of precedence:
+
+ 1. Encodings you specifically tell EncodingDetector to try first
+ (the override_encodings argument to the constructor).
+
+ 2. An encoding declared within the bytestring itself, either in an
+ XML declaration (if the bytestring is to be interpreted as an XML
+ document), or in a <meta> tag (if the bytestring is to be
+ interpreted as an HTML document.)
+
+ 3. An encoding detected through textual analysis by chardet,
+ cchardet, or a similar external library.
+
+ 4. UTF-8.
+
+ 5. Windows-1252.
+ """
+ def __init__(self, markup, override_encodings=None, is_html=False):
+ self.override_encodings = override_encodings or []
+ self.chardet_encoding = None
+ self.is_html = is_html
+ self.declared_encoding = None
+
+ # First order of business: strip a byte-order mark.
+ self.markup, self.sniffed_encoding = self.strip_byte_order_mark(markup)
+
+ def _usable(self, encoding, tried):
+ if encoding is not None:
+ encoding = encoding.lower()
+ if encoding not in tried:
+ tried.add(encoding)
+ return True
+ return False
+
+ @property
+ def encodings(self):
+ """Yield a number of encodings that might work for this markup."""
+ tried = set()
+ for e in self.override_encodings:
+ if self._usable(e, tried):
+ yield e
+
+ # Did the document originally start with a byte-order mark
+ # that indicated its encoding?
+ if self._usable(self.sniffed_encoding, tried):
+ yield self.sniffed_encoding
+
+ # Look within the document for an XML or HTML encoding
+ # declaration.
+ if self.declared_encoding is None:
+ self.declared_encoding = self.find_declared_encoding(
+ self.markup, self.is_html)
+ if self._usable(self.declared_encoding, tried):
+ yield self.declared_encoding
+
+ # Use third-party character set detection to guess at the
+ # encoding.
+ if self.chardet_encoding is None:
+ self.chardet_encoding = chardet_dammit(self.markup)
+ if self._usable(self.chardet_encoding, tried):
+ yield self.chardet_encoding
+
+ # As a last-ditch effort, try utf-8 and windows-1252.
+ for e in ('utf-8', 'windows-1252'):
+ if self._usable(e, tried):
+ yield e
+
+ @classmethod
+ def strip_byte_order_mark(cls, data):
+ """If a byte-order mark is present, strip it and return the encoding it implies."""
+ encoding = None
+ if (len(data) >= 4) and (data[:2] == b'\xfe\xff') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16be'
+ data = data[2:]
+ elif (len(data) >= 4) and (data[:2] == b'\xff\xfe') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16le'
+ data = data[2:]
+ elif data[:3] == b'\xef\xbb\xbf':
+ encoding = 'utf-8'
+ data = data[3:]
+ elif data[:4] == b'\x00\x00\xfe\xff':
+ encoding = 'utf-32be'
+ data = data[4:]
+ elif data[:4] == b'\xff\xfe\x00\x00':
+ encoding = 'utf-32le'
+ data = data[4:]
+ return data, encoding
+
+ @classmethod
+ def find_declared_encoding(cls, markup, is_html=False, search_entire_document=False):
+ """Given a document, tries to find its declared encoding.
+
+ An XML encoding is declared at the beginning of the document.
+
+ An HTML encoding is declared in a <meta> tag, hopefully near the
+ beginning of the document.
+ """
+ if search_entire_document:
+ xml_endpos = html_endpos = len(markup)
+ else:
+ xml_endpos = 1024
+ html_endpos = max(2048, int(len(markup) * 0.05))
+
+ declared_encoding = None
+ declared_encoding_match = xml_encoding_re.search(markup, endpos=xml_endpos)
+ if not declared_encoding_match and is_html:
+ declared_encoding_match = html_meta_re.search(markup, endpos=html_endpos)
+ if declared_encoding_match is not None:
+ declared_encoding = declared_encoding_match.groups()[0].decode(
+ 'ascii')
+ if declared_encoding:
+ return declared_encoding.lower()
+ return None
+
+class UnicodeDammit:
+ """A class for detecting the encoding of a *ML document and
+ converting it to a Unicode string. If the source encoding is
+ windows-1252, can replace MS smart quotes with their HTML or XML
+ equivalents."""
+
+ # This dictionary maps commonly seen values for "charset" in HTML
+ # meta tags to the corresponding Python codec names. It only covers
+ # values that aren't in Python's aliases and can't be determined
+ # by the heuristics in find_codec.
+ CHARSET_ALIASES = {"macintosh": "mac-roman",
+ "x-sjis": "shift-jis"}
+
+ ENCODINGS_WITH_SMART_QUOTES = [
+ "windows-1252",
+ "iso-8859-1",
+ "iso-8859-2",
+ ]
+
+ def __init__(self, markup, override_encodings=[],
+ smart_quotes_to=None, is_html=False):
+ self.smart_quotes_to = smart_quotes_to
+ self.tried_encodings = []
+ self.contains_replacement_characters = False
+ self.is_html = is_html
+
+ self.detector = EncodingDetector(markup, override_encodings, is_html)
+
+ # Short-circuit if the data is in Unicode to begin with.
+ if isinstance(markup, unicode) or markup == '':
+ self.markup = markup
+ self.unicode_markup = unicode(markup)
+ self.original_encoding = None
+ return
+
+ # The encoding detector may have stripped a byte-order mark.
+ # Use the stripped markup from this point on.
+ self.markup = self.detector.markup
+
+ u = None
+ for encoding in self.detector.encodings:
+ markup = self.detector.markup
+ u = self._convert_from(encoding)
+ if u is not None:
+ break
+
+ if not u:
+ # None of the encodings worked. As an absolute last resort,
+ # try them again with character replacement.
+
+ for encoding in self.detector.encodings:
+ if encoding != "ascii":
+ u = self._convert_from(encoding, "replace")
+ if u is not None:
+ logging.warning(
+ "Some characters could not be decoded, and were "
+ "replaced with REPLACEMENT CHARACTER.")
+ self.contains_replacement_characters = True
+ break
+
+ # If none of that worked, we could at this point force it to
+ # ASCII, but that would destroy so much data that I think
+ # giving up is better.
+ self.unicode_markup = u
+ if not u:
+ self.original_encoding = None
+
+ def _sub_ms_char(self, match):
+ """Changes a MS smart quote character to an XML or HTML
+ entity, or an ASCII character."""
+ orig = match.group(1)
+ if self.smart_quotes_to == 'ascii':
+ sub = self.MS_CHARS_TO_ASCII.get(orig).encode()
+ else:
+ sub = self.MS_CHARS.get(orig)
+ if type(sub) == tuple:
+ if self.smart_quotes_to == 'xml':
+ sub = '&#x'.encode() + sub[1].encode() + ';'.encode()
+ else:
+ sub = '&'.encode() + sub[0].encode() + ';'.encode()
+ else:
+ sub = sub.encode()
+ return sub
+
+ def _convert_from(self, proposed, errors="strict"):
+ proposed = self.find_codec(proposed)
+ if not proposed or (proposed, errors) in self.tried_encodings:
+ return None
+ self.tried_encodings.append((proposed, errors))
+ markup = self.markup
+ # Convert smart quotes to HTML if coming from an encoding
+ # that might have them.
+ if (self.smart_quotes_to is not None
+ and proposed in self.ENCODINGS_WITH_SMART_QUOTES):
+ smart_quotes_re = b"([\x80-\x9f])"
+ smart_quotes_compiled = re.compile(smart_quotes_re)
+ markup = smart_quotes_compiled.sub(self._sub_ms_char, markup)
+
+ try:
+ #print "Trying to convert document to %s (errors=%s)" % (
+ # proposed, errors)
+ u = self._to_unicode(markup, proposed, errors)
+ self.markup = u
+ self.original_encoding = proposed
+ except Exception as e:
+ #print "That didn't work!"
+ #print e
+ return None
+ #print "Correct encoding: %s" % proposed
+ return self.markup
+
+ def _to_unicode(self, data, encoding, errors="strict"):
+ '''Given a string and its encoding, decodes the string into Unicode.
+ %encoding is a string recognized by encodings.aliases'''
+ return unicode(data, encoding, errors)
+
+ @property
+ def declared_html_encoding(self):
+ if not self.is_html:
+ return None
+ return self.detector.declared_encoding
+
+ def find_codec(self, charset):
+ value = (self._codec(self.CHARSET_ALIASES.get(charset, charset))
+ or (charset and self._codec(charset.replace("-", "")))
+ or (charset and self._codec(charset.replace("-", "_")))
+ or (charset and charset.lower())
+ or charset
+ )
+ if value:
+ return value.lower()
+ return None
+
+ def _codec(self, charset):
+ if not charset:
+ return charset
+ codec = None
+ try:
+ codecs.lookup(charset)
+ codec = charset
+ except (LookupError, ValueError):
+ pass
+ return codec
+
+
+ # A partial mapping of ISO-Latin-1 to HTML entities/XML numeric entities.
+ MS_CHARS = {b'\x80': ('euro', '20AC'),
+ b'\x81': ' ',
+ b'\x82': ('sbquo', '201A'),
+ b'\x83': ('fnof', '192'),
+ b'\x84': ('bdquo', '201E'),
+ b'\x85': ('hellip', '2026'),
+ b'\x86': ('dagger', '2020'),
+ b'\x87': ('Dagger', '2021'),
+ b'\x88': ('circ', '2C6'),
+ b'\x89': ('permil', '2030'),
+ b'\x8A': ('Scaron', '160'),
+ b'\x8B': ('lsaquo', '2039'),
+ b'\x8C': ('OElig', '152'),
+ b'\x8D': '?',
+ b'\x8E': ('#x17D', '17D'),
+ b'\x8F': '?',
+ b'\x90': '?',
+ b'\x91': ('lsquo', '2018'),
+ b'\x92': ('rsquo', '2019'),
+ b'\x93': ('ldquo', '201C'),
+ b'\x94': ('rdquo', '201D'),
+ b'\x95': ('bull', '2022'),
+ b'\x96': ('ndash', '2013'),
+ b'\x97': ('mdash', '2014'),
+ b'\x98': ('tilde', '2DC'),
+ b'\x99': ('trade', '2122'),
+ b'\x9a': ('scaron', '161'),
+ b'\x9b': ('rsaquo', '203A'),
+ b'\x9c': ('oelig', '153'),
+ b'\x9d': '?',
+ b'\x9e': ('#x17E', '17E'),
+ b'\x9f': ('Yuml', ''),}
+
+ # A parochial partial mapping of ISO-Latin-1 to ASCII. Contains
+ # horrors like stripping diacritical marks to turn á into a, but also
+ # contains non-horrors like turning “ into ".
+ MS_CHARS_TO_ASCII = {
+ b'\x80' : 'EUR',
+ b'\x81' : ' ',
+ b'\x82' : ',',
+ b'\x83' : 'f',
+ b'\x84' : ',,',
+ b'\x85' : '...',
+ b'\x86' : '+',
+ b'\x87' : '++',
+ b'\x88' : '^',
+ b'\x89' : '%',
+ b'\x8a' : 'S',
+ b'\x8b' : '<',
+ b'\x8c' : 'OE',
+ b'\x8d' : '?',
+ b'\x8e' : 'Z',
+ b'\x8f' : '?',
+ b'\x90' : '?',
+ b'\x91' : "'",
+ b'\x92' : "'",
+ b'\x93' : '"',
+ b'\x94' : '"',
+ b'\x95' : '*',
+ b'\x96' : '-',
+ b'\x97' : '--',
+ b'\x98' : '~',
+ b'\x99' : '(TM)',
+ b'\x9a' : 's',
+ b'\x9b' : '>',
+ b'\x9c' : 'oe',
+ b'\x9d' : '?',
+ b'\x9e' : 'z',
+ b'\x9f' : 'Y',
+ b'\xa0' : ' ',
+ b'\xa1' : '!',
+ b'\xa2' : 'c',
+ b'\xa3' : 'GBP',
+ b'\xa4' : '$', #This approximation is especially parochial--this is the
+ #generic currency symbol.
+ b'\xa5' : 'YEN',
+ b'\xa6' : '|',
+ b'\xa7' : 'S',
+ b'\xa8' : '..',
+ b'\xa9' : '',
+ b'\xaa' : '(th)',
+ b'\xab' : '<<',
+ b'\xac' : '!',
+ b'\xad' : ' ',
+ b'\xae' : '(R)',
+ b'\xaf' : '-',
+ b'\xb0' : 'o',
+ b'\xb1' : '+-',
+ b'\xb2' : '2',
+ b'\xb3' : '3',
+ b'\xb4' : ("'", 'acute'),
+ b'\xb5' : 'u',
+ b'\xb6' : 'P',
+ b'\xb7' : '*',
+ b'\xb8' : ',',
+ b'\xb9' : '1',
+ b'\xba' : '(th)',
+ b'\xbb' : '>>',
+ b'\xbc' : '1/4',
+ b'\xbd' : '1/2',
+ b'\xbe' : '3/4',
+ b'\xbf' : '?',
+ b'\xc0' : 'A',
+ b'\xc1' : 'A',
+ b'\xc2' : 'A',
+ b'\xc3' : 'A',
+ b'\xc4' : 'A',
+ b'\xc5' : 'A',
+ b'\xc6' : 'AE',
+ b'\xc7' : 'C',
+ b'\xc8' : 'E',
+ b'\xc9' : 'E',
+ b'\xca' : 'E',
+ b'\xcb' : 'E',
+ b'\xcc' : 'I',
+ b'\xcd' : 'I',
+ b'\xce' : 'I',
+ b'\xcf' : 'I',
+ b'\xd0' : 'D',
+ b'\xd1' : 'N',
+ b'\xd2' : 'O',
+ b'\xd3' : 'O',
+ b'\xd4' : 'O',
+ b'\xd5' : 'O',
+ b'\xd6' : 'O',
+ b'\xd7' : '*',
+ b'\xd8' : 'O',
+ b'\xd9' : 'U',
+ b'\xda' : 'U',
+ b'\xdb' : 'U',
+ b'\xdc' : 'U',
+ b'\xdd' : 'Y',
+ b'\xde' : 'b',
+ b'\xdf' : 'B',
+ b'\xe0' : 'a',
+ b'\xe1' : 'a',
+ b'\xe2' : 'a',
+ b'\xe3' : 'a',
+ b'\xe4' : 'a',
+ b'\xe5' : 'a',
+ b'\xe6' : 'ae',
+ b'\xe7' : 'c',
+ b'\xe8' : 'e',
+ b'\xe9' : 'e',
+ b'\xea' : 'e',
+ b'\xeb' : 'e',
+ b'\xec' : 'i',
+ b'\xed' : 'i',
+ b'\xee' : 'i',
+ b'\xef' : 'i',
+ b'\xf0' : 'o',
+ b'\xf1' : 'n',
+ b'\xf2' : 'o',
+ b'\xf3' : 'o',
+ b'\xf4' : 'o',
+ b'\xf5' : 'o',
+ b'\xf6' : 'o',
+ b'\xf7' : '/',
+ b'\xf8' : 'o',
+ b'\xf9' : 'u',
+ b'\xfa' : 'u',
+ b'\xfb' : 'u',
+ b'\xfc' : 'u',
+ b'\xfd' : 'y',
+ b'\xfe' : 'b',
+ b'\xff' : 'y',
+ }
+
+ # A map used when removing rogue Windows-1252/ISO-8859-1
+ # characters in otherwise UTF-8 documents.
+ #
+ # Note that \x81, \x8d, \x8f, \x90, and \x9d are undefined in
+ # Windows-1252.
+ WINDOWS_1252_TO_UTF8 = {
+ 0x80 : b'\xe2\x82\xac', # €
+ 0x82 : b'\xe2\x80\x9a', # ‚
+ 0x83 : b'\xc6\x92', # ƒ
+ 0x84 : b'\xe2\x80\x9e', # „
+ 0x85 : b'\xe2\x80\xa6', # …
+ 0x86 : b'\xe2\x80\xa0', # †
+ 0x87 : b'\xe2\x80\xa1', # ‡
+ 0x88 : b'\xcb\x86', # ˆ
+ 0x89 : b'\xe2\x80\xb0', # ‰
+ 0x8a : b'\xc5\xa0', # Š
+ 0x8b : b'\xe2\x80\xb9', # ‹
+ 0x8c : b'\xc5\x92', # Œ
+ 0x8e : b'\xc5\xbd', # Ž
+ 0x91 : b'\xe2\x80\x98', # ‘
+ 0x92 : b'\xe2\x80\x99', # ’
+ 0x93 : b'\xe2\x80\x9c', # “
+ 0x94 : b'\xe2\x80\x9d', # ”
+ 0x95 : b'\xe2\x80\xa2', # •
+ 0x96 : b'\xe2\x80\x93', # –
+ 0x97 : b'\xe2\x80\x94', # —
+ 0x98 : b'\xcb\x9c', # ˜
+ 0x99 : b'\xe2\x84\xa2', # ™
+ 0x9a : b'\xc5\xa1', # š
+ 0x9b : b'\xe2\x80\xba', # ›
+ 0x9c : b'\xc5\x93', # œ
+ 0x9e : b'\xc5\xbe', # ž
+ 0x9f : b'\xc5\xb8', # Ÿ
+ 0xa0 : b'\xc2\xa0', #  
+ 0xa1 : b'\xc2\xa1', # ¡
+ 0xa2 : b'\xc2\xa2', # ¢
+ 0xa3 : b'\xc2\xa3', # £
+ 0xa4 : b'\xc2\xa4', # ¤
+ 0xa5 : b'\xc2\xa5', # ¥
+ 0xa6 : b'\xc2\xa6', # ¦
+ 0xa7 : b'\xc2\xa7', # §
+ 0xa8 : b'\xc2\xa8', # ¨
+ 0xa9 : b'\xc2\xa9', # ©
+ 0xaa : b'\xc2\xaa', # ª
+ 0xab : b'\xc2\xab', # «
+ 0xac : b'\xc2\xac', # ¬
+ 0xad : b'\xc2\xad', # ­
+ 0xae : b'\xc2\xae', # ®
+ 0xaf : b'\xc2\xaf', # ¯
+ 0xb0 : b'\xc2\xb0', # °
+ 0xb1 : b'\xc2\xb1', # ±
+ 0xb2 : b'\xc2\xb2', # ²
+ 0xb3 : b'\xc2\xb3', # ³
+ 0xb4 : b'\xc2\xb4', # ´
+ 0xb5 : b'\xc2\xb5', # µ
+ 0xb6 : b'\xc2\xb6', # ¶
+ 0xb7 : b'\xc2\xb7', # ·
+ 0xb8 : b'\xc2\xb8', # ¸
+ 0xb9 : b'\xc2\xb9', # ¹
+ 0xba : b'\xc2\xba', # º
+ 0xbb : b'\xc2\xbb', # »
+ 0xbc : b'\xc2\xbc', # ¼
+ 0xbd : b'\xc2\xbd', # ½
+ 0xbe : b'\xc2\xbe', # ¾
+ 0xbf : b'\xc2\xbf', # ¿
+ 0xc0 : b'\xc3\x80', # À
+ 0xc1 : b'\xc3\x81', # Á
+ 0xc2 : b'\xc3\x82', # Â
+ 0xc3 : b'\xc3\x83', # Ã
+ 0xc4 : b'\xc3\x84', # Ä
+ 0xc5 : b'\xc3\x85', # Å
+ 0xc6 : b'\xc3\x86', # Æ
+ 0xc7 : b'\xc3\x87', # Ç
+ 0xc8 : b'\xc3\x88', # È
+ 0xc9 : b'\xc3\x89', # É
+ 0xca : b'\xc3\x8a', # Ê
+ 0xcb : b'\xc3\x8b', # Ë
+ 0xcc : b'\xc3\x8c', # Ì
+ 0xcd : b'\xc3\x8d', # Í
+ 0xce : b'\xc3\x8e', # Î
+ 0xcf : b'\xc3\x8f', # Ï
+ 0xd0 : b'\xc3\x90', # Ð
+ 0xd1 : b'\xc3\x91', # Ñ
+ 0xd2 : b'\xc3\x92', # Ò
+ 0xd3 : b'\xc3\x93', # Ó
+ 0xd4 : b'\xc3\x94', # Ô
+ 0xd5 : b'\xc3\x95', # Õ
+ 0xd6 : b'\xc3\x96', # Ö
+ 0xd7 : b'\xc3\x97', # ×
+ 0xd8 : b'\xc3\x98', # Ø
+ 0xd9 : b'\xc3\x99', # Ù
+ 0xda : b'\xc3\x9a', # Ú
+ 0xdb : b'\xc3\x9b', # Û
+ 0xdc : b'\xc3\x9c', # Ü
+ 0xdd : b'\xc3\x9d', # Ý
+ 0xde : b'\xc3\x9e', # Þ
+ 0xdf : b'\xc3\x9f', # ß
+ 0xe0 : b'\xc3\xa0', # à
+ 0xe1 : b'\xa1', # á
+ 0xe2 : b'\xc3\xa2', # â
+ 0xe3 : b'\xc3\xa3', # ã
+ 0xe4 : b'\xc3\xa4', # ä
+ 0xe5 : b'\xc3\xa5', # å
+ 0xe6 : b'\xc3\xa6', # æ
+ 0xe7 : b'\xc3\xa7', # ç
+ 0xe8 : b'\xc3\xa8', # è
+ 0xe9 : b'\xc3\xa9', # é
+ 0xea : b'\xc3\xaa', # ê
+ 0xeb : b'\xc3\xab', # ë
+ 0xec : b'\xc3\xac', # ì
+ 0xed : b'\xc3\xad', # í
+ 0xee : b'\xc3\xae', # î
+ 0xef : b'\xc3\xaf', # ï
+ 0xf0 : b'\xc3\xb0', # ð
+ 0xf1 : b'\xc3\xb1', # ñ
+ 0xf2 : b'\xc3\xb2', # ò
+ 0xf3 : b'\xc3\xb3', # ó
+ 0xf4 : b'\xc3\xb4', # ô
+ 0xf5 : b'\xc3\xb5', # õ
+ 0xf6 : b'\xc3\xb6', # ö
+ 0xf7 : b'\xc3\xb7', # ÷
+ 0xf8 : b'\xc3\xb8', # ø
+ 0xf9 : b'\xc3\xb9', # ù
+ 0xfa : b'\xc3\xba', # ú
+ 0xfb : b'\xc3\xbb', # û
+ 0xfc : b'\xc3\xbc', # ü
+ 0xfd : b'\xc3\xbd', # ý
+ 0xfe : b'\xc3\xbe', # þ
+ }
+
+ MULTIBYTE_MARKERS_AND_SIZES = [
+ (0xc2, 0xdf, 2), # 2-byte characters start with a byte C2-DF
+ (0xe0, 0xef, 3), # 3-byte characters start with E0-EF
+ (0xf0, 0xf4, 4), # 4-byte characters start with F0-F4
+ ]
+
+ FIRST_MULTIBYTE_MARKER = MULTIBYTE_MARKERS_AND_SIZES[0][0]
+ LAST_MULTIBYTE_MARKER = MULTIBYTE_MARKERS_AND_SIZES[-1][1]
+
+ @classmethod
+ def detwingle(cls, in_bytes, main_encoding="utf8",
+ embedded_encoding="windows-1252"):
+ """Fix characters from one encoding embedded in some other encoding.
+
+ Currently the only situation supported is Windows-1252 (or its
+ subset ISO-8859-1), embedded in UTF-8.
+
+ The input must be a bytestring. If you've already converted
+ the document to Unicode, you're too late.
+
+ The output is a bytestring in which `embedded_encoding`
+ characters have been converted to their `main_encoding`
+ equivalents.
+ """
+ if embedded_encoding.replace('_', '-').lower() not in (
+ 'windows-1252', 'windows_1252'):
+ raise NotImplementedError(
+ "Windows-1252 and ISO-8859-1 are the only currently supported "
+ "embedded encodings.")
+
+ if main_encoding.lower() not in ('utf8', 'utf-8'):
+ raise NotImplementedError(
+ "UTF-8 is the only currently supported main encoding.")
+
+ byte_chunks = []
+
+ chunk_start = 0
+ pos = 0
+ while pos < len(in_bytes):
+ byte = in_bytes[pos]
+ if not isinstance(byte, int):
+ # Python 2.x
+ byte = ord(byte)
+ if (byte >= cls.FIRST_MULTIBYTE_MARKER
+ and byte <= cls.LAST_MULTIBYTE_MARKER):
+ # This is the start of a UTF-8 multibyte character. Skip
+ # to the end.
+ for start, end, size in cls.MULTIBYTE_MARKERS_AND_SIZES:
+ if byte >= start and byte <= end:
+ pos += size
+ break
+ elif byte >= 0x80 and byte in cls.WINDOWS_1252_TO_UTF8:
+ # We found a Windows-1252 character!
+ # Save the string up to this point as a chunk.
+ byte_chunks.append(in_bytes[chunk_start:pos])
+
+ # Now translate the Windows-1252 character into UTF-8
+ # and add it as another, one-byte chunk.
+ byte_chunks.append(cls.WINDOWS_1252_TO_UTF8[byte])
+ pos += 1
+ chunk_start = pos
+ else:
+ # Go on to the next character.
+ pos += 1
+ if chunk_start == 0:
+ # The string is unchanged.
+ return in_bytes
+ else:
+ # Store the final chunk.
+ byte_chunks.append(in_bytes[chunk_start:])
+ return b''.join(byte_chunks)
+
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/diagnose.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/diagnose.py
new file mode 100644
index 00000000000..4d0b00afadd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/diagnose.py
@@ -0,0 +1,204 @@
+"""Diagnostic functions, mainly for use when doing tech support."""
+import cProfile
+from StringIO import StringIO
+from HTMLParser import HTMLParser
+import bs4
+from bs4 import BeautifulSoup, __version__
+from bs4.builder import builder_registry
+
+import os
+import pstats
+import random
+import tempfile
+import time
+import traceback
+import sys
+import cProfile
+
+def diagnose(data):
+ """Diagnostic suite for isolating common problems."""
+ print "Diagnostic running on Beautiful Soup %s" % __version__
+ print "Python version %s" % sys.version
+
+ basic_parsers = ["html.parser", "html5lib", "lxml"]
+ for name in basic_parsers:
+ for builder in builder_registry.builders:
+ if name in builder.features:
+ break
+ else:
+ basic_parsers.remove(name)
+ print (
+ "I noticed that %s is not installed. Installing it may help." %
+ name)
+
+ if 'lxml' in basic_parsers:
+ basic_parsers.append(["lxml", "xml"])
+ from lxml import etree
+ print "Found lxml version %s" % ".".join(map(str,etree.LXML_VERSION))
+
+ if 'html5lib' in basic_parsers:
+ import html5lib
+ print "Found html5lib version %s" % html5lib.__version__
+
+ if hasattr(data, 'read'):
+ data = data.read()
+ elif os.path.exists(data):
+ print '"%s" looks like a filename. Reading data from the file.' % data
+ data = open(data).read()
+ elif data.startswith("http:") or data.startswith("https:"):
+ print '"%s" looks like a URL. Beautiful Soup is not an HTTP client.' % data
+ print "You need to use some other library to get the document behind the URL, and feed that document to Beautiful Soup."
+ return
+ print
+
+ for parser in basic_parsers:
+ print "Trying to parse your markup with %s" % parser
+ success = False
+ try:
+ soup = BeautifulSoup(data, parser)
+ success = True
+ except Exception, e:
+ print "%s could not parse the markup." % parser
+ traceback.print_exc()
+ if success:
+ print "Here's what %s did with the markup:" % parser
+ print soup.prettify()
+
+ print "-" * 80
+
+def lxml_trace(data, html=True, **kwargs):
+ """Print out the lxml events that occur during parsing.
+
+ This lets you see how lxml parses a document when no Beautiful
+ Soup code is running.
+ """
+ from lxml import etree
+ for event, element in etree.iterparse(StringIO(data), html=html, **kwargs):
+ print("%s, %4s, %s" % (event, element.tag, element.text))
+
+class AnnouncingParser(HTMLParser):
+ """Announces HTMLParser parse events, without doing anything else."""
+
+ def _p(self, s):
+ print(s)
+
+ def handle_starttag(self, name, attrs):
+ self._p("%s START" % name)
+
+ def handle_endtag(self, name):
+ self._p("%s END" % name)
+
+ def handle_data(self, data):
+ self._p("%s DATA" % data)
+
+ def handle_charref(self, name):
+ self._p("%s CHARREF" % name)
+
+ def handle_entityref(self, name):
+ self._p("%s ENTITYREF" % name)
+
+ def handle_comment(self, data):
+ self._p("%s COMMENT" % data)
+
+ def handle_decl(self, data):
+ self._p("%s DECL" % data)
+
+ def unknown_decl(self, data):
+ self._p("%s UNKNOWN-DECL" % data)
+
+ def handle_pi(self, data):
+ self._p("%s PI" % data)
+
+def htmlparser_trace(data):
+ """Print out the HTMLParser events that occur during parsing.
+
+ This lets you see how HTMLParser parses a document when no
+ Beautiful Soup code is running.
+ """
+ parser = AnnouncingParser()
+ parser.feed(data)
+
+_vowels = "aeiou"
+_consonants = "bcdfghjklmnpqrstvwxyz"
+
+def rword(length=5):
+ "Generate a random word-like string."
+ s = ''
+ for i in range(length):
+ if i % 2 == 0:
+ t = _consonants
+ else:
+ t = _vowels
+ s += random.choice(t)
+ return s
+
+def rsentence(length=4):
+ "Generate a random sentence-like string."
+ return " ".join(rword(random.randint(4,9)) for i in range(length))
+
+def rdoc(num_elements=1000):
+ """Randomly generate an invalid HTML document."""
+ tag_names = ['p', 'div', 'span', 'i', 'b', 'script', 'table']
+ elements = []
+ for i in range(num_elements):
+ choice = random.randint(0,3)
+ if choice == 0:
+ # New tag.
+ tag_name = random.choice(tag_names)
+ elements.append("<%s>" % tag_name)
+ elif choice == 1:
+ elements.append(rsentence(random.randint(1,4)))
+ elif choice == 2:
+ # Close a tag.
+ tag_name = random.choice(tag_names)
+ elements.append("</%s>" % tag_name)
+ return "<html>" + "\n".join(elements) + "</html>"
+
+def benchmark_parsers(num_elements=100000):
+ """Very basic head-to-head performance benchmark."""
+ print "Comparative parser benchmark on Beautiful Soup %s" % __version__
+ data = rdoc(num_elements)
+ print "Generated a large invalid HTML document (%d bytes)." % len(data)
+
+ for parser in ["lxml", ["lxml", "html"], "html5lib", "html.parser"]:
+ success = False
+ try:
+ a = time.time()
+ soup = BeautifulSoup(data, parser)
+ b = time.time()
+ success = True
+ except Exception, e:
+ print "%s could not parse the markup." % parser
+ traceback.print_exc()
+ if success:
+ print "BS4+%s parsed the markup in %.2fs." % (parser, b-a)
+
+ from lxml import etree
+ a = time.time()
+ etree.HTML(data)
+ b = time.time()
+ print "Raw lxml parsed the markup in %.2fs." % (b-a)
+
+ import html5lib
+ parser = html5lib.HTMLParser()
+ a = time.time()
+ parser.parse(data)
+ b = time.time()
+ print "Raw html5lib parsed the markup in %.2fs." % (b-a)
+
+def profile(num_elements=100000, parser="lxml"):
+
+ filehandle = tempfile.NamedTemporaryFile()
+ filename = filehandle.name
+
+ data = rdoc(num_elements)
+ vars = dict(bs4=bs4, data=data, parser=parser)
+ cProfile.runctx('bs4.BeautifulSoup(data, parser)' , vars, vars, filename)
+
+ stats = pstats.Stats(filename)
+ # stats.strip_dirs()
+ stats.sort_stats("cumulative")
+ stats.print_stats('_html5lib|bs4', 50)
+
+if __name__ == '__main__':
+ diagnose(sys.stdin.read())
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/element.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/element.py
new file mode 100644
index 00000000000..da9afdf48ec
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/element.py
@@ -0,0 +1,1611 @@
+import collections
+import re
+import sys
+import warnings
+from bs4.dammit import EntitySubstitution
+
+DEFAULT_OUTPUT_ENCODING = "utf-8"
+PY3K = (sys.version_info[0] > 2)
+
+whitespace_re = re.compile("\s+")
+
+def _alias(attr):
+ """Alias one attribute name to another for backward compatibility"""
+ @property
+ def alias(self):
+ return getattr(self, attr)
+
+ @alias.setter
+ def alias(self):
+ return setattr(self, attr)
+ return alias
+
+
+class NamespacedAttribute(unicode):
+
+ def __new__(cls, prefix, name, namespace=None):
+ if name is None:
+ obj = unicode.__new__(cls, prefix)
+ elif prefix is None:
+ # Not really namespaced.
+ obj = unicode.__new__(cls, name)
+ else:
+ obj = unicode.__new__(cls, prefix + ":" + name)
+ obj.prefix = prefix
+ obj.name = name
+ obj.namespace = namespace
+ return obj
+
+class AttributeValueWithCharsetSubstitution(unicode):
+ """A stand-in object for a character encoding specified in HTML."""
+
+class CharsetMetaAttributeValue(AttributeValueWithCharsetSubstitution):
+ """A generic stand-in for the value of a meta tag's 'charset' attribute.
+
+ When Beautiful Soup parses the markup '<meta charset="utf8">', the
+ value of the 'charset' attribute will be one of these objects.
+ """
+
+ def __new__(cls, original_value):
+ obj = unicode.__new__(cls, original_value)
+ obj.original_value = original_value
+ return obj
+
+ def encode(self, encoding):
+ return encoding
+
+
+class ContentMetaAttributeValue(AttributeValueWithCharsetSubstitution):
+ """A generic stand-in for the value of a meta tag's 'content' attribute.
+
+ When Beautiful Soup parses the markup:
+ <meta http-equiv="content-type" content="text/html; charset=utf8">
+
+ The value of the 'content' attribute will be one of these objects.
+ """
+
+ CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
+
+ def __new__(cls, original_value):
+ match = cls.CHARSET_RE.search(original_value)
+ if match is None:
+ # No substitution necessary.
+ return unicode.__new__(unicode, original_value)
+
+ obj = unicode.__new__(cls, original_value)
+ obj.original_value = original_value
+ return obj
+
+ def encode(self, encoding):
+ def rewrite(match):
+ return match.group(1) + encoding
+ return self.CHARSET_RE.sub(rewrite, self.original_value)
+
+class HTMLAwareEntitySubstitution(EntitySubstitution):
+
+ """Entity substitution rules that are aware of some HTML quirks.
+
+ Specifically, the contents of <script> and <style> tags should not
+ undergo entity substitution.
+
+ Incoming NavigableString objects are checked to see if they're the
+ direct children of a <script> or <style> tag.
+ """
+
+ cdata_containing_tags = set(["script", "style"])
+
+ preformatted_tags = set(["pre"])
+
+ @classmethod
+ def _substitute_if_appropriate(cls, ns, f):
+ if (isinstance(ns, NavigableString)
+ and ns.parent is not None
+ and ns.parent.name in cls.cdata_containing_tags):
+ # Do nothing.
+ return ns
+ # Substitute.
+ return f(ns)
+
+ @classmethod
+ def substitute_html(cls, ns):
+ return cls._substitute_if_appropriate(
+ ns, EntitySubstitution.substitute_html)
+
+ @classmethod
+ def substitute_xml(cls, ns):
+ return cls._substitute_if_appropriate(
+ ns, EntitySubstitution.substitute_xml)
+
+class PageElement(object):
+ """Contains the navigational information for some part of the page
+ (either a tag or a piece of text)"""
+
+ # There are five possible values for the "formatter" argument passed in
+ # to methods like encode() and prettify():
+ #
+ # "html" - All Unicode characters with corresponding HTML entities
+ # are converted to those entities on output.
+ # "minimal" - Bare ampersands and angle brackets are converted to
+ # XML entities: &amp; &lt; &gt;
+ # None - The null formatter. Unicode characters are never
+ # converted to entities. This is not recommended, but it's
+ # faster than "minimal".
+ # A function - This function will be called on every string that
+ # needs to undergo entity substitution.
+ #
+
+ # In an HTML document, the default "html" and "minimal" functions
+ # will leave the contents of <script> and <style> tags alone. For
+ # an XML document, all tags will be given the same treatment.
+
+ HTML_FORMATTERS = {
+ "html" : HTMLAwareEntitySubstitution.substitute_html,
+ "minimal" : HTMLAwareEntitySubstitution.substitute_xml,
+ None : None
+ }
+
+ XML_FORMATTERS = {
+ "html" : EntitySubstitution.substitute_html,
+ "minimal" : EntitySubstitution.substitute_xml,
+ None : None
+ }
+
+ def format_string(self, s, formatter='minimal'):
+ """Format the given string using the given formatter."""
+ if not callable(formatter):
+ formatter = self._formatter_for_name(formatter)
+ if formatter is None:
+ output = s
+ else:
+ output = formatter(s)
+ return output
+
+ @property
+ def _is_xml(self):
+ """Is this element part of an XML tree or an HTML tree?
+
+ This is used when mapping a formatter name ("minimal") to an
+ appropriate function (one that performs entity-substitution on
+ the contents of <script> and <style> tags, or not). It's
+ inefficient, but it should be called very rarely.
+ """
+ if self.parent is None:
+ # This is the top-level object. It should have .is_xml set
+ # from tree creation. If not, take a guess--BS is usually
+ # used on HTML markup.
+ return getattr(self, 'is_xml', False)
+ return self.parent._is_xml
+
+ def _formatter_for_name(self, name):
+ "Look up a formatter function based on its name and the tree."
+ if self._is_xml:
+ return self.XML_FORMATTERS.get(
+ name, EntitySubstitution.substitute_xml)
+ else:
+ return self.HTML_FORMATTERS.get(
+ name, HTMLAwareEntitySubstitution.substitute_xml)
+
+ def setup(self, parent=None, previous_element=None):
+ """Sets up the initial relations between this element and
+ other elements."""
+ self.parent = parent
+ self.previous_element = previous_element
+ if previous_element is not None:
+ self.previous_element.next_element = self
+ self.next_element = None
+ self.previous_sibling = None
+ self.next_sibling = None
+ if self.parent is not None and self.parent.contents:
+ self.previous_sibling = self.parent.contents[-1]
+ self.previous_sibling.next_sibling = self
+
+ nextSibling = _alias("next_sibling") # BS3
+ previousSibling = _alias("previous_sibling") # BS3
+
+ def replace_with(self, replace_with):
+ if replace_with is self:
+ return
+ if replace_with is self.parent:
+ raise ValueError("Cannot replace a Tag with its parent.")
+ old_parent = self.parent
+ my_index = self.parent.index(self)
+ self.extract()
+ old_parent.insert(my_index, replace_with)
+ return self
+ replaceWith = replace_with # BS3
+
+ def unwrap(self):
+ my_parent = self.parent
+ my_index = self.parent.index(self)
+ self.extract()
+ for child in reversed(self.contents[:]):
+ my_parent.insert(my_index, child)
+ return self
+ replace_with_children = unwrap
+ replaceWithChildren = unwrap # BS3
+
+ def wrap(self, wrap_inside):
+ me = self.replace_with(wrap_inside)
+ wrap_inside.append(me)
+ return wrap_inside
+
+ def extract(self):
+ """Destructively rips this element out of the tree."""
+ if self.parent is not None:
+ del self.parent.contents[self.parent.index(self)]
+
+ #Find the two elements that would be next to each other if
+ #this element (and any children) hadn't been parsed. Connect
+ #the two.
+ last_child = self._last_descendant()
+ next_element = last_child.next_element
+
+ if self.previous_element is not None:
+ self.previous_element.next_element = next_element
+ if next_element is not None:
+ next_element.previous_element = self.previous_element
+ self.previous_element = None
+ last_child.next_element = None
+
+ self.parent = None
+ if self.previous_sibling is not None:
+ self.previous_sibling.next_sibling = self.next_sibling
+ if self.next_sibling is not None:
+ self.next_sibling.previous_sibling = self.previous_sibling
+ self.previous_sibling = self.next_sibling = None
+ return self
+
+ def _last_descendant(self, is_initialized=True, accept_self=True):
+ "Finds the last element beneath this object to be parsed."
+ if is_initialized and self.next_sibling:
+ last_child = self.next_sibling.previous_element
+ else:
+ last_child = self
+ while isinstance(last_child, Tag) and last_child.contents:
+ last_child = last_child.contents[-1]
+ if not accept_self and last_child == self:
+ last_child = None
+ return last_child
+ # BS3: Not part of the API!
+ _lastRecursiveChild = _last_descendant
+
+ def insert(self, position, new_child):
+ if new_child is self:
+ raise ValueError("Cannot insert a tag into itself.")
+ if (isinstance(new_child, basestring)
+ and not isinstance(new_child, NavigableString)):
+ new_child = NavigableString(new_child)
+
+ position = min(position, len(self.contents))
+ if hasattr(new_child, 'parent') and new_child.parent is not None:
+ # We're 'inserting' an element that's already one
+ # of this object's children.
+ if new_child.parent is self:
+ current_index = self.index(new_child)
+ if current_index < position:
+ # We're moving this element further down the list
+ # of this object's children. That means that when
+ # we extract this element, our target index will
+ # jump down one.
+ position -= 1
+ new_child.extract()
+
+ new_child.parent = self
+ previous_child = None
+ if position == 0:
+ new_child.previous_sibling = None
+ new_child.previous_element = self
+ else:
+ previous_child = self.contents[position - 1]
+ new_child.previous_sibling = previous_child
+ new_child.previous_sibling.next_sibling = new_child
+ new_child.previous_element = previous_child._last_descendant(False)
+ if new_child.previous_element is not None:
+ new_child.previous_element.next_element = new_child
+
+ new_childs_last_element = new_child._last_descendant(False)
+
+ if position >= len(self.contents):
+ new_child.next_sibling = None
+
+ parent = self
+ parents_next_sibling = None
+ while parents_next_sibling is None and parent is not None:
+ parents_next_sibling = parent.next_sibling
+ parent = parent.parent
+ if parents_next_sibling is not None:
+ # We found the element that comes next in the document.
+ break
+ if parents_next_sibling is not None:
+ new_childs_last_element.next_element = parents_next_sibling
+ else:
+ # The last element of this tag is the last element in
+ # the document.
+ new_childs_last_element.next_element = None
+ else:
+ next_child = self.contents[position]
+ new_child.next_sibling = next_child
+ if new_child.next_sibling is not None:
+ new_child.next_sibling.previous_sibling = new_child
+ new_childs_last_element.next_element = next_child
+
+ if new_childs_last_element.next_element is not None:
+ new_childs_last_element.next_element.previous_element = new_childs_last_element
+ self.contents.insert(position, new_child)
+
+ def append(self, tag):
+ """Appends the given tag to the contents of this tag."""
+ self.insert(len(self.contents), tag)
+
+ def insert_before(self, predecessor):
+ """Makes the given element the immediate predecessor of this one.
+
+ The two elements will have the same parent, and the given element
+ will be immediately before this one.
+ """
+ if self is predecessor:
+ raise ValueError("Can't insert an element before itself.")
+ parent = self.parent
+ if parent is None:
+ raise ValueError(
+ "Element has no parent, so 'before' has no meaning.")
+ # Extract first so that the index won't be screwed up if they
+ # are siblings.
+ if isinstance(predecessor, PageElement):
+ predecessor.extract()
+ index = parent.index(self)
+ parent.insert(index, predecessor)
+
+ def insert_after(self, successor):
+ """Makes the given element the immediate successor of this one.
+
+ The two elements will have the same parent, and the given element
+ will be immediately after this one.
+ """
+ if self is successor:
+ raise ValueError("Can't insert an element after itself.")
+ parent = self.parent
+ if parent is None:
+ raise ValueError(
+ "Element has no parent, so 'after' has no meaning.")
+ # Extract first so that the index won't be screwed up if they
+ # are siblings.
+ if isinstance(successor, PageElement):
+ successor.extract()
+ index = parent.index(self)
+ parent.insert(index+1, successor)
+
+ def find_next(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the first item that matches the given criteria and
+ appears after this Tag in the document."""
+ return self._find_one(self.find_all_next, name, attrs, text, **kwargs)
+ findNext = find_next # BS3
+
+ def find_all_next(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns all items that match the given criteria and appear
+ after this Tag in the document."""
+ return self._find_all(name, attrs, text, limit, self.next_elements,
+ **kwargs)
+ findAllNext = find_all_next # BS3
+
+ def find_next_sibling(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the closest sibling to this Tag that matches the
+ given criteria and appears after this Tag in the document."""
+ return self._find_one(self.find_next_siblings, name, attrs, text,
+ **kwargs)
+ findNextSibling = find_next_sibling # BS3
+
+ def find_next_siblings(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns the siblings of this Tag that match the given
+ criteria and appear after this Tag in the document."""
+ return self._find_all(name, attrs, text, limit,
+ self.next_siblings, **kwargs)
+ findNextSiblings = find_next_siblings # BS3
+ fetchNextSiblings = find_next_siblings # BS2
+
+ def find_previous(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the first item that matches the given criteria and
+ appears before this Tag in the document."""
+ return self._find_one(
+ self.find_all_previous, name, attrs, text, **kwargs)
+ findPrevious = find_previous # BS3
+
+ def find_all_previous(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns all items that match the given criteria and appear
+ before this Tag in the document."""
+ return self._find_all(name, attrs, text, limit, self.previous_elements,
+ **kwargs)
+ findAllPrevious = find_all_previous # BS3
+ fetchPrevious = find_all_previous # BS2
+
+ def find_previous_sibling(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the closest sibling to this Tag that matches the
+ given criteria and appears before this Tag in the document."""
+ return self._find_one(self.find_previous_siblings, name, attrs, text,
+ **kwargs)
+ findPreviousSibling = find_previous_sibling # BS3
+
+ def find_previous_siblings(self, name=None, attrs={}, text=None,
+ limit=None, **kwargs):
+ """Returns the siblings of this Tag that match the given
+ criteria and appear before this Tag in the document."""
+ return self._find_all(name, attrs, text, limit,
+ self.previous_siblings, **kwargs)
+ findPreviousSiblings = find_previous_siblings # BS3
+ fetchPreviousSiblings = find_previous_siblings # BS2
+
+ def find_parent(self, name=None, attrs={}, **kwargs):
+ """Returns the closest parent of this Tag that matches the given
+ criteria."""
+ # NOTE: We can't use _find_one because findParents takes a different
+ # set of arguments.
+ r = None
+ l = self.find_parents(name, attrs, 1, **kwargs)
+ if l:
+ r = l[0]
+ return r
+ findParent = find_parent # BS3
+
+ def find_parents(self, name=None, attrs={}, limit=None, **kwargs):
+ """Returns the parents of this Tag that match the given
+ criteria."""
+
+ return self._find_all(name, attrs, None, limit, self.parents,
+ **kwargs)
+ findParents = find_parents # BS3
+ fetchParents = find_parents # BS2
+
+ @property
+ def next(self):
+ return self.next_element
+
+ @property
+ def previous(self):
+ return self.previous_element
+
+ #These methods do the real heavy lifting.
+
+ def _find_one(self, method, name, attrs, text, **kwargs):
+ r = None
+ l = method(name, attrs, text, 1, **kwargs)
+ if l:
+ r = l[0]
+ return r
+
+ def _find_all(self, name, attrs, text, limit, generator, **kwargs):
+ "Iterates over a generator looking for things that match."
+
+ if isinstance(name, SoupStrainer):
+ strainer = name
+ else:
+ strainer = SoupStrainer(name, attrs, text, **kwargs)
+
+ if text is None and not limit and not attrs and not kwargs:
+ if name is True or name is None:
+ # Optimization to find all tags.
+ result = (element for element in generator
+ if isinstance(element, Tag))
+ return ResultSet(strainer, result)
+ elif isinstance(name, basestring):
+ # Optimization to find all tags with a given name.
+ result = (element for element in generator
+ if isinstance(element, Tag)
+ and element.name == name)
+ return ResultSet(strainer, result)
+ results = ResultSet(strainer)
+ while True:
+ try:
+ i = next(generator)
+ except StopIteration:
+ break
+ if i:
+ found = strainer.search(i)
+ if found:
+ results.append(found)
+ if limit and len(results) >= limit:
+ break
+ return results
+
+ #These generators can be used to navigate starting from both
+ #NavigableStrings and Tags.
+ @property
+ def next_elements(self):
+ i = self.next_element
+ while i is not None:
+ yield i
+ i = i.next_element
+
+ @property
+ def next_siblings(self):
+ i = self.next_sibling
+ while i is not None:
+ yield i
+ i = i.next_sibling
+
+ @property
+ def previous_elements(self):
+ i = self.previous_element
+ while i is not None:
+ yield i
+ i = i.previous_element
+
+ @property
+ def previous_siblings(self):
+ i = self.previous_sibling
+ while i is not None:
+ yield i
+ i = i.previous_sibling
+
+ @property
+ def parents(self):
+ i = self.parent
+ while i is not None:
+ yield i
+ i = i.parent
+
+ # Methods for supporting CSS selectors.
+
+ tag_name_re = re.compile('^[a-z0-9]+$')
+
+ # /^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
+ # \---/ \---/\-------------/ \-------/
+ # | | | |
+ # | | | The value
+ # | | ~,|,^,$,* or =
+ # | Attribute
+ # Tag
+ attribselect_re = re.compile(
+ r'^(?P<tag>\w+)?\[(?P<attribute>\w+)(?P<operator>[=~\|\^\$\*]?)' +
+ r'=?"?(?P<value>[^\]"]*)"?\]$'
+ )
+
+ def _attr_value_as_string(self, value, default=None):
+ """Force an attribute value into a string representation.
+
+ A multi-valued attribute will be converted into a
+ space-separated stirng.
+ """
+ value = self.get(value, default)
+ if isinstance(value, list) or isinstance(value, tuple):
+ value =" ".join(value)
+ return value
+
+ def _tag_name_matches_and(self, function, tag_name):
+ if not tag_name:
+ return function
+ else:
+ def _match(tag):
+ return tag.name == tag_name and function(tag)
+ return _match
+
+ def _attribute_checker(self, operator, attribute, value=''):
+ """Create a function that performs a CSS selector operation.
+
+ Takes an operator, attribute and optional value. Returns a
+ function that will return True for elements that match that
+ combination.
+ """
+ if operator == '=':
+ # string representation of `attribute` is equal to `value`
+ return lambda el: el._attr_value_as_string(attribute) == value
+ elif operator == '~':
+ # space-separated list representation of `attribute`
+ # contains `value`
+ def _includes_value(element):
+ attribute_value = element.get(attribute, [])
+ if not isinstance(attribute_value, list):
+ attribute_value = attribute_value.split()
+ return value in attribute_value
+ return _includes_value
+ elif operator == '^':
+ # string representation of `attribute` starts with `value`
+ return lambda el: el._attr_value_as_string(
+ attribute, '').startswith(value)
+ elif operator == '$':
+ # string represenation of `attribute` ends with `value`
+ return lambda el: el._attr_value_as_string(
+ attribute, '').endswith(value)
+ elif operator == '*':
+ # string representation of `attribute` contains `value`
+ return lambda el: value in el._attr_value_as_string(attribute, '')
+ elif operator == '|':
+ # string representation of `attribute` is either exactly
+ # `value` or starts with `value` and then a dash.
+ def _is_or_starts_with_dash(element):
+ attribute_value = element._attr_value_as_string(attribute, '')
+ return (attribute_value == value or attribute_value.startswith(
+ value + '-'))
+ return _is_or_starts_with_dash
+ else:
+ return lambda el: el.has_attr(attribute)
+
+ # Old non-property versions of the generators, for backwards
+ # compatibility with BS3.
+ def nextGenerator(self):
+ return self.next_elements
+
+ def nextSiblingGenerator(self):
+ return self.next_siblings
+
+ def previousGenerator(self):
+ return self.previous_elements
+
+ def previousSiblingGenerator(self):
+ return self.previous_siblings
+
+ def parentGenerator(self):
+ return self.parents
+
+
+class NavigableString(unicode, PageElement):
+
+ PREFIX = ''
+ SUFFIX = ''
+
+ def __new__(cls, value):
+ """Create a new NavigableString.
+
+ When unpickling a NavigableString, this method is called with
+ the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be
+ passed in to the superclass's __new__ or the superclass won't know
+ how to handle non-ASCII characters.
+ """
+ if isinstance(value, unicode):
+ return unicode.__new__(cls, value)
+ return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
+
+ def __copy__(self):
+ return self
+
+ def __getnewargs__(self):
+ return (unicode(self),)
+
+ def __getattr__(self, attr):
+ """text.string gives you text. This is for backwards
+ compatibility for Navigable*String, but for CData* it lets you
+ get the string without the CData wrapper."""
+ if attr == 'string':
+ return self
+ else:
+ raise AttributeError(
+ "'%s' object has no attribute '%s'" % (
+ self.__class__.__name__, attr))
+
+ def output_ready(self, formatter="minimal"):
+ output = self.format_string(self, formatter)
+ return self.PREFIX + output + self.SUFFIX
+
+ @property
+ def name(self):
+ return None
+
+ @name.setter
+ def name(self, name):
+ raise AttributeError("A NavigableString cannot be given a name.")
+
+class PreformattedString(NavigableString):
+ """A NavigableString not subject to the normal formatting rules.
+
+ The string will be passed into the formatter (to trigger side effects),
+ but the return value will be ignored.
+ """
+
+ def output_ready(self, formatter="minimal"):
+ """CData strings are passed into the formatter.
+ But the return value is ignored."""
+ self.format_string(self, formatter)
+ return self.PREFIX + self + self.SUFFIX
+
+class CData(PreformattedString):
+
+ PREFIX = u'<![CDATA['
+ SUFFIX = u']]>'
+
+class ProcessingInstruction(PreformattedString):
+
+ PREFIX = u'<?'
+ SUFFIX = u'?>'
+
+class Comment(PreformattedString):
+
+ PREFIX = u'<!--'
+ SUFFIX = u'-->'
+
+
+class Declaration(PreformattedString):
+ PREFIX = u'<!'
+ SUFFIX = u'!>'
+
+
+class Doctype(PreformattedString):
+
+ @classmethod
+ def for_name_and_ids(cls, name, pub_id, system_id):
+ value = name or ''
+ if pub_id is not None:
+ value += ' PUBLIC "%s"' % pub_id
+ if system_id is not None:
+ value += ' "%s"' % system_id
+ elif system_id is not None:
+ value += ' SYSTEM "%s"' % system_id
+
+ return Doctype(value)
+
+ PREFIX = u'<!DOCTYPE '
+ SUFFIX = u'>\n'
+
+
+class Tag(PageElement):
+
+ """Represents a found HTML tag with its attributes and contents."""
+
+ def __init__(self, parser=None, builder=None, name=None, namespace=None,
+ prefix=None, attrs=None, parent=None, previous=None):
+ "Basic constructor."
+
+ if parser is None:
+ self.parser_class = None
+ else:
+ # We don't actually store the parser object: that lets extracted
+ # chunks be garbage-collected.
+ self.parser_class = parser.__class__
+ if name is None:
+ raise ValueError("No value provided for new tag's name.")
+ self.name = name
+ self.namespace = namespace
+ self.prefix = prefix
+ if attrs is None:
+ attrs = {}
+ elif attrs and builder.cdata_list_attributes:
+ attrs = builder._replace_cdata_list_attribute_values(
+ self.name, attrs)
+ else:
+ attrs = dict(attrs)
+ self.attrs = attrs
+ self.contents = []
+ self.setup(parent, previous)
+ self.hidden = False
+
+ # Set up any substitutions, such as the charset in a META tag.
+ if builder is not None:
+ builder.set_up_substitutions(self)
+ self.can_be_empty_element = builder.can_be_empty_element(name)
+ else:
+ self.can_be_empty_element = False
+
+ parserClass = _alias("parser_class") # BS3
+
+ @property
+ def is_empty_element(self):
+ """Is this tag an empty-element tag? (aka a self-closing tag)
+
+ A tag that has contents is never an empty-element tag.
+
+ A tag that has no contents may or may not be an empty-element
+ tag. It depends on the builder used to create the tag. If the
+ builder has a designated list of empty-element tags, then only
+ a tag whose name shows up in that list is considered an
+ empty-element tag.
+
+ If the builder has no designated list of empty-element tags,
+ then any tag with no contents is an empty-element tag.
+ """
+ return len(self.contents) == 0 and self.can_be_empty_element
+ isSelfClosing = is_empty_element # BS3
+
+ @property
+ def string(self):
+ """Convenience property to get the single string within this tag.
+
+ :Return: If this tag has a single string child, return value
+ is that string. If this tag has no children, or more than one
+ child, return value is None. If this tag has one child tag,
+ return value is the 'string' attribute of the child tag,
+ recursively.
+ """
+ if len(self.contents) != 1:
+ return None
+ child = self.contents[0]
+ if isinstance(child, NavigableString):
+ return child
+ return child.string
+
+ @string.setter
+ def string(self, string):
+ self.clear()
+ self.append(string.__class__(string))
+
+ def _all_strings(self, strip=False, types=(NavigableString, CData)):
+ """Yield all strings of certain classes, possibly stripping them.
+
+ By default, yields only NavigableString and CData objects. So
+ no comments, processing instructions, etc.
+ """
+ for descendant in self.descendants:
+ if (
+ (types is None and not isinstance(descendant, NavigableString))
+ or
+ (types is not None and type(descendant) not in types)):
+ continue
+ if strip:
+ descendant = descendant.strip()
+ if len(descendant) == 0:
+ continue
+ yield descendant
+
+ strings = property(_all_strings)
+
+ @property
+ def stripped_strings(self):
+ for string in self._all_strings(True):
+ yield string
+
+ def get_text(self, separator=u"", strip=False,
+ types=(NavigableString, CData)):
+ """
+ Get all child strings, concatenated using the given separator.
+ """
+ return separator.join([s for s in self._all_strings(
+ strip, types=types)])
+ getText = get_text
+ text = property(get_text)
+
+ def decompose(self):
+ """Recursively destroys the contents of this tree."""
+ self.extract()
+ i = self
+ while i is not None:
+ next = i.next_element
+ i.__dict__.clear()
+ i.contents = []
+ i = next
+
+ def clear(self, decompose=False):
+ """
+ Extract all children. If decompose is True, decompose instead.
+ """
+ if decompose:
+ for element in self.contents[:]:
+ if isinstance(element, Tag):
+ element.decompose()
+ else:
+ element.extract()
+ else:
+ for element in self.contents[:]:
+ element.extract()
+
+ def index(self, element):
+ """
+ Find the index of a child by identity, not value. Avoids issues with
+ tag.contents.index(element) getting the index of equal elements.
+ """
+ for i, child in enumerate(self.contents):
+ if child is element:
+ return i
+ raise ValueError("Tag.index: element not in tag")
+
+ def get(self, key, default=None):
+ """Returns the value of the 'key' attribute for the tag, or
+ the value given for 'default' if it doesn't have that
+ attribute."""
+ return self.attrs.get(key, default)
+
+ def has_attr(self, key):
+ return key in self.attrs
+
+ def __hash__(self):
+ return str(self).__hash__()
+
+ def __getitem__(self, key):
+ """tag[key] returns the value of the 'key' attribute for the tag,
+ and throws an exception if it's not there."""
+ return self.attrs[key]
+
+ def __iter__(self):
+ "Iterating over a tag iterates over its contents."
+ return iter(self.contents)
+
+ def __len__(self):
+ "The length of a tag is the length of its list of contents."
+ return len(self.contents)
+
+ def __contains__(self, x):
+ return x in self.contents
+
+ def __nonzero__(self):
+ "A tag is non-None even if it has no contents."
+ return True
+
+ def __setitem__(self, key, value):
+ """Setting tag[key] sets the value of the 'key' attribute for the
+ tag."""
+ self.attrs[key] = value
+
+ def __delitem__(self, key):
+ "Deleting tag[key] deletes all 'key' attributes for the tag."
+ self.attrs.pop(key, None)
+
+ def __call__(self, *args, **kwargs):
+ """Calling a tag like a function is the same as calling its
+ find_all() method. Eg. tag('a') returns a list of all the A tags
+ found within this tag."""
+ return self.find_all(*args, **kwargs)
+
+ def __getattr__(self, tag):
+ #print "Getattr %s.%s" % (self.__class__, tag)
+ if len(tag) > 3 and tag.endswith('Tag'):
+ # BS3: soup.aTag -> "soup.find("a")
+ tag_name = tag[:-3]
+ warnings.warn(
+ '.%sTag is deprecated, use .find("%s") instead.' % (
+ tag_name, tag_name))
+ return self.find(tag_name)
+ # We special case contents to avoid recursion.
+ elif not tag.startswith("__") and not tag=="contents":
+ return self.find(tag)
+ raise AttributeError(
+ "'%s' object has no attribute '%s'" % (self.__class__, tag))
+
+ def __eq__(self, other):
+ """Returns true iff this tag has the same name, the same attributes,
+ and the same contents (recursively) as the given tag."""
+ if self is other:
+ return True
+ if (not hasattr(other, 'name') or
+ not hasattr(other, 'attrs') or
+ not hasattr(other, 'contents') or
+ self.name != other.name or
+ self.attrs != other.attrs or
+ len(self) != len(other)):
+ return False
+ for i, my_child in enumerate(self.contents):
+ if my_child != other.contents[i]:
+ return False
+ return True
+
+ def __ne__(self, other):
+ """Returns true iff this tag is not identical to the other tag,
+ as defined in __eq__."""
+ return not self == other
+
+ def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+ """Renders this tag as a string."""
+ return self.encode(encoding)
+
+ def __unicode__(self):
+ return self.decode()
+
+ def __str__(self):
+ return self.encode()
+
+ if PY3K:
+ __str__ = __repr__ = __unicode__
+
+ def encode(self, encoding=DEFAULT_OUTPUT_ENCODING,
+ indent_level=None, formatter="minimal",
+ errors="xmlcharrefreplace"):
+ # Turn the data structure into Unicode, then encode the
+ # Unicode.
+ u = self.decode(indent_level, encoding, formatter)
+ return u.encode(encoding, errors)
+
+ def _should_pretty_print(self, indent_level):
+ """Should this tag be pretty-printed?"""
+ return (
+ indent_level is not None and
+ (self.name not in HTMLAwareEntitySubstitution.preformatted_tags
+ or self._is_xml))
+
+ def decode(self, indent_level=None,
+ eventual_encoding=DEFAULT_OUTPUT_ENCODING,
+ formatter="minimal"):
+ """Returns a Unicode representation of this tag and its contents.
+
+ :param eventual_encoding: The tag is destined to be
+ encoded into this encoding. This method is _not_
+ responsible for performing that encoding. This information
+ is passed in so that it can be substituted in if the
+ document contains a <META> tag that mentions the document's
+ encoding.
+ """
+
+ # First off, turn a string formatter into a function. This
+ # will stop the lookup from happening over and over again.
+ if not callable(formatter):
+ formatter = self._formatter_for_name(formatter)
+
+ attrs = []
+ if self.attrs:
+ for key, val in sorted(self.attrs.items()):
+ if val is None:
+ decoded = key
+ else:
+ if isinstance(val, list) or isinstance(val, tuple):
+ val = ' '.join(val)
+ elif not isinstance(val, basestring):
+ val = unicode(val)
+ elif (
+ isinstance(val, AttributeValueWithCharsetSubstitution)
+ and eventual_encoding is not None):
+ val = val.encode(eventual_encoding)
+
+ text = self.format_string(val, formatter)
+ decoded = (
+ unicode(key) + '='
+ + EntitySubstitution.quoted_attribute_value(text))
+ attrs.append(decoded)
+ close = ''
+ closeTag = ''
+
+ prefix = ''
+ if self.prefix:
+ prefix = self.prefix + ":"
+
+ if self.is_empty_element:
+ close = '/'
+ else:
+ closeTag = '</%s%s>' % (prefix, self.name)
+
+ pretty_print = self._should_pretty_print(indent_level)
+ space = ''
+ indent_space = ''
+ if indent_level is not None:
+ indent_space = (' ' * (indent_level - 1))
+ if pretty_print:
+ space = indent_space
+ indent_contents = indent_level + 1
+ else:
+ indent_contents = None
+ contents = self.decode_contents(
+ indent_contents, eventual_encoding, formatter)
+
+ if self.hidden:
+ # This is the 'document root' object.
+ s = contents
+ else:
+ s = []
+ attribute_string = ''
+ if attrs:
+ attribute_string = ' ' + ' '.join(attrs)
+ if indent_level is not None:
+ # Even if this particular tag is not pretty-printed,
+ # we should indent up to the start of the tag.
+ s.append(indent_space)
+ s.append('<%s%s%s%s>' % (
+ prefix, self.name, attribute_string, close))
+ if pretty_print:
+ s.append("\n")
+ s.append(contents)
+ if pretty_print and contents and contents[-1] != "\n":
+ s.append("\n")
+ if pretty_print and closeTag:
+ s.append(space)
+ s.append(closeTag)
+ if indent_level is not None and closeTag and self.next_sibling:
+ # Even if this particular tag is not pretty-printed,
+ # we're now done with the tag, and we should add a
+ # newline if appropriate.
+ s.append("\n")
+ s = ''.join(s)
+ return s
+
+ def prettify(self, encoding=None, formatter="minimal"):
+ if encoding is None:
+ return self.decode(True, formatter=formatter)
+ else:
+ return self.encode(encoding, True, formatter=formatter)
+
+ def decode_contents(self, indent_level=None,
+ eventual_encoding=DEFAULT_OUTPUT_ENCODING,
+ formatter="minimal"):
+ """Renders the contents of this tag as a Unicode string.
+
+ :param eventual_encoding: The tag is destined to be
+ encoded into this encoding. This method is _not_
+ responsible for performing that encoding. This information
+ is passed in so that it can be substituted in if the
+ document contains a <META> tag that mentions the document's
+ encoding.
+ """
+ # First off, turn a string formatter into a function. This
+ # will stop the lookup from happening over and over again.
+ if not callable(formatter):
+ formatter = self._formatter_for_name(formatter)
+
+ pretty_print = (indent_level is not None)
+ s = []
+ for c in self:
+ text = None
+ if isinstance(c, NavigableString):
+ text = c.output_ready(formatter)
+ elif isinstance(c, Tag):
+ s.append(c.decode(indent_level, eventual_encoding,
+ formatter))
+ if text and indent_level and not self.name == 'pre':
+ text = text.strip()
+ if text:
+ if pretty_print and not self.name == 'pre':
+ s.append(" " * (indent_level - 1))
+ s.append(text)
+ if pretty_print and not self.name == 'pre':
+ s.append("\n")
+ return ''.join(s)
+
+ def encode_contents(
+ self, indent_level=None, encoding=DEFAULT_OUTPUT_ENCODING,
+ formatter="minimal"):
+ """Renders the contents of this tag as a bytestring."""
+ contents = self.decode_contents(indent_level, encoding, formatter)
+ return contents.encode(encoding)
+
+ # Old method for BS3 compatibility
+ def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
+ prettyPrint=False, indentLevel=0):
+ if not prettyPrint:
+ indentLevel = None
+ return self.encode_contents(
+ indent_level=indentLevel, encoding=encoding)
+
+ #Soup methods
+
+ def find(self, name=None, attrs={}, recursive=True, text=None,
+ **kwargs):
+ """Return only the first child of this Tag matching the given
+ criteria."""
+ r = None
+ l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
+ if l:
+ r = l[0]
+ return r
+ findChild = find
+
+ def find_all(self, name=None, attrs={}, recursive=True, text=None,
+ limit=None, **kwargs):
+ """Extracts a list of Tag objects that match the given
+ criteria. You can specify the name of the Tag and any
+ attributes you want the Tag to have.
+
+ The value of a key-value pair in the 'attrs' map can be a
+ string, a list of strings, a regular expression object, or a
+ callable that takes a string and returns whether or not the
+ string matches for some custom definition of 'matches'. The
+ same is true of the tag name."""
+
+ generator = self.descendants
+ if not recursive:
+ generator = self.children
+ return self._find_all(name, attrs, text, limit, generator, **kwargs)
+ findAll = find_all # BS3
+ findChildren = find_all # BS2
+
+ #Generator methods
+ @property
+ def children(self):
+ # return iter() to make the purpose of the method clear
+ return iter(self.contents) # XXX This seems to be untested.
+
+ @property
+ def descendants(self):
+ if not len(self.contents):
+ return
+ stopNode = self._last_descendant().next_element
+ current = self.contents[0]
+ while current is not stopNode:
+ yield current
+ current = current.next_element
+
+ # CSS selector code
+
+ _selector_combinators = ['>', '+', '~']
+ _select_debug = False
+ def select(self, selector, _candidate_generator=None):
+ """Perform a CSS selection operation on the current element."""
+ tokens = selector.split()
+ current_context = [self]
+
+ if tokens[-1] in self._selector_combinators:
+ raise ValueError(
+ 'Final combinator "%s" is missing an argument.' % tokens[-1])
+ if self._select_debug:
+ print 'Running CSS selector "%s"' % selector
+ for index, token in enumerate(tokens):
+ if self._select_debug:
+ print ' Considering token "%s"' % token
+ recursive_candidate_generator = None
+ tag_name = None
+ if tokens[index-1] in self._selector_combinators:
+ # This token was consumed by the previous combinator. Skip it.
+ if self._select_debug:
+ print ' Token was consumed by the previous combinator.'
+ continue
+ # Each operation corresponds to a checker function, a rule
+ # for determining whether a candidate matches the
+ # selector. Candidates are generated by the active
+ # iterator.
+ checker = None
+
+ m = self.attribselect_re.match(token)
+ if m is not None:
+ # Attribute selector
+ tag_name, attribute, operator, value = m.groups()
+ checker = self._attribute_checker(operator, attribute, value)
+
+ elif '#' in token:
+ # ID selector
+ tag_name, tag_id = token.split('#', 1)
+ def id_matches(tag):
+ return tag.get('id', None) == tag_id
+ checker = id_matches
+
+ elif '.' in token:
+ # Class selector
+ tag_name, klass = token.split('.', 1)
+ classes = set(klass.split('.'))
+ def classes_match(candidate):
+ return classes.issubset(candidate.get('class', []))
+ checker = classes_match
+
+ elif ':' in token:
+ # Pseudo-class
+ tag_name, pseudo = token.split(':', 1)
+ if tag_name == '':
+ raise ValueError(
+ "A pseudo-class must be prefixed with a tag name.")
+ pseudo_attributes = re.match('([a-zA-Z\d-]+)\(([a-zA-Z\d]+)\)', pseudo)
+ found = []
+ if pseudo_attributes is not None:
+ pseudo_type, pseudo_value = pseudo_attributes.groups()
+ if pseudo_type == 'nth-of-type':
+ try:
+ pseudo_value = int(pseudo_value)
+ except:
+ raise NotImplementedError(
+ 'Only numeric values are currently supported for the nth-of-type pseudo-class.')
+ if pseudo_value < 1:
+ raise ValueError(
+ 'nth-of-type pseudo-class value must be at least 1.')
+ class Counter(object):
+ def __init__(self, destination):
+ self.count = 0
+ self.destination = destination
+
+ def nth_child_of_type(self, tag):
+ self.count += 1
+ if self.count == self.destination:
+ return True
+ if self.count > self.destination:
+ # Stop the generator that's sending us
+ # these things.
+ raise StopIteration()
+ return False
+ checker = Counter(pseudo_value).nth_child_of_type
+ else:
+ raise NotImplementedError(
+ 'Only the following pseudo-classes are implemented: nth-of-type.')
+
+ elif token == '*':
+ # Star selector -- matches everything
+ pass
+ elif token == '>':
+ # Run the next token as a CSS selector against the
+ # direct children of each tag in the current context.
+ recursive_candidate_generator = lambda tag: tag.children
+ elif token == '~':
+ # Run the next token as a CSS selector against the
+ # siblings of each tag in the current context.
+ recursive_candidate_generator = lambda tag: tag.next_siblings
+ elif token == '+':
+ # For each tag in the current context, run the next
+ # token as a CSS selector against the tag's next
+ # sibling that's a tag.
+ def next_tag_sibling(tag):
+ yield tag.find_next_sibling(True)
+ recursive_candidate_generator = next_tag_sibling
+
+ elif self.tag_name_re.match(token):
+ # Just a tag name.
+ tag_name = token
+ else:
+ raise ValueError(
+ 'Unsupported or invalid CSS selector: "%s"' % token)
+
+ if recursive_candidate_generator:
+ # This happens when the selector looks like "> foo".
+ #
+ # The generator calls select() recursively on every
+ # member of the current context, passing in a different
+ # candidate generator and a different selector.
+ #
+ # In the case of "> foo", the candidate generator is
+ # one that yields a tag's direct children (">"), and
+ # the selector is "foo".
+ next_token = tokens[index+1]
+ def recursive_select(tag):
+ if self._select_debug:
+ print ' Calling select("%s") recursively on %s %s' % (next_token, tag.name, tag.attrs)
+ print '-' * 40
+ for i in tag.select(next_token, recursive_candidate_generator):
+ if self._select_debug:
+ print '(Recursive select picked up candidate %s %s)' % (i.name, i.attrs)
+ yield i
+ if self._select_debug:
+ print '-' * 40
+ _use_candidate_generator = recursive_select
+ elif _candidate_generator is None:
+ # By default, a tag's candidates are all of its
+ # children. If tag_name is defined, only yield tags
+ # with that name.
+ if self._select_debug:
+ if tag_name:
+ check = "[any]"
+ else:
+ check = tag_name
+ print ' Default candidate generator, tag name="%s"' % check
+ if self._select_debug:
+ # This is redundant with later code, but it stops
+ # a bunch of bogus tags from cluttering up the
+ # debug log.
+ def default_candidate_generator(tag):
+ for child in tag.descendants:
+ if not isinstance(child, Tag):
+ continue
+ if tag_name and not child.name == tag_name:
+ continue
+ yield child
+ _use_candidate_generator = default_candidate_generator
+ else:
+ _use_candidate_generator = lambda tag: tag.descendants
+ else:
+ _use_candidate_generator = _candidate_generator
+
+ new_context = []
+ new_context_ids = set([])
+ for tag in current_context:
+ if self._select_debug:
+ print " Running candidate generator on %s %s" % (
+ tag.name, repr(tag.attrs))
+ for candidate in _use_candidate_generator(tag):
+ if not isinstance(candidate, Tag):
+ continue
+ if tag_name and candidate.name != tag_name:
+ continue
+ if checker is not None:
+ try:
+ result = checker(candidate)
+ except StopIteration:
+ # The checker has decided we should no longer
+ # run the generator.
+ break
+ if checker is None or result:
+ if self._select_debug:
+ print " SUCCESS %s %s" % (candidate.name, repr(candidate.attrs))
+ if id(candidate) not in new_context_ids:
+ # If a tag matches a selector more than once,
+ # don't include it in the context more than once.
+ new_context.append(candidate)
+ new_context_ids.add(id(candidate))
+ elif self._select_debug:
+ print " FAILURE %s %s" % (candidate.name, repr(candidate.attrs))
+
+ current_context = new_context
+
+ if self._select_debug:
+ print "Final verdict:"
+ for i in current_context:
+ print " %s %s" % (i.name, i.attrs)
+ return current_context
+
+ # Old names for backwards compatibility
+ def childGenerator(self):
+ return self.children
+
+ def recursiveChildGenerator(self):
+ return self.descendants
+
+ def has_key(self, key):
+ """This was kind of misleading because has_key() (attributes)
+ was different from __in__ (contents). has_key() is gone in
+ Python 3, anyway."""
+ warnings.warn('has_key is deprecated. Use has_attr("%s") instead.' % (
+ key))
+ return self.has_attr(key)
+
+# Next, a couple classes to represent queries and their results.
+class SoupStrainer(object):
+ """Encapsulates a number of ways of matching a markup element (tag or
+ text)."""
+
+ def __init__(self, name=None, attrs={}, text=None, **kwargs):
+ self.name = self._normalize_search_value(name)
+ if not isinstance(attrs, dict):
+ # Treat a non-dict value for attrs as a search for the 'class'
+ # attribute.
+ kwargs['class'] = attrs
+ attrs = None
+
+ if 'class_' in kwargs:
+ # Treat class_="foo" as a search for the 'class'
+ # attribute, overriding any non-dict value for attrs.
+ kwargs['class'] = kwargs['class_']
+ del kwargs['class_']
+
+ if kwargs:
+ if attrs:
+ attrs = attrs.copy()
+ attrs.update(kwargs)
+ else:
+ attrs = kwargs
+ normalized_attrs = {}
+ for key, value in attrs.items():
+ normalized_attrs[key] = self._normalize_search_value(value)
+
+ self.attrs = normalized_attrs
+ self.text = self._normalize_search_value(text)
+
+ def _normalize_search_value(self, value):
+ # Leave it alone if it's a Unicode string, a callable, a
+ # regular expression, a boolean, or None.
+ if (isinstance(value, unicode) or callable(value) or hasattr(value, 'match')
+ or isinstance(value, bool) or value is None):
+ return value
+
+ # If it's a bytestring, convert it to Unicode, treating it as UTF-8.
+ if isinstance(value, bytes):
+ return value.decode("utf8")
+
+ # If it's listlike, convert it into a list of strings.
+ if hasattr(value, '__iter__'):
+ new_value = []
+ for v in value:
+ if (hasattr(v, '__iter__') and not isinstance(v, bytes)
+ and not isinstance(v, unicode)):
+ # This is almost certainly the user's mistake. In the
+ # interests of avoiding infinite loops, we'll let
+ # it through as-is rather than doing a recursive call.
+ new_value.append(v)
+ else:
+ new_value.append(self._normalize_search_value(v))
+ return new_value
+
+ # Otherwise, convert it into a Unicode string.
+ # The unicode(str()) thing is so this will do the same thing on Python 2
+ # and Python 3.
+ return unicode(str(value))
+
+ def __str__(self):
+ if self.text:
+ return self.text
+ else:
+ return "%s|%s" % (self.name, self.attrs)
+
+ def search_tag(self, markup_name=None, markup_attrs={}):
+ found = None
+ markup = None
+ if isinstance(markup_name, Tag):
+ markup = markup_name
+ markup_attrs = markup
+ call_function_with_tag_data = (
+ isinstance(self.name, collections.Callable)
+ and not isinstance(markup_name, Tag))
+
+ if ((not self.name)
+ or call_function_with_tag_data
+ or (markup and self._matches(markup, self.name))
+ or (not markup and self._matches(markup_name, self.name))):
+ if call_function_with_tag_data:
+ match = self.name(markup_name, markup_attrs)
+ else:
+ match = True
+ markup_attr_map = None
+ for attr, match_against in list(self.attrs.items()):
+ if not markup_attr_map:
+ if hasattr(markup_attrs, 'get'):
+ markup_attr_map = markup_attrs
+ else:
+ markup_attr_map = {}
+ for k, v in markup_attrs:
+ markup_attr_map[k] = v
+ attr_value = markup_attr_map.get(attr)
+ if not self._matches(attr_value, match_against):
+ match = False
+ break
+ if match:
+ if markup:
+ found = markup
+ else:
+ found = markup_name
+ if found and self.text and not self._matches(found.string, self.text):
+ found = None
+ return found
+ searchTag = search_tag
+
+ def search(self, markup):
+ # print 'looking for %s in %s' % (self, markup)
+ found = None
+ # If given a list of items, scan it for a text element that
+ # matches.
+ if hasattr(markup, '__iter__') and not isinstance(markup, (Tag, basestring)):
+ for element in markup:
+ if isinstance(element, NavigableString) \
+ and self.search(element):
+ found = element
+ break
+ # If it's a Tag, make sure its name or attributes match.
+ # Don't bother with Tags if we're searching for text.
+ elif isinstance(markup, Tag):
+ if not self.text or self.name or self.attrs:
+ found = self.search_tag(markup)
+ # If it's text, make sure the text matches.
+ elif isinstance(markup, NavigableString) or \
+ isinstance(markup, basestring):
+ if not self.name and not self.attrs and self._matches(markup, self.text):
+ found = markup
+ else:
+ raise Exception(
+ "I don't know how to match against a %s" % markup.__class__)
+ return found
+
+ def _matches(self, markup, match_against):
+ # print u"Matching %s against %s" % (markup, match_against)
+ result = False
+ if isinstance(markup, list) or isinstance(markup, tuple):
+ # This should only happen when searching a multi-valued attribute
+ # like 'class'.
+ if (isinstance(match_against, unicode)
+ and ' ' in match_against):
+ # A bit of a special case. If they try to match "foo
+ # bar" on a multivalue attribute's value, only accept
+ # the literal value "foo bar"
+ #
+ # XXX This is going to be pretty slow because we keep
+ # splitting match_against. But it shouldn't come up
+ # too often.
+ return (whitespace_re.split(match_against) == markup)
+ else:
+ for item in markup:
+ if self._matches(item, match_against):
+ return True
+ return False
+
+ if match_against is True:
+ # True matches any non-None value.
+ return markup is not None
+
+ if isinstance(match_against, collections.Callable):
+ return match_against(markup)
+
+ # Custom callables take the tag as an argument, but all
+ # other ways of matching match the tag name as a string.
+ if isinstance(markup, Tag):
+ markup = markup.name
+
+ # Ensure that `markup` is either a Unicode string, or None.
+ markup = self._normalize_search_value(markup)
+
+ if markup is None:
+ # None matches None, False, an empty string, an empty list, and so on.
+ return not match_against
+
+ if isinstance(match_against, unicode):
+ # Exact string match
+ return markup == match_against
+
+ if hasattr(match_against, 'match'):
+ # Regexp match
+ return match_against.search(markup)
+
+ if hasattr(match_against, '__iter__'):
+ # The markup must be an exact match against something
+ # in the iterable.
+ return markup in match_against
+
+
+class ResultSet(list):
+ """A ResultSet is just a list that keeps track of the SoupStrainer
+ that created it."""
+ def __init__(self, source, result=()):
+ super(ResultSet, self).__init__(result)
+ self.source = source
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/testing.py b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/testing.py
new file mode 100644
index 00000000000..fd4495ac58c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/bs4/testing.py
@@ -0,0 +1,592 @@
+"""Helper classes for tests."""
+
+import copy
+import functools
+import unittest
+from unittest import TestCase
+from bs4 import BeautifulSoup
+from bs4.element import (
+ CharsetMetaAttributeValue,
+ Comment,
+ ContentMetaAttributeValue,
+ Doctype,
+ SoupStrainer,
+)
+
+from bs4.builder import HTMLParserTreeBuilder
+default_builder = HTMLParserTreeBuilder
+
+
+class SoupTest(unittest.TestCase):
+
+ @property
+ def default_builder(self):
+ return default_builder()
+
+ def soup(self, markup, **kwargs):
+ """Build a Beautiful Soup object from markup."""
+ builder = kwargs.pop('builder', self.default_builder)
+ return BeautifulSoup(markup, builder=builder, **kwargs)
+
+ def document_for(self, markup):
+ """Turn an HTML fragment into a document.
+
+ The details depend on the builder.
+ """
+ return self.default_builder.test_fragment_to_document(markup)
+
+ def assertSoupEquals(self, to_parse, compare_parsed_to=None):
+ builder = self.default_builder
+ obj = BeautifulSoup(to_parse, builder=builder)
+ if compare_parsed_to is None:
+ compare_parsed_to = to_parse
+
+ self.assertEqual(obj.decode(), self.document_for(compare_parsed_to))
+
+
+class HTMLTreeBuilderSmokeTest(object):
+
+ """A basic test of a treebuilder's competence.
+
+ Any HTML treebuilder, present or future, should be able to pass
+ these tests. With invalid markup, there's room for interpretation,
+ and different parsers can handle it differently. But with the
+ markup in these tests, there's not much room for interpretation.
+ """
+
+ def assertDoctypeHandled(self, doctype_fragment):
+ """Assert that a given doctype string is handled correctly."""
+ doctype_str, soup = self._document_with_doctype(doctype_fragment)
+
+ # Make sure a Doctype object was created.
+ doctype = soup.contents[0]
+ self.assertEqual(doctype.__class__, Doctype)
+ self.assertEqual(doctype, doctype_fragment)
+ self.assertEqual(str(soup)[:len(doctype_str)], doctype_str)
+
+ # Make sure that the doctype was correctly associated with the
+ # parse tree and that the rest of the document parsed.
+ self.assertEqual(soup.p.contents[0], 'foo')
+
+ def _document_with_doctype(self, doctype_fragment):
+ """Generate and parse a document with the given doctype."""
+ doctype = '<!DOCTYPE %s>' % doctype_fragment
+ markup = doctype + '\n<p>foo</p>'
+ soup = self.soup(markup)
+ return doctype, soup
+
+ def test_normal_doctypes(self):
+ """Make sure normal, everyday HTML doctypes are handled correctly."""
+ self.assertDoctypeHandled("html")
+ self.assertDoctypeHandled(
+ 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"')
+
+ def test_empty_doctype(self):
+ soup = self.soup("<!DOCTYPE>")
+ doctype = soup.contents[0]
+ self.assertEqual("", doctype.strip())
+
+ def test_public_doctype_with_url(self):
+ doctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"'
+ self.assertDoctypeHandled(doctype)
+
+ def test_system_doctype(self):
+ self.assertDoctypeHandled('foo SYSTEM "http://www.example.com/"')
+
+ def test_namespaced_system_doctype(self):
+ # We can handle a namespaced doctype with a system ID.
+ self.assertDoctypeHandled('xsl:stylesheet SYSTEM "htmlent.dtd"')
+
+ def test_namespaced_public_doctype(self):
+ # Test a namespaced doctype with a public id.
+ self.assertDoctypeHandled('xsl:stylesheet PUBLIC "htmlent.dtd"')
+
+ def test_real_xhtml_document(self):
+ """A real XHTML document should come out more or less the same as it went in."""
+ markup = b"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>Hello.</title></head>
+<body>Goodbye.</body>
+</html>"""
+ soup = self.soup(markup)
+ self.assertEqual(
+ soup.encode("utf-8").replace(b"\n", b""),
+ markup.replace(b"\n", b""))
+
+ def test_deepcopy(self):
+ """Make sure you can copy the tree builder.
+
+ This is important because the builder is part of a
+ BeautifulSoup object, and we want to be able to copy that.
+ """
+ copy.deepcopy(self.default_builder)
+
+ def test_p_tag_is_never_empty_element(self):
+ """A <p> tag is never designated as an empty-element tag.
+
+ Even if the markup shows it as an empty-element tag, it
+ shouldn't be presented that way.
+ """
+ soup = self.soup("<p/>")
+ self.assertFalse(soup.p.is_empty_element)
+ self.assertEqual(str(soup.p), "<p></p>")
+
+ def test_unclosed_tags_get_closed(self):
+ """A tag that's not closed by the end of the document should be closed.
+
+ This applies to all tags except empty-element tags.
+ """
+ self.assertSoupEquals("<p>", "<p></p>")
+ self.assertSoupEquals("<b>", "<b></b>")
+
+ self.assertSoupEquals("<br>", "<br/>")
+
+ def test_br_is_always_empty_element_tag(self):
+ """A <br> tag is designated as an empty-element tag.
+
+ Some parsers treat <br></br> as one <br/> tag, some parsers as
+ two tags, but it should always be an empty-element tag.
+ """
+ soup = self.soup("<br></br>")
+ self.assertTrue(soup.br.is_empty_element)
+ self.assertEqual(str(soup.br), "<br/>")
+
+ def test_nested_formatting_elements(self):
+ self.assertSoupEquals("<em><em></em></em>")
+
+ def test_comment(self):
+ # Comments are represented as Comment objects.
+ markup = "<p>foo<!--foobar-->baz</p>"
+ self.assertSoupEquals(markup)
+
+ soup = self.soup(markup)
+ comment = soup.find(text="foobar")
+ self.assertEqual(comment.__class__, Comment)
+
+ # The comment is properly integrated into the tree.
+ foo = soup.find(text="foo")
+ self.assertEqual(comment, foo.next_element)
+ baz = soup.find(text="baz")
+ self.assertEqual(comment, baz.previous_element)
+
+ def test_preserved_whitespace_in_pre_and_textarea(self):
+ """Whitespace must be preserved in <pre> and <textarea> tags."""
+ self.assertSoupEquals("<pre> </pre>")
+ self.assertSoupEquals("<textarea> woo </textarea>")
+
+ def test_nested_inline_elements(self):
+ """Inline elements can be nested indefinitely."""
+ b_tag = "<b>Inside a B tag</b>"
+ self.assertSoupEquals(b_tag)
+
+ nested_b_tag = "<p>A <i>nested <b>tag</b></i></p>"
+ self.assertSoupEquals(nested_b_tag)
+
+ double_nested_b_tag = "<p>A <a>doubly <i>nested <b>tag</b></i></a></p>"
+ self.assertSoupEquals(nested_b_tag)
+
+ def test_nested_block_level_elements(self):
+ """Block elements can be nested."""
+ soup = self.soup('<blockquote><p><b>Foo</b></p></blockquote>')
+ blockquote = soup.blockquote
+ self.assertEqual(blockquote.p.b.string, 'Foo')
+ self.assertEqual(blockquote.b.string, 'Foo')
+
+ def test_correctly_nested_tables(self):
+ """One table can go inside another one."""
+ markup = ('<table id="1">'
+ '<tr>'
+ "<td>Here's another table:"
+ '<table id="2">'
+ '<tr><td>foo</td></tr>'
+ '</table></td>')
+
+ self.assertSoupEquals(
+ markup,
+ '<table id="1"><tr><td>Here\'s another table:'
+ '<table id="2"><tr><td>foo</td></tr></table>'
+ '</td></tr></table>')
+
+ self.assertSoupEquals(
+ "<table><thead><tr><td>Foo</td></tr></thead>"
+ "<tbody><tr><td>Bar</td></tr></tbody>"
+ "<tfoot><tr><td>Baz</td></tr></tfoot></table>")
+
+ def test_deeply_nested_multivalued_attribute(self):
+ # html5lib can set the attributes of the same tag many times
+ # as it rearranges the tree. This has caused problems with
+ # multivalued attributes.
+ markup = '<table><div><div class="css"></div></div></table>'
+ soup = self.soup(markup)
+ self.assertEqual(["css"], soup.div.div['class'])
+
+ def test_angle_brackets_in_attribute_values_are_escaped(self):
+ self.assertSoupEquals('<a b="<a>"></a>', '<a b="&lt;a&gt;"></a>')
+
+ def test_entities_in_attributes_converted_to_unicode(self):
+ expect = u'<p id="pi\N{LATIN SMALL LETTER N WITH TILDE}ata"></p>'
+ self.assertSoupEquals('<p id="pi&#241;ata"></p>', expect)
+ self.assertSoupEquals('<p id="pi&#xf1;ata"></p>', expect)
+ self.assertSoupEquals('<p id="pi&#Xf1;ata"></p>', expect)
+ self.assertSoupEquals('<p id="pi&ntilde;ata"></p>', expect)
+
+ def test_entities_in_text_converted_to_unicode(self):
+ expect = u'<p>pi\N{LATIN SMALL LETTER N WITH TILDE}ata</p>'
+ self.assertSoupEquals("<p>pi&#241;ata</p>", expect)
+ self.assertSoupEquals("<p>pi&#xf1;ata</p>", expect)
+ self.assertSoupEquals("<p>pi&#Xf1;ata</p>", expect)
+ self.assertSoupEquals("<p>pi&ntilde;ata</p>", expect)
+
+ def test_quot_entity_converted_to_quotation_mark(self):
+ self.assertSoupEquals("<p>I said &quot;good day!&quot;</p>",
+ '<p>I said "good day!"</p>')
+
+ def test_out_of_range_entity(self):
+ expect = u"\N{REPLACEMENT CHARACTER}"
+ self.assertSoupEquals("&#10000000000000;", expect)
+ self.assertSoupEquals("&#x10000000000000;", expect)
+ self.assertSoupEquals("&#1000000000;", expect)
+
+ def test_multipart_strings(self):
+ "Mostly to prevent a recurrence of a bug in the html5lib treebuilder."
+ soup = self.soup("<html><h2>\nfoo</h2><p></p></html>")
+ self.assertEqual("p", soup.h2.string.next_element.name)
+ self.assertEqual("p", soup.p.name)
+
+ def test_basic_namespaces(self):
+ """Parsers don't need to *understand* namespaces, but at the
+ very least they should not choke on namespaces or lose
+ data."""
+
+ markup = b'<html xmlns="http://www.w3.org/1999/xhtml" xmlns:mathml="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg"><head></head><body><mathml:msqrt>4</mathml:msqrt><b svg:fill="red"></b></body></html>'
+ soup = self.soup(markup)
+ self.assertEqual(markup, soup.encode())
+ html = soup.html
+ self.assertEqual('http://www.w3.org/1999/xhtml', soup.html['xmlns'])
+ self.assertEqual(
+ 'http://www.w3.org/1998/Math/MathML', soup.html['xmlns:mathml'])
+ self.assertEqual(
+ 'http://www.w3.org/2000/svg', soup.html['xmlns:svg'])
+
+ def test_multivalued_attribute_value_becomes_list(self):
+ markup = b'<a class="foo bar">'
+ soup = self.soup(markup)
+ self.assertEqual(['foo', 'bar'], soup.a['class'])
+
+ #
+ # Generally speaking, tests below this point are more tests of
+ # Beautiful Soup than tests of the tree builders. But parsers are
+ # weird, so we run these tests separately for every tree builder
+ # to detect any differences between them.
+ #
+
+ def test_can_parse_unicode_document(self):
+ # A seemingly innocuous document... but it's in Unicode! And
+ # it contains characters that can't be represented in the
+ # encoding found in the declaration! The horror!
+ markup = u'<html><head><meta encoding="euc-jp"></head><body>Sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu!</body>'
+ soup = self.soup(markup)
+ self.assertEqual(u'Sacr\xe9 bleu!', soup.body.string)
+
+ def test_soupstrainer(self):
+ """Parsers should be able to work with SoupStrainers."""
+ strainer = SoupStrainer("b")
+ soup = self.soup("A <b>bold</b> <meta/> <i>statement</i>",
+ parse_only=strainer)
+ self.assertEqual(soup.decode(), "<b>bold</b>")
+
+ def test_single_quote_attribute_values_become_double_quotes(self):
+ self.assertSoupEquals("<foo attr='bar'></foo>",
+ '<foo attr="bar"></foo>')
+
+ def test_attribute_values_with_nested_quotes_are_left_alone(self):
+ text = """<foo attr='bar "brawls" happen'>a</foo>"""
+ self.assertSoupEquals(text)
+
+ def test_attribute_values_with_double_nested_quotes_get_quoted(self):
+ text = """<foo attr='bar "brawls" happen'>a</foo>"""
+ soup = self.soup(text)
+ soup.foo['attr'] = 'Brawls happen at "Bob\'s Bar"'
+ self.assertSoupEquals(
+ soup.foo.decode(),
+ """<foo attr="Brawls happen at &quot;Bob\'s Bar&quot;">a</foo>""")
+
+ def test_ampersand_in_attribute_value_gets_escaped(self):
+ self.assertSoupEquals('<this is="really messed up & stuff"></this>',
+ '<this is="really messed up &amp; stuff"></this>')
+
+ self.assertSoupEquals(
+ '<a href="http://example.org?a=1&b=2;3">foo</a>',
+ '<a href="http://example.org?a=1&amp;b=2;3">foo</a>')
+
+ def test_escaped_ampersand_in_attribute_value_is_left_alone(self):
+ self.assertSoupEquals('<a href="http://example.org?a=1&amp;b=2;3"></a>')
+
+ def test_entities_in_strings_converted_during_parsing(self):
+ # Both XML and HTML entities are converted to Unicode characters
+ # during parsing.
+ text = "<p>&lt;&lt;sacr&eacute;&#32;bleu!&gt;&gt;</p>"
+ expected = u"<p>&lt;&lt;sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu!&gt;&gt;</p>"
+ self.assertSoupEquals(text, expected)
+
+ def test_smart_quotes_converted_on_the_way_in(self):
+ # Microsoft smart quotes are converted to Unicode characters during
+ # parsing.
+ quote = b"<p>\x91Foo\x92</p>"
+ soup = self.soup(quote)
+ self.assertEqual(
+ soup.p.string,
+ u"\N{LEFT SINGLE QUOTATION MARK}Foo\N{RIGHT SINGLE QUOTATION MARK}")
+
+ def test_non_breaking_spaces_converted_on_the_way_in(self):
+ soup = self.soup("<a>&nbsp;&nbsp;</a>")
+ self.assertEqual(soup.a.string, u"\N{NO-BREAK SPACE}" * 2)
+
+ def test_entities_converted_on_the_way_out(self):
+ text = "<p>&lt;&lt;sacr&eacute;&#32;bleu!&gt;&gt;</p>"
+ expected = u"<p>&lt;&lt;sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu!&gt;&gt;</p>".encode("utf-8")
+ soup = self.soup(text)
+ self.assertEqual(soup.p.encode("utf-8"), expected)
+
+ def test_real_iso_latin_document(self):
+ # Smoke test of interrelated functionality, using an
+ # easy-to-understand document.
+
+ # Here it is in Unicode. Note that it claims to be in ISO-Latin-1.
+ unicode_html = u'<html><head><meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type"/></head><body><p>Sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu!</p></body></html>'
+
+ # That's because we're going to encode it into ISO-Latin-1, and use
+ # that to test.
+ iso_latin_html = unicode_html.encode("iso-8859-1")
+
+ # Parse the ISO-Latin-1 HTML.
+ soup = self.soup(iso_latin_html)
+ # Encode it to UTF-8.
+ result = soup.encode("utf-8")
+
+ # What do we expect the result to look like? Well, it would
+ # look like unicode_html, except that the META tag would say
+ # UTF-8 instead of ISO-Latin-1.
+ expected = unicode_html.replace("ISO-Latin-1", "utf-8")
+
+ # And, of course, it would be in UTF-8, not Unicode.
+ expected = expected.encode("utf-8")
+
+ # Ta-da!
+ self.assertEqual(result, expected)
+
+ def test_real_shift_jis_document(self):
+ # Smoke test to make sure the parser can handle a document in
+ # Shift-JIS encoding, without choking.
+ shift_jis_html = (
+ b'<html><head></head><body><pre>'
+ b'\x82\xb1\x82\xea\x82\xcdShift-JIS\x82\xc5\x83R\x81[\x83f'
+ b'\x83B\x83\x93\x83O\x82\xb3\x82\xea\x82\xbd\x93\xfa\x96{\x8c'
+ b'\xea\x82\xcc\x83t\x83@\x83C\x83\x8b\x82\xc5\x82\xb7\x81B'
+ b'</pre></body></html>')
+ unicode_html = shift_jis_html.decode("shift-jis")
+ soup = self.soup(unicode_html)
+
+ # Make sure the parse tree is correctly encoded to various
+ # encodings.
+ self.assertEqual(soup.encode("utf-8"), unicode_html.encode("utf-8"))
+ self.assertEqual(soup.encode("euc_jp"), unicode_html.encode("euc_jp"))
+
+ def test_real_hebrew_document(self):
+ # A real-world test to make sure we can convert ISO-8859-9 (a
+ # Hebrew encoding) to UTF-8.
+ hebrew_document = b'<html><head><title>Hebrew (ISO 8859-8) in Visual Directionality</title></head><body><h1>Hebrew (ISO 8859-8) in Visual Directionality</h1>\xed\xe5\xec\xf9</body></html>'
+ soup = self.soup(
+ hebrew_document, from_encoding="iso8859-8")
+ self.assertEqual(soup.original_encoding, 'iso8859-8')
+ self.assertEqual(
+ soup.encode('utf-8'),
+ hebrew_document.decode("iso8859-8").encode("utf-8"))
+
+ def test_meta_tag_reflects_current_encoding(self):
+ # Here's the <meta> tag saying that a document is
+ # encoded in Shift-JIS.
+ meta_tag = ('<meta content="text/html; charset=x-sjis" '
+ 'http-equiv="Content-type"/>')
+
+ # Here's a document incorporating that meta tag.
+ shift_jis_html = (
+ '<html><head>\n%s\n'
+ '<meta http-equiv="Content-language" content="ja"/>'
+ '</head><body>Shift-JIS markup goes here.') % meta_tag
+ soup = self.soup(shift_jis_html)
+
+ # Parse the document, and the charset is seemingly unaffected.
+ parsed_meta = soup.find('meta', {'http-equiv': 'Content-type'})
+ content = parsed_meta['content']
+ self.assertEqual('text/html; charset=x-sjis', content)
+
+ # But that value is actually a ContentMetaAttributeValue object.
+ self.assertTrue(isinstance(content, ContentMetaAttributeValue))
+
+ # And it will take on a value that reflects its current
+ # encoding.
+ self.assertEqual('text/html; charset=utf8', content.encode("utf8"))
+
+ # For the rest of the story, see TestSubstitutions in
+ # test_tree.py.
+
+ def test_html5_style_meta_tag_reflects_current_encoding(self):
+ # Here's the <meta> tag saying that a document is
+ # encoded in Shift-JIS.
+ meta_tag = ('<meta id="encoding" charset="x-sjis" />')
+
+ # Here's a document incorporating that meta tag.
+ shift_jis_html = (
+ '<html><head>\n%s\n'
+ '<meta http-equiv="Content-language" content="ja"/>'
+ '</head><body>Shift-JIS markup goes here.') % meta_tag
+ soup = self.soup(shift_jis_html)
+
+ # Parse the document, and the charset is seemingly unaffected.
+ parsed_meta = soup.find('meta', id="encoding")
+ charset = parsed_meta['charset']
+ self.assertEqual('x-sjis', charset)
+
+ # But that value is actually a CharsetMetaAttributeValue object.
+ self.assertTrue(isinstance(charset, CharsetMetaAttributeValue))
+
+ # And it will take on a value that reflects its current
+ # encoding.
+ self.assertEqual('utf8', charset.encode("utf8"))
+
+ def test_tag_with_no_attributes_can_have_attributes_added(self):
+ data = self.soup("<a>text</a>")
+ data.a['foo'] = 'bar'
+ self.assertEqual('<a foo="bar">text</a>', data.a.decode())
+
+class XMLTreeBuilderSmokeTest(object):
+
+ def test_docstring_generated(self):
+ soup = self.soup("<root/>")
+ self.assertEqual(
+ soup.encode(), b'<?xml version="1.0" encoding="utf-8"?>\n<root/>')
+
+ def test_real_xhtml_document(self):
+ """A real XHTML document should come out *exactly* the same as it went in."""
+ markup = b"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>Hello.</title></head>
+<body>Goodbye.</body>
+</html>"""
+ soup = self.soup(markup)
+ self.assertEqual(
+ soup.encode("utf-8"), markup)
+
+ def test_formatter_processes_script_tag_for_xml_documents(self):
+ doc = """
+ <script type="text/javascript">
+ </script>
+"""
+ soup = BeautifulSoup(doc, "xml")
+ # lxml would have stripped this while parsing, but we can add
+ # it later.
+ soup.script.string = 'console.log("< < hey > > ");'
+ encoded = soup.encode()
+ self.assertTrue(b"&lt; &lt; hey &gt; &gt;" in encoded)
+
+ def test_can_parse_unicode_document(self):
+ markup = u'<?xml version="1.0" encoding="euc-jp"><root>Sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu!</root>'
+ soup = self.soup(markup)
+ self.assertEqual(u'Sacr\xe9 bleu!', soup.root.string)
+
+ def test_popping_namespaced_tag(self):
+ markup = '<rss xmlns:dc="foo"><dc:creator>b</dc:creator><dc:date>2012-07-02T20:33:42Z</dc:date><dc:rights>c</dc:rights><image>d</image></rss>'
+ soup = self.soup(markup)
+ self.assertEqual(
+ unicode(soup.rss), markup)
+
+ def test_docstring_includes_correct_encoding(self):
+ soup = self.soup("<root/>")
+ self.assertEqual(
+ soup.encode("latin1"),
+ b'<?xml version="1.0" encoding="latin1"?>\n<root/>')
+
+ def test_large_xml_document(self):
+ """A large XML document should come out the same as it went in."""
+ markup = (b'<?xml version="1.0" encoding="utf-8"?>\n<root>'
+ + b'0' * (2**12)
+ + b'</root>')
+ soup = self.soup(markup)
+ self.assertEqual(soup.encode("utf-8"), markup)
+
+
+ def test_tags_are_empty_element_if_and_only_if_they_are_empty(self):
+ self.assertSoupEquals("<p>", "<p/>")
+ self.assertSoupEquals("<p>foo</p>")
+
+ def test_namespaces_are_preserved(self):
+ markup = '<root xmlns:a="http://example.com/" xmlns:b="http://example.net/"><a:foo>This tag is in the a namespace</a:foo><b:foo>This tag is in the b namespace</b:foo></root>'
+ soup = self.soup(markup)
+ root = soup.root
+ self.assertEqual("http://example.com/", root['xmlns:a'])
+ self.assertEqual("http://example.net/", root['xmlns:b'])
+
+ def test_closing_namespaced_tag(self):
+ markup = '<p xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>20010504</dc:date></p>'
+ soup = self.soup(markup)
+ self.assertEqual(unicode(soup.p), markup)
+
+ def test_namespaced_attributes(self):
+ markup = '<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><bar xsi:schemaLocation="http://www.example.com"/></foo>'
+ soup = self.soup(markup)
+ self.assertEqual(unicode(soup.foo), markup)
+
+ def test_namespaced_attributes_xml_namespace(self):
+ markup = '<foo xml:lang="fr">bar</foo>'
+ soup = self.soup(markup)
+ self.assertEqual(unicode(soup.foo), markup)
+
+class HTML5TreeBuilderSmokeTest(HTMLTreeBuilderSmokeTest):
+ """Smoke test for a tree builder that supports HTML5."""
+
+ def test_real_xhtml_document(self):
+ # Since XHTML is not HTML5, HTML5 parsers are not tested to handle
+ # XHTML documents in any particular way.
+ pass
+
+ def test_html_tags_have_namespace(self):
+ markup = "<a>"
+ soup = self.soup(markup)
+ self.assertEqual("http://www.w3.org/1999/xhtml", soup.a.namespace)
+
+ def test_svg_tags_have_namespace(self):
+ markup = '<svg><circle/></svg>'
+ soup = self.soup(markup)
+ namespace = "http://www.w3.org/2000/svg"
+ self.assertEqual(namespace, soup.svg.namespace)
+ self.assertEqual(namespace, soup.circle.namespace)
+
+
+ def test_mathml_tags_have_namespace(self):
+ markup = '<math><msqrt>5</msqrt></math>'
+ soup = self.soup(markup)
+ namespace = 'http://www.w3.org/1998/Math/MathML'
+ self.assertEqual(namespace, soup.math.namespace)
+ self.assertEqual(namespace, soup.msqrt.namespace)
+
+ def test_xml_declaration_becomes_comment(self):
+ markup = '<?xml version="1.0" encoding="utf-8"?><html></html>'
+ soup = self.soup(markup)
+ self.assertTrue(isinstance(soup.contents[0], Comment))
+ self.assertEqual(soup.contents[0], '?xml version="1.0" encoding="utf-8"?')
+ self.assertEqual("html", soup.contents[0].next_element.name)
+
+def skipIf(condition, reason):
+ def nothing(test, *args, **kwargs):
+ return None
+
+ def decorator(test_item):
+ if condition:
+ return nothing
+ else:
+ return test_item
+
+ return decorator
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/doc/Makefile b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/Makefile
new file mode 100644
index 00000000000..8c833d2cedb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BeautifulSoup.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BeautifulSoup.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/BeautifulSoup"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BeautifulSoup"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/6.1.jpg b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/6.1.jpg
new file mode 100644
index 00000000000..97014f0ec04
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/6.1.jpg
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/conf.py b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/conf.py
new file mode 100644
index 00000000000..102c3cf972a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/conf.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+#
+# Beautiful Soup documentation build configuration file, created by
+# sphinx-quickstart on Thu Jan 26 11:22:55 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Beautiful Soup'
+copyright = u'2012, Leonard Richardson'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '4'
+# The full version, including alpha/beta/rc tags.
+release = '4.2.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'BeautifulSoupdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'BeautifulSoup.tex', u'Beautiful Soup Documentation',
+ u'Leonard Richardson', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'beautifulsoup', u'Beautiful Soup Documentation',
+ [u'Leonard Richardson'], 1)
+]
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'Beautiful Soup'
+epub_author = u'Leonard Richardson'
+epub_publisher = u'Leonard Richardson'
+epub_copyright = u'2012, Leonard Richardson'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/index.rst b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/index.rst
new file mode 100644
index 00000000000..0e5f6d174ee
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/doc/source/index.rst
@@ -0,0 +1,3049 @@
+Beautiful Soup Documentation
+============================
+
+.. image:: 6.1.jpg
+ :align: right
+ :alt: "The Fish-Footman began by producing from under his arm a great letter, nearly as large as himself."
+
+`Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_ is a
+Python library for pulling data out of HTML and XML files. It works
+with your favorite parser to provide idiomatic ways of navigating,
+searching, and modifying the parse tree. It commonly saves programmers
+hours or days of work.
+
+These instructions illustrate all major features of Beautiful Soup 4,
+with examples. I show you what the library is good for, how it works,
+how to use it, how to make it do what you want, and what to do when it
+violates your expectations.
+
+The examples in this documentation should work the same way in Python
+2.7 and Python 3.2.
+
+You might be looking for the documentation for `Beautiful Soup 3
+<http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_.
+If so, you should know that Beautiful Soup 3 is no longer being
+developed, and that Beautiful Soup 4 is recommended for all new
+projects. If you want to learn about the differences between Beautiful
+Soup 3 and Beautiful Soup 4, see `Porting code to BS4`_.
+
+This documentation has been translated into other languages by its users.
+
+* 이 문서는 한국어 번역도 가능합니다. (`외부 링크 <http://coreapython.hosting.paran.com/etc/beautifulsoup4.html>`_)
+
+Getting help
+------------
+
+If you have questions about Beautiful Soup, or run into problems,
+`send mail to the discussion group
+<https://groups.google.com/forum/?fromgroups#!forum/beautifulsoup>`_. If
+your problem involves parsing an HTML document, be sure to mention
+:ref:`what the diagnose() function says <diagnose>` about
+that document.
+
+Quick Start
+===========
+
+Here's an HTML document I'll be using as an example throughout this
+document. It's part of a story from `Alice in Wonderland`::
+
+ html_doc = """
+ <html><head><title>The Dormouse's story</title></head>
+ <body>
+ <p class="title"><b>The Dormouse's story</b></p>
+
+ <p class="story">Once upon a time there were three little sisters; and their names were
+ <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
+ <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
+ <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
+ and they lived at the bottom of a well.</p>
+
+ <p class="story">...</p>
+ """
+
+Running the "three sisters" document through Beautiful Soup gives us a
+``BeautifulSoup`` object, which represents the document as a nested
+data structure::
+
+ from bs4 import BeautifulSoup
+ soup = BeautifulSoup(html_doc)
+
+ print(soup.prettify())
+ # <html>
+ # <head>
+ # <title>
+ # The Dormouse's story
+ # </title>
+ # </head>
+ # <body>
+ # <p class="title">
+ # <b>
+ # The Dormouse's story
+ # </b>
+ # </p>
+ # <p class="story">
+ # Once upon a time there were three little sisters; and their names were
+ # <a class="sister" href="http://example.com/elsie" id="link1">
+ # Elsie
+ # </a>
+ # ,
+ # <a class="sister" href="http://example.com/lacie" id="link2">
+ # Lacie
+ # </a>
+ # and
+ # <a class="sister" href="http://example.com/tillie" id="link2">
+ # Tillie
+ # </a>
+ # ; and they lived at the bottom of a well.
+ # </p>
+ # <p class="story">
+ # ...
+ # </p>
+ # </body>
+ # </html>
+
+Here are some simple ways to navigate that data structure::
+
+ soup.title
+ # <title>The Dormouse's story</title>
+
+ soup.title.name
+ # u'title'
+
+ soup.title.string
+ # u'The Dormouse's story'
+
+ soup.title.parent.name
+ # u'head'
+
+ soup.p
+ # <p class="title"><b>The Dormouse's story</b></p>
+
+ soup.p['class']
+ # u'title'
+
+ soup.a
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+ soup.find_all('a')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.find(id="link3")
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
+
+One common task is extracting all the URLs found within a page's <a> tags::
+
+ for link in soup.find_all('a'):
+ print(link.get('href'))
+ # http://example.com/elsie
+ # http://example.com/lacie
+ # http://example.com/tillie
+
+Another common task is extracting all the text from a page::
+
+ print(soup.get_text())
+ # The Dormouse's story
+ #
+ # The Dormouse's story
+ #
+ # Once upon a time there were three little sisters; and their names were
+ # Elsie,
+ # Lacie and
+ # Tillie;
+ # and they lived at the bottom of a well.
+ #
+ # ...
+
+Does this look like what you need? If so, read on.
+
+Installing Beautiful Soup
+=========================
+
+If you're using a recent version of Debian or Ubuntu Linux, you can
+install Beautiful Soup with the system package manager:
+
+:kbd:`$ apt-get install python-bs4`
+
+Beautiful Soup 4 is published through PyPi, so if you can't install it
+with the system packager, you can install it with ``easy_install`` or
+``pip``. The package name is ``beautifulsoup4``, and the same package
+works on Python 2 and Python 3.
+
+:kbd:`$ easy_install beautifulsoup4`
+
+:kbd:`$ pip install beautifulsoup4`
+
+(The ``BeautifulSoup`` package is probably `not` what you want. That's
+the previous major release, `Beautiful Soup 3`_. Lots of software uses
+BS3, so it's still available, but if you're writing new code you
+should install ``beautifulsoup4``.)
+
+If you don't have ``easy_install`` or ``pip`` installed, you can
+`download the Beautiful Soup 4 source tarball
+<http://www.crummy.com/software/BeautifulSoup/download/4.x/>`_ and
+install it with ``setup.py``.
+
+:kbd:`$ python setup.py install`
+
+If all else fails, the license for Beautiful Soup allows you to
+package the entire library with your application. You can download the
+tarball, copy its ``bs4`` directory into your application's codebase,
+and use Beautiful Soup without installing it at all.
+
+I use Python 2.7 and Python 3.2 to develop Beautiful Soup, but it
+should work with other recent versions.
+
+Problems after installation
+---------------------------
+
+Beautiful Soup is packaged as Python 2 code. When you install it for
+use with Python 3, it's automatically converted to Python 3 code. If
+you don't install the package, the code won't be converted. There have
+also been reports on Windows machines of the wrong version being
+installed.
+
+If you get the ``ImportError`` "No module named HTMLParser", your
+problem is that you're running the Python 2 version of the code under
+Python 3.
+
+If you get the ``ImportError`` "No module named html.parser", your
+problem is that you're running the Python 3 version of the code under
+Python 2.
+
+In both cases, your best bet is to completely remove the Beautiful
+Soup installation from your system (including any directory created
+when you unzipped the tarball) and try the installation again.
+
+If you get the ``SyntaxError`` "Invalid syntax" on the line
+``ROOT_TAG_NAME = u'[document]'``, you need to convert the Python 2
+code to Python 3. You can do this either by installing the package:
+
+:kbd:`$ python3 setup.py install`
+
+or by manually running Python's ``2to3`` conversion script on the
+``bs4`` directory:
+
+:kbd:`$ 2to3-3.2 -w bs4`
+
+.. _parser-installation:
+
+
+Installing a parser
+-------------------
+
+Beautiful Soup supports the HTML parser included in Python's standard
+library, but it also supports a number of third-party Python parsers.
+One is the `lxml parser <http://lxml.de/>`_. Depending on your setup,
+you might install lxml with one of these commands:
+
+:kbd:`$ apt-get install python-lxml`
+
+:kbd:`$ easy_install lxml`
+
+:kbd:`$ pip install lxml`
+
+Another alternative is the pure-Python `html5lib parser
+<http://code.google.com/p/html5lib/>`_, which parses HTML the way a
+web browser does. Depending on your setup, you might install html5lib
+with one of these commands:
+
+:kbd:`$ apt-get install python-html5lib`
+
+:kbd:`$ easy_install html5lib`
+
+:kbd:`$ pip install html5lib`
+
+This table summarizes the advantages and disadvantages of each parser library:
+
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+| Parser | Typical usage | Advantages | Disadvantages |
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+| Python's html.parser | ``BeautifulSoup(markup, "html.parser")`` | * Batteries included | * Not very lenient |
+| | | * Decent speed | (before Python 2.7.3 |
+| | | * Lenient (as of Python 2.7.3 | or 3.2.2) |
+| | | and 3.2.) | |
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+| lxml's HTML parser | ``BeautifulSoup(markup, "lxml")`` | * Very fast | * External C dependency |
+| | | * Lenient | |
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+| lxml's XML parser | ``BeautifulSoup(markup, ["lxml", "xml"])`` | * Very fast | * External C dependency |
+| | ``BeautifulSoup(markup, "xml")`` | * The only currently supported | |
+| | | XML parser | |
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+| html5lib | ``BeautifulSoup(markup, "html5lib")`` | * Extremely lenient | * Very slow |
+| | | * Parses pages the same way a | * External Python |
+| | | web browser does | dependency |
+| | | * Creates valid HTML5 | |
++----------------------+--------------------------------------------+--------------------------------+--------------------------+
+
+If you can, I recommend you install and use lxml for speed. If you're
+using a version of Python 2 earlier than 2.7.3, or a version of Python
+3 earlier than 3.2.2, it's `essential` that you install lxml or
+html5lib--Python's built-in HTML parser is just not very good in older
+versions.
+
+Note that if a document is invalid, different parsers will generate
+different Beautiful Soup trees for it. See `Differences
+between parsers`_ for details.
+
+Making the soup
+===============
+
+To parse a document, pass it into the ``BeautifulSoup``
+constructor. You can pass in a string or an open filehandle::
+
+ from bs4 import BeautifulSoup
+
+ soup = BeautifulSoup(open("index.html"))
+
+ soup = BeautifulSoup("<html>data</html>")
+
+First, the document is converted to Unicode, and HTML entities are
+converted to Unicode characters::
+
+ BeautifulSoup("Sacr&eacute; bleu!")
+ <html><head></head><body>Sacré bleu!</body></html>
+
+Beautiful Soup then parses the document using the best available
+parser. It will use an HTML parser unless you specifically tell it to
+use an XML parser. (See `Parsing XML`_.)
+
+Kinds of objects
+================
+
+Beautiful Soup transforms a complex HTML document into a complex tree
+of Python objects. But you'll only ever have to deal with about four
+`kinds` of objects.
+
+.. _Tag:
+
+``Tag``
+-------
+
+A ``Tag`` object corresponds to an XML or HTML tag in the original document::
+
+ soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
+ tag = soup.b
+ type(tag)
+ # <class 'bs4.element.Tag'>
+
+Tags have a lot of attributes and methods, and I'll cover most of them
+in `Navigating the tree`_ and `Searching the tree`_. For now, the most
+important features of a tag are its name and attributes.
+
+Name
+^^^^
+
+Every tag has a name, accessible as ``.name``::
+
+ tag.name
+ # u'b'
+
+If you change a tag's name, the change will be reflected in any HTML
+markup generated by Beautiful Soup::
+
+ tag.name = "blockquote"
+ tag
+ # <blockquote class="boldest">Extremely bold</blockquote>
+
+Attributes
+^^^^^^^^^^
+
+A tag may have any number of attributes. The tag ``<b
+class="boldest">`` has an attribute "class" whose value is
+"boldest". You can access a tag's attributes by treating the tag like
+a dictionary::
+
+ tag['class']
+ # u'boldest'
+
+You can access that dictionary directly as ``.attrs``::
+
+ tag.attrs
+ # {u'class': u'boldest'}
+
+You can add, remove, and modify a tag's attributes. Again, this is
+done by treating the tag as a dictionary::
+
+ tag['class'] = 'verybold'
+ tag['id'] = 1
+ tag
+ # <blockquote class="verybold" id="1">Extremely bold</blockquote>
+
+ del tag['class']
+ del tag['id']
+ tag
+ # <blockquote>Extremely bold</blockquote>
+
+ tag['class']
+ # KeyError: 'class'
+ print(tag.get('class'))
+ # None
+
+.. _multivalue:
+
+Multi-valued attributes
+&&&&&&&&&&&&&&&&&&&&&&&
+
+HTML 4 defines a few attributes that can have multiple values. HTML 5
+removes a couple of them, but defines a few more. The most common
+multi-valued attribute is ``class`` (that is, a tag can have more than
+one CSS class). Others include ``rel``, ``rev``, ``accept-charset``,
+``headers``, and ``accesskey``. Beautiful Soup presents the value(s)
+of a multi-valued attribute as a list::
+
+ css_soup = BeautifulSoup('<p class="body strikeout"></p>')
+ css_soup.p['class']
+ # ["body", "strikeout"]
+
+ css_soup = BeautifulSoup('<p class="body"></p>')
+ css_soup.p['class']
+ # ["body"]
+
+If an attribute `looks` like it has more than one value, but it's not
+a multi-valued attribute as defined by any version of the HTML
+standard, Beautiful Soup will leave the attribute alone::
+
+ id_soup = BeautifulSoup('<p id="my id"></p>')
+ id_soup.p['id']
+ # 'my id'
+
+When you turn a tag back into a string, multiple attribute values are
+consolidated::
+
+ rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')
+ rel_soup.a['rel']
+ # ['index']
+ rel_soup.a['rel'] = ['index', 'contents']
+ print(rel_soup.p)
+ # <p>Back to the <a rel="index contents">homepage</a></p>
+
+If you parse a document as XML, there are no multi-valued attributes::
+
+ xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
+ xml_soup.p['class']
+ # u'body strikeout'
+
+
+
+``NavigableString``
+-------------------
+
+A string corresponds to a bit of text within a tag. Beautiful Soup
+uses the ``NavigableString`` class to contain these bits of text::
+
+ tag.string
+ # u'Extremely bold'
+ type(tag.string)
+ # <class 'bs4.element.NavigableString'>
+
+A ``NavigableString`` is just like a Python Unicode string, except
+that it also supports some of the features described in `Navigating
+the tree`_ and `Searching the tree`_. You can convert a
+``NavigableString`` to a Unicode string with ``unicode()``::
+
+ unicode_string = unicode(tag.string)
+ unicode_string
+ # u'Extremely bold'
+ type(unicode_string)
+ # <type 'unicode'>
+
+You can't edit a string in place, but you can replace one string with
+another, using :ref:`replace_with`::
+
+ tag.string.replace_with("No longer bold")
+ tag
+ # <blockquote>No longer bold</blockquote>
+
+``NavigableString`` supports most of the features described in
+`Navigating the tree`_ and `Searching the tree`_, but not all of
+them. In particular, since a string can't contain anything (the way a
+tag may contain a string or another tag), strings don't support the
+``.contents`` or ``.string`` attributes, or the ``find()`` method.
+
+If you want to use a ``NavigableString`` outside of Beautiful Soup,
+you should call ``unicode()`` on it to turn it into a normal Python
+Unicode string. If you don't, your string will carry around a
+reference to the entire Beautiful Soup parse tree, even when you're
+done using Beautiful Soup. This is a big waste of memory.
+
+``BeautifulSoup``
+-----------------
+
+The ``BeautifulSoup`` object itself represents the document as a
+whole. For most purposes, you can treat it as a :ref:`Tag`
+object. This means it supports most of the methods described in
+`Navigating the tree`_ and `Searching the tree`_.
+
+Since the ``BeautifulSoup`` object doesn't correspond to an actual
+HTML or XML tag, it has no name and no attributes. But sometimes it's
+useful to look at its ``.name``, so it's been given the special
+``.name`` "[document]"::
+
+ soup.name
+ # u'[document]'
+
+Comments and other special strings
+----------------------------------
+
+``Tag``, ``NavigableString``, and ``BeautifulSoup`` cover almost
+everything you'll see in an HTML or XML file, but there are a few
+leftover bits. The only one you'll probably ever need to worry about
+is the comment::
+
+ markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
+ soup = BeautifulSoup(markup)
+ comment = soup.b.string
+ type(comment)
+ # <class 'bs4.element.Comment'>
+
+The ``Comment`` object is just a special type of ``NavigableString``::
+
+ comment
+ # u'Hey, buddy. Want to buy a used parser'
+
+But when it appears as part of an HTML document, a ``Comment`` is
+displayed with special formatting::
+
+ print(soup.b.prettify())
+ # <b>
+ # <!--Hey, buddy. Want to buy a used parser?-->
+ # </b>
+
+Beautiful Soup defines classes for anything else that might show up in
+an XML document: ``CData``, ``ProcessingInstruction``,
+``Declaration``, and ``Doctype``. Just like ``Comment``, these classes
+are subclasses of ``NavigableString`` that add something extra to the
+string. Here's an example that replaces the comment with a CDATA
+block::
+
+ from bs4 import CData
+ cdata = CData("A CDATA block")
+ comment.replace_with(cdata)
+
+ print(soup.b.prettify())
+ # <b>
+ # <![CDATA[A CDATA block]]>
+ # </b>
+
+
+Navigating the tree
+===================
+
+Here's the "Three sisters" HTML document again::
+
+ html_doc = """
+ <html><head><title>The Dormouse's story</title></head>
+
+ <p class="title"><b>The Dormouse's story</b></p>
+
+ <p class="story">Once upon a time there were three little sisters; and their names were
+ <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
+ <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
+ <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
+ and they lived at the bottom of a well.</p>
+
+ <p class="story">...</p>
+ """
+
+ from bs4 import BeautifulSoup
+ soup = BeautifulSoup(html_doc)
+
+I'll use this as an example to show you how to move from one part of
+a document to another.
+
+Going down
+----------
+
+Tags may contain strings and other tags. These elements are the tag's
+`children`. Beautiful Soup provides a lot of different attributes for
+navigating and iterating over a tag's children.
+
+Note that Beautiful Soup strings don't support any of these
+attributes, because a string can't have children.
+
+Navigating using tag names
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The simplest way to navigate the parse tree is to say the name of the
+tag you want. If you want the <head> tag, just say ``soup.head``::
+
+ soup.head
+ # <head><title>The Dormouse's story</title></head>
+
+ soup.title
+ # <title>The Dormouse's story</title>
+
+You can do use this trick again and again to zoom in on a certain part
+of the parse tree. This code gets the first <b> tag beneath the <body> tag::
+
+ soup.body.b
+ # <b>The Dormouse's story</b>
+
+Using a tag name as an attribute will give you only the `first` tag by that
+name::
+
+ soup.a
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+If you need to get `all` the <a> tags, or anything more complicated
+than the first tag with a certain name, you'll need to use one of the
+methods described in `Searching the tree`_, such as `find_all()`::
+
+ soup.find_all('a')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+``.contents`` and ``.children``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A tag's children are available in a list called ``.contents``::
+
+ head_tag = soup.head
+ head_tag
+ # <head><title>The Dormouse's story</title></head>
+
+ head_tag.contents
+ [<title>The Dormouse's story</title>]
+
+ title_tag = head_tag.contents[0]
+ title_tag
+ # <title>The Dormouse's story</title>
+ title_tag.contents
+ # [u'The Dormouse's story']
+
+The ``BeautifulSoup`` object itself has children. In this case, the
+<html> tag is the child of the ``BeautifulSoup`` object.::
+
+ len(soup.contents)
+ # 1
+ soup.contents[0].name
+ # u'html'
+
+A string does not have ``.contents``, because it can't contain
+anything::
+
+ text = title_tag.contents[0]
+ text.contents
+ # AttributeError: 'NavigableString' object has no attribute 'contents'
+
+Instead of getting them as a list, you can iterate over a tag's
+children using the ``.children`` generator::
+
+ for child in title_tag.children:
+ print(child)
+ # The Dormouse's story
+
+``.descendants``
+^^^^^^^^^^^^^^^^
+
+The ``.contents`` and ``.children`` attributes only consider a tag's
+`direct` children. For instance, the <head> tag has a single direct
+child--the <title> tag::
+
+ head_tag.contents
+ # [<title>The Dormouse's story</title>]
+
+But the <title> tag itself has a child: the string "The Dormouse's
+story". There's a sense in which that string is also a child of the
+<head> tag. The ``.descendants`` attribute lets you iterate over `all`
+of a tag's children, recursively: its direct children, the children of
+its direct children, and so on::
+
+ for child in head_tag.descendants:
+ print(child)
+ # <title>The Dormouse's story</title>
+ # The Dormouse's story
+
+The <head> tag has only one child, but it has two descendants: the
+<title> tag and the <title> tag's child. The ``BeautifulSoup`` object
+only has one direct child (the <html> tag), but it has a whole lot of
+descendants::
+
+ len(list(soup.children))
+ # 1
+ len(list(soup.descendants))
+ # 25
+
+.. _.string:
+
+``.string``
+^^^^^^^^^^^
+
+If a tag has only one child, and that child is a ``NavigableString``,
+the child is made available as ``.string``::
+
+ title_tag.string
+ # u'The Dormouse's story'
+
+If a tag's only child is another tag, and `that` tag has a
+``.string``, then the parent tag is considered to have the same
+``.string`` as its child::
+
+ head_tag.contents
+ # [<title>The Dormouse's story</title>]
+
+ head_tag.string
+ # u'The Dormouse's story'
+
+If a tag contains more than one thing, then it's not clear what
+``.string`` should refer to, so ``.string`` is defined to be
+``None``::
+
+ print(soup.html.string)
+ # None
+
+.. _string-generators:
+
+``.strings`` and ``stripped_strings``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If there's more than one thing inside a tag, you can still look at
+just the strings. Use the ``.strings`` generator::
+
+ for string in soup.strings:
+ print(repr(string))
+ # u"The Dormouse's story"
+ # u'\n\n'
+ # u"The Dormouse's story"
+ # u'\n\n'
+ # u'Once upon a time there were three little sisters; and their names were\n'
+ # u'Elsie'
+ # u',\n'
+ # u'Lacie'
+ # u' and\n'
+ # u'Tillie'
+ # u';\nand they lived at the bottom of a well.'
+ # u'\n\n'
+ # u'...'
+ # u'\n'
+
+These strings tend to have a lot of extra whitespace, which you can
+remove by using the ``.stripped_strings`` generator instead::
+
+ for string in soup.stripped_strings:
+ print(repr(string))
+ # u"The Dormouse's story"
+ # u"The Dormouse's story"
+ # u'Once upon a time there were three little sisters; and their names were'
+ # u'Elsie'
+ # u','
+ # u'Lacie'
+ # u'and'
+ # u'Tillie'
+ # u';\nand they lived at the bottom of a well.'
+ # u'...'
+
+Here, strings consisting entirely of whitespace are ignored, and
+whitespace at the beginning and end of strings is removed.
+
+Going up
+--------
+
+Continuing the "family tree" analogy, every tag and every string has a
+`parent`: the tag that contains it.
+
+.. _.parent:
+
+``.parent``
+^^^^^^^^^^^
+
+You can access an element's parent with the ``.parent`` attribute. In
+the example "three sisters" document, the <head> tag is the parent
+of the <title> tag::
+
+ title_tag = soup.title
+ title_tag
+ # <title>The Dormouse's story</title>
+ title_tag.parent
+ # <head><title>The Dormouse's story</title></head>
+
+The title string itself has a parent: the <title> tag that contains
+it::
+
+ title_tag.string.parent
+ # <title>The Dormouse's story</title>
+
+The parent of a top-level tag like <html> is the ``BeautifulSoup`` object
+itself::
+
+ html_tag = soup.html
+ type(html_tag.parent)
+ # <class 'bs4.BeautifulSoup'>
+
+And the ``.parent`` of a ``BeautifulSoup`` object is defined as None::
+
+ print(soup.parent)
+ # None
+
+.. _.parents:
+
+``.parents``
+^^^^^^^^^^^^
+
+You can iterate over all of an element's parents with
+``.parents``. This example uses ``.parents`` to travel from an <a> tag
+buried deep within the document, to the very top of the document::
+
+ link = soup.a
+ link
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+ for parent in link.parents:
+ if parent is None:
+ print(parent)
+ else:
+ print(parent.name)
+ # p
+ # body
+ # html
+ # [document]
+ # None
+
+Going sideways
+--------------
+
+Consider a simple document like this::
+
+ sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>")
+ print(sibling_soup.prettify())
+ # <html>
+ # <body>
+ # <a>
+ # <b>
+ # text1
+ # </b>
+ # <c>
+ # text2
+ # </c>
+ # </a>
+ # </body>
+ # </html>
+
+The <b> tag and the <c> tag are at the same level: they're both direct
+children of the same tag. We call them `siblings`. When a document is
+pretty-printed, siblings show up at the same indentation level. You
+can also use this relationship in the code you write.
+
+``.next_sibling`` and ``.previous_sibling``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can use ``.next_sibling`` and ``.previous_sibling`` to navigate
+between page elements that are on the same level of the parse tree::
+
+ sibling_soup.b.next_sibling
+ # <c>text2</c>
+
+ sibling_soup.c.previous_sibling
+ # <b>text1</b>
+
+The <b> tag has a ``.next_sibling``, but no ``.previous_sibling``,
+because there's nothing before the <b> tag `on the same level of the
+tree`. For the same reason, the <c> tag has a ``.previous_sibling``
+but no ``.next_sibling``::
+
+ print(sibling_soup.b.previous_sibling)
+ # None
+ print(sibling_soup.c.next_sibling)
+ # None
+
+The strings "text1" and "text2" are `not` siblings, because they don't
+have the same parent::
+
+ sibling_soup.b.string
+ # u'text1'
+
+ print(sibling_soup.b.string.next_sibling)
+ # None
+
+In real documents, the ``.next_sibling`` or ``.previous_sibling`` of a
+tag will usually be a string containing whitespace. Going back to the
+"three sisters" document::
+
+ <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
+ <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
+ <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
+
+You might think that the ``.next_sibling`` of the first <a> tag would
+be the second <a> tag. But actually, it's a string: the comma and
+newline that separate the first <a> tag from the second::
+
+ link = soup.a
+ link
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+ link.next_sibling
+ # u',\n'
+
+The second <a> tag is actually the ``.next_sibling`` of the comma::
+
+ link.next_sibling.next_sibling
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
+
+.. _sibling-generators:
+
+``.next_siblings`` and ``.previous_siblings``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can iterate over a tag's siblings with ``.next_siblings`` or
+``.previous_siblings``::
+
+ for sibling in soup.a.next_siblings:
+ print(repr(sibling))
+ # u',\n'
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
+ # u' and\n'
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
+ # u'; and they lived at the bottom of a well.'
+ # None
+
+ for sibling in soup.find(id="link3").previous_siblings:
+ print(repr(sibling))
+ # ' and\n'
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
+ # u',\n'
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+ # u'Once upon a time there were three little sisters; and their names were\n'
+ # None
+
+Going back and forth
+--------------------
+
+Take a look at the beginning of the "three sisters" document::
+
+ <html><head><title>The Dormouse's story</title></head>
+ <p class="title"><b>The Dormouse's story</b></p>
+
+An HTML parser takes this string of characters and turns it into a
+series of events: "open an <html> tag", "open a <head> tag", "open a
+<title> tag", "add a string", "close the <title> tag", "open a <p>
+tag", and so on. Beautiful Soup offers tools for reconstructing the
+initial parse of the document.
+
+.. _element-generators:
+
+``.next_element`` and ``.previous_element``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``.next_element`` attribute of a string or tag points to whatever
+was parsed immediately afterwards. It might be the same as
+``.next_sibling``, but it's usually drastically different.
+
+Here's the final <a> tag in the "three sisters" document. Its
+``.next_sibling`` is a string: the conclusion of the sentence that was
+interrupted by the start of the <a> tag.::
+
+ last_a_tag = soup.find("a", id="link3")
+ last_a_tag
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
+
+ last_a_tag.next_sibling
+ # '; and they lived at the bottom of a well.'
+
+But the ``.next_element`` of that <a> tag, the thing that was parsed
+immediately after the <a> tag, is `not` the rest of that sentence:
+it's the word "Tillie"::
+
+ last_a_tag.next_element
+ # u'Tillie'
+
+That's because in the original markup, the word "Tillie" appeared
+before that semicolon. The parser encountered an <a> tag, then the
+word "Tillie", then the closing </a> tag, then the semicolon and rest of
+the sentence. The semicolon is on the same level as the <a> tag, but the
+word "Tillie" was encountered first.
+
+The ``.previous_element`` attribute is the exact opposite of
+``.next_element``. It points to whatever element was parsed
+immediately before this one::
+
+ last_a_tag.previous_element
+ # u' and\n'
+ last_a_tag.previous_element.next_element
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
+
+``.next_elements`` and ``.previous_elements``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You should get the idea by now. You can use these iterators to move
+forward or backward in the document as it was parsed::
+
+ for element in last_a_tag.next_elements:
+ print(repr(element))
+ # u'Tillie'
+ # u';\nand they lived at the bottom of a well.'
+ # u'\n\n'
+ # <p class="story">...</p>
+ # u'...'
+ # u'\n'
+ # None
+
+Searching the tree
+==================
+
+Beautiful Soup defines a lot of methods for searching the parse tree,
+but they're all very similar. I'm going to spend a lot of time explaining
+the two most popular methods: ``find()`` and ``find_all()``. The other
+methods take almost exactly the same arguments, so I'll just cover
+them briefly.
+
+Once again, I'll be using the "three sisters" document as an example::
+
+ html_doc = """
+ <html><head><title>The Dormouse's story</title></head>
+
+ <p class="title"><b>The Dormouse's story</b></p>
+
+ <p class="story">Once upon a time there were three little sisters; and their names were
+ <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
+ <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
+ <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
+ and they lived at the bottom of a well.</p>
+
+ <p class="story">...</p>
+ """
+
+ from bs4 import BeautifulSoup
+ soup = BeautifulSoup(html_doc)
+
+By passing in a filter to an argument like ``find_all()``, you can
+zoom in on the parts of the document you're interested in.
+
+Kinds of filters
+----------------
+
+Before talking in detail about ``find_all()`` and similar methods, I
+want to show examples of different filters you can pass into these
+methods. These filters show up again and again, throughout the
+search API. You can use them to filter based on a tag's name,
+on its attributes, on the text of a string, or on some combination of
+these.
+
+.. _a string:
+
+A string
+^^^^^^^^
+
+The simplest filter is a string. Pass a string to a search method and
+Beautiful Soup will perform a match against that exact string. This
+code finds all the <b> tags in the document::
+
+ soup.find_all('b')
+ # [<b>The Dormouse's story</b>]
+
+If you pass in a byte string, Beautiful Soup will assume the string is
+encoded as UTF-8. You can avoid this by passing in a Unicode string instead.
+
+.. _a regular expression:
+
+A regular expression
+^^^^^^^^^^^^^^^^^^^^
+
+If you pass in a regular expression object, Beautiful Soup will filter
+against that regular expression using its ``match()`` method. This code
+finds all the tags whose names start with the letter "b"; in this
+case, the <body> tag and the <b> tag::
+
+ import re
+ for tag in soup.find_all(re.compile("^b")):
+ print(tag.name)
+ # body
+ # b
+
+This code finds all the tags whose names contain the letter 't'::
+
+ for tag in soup.find_all(re.compile("t")):
+ print(tag.name)
+ # html
+ # title
+
+.. _a list:
+
+A list
+^^^^^^
+
+If you pass in a list, Beautiful Soup will allow a string match
+against `any` item in that list. This code finds all the <a> tags
+`and` all the <b> tags::
+
+ soup.find_all(["a", "b"])
+ # [<b>The Dormouse's story</b>,
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+.. _the value True:
+
+``True``
+^^^^^^^^
+
+The value ``True`` matches everything it can. This code finds `all`
+the tags in the document, but none of the text strings::
+
+ for tag in soup.find_all(True):
+ print(tag.name)
+ # html
+ # head
+ # title
+ # body
+ # p
+ # b
+ # p
+ # a
+ # a
+ # a
+ # p
+
+.. a function:
+
+A function
+^^^^^^^^^^
+
+If none of the other matches work for you, define a function that
+takes an element as its only argument. The function should return
+``True`` if the argument matches, and ``False`` otherwise.
+
+Here's a function that returns ``True`` if a tag defines the "class"
+attribute but doesn't define the "id" attribute::
+
+ def has_class_but_no_id(tag):
+ return tag.has_attr('class') and not tag.has_attr('id')
+
+Pass this function into ``find_all()`` and you'll pick up all the <p>
+tags::
+
+ soup.find_all(has_class_but_no_id)
+ # [<p class="title"><b>The Dormouse's story</b></p>,
+ # <p class="story">Once upon a time there were...</p>,
+ # <p class="story">...</p>]
+
+This function only picks up the <p> tags. It doesn't pick up the <a>
+tags, because those tags define both "class" and "id". It doesn't pick
+up tags like <html> and <title>, because those tags don't define
+"class".
+
+Here's a function that returns ``True`` if a tag is surrounded by
+string objects::
+
+ from bs4 import NavigableString
+ def surrounded_by_strings(tag):
+ return (isinstance(tag.next_element, NavigableString)
+ and isinstance(tag.previous_element, NavigableString))
+
+ for tag in soup.find_all(surrounded_by_strings):
+ print tag.name
+ # p
+ # a
+ # a
+ # a
+ # p
+
+Now we're ready to look at the search methods in detail.
+
+``find_all()``
+--------------
+
+Signature: find_all(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`recursive
+<recursive>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+The ``find_all()`` method looks through a tag's descendants and
+retrieves `all` descendants that match your filters. I gave several
+examples in `Kinds of filters`_, but here are a few more::
+
+ soup.find_all("title")
+ # [<title>The Dormouse's story</title>]
+
+ soup.find_all("p", "title")
+ # [<p class="title"><b>The Dormouse's story</b></p>]
+
+ soup.find_all("a")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.find_all(id="link2")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+ import re
+ soup.find(text=re.compile("sisters"))
+ # u'Once upon a time there were three little sisters; and their names were\n'
+
+Some of these should look familiar, but others are new. What does it
+mean to pass in a value for ``text``, or ``id``? Why does
+``find_all("p", "title")`` find a <p> tag with the CSS class "title"?
+Let's look at the arguments to ``find_all()``.
+
+.. _name:
+
+The ``name`` argument
+^^^^^^^^^^^^^^^^^^^^^
+
+Pass in a value for ``name`` and you'll tell Beautiful Soup to only
+consider tags with certain names. Text strings will be ignored, as
+will tags whose names that don't match.
+
+This is the simplest usage::
+
+ soup.find_all("title")
+ # [<title>The Dormouse's story</title>]
+
+Recall from `Kinds of filters`_ that the value to ``name`` can be `a
+string`_, `a regular expression`_, `a list`_, `a function`_, or `the value
+True`_.
+
+.. _kwargs:
+
+The keyword arguments
+^^^^^^^^^^^^^^^^^^^^^
+
+Any argument that's not recognized will be turned into a filter on one
+of a tag's attributes. If you pass in a value for an argument called ``id``,
+Beautiful Soup will filter against each tag's 'id' attribute::
+
+ soup.find_all(id='link2')
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+If you pass in a value for ``href``, Beautiful Soup will filter
+against each tag's 'href' attribute::
+
+ soup.find_all(href=re.compile("elsie"))
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+You can filter an attribute based on `a string`_, `a regular
+expression`_, `a list`_, `a function`_, or `the value True`_.
+
+This code finds all tags whose ``id`` attribute has a value,
+regardless of what the value is::
+
+ soup.find_all(id=True)
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+You can filter multiple attributes at once by passing in more than one
+keyword argument::
+
+ soup.find_all(href=re.compile("elsie"), id='link1')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]
+
+Some attributes, like the data-* attributes in HTML 5, have names that
+can't be used as the names of keyword arguments::
+
+ data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
+ data_soup.find_all(data-foo="value")
+ # SyntaxError: keyword can't be an expression
+
+You can use these attributes in searches by putting them into a
+dictionary and passing the dictionary into ``find_all()`` as the
+``attrs`` argument::
+
+ data_soup.find_all(attrs={"data-foo": "value"})
+ # [<div data-foo="value">foo!</div>]
+
+.. _attrs:
+
+Searching by CSS class
+^^^^^^^^^^^^^^^^^^^^^^
+
+It's very useful to search for a tag that has a certain CSS class, but
+the name of the CSS attribute, "class", is a reserved word in
+Python. Using ``class`` as a keyword argument will give you a syntax
+error. As of Beautiful Soup 4.1.2, you can search by CSS class using
+the keyword argument ``class_``::
+
+ soup.find_all("a", class_="sister")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+As with any keyword argument, you can pass ``class_`` a string, a regular
+expression, a function, or ``True``::
+
+ soup.find_all(class_=re.compile("itl"))
+ # [<p class="title"><b>The Dormouse's story</b></p>]
+
+ def has_six_characters(css_class):
+ return css_class is not None and len(css_class) == 6
+
+ soup.find_all(class_=has_six_characters)
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+:ref:`Remember <multivalue>` that a single tag can have multiple
+values for its "class" attribute. When you search for a tag that
+matches a certain CSS class, you're matching against `any` of its CSS
+classes::
+
+ css_soup = BeautifulSoup('<p class="body strikeout"></p>')
+ css_soup.find_all("p", class_="strikeout")
+ # [<p class="body strikeout"></p>]
+
+ css_soup.find_all("p", class_="body")
+ # [<p class="body strikeout"></p>]
+
+You can also search for the exact string value of the ``class`` attribute::
+
+ css_soup.find_all("p", class_="body strikeout")
+ # [<p class="body strikeout"></p>]
+
+But searching for variants of the string value won't work::
+
+ css_soup.find_all("p", class_="strikeout body")
+ # []
+
+If you want to search for tags that match two or more CSS classes, you
+should use a CSS selector::
+
+ css_soup.select("p.strikeout.body")
+ # [<p class="body strikeout"></p>]
+
+In older versions of Beautiful Soup, which don't have the ``class_``
+shortcut, you can use the ``attrs`` trick mentioned above. Create a
+dictionary whose value for "class" is the string (or regular
+expression, or whatever) you want to search for::
+
+ soup.find_all("a", attrs={"class": "sister"})
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+.. _text:
+
+The ``text`` argument
+^^^^^^^^^^^^^^^^^^^^^
+
+With ``text`` you can search for strings instead of tags. As with
+``name`` and the keyword arguments, you can pass in `a string`_, `a
+regular expression`_, `a list`_, `a function`_, or `the value True`_.
+Here are some examples::
+
+ soup.find_all(text="Elsie")
+ # [u'Elsie']
+
+ soup.find_all(text=["Tillie", "Elsie", "Lacie"])
+ # [u'Elsie', u'Lacie', u'Tillie']
+
+ soup.find_all(text=re.compile("Dormouse"))
+ [u"The Dormouse's story", u"The Dormouse's story"]
+
+ def is_the_only_string_within_a_tag(s):
+ """Return True if this string is the only child of its parent tag."""
+ return (s == s.parent.string)
+
+ soup.find_all(text=is_the_only_string_within_a_tag)
+ # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
+
+Although ``text`` is for finding strings, you can combine it with
+arguments that find tags: Beautiful Soup will find all tags whose
+``.string`` matches your value for ``text``. This code finds the <a>
+tags whose ``.string`` is "Elsie"::
+
+ soup.find_all("a", text="Elsie")
+ # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
+
+.. _limit:
+
+The ``limit`` argument
+^^^^^^^^^^^^^^^^^^^^^^
+
+``find_all()`` returns all the tags and strings that match your
+filters. This can take a while if the document is large. If you don't
+need `all` the results, you can pass in a number for ``limit``. This
+works just like the LIMIT keyword in SQL. It tells Beautiful Soup to
+stop gathering results after it's found a certain number.
+
+There are three links in the "three sisters" document, but this code
+only finds the first two::
+
+ soup.find_all("a", limit=2)
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+.. _recursive:
+
+The ``recursive`` argument
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you call ``mytag.find_all()``, Beautiful Soup will examine all the
+descendants of ``mytag``: its children, its children's children, and
+so on. If you only want Beautiful Soup to consider direct children,
+you can pass in ``recursive=False``. See the difference here::
+
+ soup.html.find_all("title")
+ # [<title>The Dormouse's story</title>]
+
+ soup.html.find_all("title", recursive=False)
+ # []
+
+Here's that part of the document::
+
+ <html>
+ <head>
+ <title>
+ The Dormouse's story
+ </title>
+ </head>
+ ...
+
+The <title> tag is beneath the <html> tag, but it's not `directly`
+beneath the <html> tag: the <head> tag is in the way. Beautiful Soup
+finds the <title> tag when it's allowed to look at all descendants of
+the <html> tag, but when ``recursive=False`` restricts it to the
+<html> tag's immediate children, it finds nothing.
+
+Beautiful Soup offers a lot of tree-searching methods (covered below),
+and they mostly take the same arguments as ``find_all()``: ``name``,
+``attrs``, ``text``, ``limit``, and the keyword arguments. But the
+``recursive`` argument is different: ``find_all()`` and ``find()`` are
+the only methods that support it. Passing ``recursive=False`` into a
+method like ``find_parents()`` wouldn't be very useful.
+
+Calling a tag is like calling ``find_all()``
+--------------------------------------------
+
+Because ``find_all()`` is the most popular method in the Beautiful
+Soup search API, you can use a shortcut for it. If you treat the
+``BeautifulSoup`` object or a ``Tag`` object as though it were a
+function, then it's the same as calling ``find_all()`` on that
+object. These two lines of code are equivalent::
+
+ soup.find_all("a")
+ soup("a")
+
+These two lines are also equivalent::
+
+ soup.title.find_all(text=True)
+ soup.title(text=True)
+
+``find()``
+----------
+
+Signature: find(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`recursive
+<recursive>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+The ``find_all()`` method scans the entire document looking for
+results, but sometimes you only want to find one result. If you know a
+document only has one <body> tag, it's a waste of time to scan the
+entire document looking for more. Rather than passing in ``limit=1``
+every time you call ``find_all``, you can use the ``find()``
+method. These two lines of code are `nearly` equivalent::
+
+ soup.find_all('title', limit=1)
+ # [<title>The Dormouse's story</title>]
+
+ soup.find('title')
+ # <title>The Dormouse's story</title>
+
+The only difference is that ``find_all()`` returns a list containing
+the single result, and ``find()`` just returns the result.
+
+If ``find_all()`` can't find anything, it returns an empty list. If
+``find()`` can't find anything, it returns ``None``::
+
+ print(soup.find("nosuchtag"))
+ # None
+
+Remember the ``soup.head.title`` trick from `Navigating using tag
+names`_? That trick works by repeatedly calling ``find()``::
+
+ soup.head.title
+ # <title>The Dormouse's story</title>
+
+ soup.find("head").find("title")
+ # <title>The Dormouse's story</title>
+
+``find_parents()`` and ``find_parent()``
+----------------------------------------
+
+Signature: find_parents(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+Signature: find_parent(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+I spent a lot of time above covering ``find_all()`` and
+``find()``. The Beautiful Soup API defines ten other methods for
+searching the tree, but don't be afraid. Five of these methods are
+basically the same as ``find_all()``, and the other five are basically
+the same as ``find()``. The only differences are in what parts of the
+tree they search.
+
+First let's consider ``find_parents()`` and
+``find_parent()``. Remember that ``find_all()`` and ``find()`` work
+their way down the tree, looking at tag's descendants. These methods
+do the opposite: they work their way `up` the tree, looking at a tag's
+(or a string's) parents. Let's try them out, starting from a string
+buried deep in the "three daughters" document::
+
+ a_string = soup.find(text="Lacie")
+ a_string
+ # u'Lacie'
+
+ a_string.find_parents("a")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+ a_string.find_parent("p")
+ # <p class="story">Once upon a time there were three little sisters; and their names were
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
+ # and they lived at the bottom of a well.</p>
+
+ a_string.find_parents("p", class="title")
+ # []
+
+One of the three <a> tags is the direct parent of the string in
+question, so our search finds it. One of the three <p> tags is an
+indirect parent of the string, and our search finds that as
+well. There's a <p> tag with the CSS class "title" `somewhere` in the
+document, but it's not one of this string's parents, so we can't find
+it with ``find_parents()``.
+
+You may have made the connection between ``find_parent()`` and
+``find_parents()``, and the `.parent`_ and `.parents`_ attributes
+mentioned earlier. The connection is very strong. These search methods
+actually use ``.parents`` to iterate over all the parents, and check
+each one against the provided filter to see if it matches.
+
+``find_next_siblings()`` and ``find_next_sibling()``
+----------------------------------------------------
+
+Signature: find_next_siblings(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+Signature: find_next_sibling(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+These methods use :ref:`.next_siblings <sibling-generators>` to
+iterate over the rest of an element's siblings in the tree. The
+``find_next_siblings()`` method returns all the siblings that match,
+and ``find_next_sibling()`` only returns the first one::
+
+ first_link = soup.a
+ first_link
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+ first_link.find_next_siblings("a")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ first_story_paragraph = soup.find("p", "story")
+ first_story_paragraph.find_next_sibling("p")
+ # <p class="story">...</p>
+
+``find_previous_siblings()`` and ``find_previous_sibling()``
+------------------------------------------------------------
+
+Signature: find_previous_siblings(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+Signature: find_previous_sibling(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+These methods use :ref:`.previous_siblings <sibling-generators>` to iterate over an element's
+siblings that precede it in the tree. The ``find_previous_siblings()``
+method returns all the siblings that match, and
+``find_previous_sibling()`` only returns the first one::
+
+ last_link = soup.find("a", id="link3")
+ last_link
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
+
+ last_link.find_previous_siblings("a")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+ first_story_paragraph = soup.find("p", "story")
+ first_story_paragraph.find_previous_sibling("p")
+ # <p class="title"><b>The Dormouse's story</b></p>
+
+
+``find_all_next()`` and ``find_next()``
+---------------------------------------
+
+Signature: find_all_next(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+Signature: find_next(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+These methods use :ref:`.next_elements <element-generators>` to
+iterate over whatever tags and strings that come after it in the
+document. The ``find_all_next()`` method returns all matches, and
+``find_next()`` only returns the first match::
+
+ first_link = soup.a
+ first_link
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+ first_link.find_all_next(text=True)
+ # [u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie',
+ # u';\nand they lived at the bottom of a well.', u'\n\n', u'...', u'\n']
+
+ first_link.find_next("p")
+ # <p class="story">...</p>
+
+In the first example, the string "Elsie" showed up, even though it was
+contained within the <a> tag we started from. In the second example,
+the last <p> tag in the document showed up, even though it's not in
+the same part of the tree as the <a> tag we started from. For these
+methods, all that matters is that an element match the filter, and
+show up later in the document than the starting element.
+
+``find_all_previous()`` and ``find_previous()``
+-----------------------------------------------
+
+Signature: find_all_previous(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`)
+
+Signature: find_previous(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`text <text>`, :ref:`**kwargs <kwargs>`)
+
+These methods use :ref:`.previous_elements <element-generators>` to
+iterate over the tags and strings that came before it in the
+document. The ``find_all_previous()`` method returns all matches, and
+``find_previous()`` only returns the first match::
+
+ first_link = soup.a
+ first_link
+ # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
+
+ first_link.find_all_previous("p")
+ # [<p class="story">Once upon a time there were three little sisters; ...</p>,
+ # <p class="title"><b>The Dormouse's story</b></p>]
+
+ first_link.find_previous("title")
+ # <title>The Dormouse's story</title>
+
+The call to ``find_all_previous("p")`` found the first paragraph in
+the document (the one with class="title"), but it also finds the
+second paragraph, the <p> tag that contains the <a> tag we started
+with. This shouldn't be too surprising: we're looking at all the tags
+that show up earlier in the document than the one we started with. A
+<p> tag that contains an <a> tag must have shown up before the <a>
+tag it contains.
+
+CSS selectors
+-------------
+
+Beautiful Soup supports the most commonly-used `CSS selectors
+<http://www.w3.org/TR/CSS2/selector.html>`_. Just pass a string into
+the ``.select()`` method of a ``Tag`` object or the ``BeautifulSoup``
+object itself.
+
+You can find tags::
+
+ soup.select("title")
+ # [<title>The Dormouse's story</title>]
+
+ soup.select("p nth-of-type(3)")
+ # [<p class="story">...</p>]
+
+Find tags beneath other tags::
+
+ soup.select("body a")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select("html head title")
+ # [<title>The Dormouse's story</title>]
+
+Find tags `directly` beneath other tags::
+
+ soup.select("head > title")
+ # [<title>The Dormouse's story</title>]
+
+ soup.select("p > a")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select("p > a:nth-of-type(2)")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+ soup.select("p > #link1")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+ soup.select("body > a")
+ # []
+
+Find the siblings of tags::
+
+ soup.select("#link1 ~ .sister")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select("#link1 + .sister")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+Find tags by CSS class::
+
+ soup.select(".sister")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select("[class~=sister]")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+Find tags by ID::
+
+ soup.select("#link1")
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+ soup.select("a#link2")
+ # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
+
+Test for the existence of an attribute::
+
+ soup.select('a[href]')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+Find tags by attribute value::
+
+ soup.select('a[href="http://example.com/elsie"]')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+ soup.select('a[href^="http://example.com/"]')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
+ # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
+ # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select('a[href$="tillie"]')
+ # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
+
+ soup.select('a[href*=".com/el"]')
+ # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
+
+Match language codes::
+
+ multilingual_markup = """
+ <p lang="en">Hello</p>
+ <p lang="en-us">Howdy, y'all</p>
+ <p lang="en-gb">Pip-pip, old fruit</p>
+ <p lang="fr">Bonjour mes amis</p>
+ """
+ multilingual_soup = BeautifulSoup(multilingual_markup)
+ multilingual_soup.select('p[lang|=en]')
+ # [<p lang="en">Hello</p>,
+ # <p lang="en-us">Howdy, y'all</p>,
+ # <p lang="en-gb">Pip-pip, old fruit</p>]
+
+This is a convenience for users who know the CSS selector syntax. You
+can do all this stuff with the Beautiful Soup API. And if CSS
+selectors are all you need, you might as well use lxml directly,
+because it's faster. But this lets you `combine` simple CSS selectors
+with the Beautiful Soup API.
+
+
+Modifying the tree
+==================
+
+Beautiful Soup's main strength is in searching the parse tree, but you
+can also modify the tree and write your changes as a new HTML or XML
+document.
+
+Changing tag names and attributes
+---------------------------------
+
+I covered this earlier, in `Attributes`_, but it bears repeating. You
+can rename a tag, change the values of its attributes, add new
+attributes, and delete attributes::
+
+ soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
+ tag = soup.b
+
+ tag.name = "blockquote"
+ tag['class'] = 'verybold'
+ tag['id'] = 1
+ tag
+ # <blockquote class="verybold" id="1">Extremely bold</blockquote>
+
+ del tag['class']
+ del tag['id']
+ tag
+ # <blockquote>Extremely bold</blockquote>
+
+
+Modifying ``.string``
+---------------------
+
+If you set a tag's ``.string`` attribute, the tag's contents are
+replaced with the string you give::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+
+ tag = soup.a
+ tag.string = "New link text."
+ tag
+ # <a href="http://example.com/">New link text.</a>
+
+Be careful: if the tag contained other tags, they and all their
+contents will be destroyed.
+
+``append()``
+------------
+
+You can add to a tag's contents with ``Tag.append()``. It works just
+like calling ``.append()`` on a Python list::
+
+ soup = BeautifulSoup("<a>Foo</a>")
+ soup.a.append("Bar")
+
+ soup
+ # <html><head></head><body><a>FooBar</a></body></html>
+ soup.a.contents
+ # [u'Foo', u'Bar']
+
+``BeautifulSoup.new_string()`` and ``.new_tag()``
+-------------------------------------------------
+
+If you need to add a string to a document, no problem--you can pass a
+Python string in to ``append()``, or you can call the factory method
+``BeautifulSoup.new_string()``::
+
+ soup = BeautifulSoup("<b></b>")
+ tag = soup.b
+ tag.append("Hello")
+ new_string = soup.new_string(" there")
+ tag.append(new_string)
+ tag
+ # <b>Hello there.</b>
+ tag.contents
+ # [u'Hello', u' there']
+
+If you want to create a comment or some other subclass of
+``NavigableString``, pass that class as the second argument to
+``new_string()``::
+
+ from bs4 import Comment
+ new_comment = soup.new_string("Nice to see you.", Comment)
+ tag.append(new_comment)
+ tag
+ # <b>Hello there<!--Nice to see you.--></b>
+ tag.contents
+ # [u'Hello', u' there', u'Nice to see you.']
+
+(This is a new feature in Beautiful Soup 4.2.1.)
+
+What if you need to create a whole new tag? The best solution is to
+call the factory method ``BeautifulSoup.new_tag()``::
+
+ soup = BeautifulSoup("<b></b>")
+ original_tag = soup.b
+
+ new_tag = soup.new_tag("a", href="http://www.example.com")
+ original_tag.append(new_tag)
+ original_tag
+ # <b><a href="http://www.example.com"></a></b>
+
+ new_tag.string = "Link text."
+ original_tag
+ # <b><a href="http://www.example.com">Link text.</a></b>
+
+Only the first argument, the tag name, is required.
+
+``insert()``
+------------
+
+``Tag.insert()`` is just like ``Tag.append()``, except the new element
+doesn't necessarily go at the end of its parent's
+``.contents``. It'll be inserted at whatever numeric position you
+say. It works just like ``.insert()`` on a Python list::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ tag = soup.a
+
+ tag.insert(1, "but did not endorse ")
+ tag
+ # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>
+ tag.contents
+ # [u'I linked to ', u'but did not endorse', <i>example.com</i>]
+
+``insert_before()`` and ``insert_after()``
+------------------------------------------
+
+The ``insert_before()`` method inserts a tag or string immediately
+before something else in the parse tree::
+
+ soup = BeautifulSoup("<b>stop</b>")
+ tag = soup.new_tag("i")
+ tag.string = "Don't"
+ soup.b.string.insert_before(tag)
+ soup.b
+ # <b><i>Don't</i>stop</b>
+
+The ``insert_after()`` method moves a tag or string so that it
+immediately follows something else in the parse tree::
+
+ soup.b.i.insert_after(soup.new_string(" ever "))
+ soup.b
+ # <b><i>Don't</i> ever stop</b>
+ soup.b.contents
+ # [<i>Don't</i>, u' ever ', u'stop']
+
+``clear()``
+-----------
+
+``Tag.clear()`` removes the contents of a tag::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ tag = soup.a
+
+ tag.clear()
+ tag
+ # <a href="http://example.com/"></a>
+
+``extract()``
+-------------
+
+``PageElement.extract()`` removes a tag or string from the tree. It
+returns the tag or string that was extracted::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ a_tag = soup.a
+
+ i_tag = soup.i.extract()
+
+ a_tag
+ # <a href="http://example.com/">I linked to</a>
+
+ i_tag
+ # <i>example.com</i>
+
+ print(i_tag.parent)
+ None
+
+At this point you effectively have two parse trees: one rooted at the
+``BeautifulSoup`` object you used to parse the document, and one rooted
+at the tag that was extracted. You can go on to call ``extract`` on
+a child of the element you extracted::
+
+ my_string = i_tag.string.extract()
+ my_string
+ # u'example.com'
+
+ print(my_string.parent)
+ # None
+ i_tag
+ # <i></i>
+
+
+``decompose()``
+---------------
+
+``Tag.decompose()`` removes a tag from the tree, then `completely
+destroys it and its contents`::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ a_tag = soup.a
+
+ soup.i.decompose()
+
+ a_tag
+ # <a href="http://example.com/">I linked to</a>
+
+
+.. _replace_with:
+
+``replace_with()``
+------------------
+
+``PageElement.replace_with()`` removes a tag or string from the tree,
+and replaces it with the tag or string of your choice::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ a_tag = soup.a
+
+ new_tag = soup.new_tag("b")
+ new_tag.string = "example.net"
+ a_tag.i.replace_with(new_tag)
+
+ a_tag
+ # <a href="http://example.com/">I linked to <b>example.net</b></a>
+
+``replace_with()`` returns the tag or string that was replaced, so
+that you can examine it or add it back to another part of the tree.
+
+``wrap()``
+----------
+
+``PageElement.wrap()`` wraps an element in the tag you specify. It
+returns the new wrapper::
+
+ soup = BeautifulSoup("<p>I wish I was bold.</p>")
+ soup.p.string.wrap(soup.new_tag("b"))
+ # <b>I wish I was bold.</b>
+
+ soup.p.wrap(soup.new_tag("div")
+ # <div><p><b>I wish I was bold.</b></p></div>
+
+This method is new in Beautiful Soup 4.0.5.
+
+``unwrap()``
+---------------------------
+
+``Tag.unwrap()`` is the opposite of ``wrap()``. It replaces a tag with
+whatever's inside that tag. It's good for stripping out markup::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ a_tag = soup.a
+
+ a_tag.i.unwrap()
+ a_tag
+ # <a href="http://example.com/">I linked to example.com</a>
+
+Like ``replace_with()``, ``unwrap()`` returns the tag
+that was replaced.
+
+Output
+======
+
+.. _.prettyprinting:
+
+Pretty-printing
+---------------
+
+The ``prettify()`` method will turn a Beautiful Soup parse tree into a
+nicely formatted Unicode string, with each HTML/XML tag on its own line::
+
+ markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
+ soup = BeautifulSoup(markup)
+ soup.prettify()
+ # '<html>\n <head>\n </head>\n <body>\n <a href="http://example.com/">\n...'
+
+ print(soup.prettify())
+ # <html>
+ # <head>
+ # </head>
+ # <body>
+ # <a href="http://example.com/">
+ # I linked to
+ # <i>
+ # example.com
+ # </i>
+ # </a>
+ # </body>
+ # </html>
+
+You can call ``prettify()`` on the top-level ``BeautifulSoup`` object,
+or on any of its ``Tag`` objects::
+
+ print(soup.a.prettify())
+ # <a href="http://example.com/">
+ # I linked to
+ # <i>
+ # example.com
+ # </i>
+ # </a>
+
+Non-pretty printing
+-------------------
+
+If you just want a string, with no fancy formatting, you can call
+``unicode()`` or ``str()`` on a ``BeautifulSoup`` object, or a ``Tag``
+within it::
+
+ str(soup)
+ # '<html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>'
+
+ unicode(soup.a)
+ # u'<a href="http://example.com/">I linked to <i>example.com</i></a>'
+
+The ``str()`` function returns a string encoded in UTF-8. See
+`Encodings`_ for other options.
+
+You can also call ``encode()`` to get a bytestring, and ``decode()``
+to get Unicode.
+
+.. _output_formatters:
+
+Output formatters
+-----------------
+
+If you give Beautiful Soup a document that contains HTML entities like
+"&lquot;", they'll be converted to Unicode characters::
+
+ soup = BeautifulSoup("&ldquo;Dammit!&rdquo; he said.")
+ unicode(soup)
+ # u'<html><head></head><body>\u201cDammit!\u201d he said.</body></html>'
+
+If you then convert the document to a string, the Unicode characters
+will be encoded as UTF-8. You won't get the HTML entities back::
+
+ str(soup)
+ # '<html><head></head><body>\xe2\x80\x9cDammit!\xe2\x80\x9d he said.</body></html>'
+
+By default, the only characters that are escaped upon output are bare
+ampersands and angle brackets. These get turned into "&amp;", "&lt;",
+and "&gt;", so that Beautiful Soup doesn't inadvertently generate
+invalid HTML or XML::
+
+ soup = BeautifulSoup("<p>The law firm of Dewey, Cheatem, & Howe</p>")
+ soup.p
+ # <p>The law firm of Dewey, Cheatem, &amp; Howe</p>
+
+ soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>')
+ soup.a
+ # <a href="http://example.com/?foo=val1&amp;bar=val2">A link</a>
+
+You can change this behavior by providing a value for the
+``formatter`` argument to ``prettify()``, ``encode()``, or
+``decode()``. Beautiful Soup recognizes four possible values for
+``formatter``.
+
+The default is ``formatter="minimal"``. Strings will only be processed
+enough to ensure that Beautiful Soup generates valid HTML/XML::
+
+ french = "<p>Il a dit &lt;&lt;Sacr&eacute; bleu!&gt;&gt;</p>"
+ soup = BeautifulSoup(french)
+ print(soup.prettify(formatter="minimal"))
+ # <html>
+ # <body>
+ # <p>
+ # Il a dit &lt;&lt;Sacré bleu!&gt;&gt;
+ # </p>
+ # </body>
+ # </html>
+
+If you pass in ``formatter="html"``, Beautiful Soup will convert
+Unicode characters to HTML entities whenever possible::
+
+ print(soup.prettify(formatter="html"))
+ # <html>
+ # <body>
+ # <p>
+ # Il a dit &lt;&lt;Sacr&eacute; bleu!&gt;&gt;
+ # </p>
+ # </body>
+ # </html>
+
+If you pass in ``formatter=None``, Beautiful Soup will not modify
+strings at all on output. This is the fastest option, but it may lead
+to Beautiful Soup generating invalid HTML/XML, as in these examples::
+
+ print(soup.prettify(formatter=None))
+ # <html>
+ # <body>
+ # <p>
+ # Il a dit <<Sacré bleu!>>
+ # </p>
+ # </body>
+ # </html>
+
+ link_soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>')
+ print(link_soup.a.encode(formatter=None))
+ # <a href="http://example.com/?foo=val1&bar=val2">A link</a>
+
+Finally, if you pass in a function for ``formatter``, Beautiful Soup
+will call that function once for every string and attribute value in
+the document. You can do whatever you want in this function. Here's a
+formatter that converts strings to uppercase and does absolutely
+nothing else::
+
+ def uppercase(str):
+ return str.upper()
+
+ print(soup.prettify(formatter=uppercase))
+ # <html>
+ # <body>
+ # <p>
+ # IL A DIT <<SACRÉ BLEU!>>
+ # </p>
+ # </body>
+ # </html>
+
+ print(link_soup.a.prettify(formatter=uppercase))
+ # <a href="HTTP://EXAMPLE.COM/?FOO=VAL1&BAR=VAL2">
+ # A LINK
+ # </a>
+
+If you're writing your own function, you should know about the
+``EntitySubstitution`` class in the ``bs4.dammit`` module. This class
+implements Beautiful Soup's standard formatters as class methods: the
+"html" formatter is ``EntitySubstitution.substitute_html``, and the
+"minimal" formatter is ``EntitySubstitution.substitute_xml``. You can
+use these functions to simulate ``formatter=html`` or
+``formatter==minimal``, but then do something extra.
+
+Here's an example that replaces Unicode characters with HTML entities
+whenever possible, but `also` converts all strings to uppercase::
+
+ from bs4.dammit import EntitySubstitution
+ def uppercase_and_substitute_html_entities(str):
+ return EntitySubstitution.substitute_html(str.upper())
+
+ print(soup.prettify(formatter=uppercase_and_substitute_html_entities))
+ # <html>
+ # <body>
+ # <p>
+ # IL A DIT &lt;&lt;SACR&Eacute; BLEU!&gt;&gt;
+ # </p>
+ # </body>
+ # </html>
+
+One last caveat: if you create a ``CData`` object, the text inside
+that object is always presented `exactly as it appears, with no
+formatting`. Beautiful Soup will call the formatter method, just in
+case you've written a custom method that counts all the strings in the
+document or something, but it will ignore the return value::
+
+ from bs4.element import CData
+ soup = BeautifulSoup("<a></a>")
+ soup.a.string = CData("one < three")
+ print(soup.a.prettify(formatter="xml"))
+ # <a>
+ # <![CDATA[one < three]]>
+ # </a>
+
+
+``get_text()``
+--------------
+
+If you only want the text part of a document or tag, you can use the
+``get_text()`` method. It returns all the text in a document or
+beneath a tag, as a single Unicode string::
+
+ markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
+ soup = BeautifulSoup(markup)
+
+ soup.get_text()
+ u'\nI linked to example.com\n'
+ soup.i.get_text()
+ u'example.com'
+
+You can specify a string to be used to join the bits of text
+together::
+
+ # soup.get_text("|")
+ u'\nI linked to |example.com|\n'
+
+You can tell Beautiful Soup to strip whitespace from the beginning and
+end of each bit of text::
+
+ # soup.get_text("|", strip=True)
+ u'I linked to|example.com'
+
+But at that point you might want to use the :ref:`.stripped_strings <string-generators>`
+generator instead, and process the text yourself::
+
+ [text for text in soup.stripped_strings]
+ # [u'I linked to', u'example.com']
+
+Specifying the parser to use
+============================
+
+If you just need to parse some HTML, you can dump the markup into the
+``BeautifulSoup`` constructor, and it'll probably be fine. Beautiful
+Soup will pick a parser for you and parse the data. But there are a
+few additional arguments you can pass in to the constructor to change
+which parser is used.
+
+The first argument to the ``BeautifulSoup`` constructor is a string or
+an open filehandle--the markup you want parsed. The second argument is
+`how` you'd like the markup parsed.
+
+If you don't specify anything, you'll get the best HTML parser that's
+installed. Beautiful Soup ranks lxml's parser as being the best, then
+html5lib's, then Python's built-in parser. You can override this by
+specifying one of the following:
+
+* What type of markup you want to parse. Currently supported are
+ "html", "xml", and "html5".
+
+* The name of the parser library you want to use. Currently supported
+ options are "lxml", "html5lib", and "html.parser" (Python's
+ built-in HTML parser).
+
+The section `Installing a parser`_ contrasts the supported parsers.
+
+If you don't have an appropriate parser installed, Beautiful Soup will
+ignore your request and pick a different parser. Right now, the only
+supported XML parser is lxml. If you don't have lxml installed, asking
+for an XML parser won't give you one, and asking for "lxml" won't work
+either.
+
+Differences between parsers
+---------------------------
+
+Beautiful Soup presents the same interface to a number of different
+parsers, but each parser is different. Different parsers will create
+different parse trees from the same document. The biggest differences
+are between the HTML parsers and the XML parsers. Here's a short
+document, parsed as HTML::
+
+ BeautifulSoup("<a><b /></a>")
+ # <html><head></head><body><a><b></b></a></body></html>
+
+Since an empty <b /> tag is not valid HTML, the parser turns it into a
+<b></b> tag pair.
+
+Here's the same document parsed as XML (running this requires that you
+have lxml installed). Note that the empty <b /> tag is left alone, and
+that the document is given an XML declaration instead of being put
+into an <html> tag.::
+
+ BeautifulSoup("<a><b /></a>", "xml")
+ # <?xml version="1.0" encoding="utf-8"?>
+ # <a><b/></a>
+
+There are also differences between HTML parsers. If you give Beautiful
+Soup a perfectly-formed HTML document, these differences won't
+matter. One parser will be faster than another, but they'll all give
+you a data structure that looks exactly like the original HTML
+document.
+
+But if the document is not perfectly-formed, different parsers will
+give different results. Here's a short, invalid document parsed using
+lxml's HTML parser. Note that the dangling </p> tag is simply
+ignored::
+
+ BeautifulSoup("<a></p>", "lxml")
+ # <html><body><a></a></body></html>
+
+Here's the same document parsed using html5lib::
+
+ BeautifulSoup("<a></p>", "html5lib")
+ # <html><head></head><body><a><p></p></a></body></html>
+
+Instead of ignoring the dangling </p> tag, html5lib pairs it with an
+opening <p> tag. This parser also adds an empty <head> tag to the
+document.
+
+Here's the same document parsed with Python's built-in HTML
+parser::
+
+ BeautifulSoup("<a></p>", "html.parser")
+ # <a></a>
+
+Like html5lib, this parser ignores the closing </p> tag. Unlike
+html5lib, this parser makes no attempt to create a well-formed HTML
+document by adding a <body> tag. Unlike lxml, it doesn't even bother
+to add an <html> tag.
+
+Since the document "<a></p>" is invalid, none of these techniques is
+the "correct" way to handle it. The html5lib parser uses techniques
+that are part of the HTML5 standard, so it has the best claim on being
+the "correct" way, but all three techniques are legitimate.
+
+Differences between parsers can affect your script. If you're planning
+on distributing your script to other people, or running it on multiple
+machines, you should specify a parser in the ``BeautifulSoup``
+constructor. That will reduce the chances that your users parse a
+document differently from the way you parse it.
+
+Encodings
+=========
+
+Any HTML or XML document is written in a specific encoding like ASCII
+or UTF-8. But when you load that document into Beautiful Soup, you'll
+discover it's been converted to Unicode::
+
+ markup = "<h1>Sacr\xc3\xa9 bleu!</h1>"
+ soup = BeautifulSoup(markup)
+ soup.h1
+ # <h1>Sacré bleu!</h1>
+ soup.h1.string
+ # u'Sacr\xe9 bleu!'
+
+It's not magic. (That sure would be nice.) Beautiful Soup uses a
+sub-library called `Unicode, Dammit`_ to detect a document's encoding
+and convert it to Unicode. The autodetected encoding is available as
+the ``.original_encoding`` attribute of the ``BeautifulSoup`` object::
+
+ soup.original_encoding
+ 'utf-8'
+
+Unicode, Dammit guesses correctly most of the time, but sometimes it
+makes mistakes. Sometimes it guesses correctly, but only after a
+byte-by-byte search of the document that takes a very long time. If
+you happen to know a document's encoding ahead of time, you can avoid
+mistakes and delays by passing it to the ``BeautifulSoup`` constructor
+as ``from_encoding``.
+
+Here's a document written in ISO-8859-8. The document is so short that
+Unicode, Dammit can't get a good lock on it, and misidentifies it as
+ISO-8859-7::
+
+ markup = b"<h1>\xed\xe5\xec\xf9</h1>"
+ soup = BeautifulSoup(markup)
+ soup.h1
+ <h1>νεμω</h1>
+ soup.original_encoding
+ 'ISO-8859-7'
+
+We can fix this by passing in the correct ``from_encoding``::
+
+ soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
+ soup.h1
+ <h1>םולש</h1>
+ soup.original_encoding
+ 'iso8859-8'
+
+In rare cases (usually when a UTF-8 document contains text written in
+a completely different encoding), the only way to get Unicode may be
+to replace some characters with the special Unicode character
+"REPLACEMENT CHARACTER" (U+FFFD, �). If Unicode, Dammit needs to do
+this, it will set the ``.contains_replacement_characters`` attribute
+to ``True`` on the ``UnicodeDammit`` or ``BeautifulSoup`` object. This
+lets you know that the Unicode representation is not an exact
+representation of the original--some data was lost. If a document
+contains �, but ``.contains_replacement_characters`` is ``False``,
+you'll know that the � was there originally (as it is in this
+paragraph) and doesn't stand in for missing data.
+
+Output encoding
+---------------
+
+When you write out a document from Beautiful Soup, you get a UTF-8
+document, even if the document wasn't in UTF-8 to begin with. Here's a
+document written in the Latin-1 encoding::
+
+ markup = b'''
+ <html>
+ <head>
+ <meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type" />
+ </head>
+ <body>
+ <p>Sacr\xe9 bleu!</p>
+ </body>
+ </html>
+ '''
+
+ soup = BeautifulSoup(markup)
+ print(soup.prettify())
+ # <html>
+ # <head>
+ # <meta content="text/html; charset=utf-8" http-equiv="Content-type" />
+ # </head>
+ # <body>
+ # <p>
+ # Sacré bleu!
+ # </p>
+ # </body>
+ # </html>
+
+Note that the <meta> tag has been rewritten to reflect the fact that
+the document is now in UTF-8.
+
+If you don't want UTF-8, you can pass an encoding into ``prettify()``::
+
+ print(soup.prettify("latin-1"))
+ # <html>
+ # <head>
+ # <meta content="text/html; charset=latin-1" http-equiv="Content-type" />
+ # ...
+
+You can also call encode() on the ``BeautifulSoup`` object, or any
+element in the soup, just as if it were a Python string::
+
+ soup.p.encode("latin-1")
+ # '<p>Sacr\xe9 bleu!</p>'
+
+ soup.p.encode("utf-8")
+ # '<p>Sacr\xc3\xa9 bleu!</p>'
+
+Any characters that can't be represented in your chosen encoding will
+be converted into numeric XML entity references. Here's a document
+that includes the Unicode character SNOWMAN::
+
+ markup = u"<b>\N{SNOWMAN}</b>"
+ snowman_soup = BeautifulSoup(markup)
+ tag = snowman_soup.b
+
+The SNOWMAN character can be part of a UTF-8 document (it looks like
+☃), but there's no representation for that character in ISO-Latin-1 or
+ASCII, so it's converted into "&#9731" for those encodings::
+
+ print(tag.encode("utf-8"))
+ # <b>☃</b>
+
+ print tag.encode("latin-1")
+ # <b>&#9731;</b>
+
+ print tag.encode("ascii")
+ # <b>&#9731;</b>
+
+Unicode, Dammit
+---------------
+
+You can use Unicode, Dammit without using Beautiful Soup. It's useful
+whenever you have data in an unknown encoding and you just want it to
+become Unicode::
+
+ from bs4 import UnicodeDammit
+ dammit = UnicodeDammit("Sacr\xc3\xa9 bleu!")
+ print(dammit.unicode_markup)
+ # Sacré bleu!
+ dammit.original_encoding
+ # 'utf-8'
+
+Unicode, Dammit's guesses will get a lot more accurate if you install
+the ``chardet`` or ``cchardet`` Python libraries. The more data you
+give Unicode, Dammit, the more accurately it will guess. If you have
+your own suspicions as to what the encoding might be, you can pass
+them in as a list::
+
+ dammit = UnicodeDammit("Sacr\xe9 bleu!", ["latin-1", "iso-8859-1"])
+ print(dammit.unicode_markup)
+ # Sacré bleu!
+ dammit.original_encoding
+ # 'latin-1'
+
+Unicode, Dammit has two special features that Beautiful Soup doesn't
+use.
+
+Smart quotes
+^^^^^^^^^^^^
+
+You can use Unicode, Dammit to convert Microsoft smart quotes to HTML or XML
+entities::
+
+ markup = b"<p>I just \x93love\x94 Microsoft Word\x92s smart quotes</p>"
+
+ UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup
+ # u'<p>I just &ldquo;love&rdquo; Microsoft Word&rsquo;s smart quotes</p>'
+
+ UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup
+ # u'<p>I just &#x201C;love&#x201D; Microsoft Word&#x2019;s smart quotes</p>'
+
+You can also convert Microsoft smart quotes to ASCII quotes::
+
+ UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup
+ # u'<p>I just "love" Microsoft Word\'s smart quotes</p>'
+
+Hopefully you'll find this feature useful, but Beautiful Soup doesn't
+use it. Beautiful Soup prefers the default behavior, which is to
+convert Microsoft smart quotes to Unicode characters along with
+everything else::
+
+ UnicodeDammit(markup, ["windows-1252"]).unicode_markup
+ # u'<p>I just \u201clove\u201d Microsoft Word\u2019s smart quotes</p>'
+
+Inconsistent encodings
+^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes a document is mostly in UTF-8, but contains Windows-1252
+characters such as (again) Microsoft smart quotes. This can happen
+when a website includes data from multiple sources. You can use
+``UnicodeDammit.detwingle()`` to turn such a document into pure
+UTF-8. Here's a simple example::
+
+ snowmen = (u"\N{SNOWMAN}" * 3)
+ quote = (u"\N{LEFT DOUBLE QUOTATION MARK}I like snowmen!\N{RIGHT DOUBLE QUOTATION MARK}")
+ doc = snowmen.encode("utf8") + quote.encode("windows_1252")
+
+This document is a mess. The snowmen are in UTF-8 and the quotes are
+in Windows-1252. You can display the snowmen or the quotes, but not
+both::
+
+ print(doc)
+ # ☃☃☃�I like snowmen!�
+
+ print(doc.decode("windows-1252"))
+ # ☃☃☃“I like snowmen!”
+
+Decoding the document as UTF-8 raises a ``UnicodeDecodeError``, and
+decoding it as Windows-1252 gives you gibberish. Fortunately,
+``UnicodeDammit.detwingle()`` will convert the string to pure UTF-8,
+allowing you to decode it to Unicode and display the snowmen and quote
+marks simultaneously::
+
+ new_doc = UnicodeDammit.detwingle(doc)
+ print(new_doc.decode("utf8"))
+ # ☃☃☃“I like snowmen!”
+
+``UnicodeDammit.detwingle()`` only knows how to handle Windows-1252
+embedded in UTF-8 (or vice versa, I suppose), but this is the most
+common case.
+
+Note that you must know to call ``UnicodeDammit.detwingle()`` on your
+data before passing it into ``BeautifulSoup`` or the ``UnicodeDammit``
+constructor. Beautiful Soup assumes that a document has a single
+encoding, whatever it might be. If you pass it a document that
+contains both UTF-8 and Windows-1252, it's likely to think the whole
+document is Windows-1252, and the document will come out looking like
+` ☃☃☃“I like snowmen!”`.
+
+``UnicodeDammit.detwingle()`` is new in Beautiful Soup 4.1.0.
+
+Parsing only part of a document
+===============================
+
+Let's say you want to use Beautiful Soup look at a document's <a>
+tags. It's a waste of time and memory to parse the entire document and
+then go over it again looking for <a> tags. It would be much faster to
+ignore everything that wasn't an <a> tag in the first place. The
+``SoupStrainer`` class allows you to choose which parts of an incoming
+document are parsed. You just create a ``SoupStrainer`` and pass it in
+to the ``BeautifulSoup`` constructor as the ``parse_only`` argument.
+
+(Note that *this feature won't work if you're using the html5lib parser*.
+If you use html5lib, the whole document will be parsed, no
+matter what. This is because html5lib constantly rearranges the parse
+tree as it works, and if some part of the document didn't actually
+make it into the parse tree, it'll crash. To avoid confusion, in the
+examples below I'll be forcing Beautiful Soup to use Python's
+built-in parser.)
+
+``SoupStrainer``
+----------------
+
+The ``SoupStrainer`` class takes the same arguments as a typical
+method from `Searching the tree`_: :ref:`name <name>`, :ref:`attrs
+<attrs>`, :ref:`text <text>`, and :ref:`**kwargs <kwargs>`. Here are
+three ``SoupStrainer`` objects::
+
+ from bs4 import SoupStrainer
+
+ only_a_tags = SoupStrainer("a")
+
+ only_tags_with_id_link2 = SoupStrainer(id="link2")
+
+ def is_short_string(string):
+ return len(string) < 10
+
+ only_short_strings = SoupStrainer(text=is_short_string)
+
+I'm going to bring back the "three sisters" document one more time,
+and we'll see what the document looks like when it's parsed with these
+three ``SoupStrainer`` objects::
+
+ html_doc = """
+ <html><head><title>The Dormouse's story</title></head>
+
+ <p class="title"><b>The Dormouse's story</b></p>
+
+ <p class="story">Once upon a time there were three little sisters; and their names were
+ <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
+ <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
+ <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
+ and they lived at the bottom of a well.</p>
+
+ <p class="story">...</p>
+ """
+
+ print(BeautifulSoup(html_doc, "html.parser", parse_only=only_a_tags).prettify())
+ # <a class="sister" href="http://example.com/elsie" id="link1">
+ # Elsie
+ # </a>
+ # <a class="sister" href="http://example.com/lacie" id="link2">
+ # Lacie
+ # </a>
+ # <a class="sister" href="http://example.com/tillie" id="link3">
+ # Tillie
+ # </a>
+
+ print(BeautifulSoup(html_doc, "html.parser", parse_only=only_tags_with_id_link2).prettify())
+ # <a class="sister" href="http://example.com/lacie" id="link2">
+ # Lacie
+ # </a>
+
+ print(BeautifulSoup(html_doc, "html.parser", parse_only=only_short_strings).prettify())
+ # Elsie
+ # ,
+ # Lacie
+ # and
+ # Tillie
+ # ...
+ #
+
+You can also pass a ``SoupStrainer`` into any of the methods covered
+in `Searching the tree`_. This probably isn't terribly useful, but I
+thought I'd mention it::
+
+ soup = BeautifulSoup(html_doc)
+ soup.find_all(only_short_strings)
+ # [u'\n\n', u'\n\n', u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie',
+ # u'\n\n', u'...', u'\n']
+
+Troubleshooting
+===============
+
+.. _diagnose:
+
+``diagnose()``
+--------------
+
+If you're having trouble understanding what Beautiful Soup does to a
+document, pass the document into the ``diagnose()`` function. (New in
+Beautiful Soup 4.2.0.) Beautiful Soup will print out a report showing
+you how different parsers handle the document, and tell you if you're
+missing a parser that Beautiful Soup could be using::
+
+ from bs4.diagnose import diagnose
+ data = open("bad.html").read()
+ diagnose(data)
+
+ # Diagnostic running on Beautiful Soup 4.2.0
+ # Python version 2.7.3 (default, Aug 1 2012, 05:16:07)
+ # I noticed that html5lib is not installed. Installing it may help.
+ # Found lxml version 2.3.2.0
+ #
+ # Trying to parse your data with html.parser
+ # Here's what html.parser did with the document:
+ # ...
+
+Just looking at the output of diagnose() may show you how to solve the
+problem. Even if not, you can paste the output of ``diagnose()`` when
+asking for help.
+
+Errors when parsing a document
+------------------------------
+
+There are two different kinds of parse errors. There are crashes,
+where you feed a document to Beautiful Soup and it raises an
+exception, usually an ``HTMLParser.HTMLParseError``. And there is
+unexpected behavior, where a Beautiful Soup parse tree looks a lot
+different than the document used to create it.
+
+Almost none of these problems turn out to be problems with Beautiful
+Soup. This is not because Beautiful Soup is an amazingly well-written
+piece of software. It's because Beautiful Soup doesn't include any
+parsing code. Instead, it relies on external parsers. If one parser
+isn't working on a certain document, the best solution is to try a
+different parser. See `Installing a parser`_ for details and a parser
+comparison.
+
+The most common parse errors are ``HTMLParser.HTMLParseError:
+malformed start tag`` and ``HTMLParser.HTMLParseError: bad end
+tag``. These are both generated by Python's built-in HTML parser
+library, and the solution is to :ref:`install lxml or
+html5lib. <parser-installation>`
+
+The most common type of unexpected behavior is that you can't find a
+tag that you know is in the document. You saw it going in, but
+``find_all()`` returns ``[]`` or ``find()`` returns ``None``. This is
+another common problem with Python's built-in HTML parser, which
+sometimes skips tags it doesn't understand. Again, the solution is to
+:ref:`install lxml or html5lib. <parser-installation>`
+
+Version mismatch problems
+-------------------------
+
+* ``SyntaxError: Invalid syntax`` (on the line ``ROOT_TAG_NAME =
+ u'[document]'``): Caused by running the Python 2 version of
+ Beautiful Soup under Python 3, without converting the code.
+
+* ``ImportError: No module named HTMLParser`` - Caused by running the
+ Python 2 version of Beautiful Soup under Python 3.
+
+* ``ImportError: No module named html.parser`` - Caused by running the
+ Python 3 version of Beautiful Soup under Python 2.
+
+* ``ImportError: No module named BeautifulSoup`` - Caused by running
+ Beautiful Soup 3 code on a system that doesn't have BS3
+ installed. Or, by writing Beautiful Soup 4 code without knowing that
+ the package name has changed to ``bs4``.
+
+* ``ImportError: No module named bs4`` - Caused by running Beautiful
+ Soup 4 code on a system that doesn't have BS4 installed.
+
+.. _parsing-xml:
+
+Parsing XML
+-----------
+
+By default, Beautiful Soup parses documents as HTML. To parse a
+document as XML, pass in "xml" as the second argument to the
+``BeautifulSoup`` constructor::
+
+ soup = BeautifulSoup(markup, "xml")
+
+You'll need to :ref:`have lxml installed <parser-installation>`.
+
+Other parser problems
+---------------------
+
+* If your script works on one computer but not another, it's probably
+ because the two computers have different parser libraries
+ available. For example, you may have developed the script on a
+ computer that has lxml installed, and then tried to run it on a
+ computer that only has html5lib installed. See `Differences between
+ parsers`_ for why this matters, and fix the problem by mentioning a
+ specific parser library in the ``BeautifulSoup`` constructor.
+
+* Because `HTML tags and attributes are case-insensitive
+ <http://www.w3.org/TR/html5/syntax.html#syntax>`_, all three HTML
+ parsers convert tag and attribute names to lowercase. That is, the
+ markup <TAG></TAG> is converted to <tag></tag>. If you want to
+ preserve mixed-case or uppercase tags and attributes, you'll need to
+ :ref:`parse the document as XML. <parsing-xml>`
+
+.. _misc:
+
+Miscellaneous
+-------------
+
+* ``UnicodeEncodeError: 'charmap' codec can't encode character
+ u'\xfoo' in position bar`` (or just about any other
+ ``UnicodeEncodeError``) - This is not a problem with Beautiful Soup.
+ This problem shows up in two main situations. First, when you try to
+ print a Unicode character that your console doesn't know how to
+ display. (See `this page on the Python wiki
+ <http://wiki.python.org/moin/PrintFails>`_ for help.) Second, when
+ you're writing to a file and you pass in a Unicode character that's
+ not supported by your default encoding. In this case, the simplest
+ solution is to explicitly encode the Unicode string into UTF-8 with
+ ``u.encode("utf8")``.
+
+* ``KeyError: [attr]`` - Caused by accessing ``tag['attr']`` when the
+ tag in question doesn't define the ``attr`` attribute. The most
+ common errors are ``KeyError: 'href'`` and ``KeyError:
+ 'class'``. Use ``tag.get('attr')`` if you're not sure ``attr`` is
+ defined, just as you would with a Python dictionary.
+
+* ``AttributeError: 'ResultSet' object has no attribute 'foo'`` - This
+ usually happens because you expected ``find_all()`` to return a
+ single tag or string. But ``find_all()`` returns a _list_ of tags
+ and strings--a ``ResultSet`` object. You need to iterate over the
+ list and look at the ``.foo`` of each one. Or, if you really only
+ want one result, you need to use ``find()`` instead of
+ ``find_all()``.
+
+* ``AttributeError: 'NoneType' object has no attribute 'foo'`` - This
+ usually happens because you called ``find()`` and then tried to
+ access the `.foo`` attribute of the result. But in your case,
+ ``find()`` didn't find anything, so it returned ``None``, instead of
+ returning a tag or a string. You need to figure out why your
+ ``find()`` call isn't returning anything.
+
+Improving Performance
+---------------------
+
+Beautiful Soup will never be as fast as the parsers it sits on top
+of. If response time is critical, if you're paying for computer time
+by the hour, or if there's any other reason why computer time is more
+valuable than programmer time, you should forget about Beautiful Soup
+and work directly atop `lxml <http://lxml.de/>`_.
+
+That said, there are things you can do to speed up Beautiful Soup. If
+you're not using lxml as the underlying parser, my advice is to
+:ref:`start <parser-installation>`. Beautiful Soup parses documents
+significantly faster using lxml than using html.parser or html5lib.
+
+You can speed up encoding detection significantly by installing the
+`cchardet <http://pypi.python.org/pypi/cchardet/>`_ library.
+
+`Parsing only part of a document`_ won't save you much time parsing
+the document, but it can save a lot of memory, and it'll make
+`searching` the document much faster.
+
+Beautiful Soup 3
+================
+
+Beautiful Soup 3 is the previous release series, and is no longer
+being actively developed. It's currently packaged with all major Linux
+distributions:
+
+:kbd:`$ apt-get install python-beautifulsoup`
+
+It's also published through PyPi as ``BeautifulSoup``.:
+
+:kbd:`$ easy_install BeautifulSoup`
+
+:kbd:`$ pip install BeautifulSoup`
+
+You can also `download a tarball of Beautiful Soup 3.2.0
+<http://www.crummy.com/software/BeautifulSoup/bs3/download/3.x/BeautifulSoup-3.2.0.tar.gz>`_.
+
+If you ran ``easy_install beautifulsoup`` or ``easy_install
+BeautifulSoup``, but your code doesn't work, you installed Beautiful
+Soup 3 by mistake. You need to run ``easy_install beautifulsoup4``.
+
+`The documentation for Beautiful Soup 3 is archived online
+<http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_. If
+your first language is Chinese, it might be easier for you to read
+`the Chinese translation of the Beautiful Soup 3 documentation
+<http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html>`_,
+then read this document to find out about the changes made in
+Beautiful Soup 4.
+
+Porting code to BS4
+-------------------
+
+Most code written against Beautiful Soup 3 will work against Beautiful
+Soup 4 with one simple change. All you should have to do is change the
+package name from ``BeautifulSoup`` to ``bs4``. So this::
+
+ from BeautifulSoup import BeautifulSoup
+
+becomes this::
+
+ from bs4 import BeautifulSoup
+
+* If you get the ``ImportError`` "No module named BeautifulSoup", your
+ problem is that you're trying to run Beautiful Soup 3 code, but you
+ only have Beautiful Soup 4 installed.
+
+* If you get the ``ImportError`` "No module named bs4", your problem
+ is that you're trying to run Beautiful Soup 4 code, but you only
+ have Beautiful Soup 3 installed.
+
+Although BS4 is mostly backwards-compatible with BS3, most of its
+methods have been deprecated and given new names for `PEP 8 compliance
+<http://www.python.org/dev/peps/pep-0008/>`_. There are numerous other
+renames and changes, and a few of them break backwards compatibility.
+
+Here's what you'll need to know to convert your BS3 code and habits to BS4:
+
+You need a parser
+^^^^^^^^^^^^^^^^^
+
+Beautiful Soup 3 used Python's ``SGMLParser``, a module that was
+deprecated and removed in Python 3.0. Beautiful Soup 4 uses
+``html.parser`` by default, but you can plug in lxml or html5lib and
+use that instead. See `Installing a parser`_ for a comparison.
+
+Since ``html.parser`` is not the same parser as ``SGMLParser``, it
+will treat invalid markup differently. Usually the "difference" is
+that ``html.parser`` crashes. In that case, you'll need to install
+another parser. But sometimes ``html.parser`` just creates a different
+parse tree than ``SGMLParser`` would. If this happens, you may need to
+update your BS3 scraping code to deal with the new tree.
+
+Method names
+^^^^^^^^^^^^
+
+* ``renderContents`` -> ``encode_contents``
+* ``replaceWith`` -> ``replace_with``
+* ``replaceWithChildren`` -> ``unwrap``
+* ``findAll`` -> ``find_all``
+* ``findAllNext`` -> ``find_all_next``
+* ``findAllPrevious`` -> ``find_all_previous``
+* ``findNext`` -> ``find_next``
+* ``findNextSibling`` -> ``find_next_sibling``
+* ``findNextSiblings`` -> ``find_next_siblings``
+* ``findParent`` -> ``find_parent``
+* ``findParents`` -> ``find_parents``
+* ``findPrevious`` -> ``find_previous``
+* ``findPreviousSibling`` -> ``find_previous_sibling``
+* ``findPreviousSiblings`` -> ``find_previous_siblings``
+* ``nextSibling`` -> ``next_sibling``
+* ``previousSibling`` -> ``previous_sibling``
+
+Some arguments to the Beautiful Soup constructor were renamed for the
+same reasons:
+
+* ``BeautifulSoup(parseOnlyThese=...)`` -> ``BeautifulSoup(parse_only=...)``
+* ``BeautifulSoup(fromEncoding=...)`` -> ``BeautifulSoup(from_encoding=...)``
+
+I renamed one method for compatibility with Python 3:
+
+* ``Tag.has_key()`` -> ``Tag.has_attr()``
+
+I renamed one attribute to use more accurate terminology:
+
+* ``Tag.isSelfClosing`` -> ``Tag.is_empty_element``
+
+I renamed three attributes to avoid using words that have special
+meaning to Python. Unlike the others, these changes are *not backwards
+compatible.* If you used these attributes in BS3, your code will break
+on BS4 until you change them.
+
+* ``UnicodeDammit.unicode`` -> ``UnicodeDammit.unicode_markup``
+* ``Tag.next`` -> ``Tag.next_element``
+* ``Tag.previous`` -> ``Tag.previous_element``
+
+Generators
+^^^^^^^^^^
+
+I gave the generators PEP 8-compliant names, and transformed them into
+properties:
+
+* ``childGenerator()`` -> ``children``
+* ``nextGenerator()`` -> ``next_elements``
+* ``nextSiblingGenerator()`` -> ``next_siblings``
+* ``previousGenerator()`` -> ``previous_elements``
+* ``previousSiblingGenerator()`` -> ``previous_siblings``
+* ``recursiveChildGenerator()`` -> ``descendants``
+* ``parentGenerator()`` -> ``parents``
+
+So instead of this::
+
+ for parent in tag.parentGenerator():
+ ...
+
+You can write this::
+
+ for parent in tag.parents:
+ ...
+
+(But the old code will still work.)
+
+Some of the generators used to yield ``None`` after they were done, and
+then stop. That was a bug. Now the generators just stop.
+
+There are two new generators, :ref:`.strings and
+.stripped_strings <string-generators>`. ``.strings`` yields
+NavigableString objects, and ``.stripped_strings`` yields Python
+strings that have had whitespace stripped.
+
+XML
+^^^
+
+There is no longer a ``BeautifulStoneSoup`` class for parsing XML. To
+parse XML you pass in "xml" as the second argument to the
+``BeautifulSoup`` constructor. For the same reason, the
+``BeautifulSoup`` constructor no longer recognizes the ``isHTML``
+argument.
+
+Beautiful Soup's handling of empty-element XML tags has been
+improved. Previously when you parsed XML you had to explicitly say
+which tags were considered empty-element tags. The ``selfClosingTags``
+argument to the constructor is no longer recognized. Instead,
+Beautiful Soup considers any empty tag to be an empty-element tag. If
+you add a child to an empty-element tag, it stops being an
+empty-element tag.
+
+Entities
+^^^^^^^^
+
+An incoming HTML or XML entity is always converted into the
+corresponding Unicode character. Beautiful Soup 3 had a number of
+overlapping ways of dealing with entities, which have been
+removed. The ``BeautifulSoup`` constructor no longer recognizes the
+``smartQuotesTo`` or ``convertEntities`` arguments. (`Unicode,
+Dammit`_ still has ``smart_quotes_to``, but its default is now to turn
+smart quotes into Unicode.) The constants ``HTML_ENTITIES``,
+``XML_ENTITIES``, and ``XHTML_ENTITIES`` have been removed, since they
+configure a feature (transforming some but not all entities into
+Unicode characters) that no longer exists.
+
+If you want to turn Unicode characters back into HTML entities on
+output, rather than turning them into UTF-8 characters, you need to
+use an :ref:`output formatter <output_formatters>`.
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+:ref:`Tag.string <.string>` now operates recursively. If tag A
+contains a single tag B and nothing else, then A.string is the same as
+B.string. (Previously, it was None.)
+
+`Multi-valued attributes`_ like ``class`` have lists of strings as
+their values, not strings. This may affect the way you search by CSS
+class.
+
+If you pass one of the ``find*`` methods both :ref:`text <text>` `and`
+a tag-specific argument like :ref:`name <name>`, Beautiful Soup will
+search for tags that match your tag-specific criteria and whose
+:ref:`Tag.string <.string>` matches your value for :ref:`text
+<text>`. It will `not` find the strings themselves. Previously,
+Beautiful Soup ignored the tag-specific arguments and looked for
+strings.
+
+The ``BeautifulSoup`` constructor no longer recognizes the
+`markupMassage` argument. It's now the parser's responsibility to
+handle markup correctly.
+
+The rarely-used alternate parser classes like
+``ICantBelieveItsBeautifulSoup`` and ``BeautifulSOAP`` have been
+removed. It's now the parser's decision how to handle ambiguous
+markup.
+
+The ``prettify()`` method now returns a Unicode string, not a bytestring.
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstrate_parser_differences.py b/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstrate_parser_differences.py
new file mode 100644
index 00000000000..d84670a53a6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstrate_parser_differences.py
@@ -0,0 +1,95 @@
+"""Demonstrate how different parsers parse the same markup.
+
+Beautiful Soup can use any of a number of different parsers. Every
+parser should behave more or less the same on valid markup, and
+Beautiful Soup's unit tests make sure this is the case. But every
+parser handles invalid markup differently. Even different versions of
+the same parser handle invalid markup differently. So instead of unit
+tests I've created this educational demonstration script.
+
+The file demonstration_markup.txt contains many lines of HTML. This
+script tests each line of markup against every parser you have
+installed, and prints out how each parser sees that markup. This may
+help you choose a parser, or understand why Beautiful Soup presents
+your document the way it does.
+"""
+
+import os
+import sys
+from bs4 import BeautifulSoup
+parsers = ['html.parser']
+
+try:
+ from bs4.builder import _lxml
+ parsers.append('lxml')
+except ImportError, e:
+ pass
+
+try:
+ from bs4.builder import _html5lib
+ parsers.append('html5lib')
+except ImportError, e:
+ pass
+
+class Demonstration(object):
+ def __init__(self, markup):
+ self.results = {}
+ self.markup = markup
+
+ def run_against(self, *parser_names):
+ uniform_results = True
+ previous_output = None
+ for parser in parser_names:
+ try:
+ soup = BeautifulSoup(self.markup, parser)
+ if markup.startswith("<div>"):
+ # Extract the interesting part
+ output = soup.div
+ else:
+ output = soup
+ except Exception, e:
+ output = "[EXCEPTION] %s" % str(e)
+ self.results[parser] = output
+ if previous_output is None:
+ previous_output = output
+ elif previous_output != output:
+ uniform_results = False
+ return uniform_results
+
+ def dump(self):
+ print "%s: %s" % ("Markup".rjust(13), self.markup.encode("utf8"))
+ for parser, output in self.results.items():
+ print "%s: %s" % (parser.rjust(13), output.encode("utf8"))
+
+different_results = []
+uniform_results = []
+
+print "= Testing the following parsers: %s =" % ", ".join(parsers)
+print
+
+input_file = sys.stdin
+if sys.stdin.isatty():
+ for filename in [
+ "demonstration_markup.txt",
+ os.path.join("scripts", "demonstration_markup.txt")]:
+ if os.path.exists(filename):
+ input_file = open(filename)
+
+for markup in input_file:
+ demo = Demonstration(markup.decode("utf8").strip().replace("\\n", "\n"))
+ is_uniform = demo.run_against(*parsers)
+ if is_uniform:
+ uniform_results.append(demo)
+ else:
+ different_results.append(demo)
+
+print "== Markup that's handled the same in every parser =="
+print
+for demo in uniform_results:
+ demo.dump()
+ print
+print "== Markup that's not handled the same in every parser =="
+print
+for demo in different_results:
+ demo.dump()
+ print
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstration_markup.txt b/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstration_markup.txt
new file mode 100644
index 00000000000..a7914a0b04a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/scripts/demonstration_markup.txt
@@ -0,0 +1,34 @@
+A bare string
+<!DOCTYPE xsl:stylesheet SYSTEM "htmlent.dtd">
+<!DOCTYPE xsl:stylesheet PUBLIC "htmlent.dtd">
+<div><![CDATA[A CDATA section where it doesn't belong]]></div>
+<div><svg><![CDATA[HTML5 does allow CDATA sections in SVG]]></svg></div>
+<div>A <meta> tag</div>
+<div>A <br> tag that supposedly has contents.</br></div>
+<div>AT&T</div>
+<div><textarea>Within a textarea, markup like <b> tags and <&<&amp; should be treated as literal</textarea></div>
+<div><script>if (i < 2) { alert("<b>Markup within script tags should be treated as literal.</b>"); }</script></div>
+<div>This numeric entity is missing the final semicolon: <x t="pi&#241ata"></div>
+<div><a href="http://example.com/</a> that attribute value never got closed</div>
+<div><a href="foo</a>, </a><a href="bar">that attribute value was closed by the subsequent tag</a></div>
+<! This document starts with a bogus declaration ><div>a</div>
+<div>This document contains <!an incomplete declaration <div>(do you see it?)</div>
+<div>This document ends with <!an incomplete declaration
+<div><a style={height:21px;}>That attribute value was bogus</a></div>
+<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">The doctype is invalid because it contains extra whitespace
+<div><table><td nowrap>That boolean attribute had no value</td></table></div>
+<div>Here's a nonexistent entity: &#foo; (do you see it?)</div>
+<div>This document ends before the entity finishes: &gt
+<div><p>Paragraphs shouldn't contain block display elements, but this one does: <dl><dt>you see?</dt></p>
+<b b="20" a="1" b="10" a="2" a="3" a="4">Multiple values for the same attribute.</b>
+<div><table><tr><td>Here's a table</td></tr></table></div>
+<div><table id="1"><tr><td>Here's a nested table:<table id="2"><tr><td>foo</td></tr></table></td></div>
+<div>This tag contains nothing but whitespace: <b> </b></div>
+<div><blockquote><p><b>This p tag is cut off by</blockquote></p>the end of the blockquote tag</div>
+<div><table><div>This table contains bare markup</div></table></div>
+<div><div id="1">\n <a href="link1">This link is never closed.\n</div>\n<div id="2">\n <div id="3">\n <a href="link2">This link is closed.</a>\n </div>\n</div></div>
+<div>This document contains a <!DOCTYPE surprise>surprise doctype</div>
+<div><a><B><Cd><EFG>Mixed case tags are folded to lowercase</efg></CD></b></A></div>
+<div><our☃>Tag name contains Unicode characters</our☃></div>
+<div><a ☃="snowman">Attribute name contains Unicode characters</a></div>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
diff --git a/chromium/third_party/catapult/third_party/beautifulsoup4/setup.py b/chromium/third_party/catapult/third_party/beautifulsoup4/setup.py
new file mode 100644
index 00000000000..0142ea00e86
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/beautifulsoup4/setup.py
@@ -0,0 +1,29 @@
+from distutils.core import setup
+
+try:
+ from distutils.command.build_py import build_py_2to3 as build_py
+except ImportError:
+ # 2.x
+ from distutils.command.build_py import build_py
+
+setup(name="beautifulsoup4",
+ version = "4.3.2",
+ author="Leonard Richardson",
+ author_email='leonardr@segfault.org',
+ url="http://www.crummy.com/software/BeautifulSoup/bs4/",
+ download_url = "http://www.crummy.com/software/BeautifulSoup/bs4/download/",
+ long_description="""Beautiful Soup sits atop an HTML or XML parser, providing Pythonic idioms for iterating, searching, and modifying the parse tree.""",
+ license="MIT",
+ packages=['bs4', 'bs4.builder', 'bs4.tests'],
+ cmdclass = {'build_py':build_py},
+ classifiers=["Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python",
+ 'Programming Language :: Python :: 3',
+ "Topic :: Text Processing :: Markup :: HTML",
+ "Topic :: Text Processing :: Markup :: XML",
+ "Topic :: Text Processing :: Markup :: SGML",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/.travis.yml b/chromium/third_party/catapult/third_party/html5lib-python/.travis.yml
new file mode 100644
index 00000000000..dd3130019e7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/.travis.yml
@@ -0,0 +1,37 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+ - "3.2"
+ - "3.3"
+ - "3.4"
+ - "pypy"
+
+env:
+ - USE_OPTIONAL=true
+ - USE_OPTIONAL=false
+
+matrix:
+ exclude:
+ - python: "2.7"
+ env: USE_OPTIONAL=false
+ - python: "3.4"
+ env: USE_OPTIONAL=false
+ include:
+ - python: "2.7"
+ env: USE_OPTIONAL=false FLAKE=true
+ - python: "3.4"
+ env: USE_OPTIONAL=false FLAKE=true
+
+before_install:
+ - git submodule update --init --recursive
+
+install:
+ - bash requirements-install.sh
+
+script:
+ - nosetests
+ - bash flake8-run.sh
+
+after_script:
+ - python debug-info.py
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/AUTHORS.rst b/chromium/third_party/catapult/third_party/html5lib-python/AUTHORS.rst
new file mode 100644
index 00000000000..fe9ae89bcc1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/AUTHORS.rst
@@ -0,0 +1,43 @@
+Credits
+=======
+
+``html5lib`` is written and maintained by:
+
+- James Graham
+- Geoffrey Sneddon
+- Łukasz Langa
+
+
+Patches and suggestions
+-----------------------
+(In chronological order, by first commit:)
+
+- Anne van Kesteren
+- Lachlan Hunt
+- lantis63
+- Sam Ruby
+- Thomas Broyer
+- Tim Fletcher
+- Mark Pilgrim
+- Ryan King
+- Philip Taylor
+- Edward Z. Yang
+- fantasai
+- Mike West
+- Philip Jägenstedt
+- Ms2ger
+- Mohammad Taha Jahangir
+- Andy Wingo
+- Juan Carlos Garcia Segovia
+- Andreas Madsack
+- Karim Valiev
+- Marc DM
+- Tony Lopes
+- lilbludevil
+- Simon Sapin
+- Jon Dufresne
+- Drew Hubl
+- Austin Kumbera
+- Jim Baker
+- Michael[tm] Smith
+- Marc Abramowitz
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/CHANGES.rst b/chromium/third_party/catapult/third_party/html5lib-python/CHANGES.rst
new file mode 100644
index 00000000000..1279c27704b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/CHANGES.rst
@@ -0,0 +1,217 @@
+Change Log
+----------
+
+0.9999999/1.0b8
+~~~~~~~~~~~~~~~
+
+Released on XXX
+
+* XXX
+
+
+0.999999/1.0b7
+~~~~~~~~~~~~~~
+
+Released on July 7, 2015
+
+* Fix #189: fix the sanitizer to allow relative URLs again (as it did
+ prior to 0.9999/1.0b5).
+
+
+0.99999/1.0b6
+~~~~~~~~~~~~~
+
+Released on April 30, 2015
+
+* Fix #188: fix the sanitizer to not throw an exception when sanitizing
+ bogus data URLs.
+
+
+0.9999/1.0b5
+~~~~~~~~~~~~
+
+Released on April 29, 2015
+
+* Fix #153: Sanitizer fails to treat some attributes as URLs. Despite how
+ this sounds, this has no known security implications. No known version
+ of IE (5.5 to current), Firefox (3 to current), Safari (6 to current),
+ Chrome (1 to current), or Opera (12 to current) will run any script
+ provided in these attributes.
+
+* Pass error message to the ParseError exception in strict parsing mode.
+
+* Allow data URIs in the sanitizer, with a whitelist of content-types.
+
+* Add support for Python implementations that don't support lone
+ surrogates (read: Jython). Fixes #2.
+
+* Remove localization of error messages. This functionality was totally
+ unused (and untested that everything was localizable), so we may as
+ well follow numerous browsers in not supporting translating technical
+ strings.
+
+* Expose treewalkers.pprint as a public API.
+
+* Add a documentEncoding property to HTML5Parser, fix #121.
+
+
+0.999
+~~~~~
+
+Released on December 23, 2013
+
+* Fix #127: add work-around for CPython issue #20007: .read(0) on
+ http.client.HTTPResponse drops the rest of the content.
+
+* Fix #115: lxml treewalker can now deal with fragments containing, at
+ their root level, text nodes with non-ASCII characters on Python 2.
+
+
+0.99
+~~~~
+
+Released on September 10, 2013
+
+* No library changes from 1.0b3; released as 0.99 as pip has changed
+ behaviour from 1.4 to avoid installing pre-release versions per
+ PEP 440.
+
+
+1.0b3
+~~~~~
+
+Released on July 24, 2013
+
+* Removed ``RecursiveTreeWalker`` from ``treewalkers._base``. Any
+ implementation using it should be moved to
+ ``NonRecursiveTreeWalker``, as everything bundled with html5lib has
+ for years.
+
+* Fix #67 so that ``BufferedStream`` to correctly returns a bytes
+ object, thereby fixing any case where html5lib is passed a
+ non-seekable RawIOBase-like object.
+
+
+1.0b2
+~~~~~
+
+Released on June 27, 2013
+
+* Removed reordering of attributes within the serializer. There is now
+ an ``alphabetical_attributes`` option which preserves the previous
+ behaviour through a new filter. This allows attribute order to be
+ preserved through html5lib if the tree builder preserves order.
+
+* Removed ``dom2sax`` from DOM treebuilders. It has been replaced by
+ ``treeadapters.sax.to_sax`` which is generic and supports any
+ treewalker; it also resolves all known bugs with ``dom2sax``.
+
+* Fix treewalker assertions on hitting bytes strings on
+ Python 2. Previous to 1.0b1, treewalkers coped with mixed
+ bytes/unicode data on Python 2; this reintroduces this prior
+ behaviour on Python 2. Behaviour is unchanged on Python 3.
+
+
+1.0b1
+~~~~~
+
+Released on May 17, 2013
+
+* Implementation updated to implement the `HTML specification
+ <http://www.whatwg.org/specs/web-apps/current-work/>`_ as of 5th May
+ 2013 (`SVN <http://svn.whatwg.org/webapps/>`_ revision r7867).
+
+* Python 3.2+ supported in a single codebase using the ``six`` library.
+
+* Removed support for Python 2.5 and older.
+
+* Removed the deprecated Beautiful Soup 3 treebuilder.
+ ``beautifulsoup4`` can use ``html5lib`` as a parser instead. Note that
+ since it doesn't support namespaces, foreign content like SVG and
+ MathML is parsed incorrectly.
+
+* Removed ``simpletree`` from the package. The default tree builder is
+ now ``etree`` (using the ``xml.etree.cElementTree`` implementation if
+ available, and ``xml.etree.ElementTree`` otherwise).
+
+* Removed the ``XHTMLSerializer`` as it never actually guaranteed its
+ output was well-formed XML, and hence provided little of use.
+
+* Removed default DOM treebuilder, so ``html5lib.treebuilders.dom`` is no
+ longer supported. ``html5lib.treebuilders.getTreeBuilder("dom")`` will
+ return the default DOM treebuilder, which uses ``xml.dom.minidom``.
+
+* Optional heuristic character encoding detection now based on
+ ``charade`` for Python 2.6 - 3.3 compatibility.
+
+* Optional ``Genshi`` treewalker support fixed.
+
+* Many bugfixes, including:
+
+ * #33: null in attribute value breaks XML AttValue;
+
+ * #4: nested, indirect descendant, <button> causes infinite loop;
+
+ * `Google Code 215
+ <http://code.google.com/p/html5lib/issues/detail?id=215>`_: Properly
+ detect seekable streams;
+
+ * `Google Code 206
+ <http://code.google.com/p/html5lib/issues/detail?id=206>`_: add
+ support for <video preload=...>, <audio preload=...>;
+
+ * `Google Code 205
+ <http://code.google.com/p/html5lib/issues/detail?id=205>`_: add
+ support for <video poster=...>;
+
+ * `Google Code 202
+ <http://code.google.com/p/html5lib/issues/detail?id=202>`_: Unicode
+ file breaks InputStream.
+
+* Source code is now mostly PEP 8 compliant.
+
+* Test harness has been improved and now depends on ``nose``.
+
+* Documentation updated and moved to http://html5lib.readthedocs.org/.
+
+
+0.95
+~~~~
+
+Released on February 11, 2012
+
+
+0.90
+~~~~
+
+Released on January 17, 2010
+
+
+0.11.1
+~~~~~~
+
+Released on June 12, 2008
+
+
+0.11
+~~~~
+
+Released on June 10, 2008
+
+
+0.10
+~~~~
+
+Released on October 7, 2007
+
+
+0.9
+~~~
+
+Released on March 11, 2007
+
+
+0.2
+~~~
+
+Released on January 8, 2007
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/CONTRIBUTING.rst b/chromium/third_party/catapult/third_party/html5lib-python/CONTRIBUTING.rst
new file mode 100644
index 00000000000..8c5e198535d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/CONTRIBUTING.rst
@@ -0,0 +1,60 @@
+Contributing
+============
+
+Pull requests are more than welcome — both to the library and to the
+documentation. Some useful information:
+
+- We aim to follow PEP 8 in the library, but ignoring the
+ 79-character-per-line limit, instead following a soft limit of 99,
+ but allowing lines over this where it is the readable thing to do.
+
+- We aim to follow PEP 257 for all docstrings, and make them properly
+ parseable by Sphinx while generating API documentation.
+
+- We keep ``pyflakes`` reporting no errors or warnings at all times.
+
+- We keep the master branch passing all tests at all times on all
+ supported versions.
+
+`Travis CI <https://travis-ci.org/html5lib/html5lib-python/>`_ is run
+against all pull requests and should enforce all of the above.
+
+We use `Opera Critic <https://critic.hoppipolla.co.uk/>`_ as an external
+code-review tool, which uses your GitHub login to authenticate. You'll
+get email notifications for issues raised in the review.
+
+
+Patch submission guidelines
+---------------------------
+
+- **Create a new Git branch specific to your change.** Do not put
+ multiple fixes/features in the same pull request. If you find an
+ unrelated bug, create a distinct branch and submit a separate pull
+ request for the bugfix. This makes life much easier for maintainers
+ and will speed up merging your patches.
+
+- **Write a test** whenever possible. Following existing tests is often
+ easiest, and a good way to tell whether the feature you're modifying
+ is easily testable.
+
+- **Make sure documentation is updated.** Keep docstrings current, and
+ if necessary, update the Sphinx documentation in ``doc/``.
+
+- **Add a changelog entry** at the top of ``CHANGES.rst`` following
+ existing entries' styles.
+
+- **Run tests with tox** if possible, to make sure your changes are
+ compatible with all supported Python versions.
+
+- **Squash commits** before submitting the pull request so that a single
+ commit contains the entire change, and only that change (see the first
+ bullet).
+
+- **Don't rebase after creating the pull request.** Merge with upstream,
+ if necessary, and use ``git commit --fixup`` for fixing issues raised
+ in a Critic review or by a failing Travis build. The reviewer will
+ squash and rebase your pull request while accepting it. Even though
+ GitHub won't recognize the pull request as accepted, the squashed
+ commits will properly specify you as the author.
+
+- **Attribute yourself** in ``AUTHORS.rst``.
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/LICENSE b/chromium/third_party/catapult/third_party/html5lib-python/LICENSE
new file mode 100644
index 00000000000..c87fa7a0006
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2006-2013 James Graham and other contributors
+
+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.
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/MANIFEST.in b/chromium/third_party/catapult/third_party/html5lib-python/MANIFEST.in
new file mode 100644
index 00000000000..1edd0b7deea
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/MANIFEST.in
@@ -0,0 +1,6 @@
+include LICENSE
+include CHANGES.rst
+include README.rst
+include requirements*.txt
+graft html5lib/tests/testdata
+recursive-include html5lib/tests *.py
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/README.chromium b/chromium/third_party/catapult/third_party/html5lib-python/README.chromium
new file mode 100644
index 00000000000..18b86c0d399
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/README.chromium
@@ -0,0 +1,11 @@
+Name: html5lib-python
+Short Name: html5lib
+URL: https://github.com/html5lib/html5lib-python
+Version: 01b1ebb7ce0146b8082b1a7315431aac023eb046
+License: MIT
+
+Description:
+Standards-compliant library for parsing and serializing HTML documents and
+fragments in Python
+
+Local Modifications: None
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/README.rst b/chromium/third_party/catapult/third_party/html5lib-python/README.rst
new file mode 100644
index 00000000000..9e0a0f74048
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/README.rst
@@ -0,0 +1,157 @@
+html5lib
+========
+
+.. image:: https://travis-ci.org/html5lib/html5lib-python.png?branch=master
+ :target: https://travis-ci.org/html5lib/html5lib-python
+
+html5lib is a pure-python library for parsing HTML. It is designed to
+conform to the WHATWG HTML specification, as is implemented by all major
+web browsers.
+
+
+Usage
+-----
+
+Simple usage follows this pattern:
+
+.. code-block:: python
+
+ import html5lib
+ with open("mydocument.html", "rb") as f:
+ document = html5lib.parse(f)
+
+or:
+
+.. code-block:: python
+
+ import html5lib
+ document = html5lib.parse("<p>Hello World!")
+
+By default, the ``document`` will be an ``xml.etree`` element instance.
+Whenever possible, html5lib chooses the accelerated ``ElementTree``
+implementation (i.e. ``xml.etree.cElementTree`` on Python 2.x).
+
+Two other tree types are supported: ``xml.dom.minidom`` and
+``lxml.etree``. To use an alternative format, specify the name of
+a treebuilder:
+
+.. code-block:: python
+
+ import html5lib
+ with open("mydocument.html", "rb") as f:
+ lxml_etree_document = html5lib.parse(f, treebuilder="lxml")
+
+When using with ``urllib2`` (Python 2), the charset from HTTP should be
+pass into html5lib as follows:
+
+.. code-block:: python
+
+ from contextlib import closing
+ from urllib2 import urlopen
+ import html5lib
+
+ with closing(urlopen("http://example.com/")) as f:
+ document = html5lib.parse(f, encoding=f.info().getparam("charset"))
+
+When using with ``urllib.request`` (Python 3), the charset from HTTP
+should be pass into html5lib as follows:
+
+.. code-block:: python
+
+ from urllib.request import urlopen
+ import html5lib
+
+ with urlopen("http://example.com/") as f:
+ document = html5lib.parse(f, encoding=f.info().get_content_charset())
+
+To have more control over the parser, create a parser object explicitly.
+For instance, to make the parser raise exceptions on parse errors, use:
+
+.. code-block:: python
+
+ import html5lib
+ with open("mydocument.html", "rb") as f:
+ parser = html5lib.HTMLParser(strict=True)
+ document = parser.parse(f)
+
+When you're instantiating parser objects explicitly, pass a treebuilder
+class as the ``tree`` keyword argument to use an alternative document
+format:
+
+.. code-block:: python
+
+ import html5lib
+ parser = html5lib.HTMLParser(tree=html5lib.getTreeBuilder("dom"))
+ minidom_document = parser.parse("<p>Hello World!")
+
+More documentation is available at http://html5lib.readthedocs.org/.
+
+
+Installation
+------------
+
+html5lib works on CPython 2.6+, CPython 3.2+ and PyPy. To install it,
+use:
+
+.. code-block:: bash
+
+ $ pip install html5lib
+
+
+Optional Dependencies
+---------------------
+
+The following third-party libraries may be used for additional
+functionality:
+
+- ``datrie`` can be used to improve parsing performance (though in
+ almost all cases the improvement is marginal);
+
+- ``lxml`` is supported as a tree format (for both building and
+ walking) under CPython (but *not* PyPy where it is known to cause
+ segfaults);
+
+- ``genshi`` has a treewalker (but not builder); and
+
+- ``charade`` can be used as a fallback when character encoding cannot
+ be determined; ``chardet``, from which it was forked, can also be used
+ on Python 2.
+
+- ``ordereddict`` can be used under Python 2.6
+ (``collections.OrderedDict`` is used instead on later versions) to
+ serialize attributes in alphabetical order.
+
+
+Bugs
+----
+
+Please report any bugs on the `issue tracker
+<https://github.com/html5lib/html5lib-python/issues>`_.
+
+
+Tests
+-----
+
+Unit tests require the ``nose`` library and can be run using the
+``nosetests`` command in the root directory; ``ordereddict`` is
+required under Python 2.6. All should pass.
+
+Test data are contained in a separate `html5lib-tests
+<https://github.com/html5lib/html5lib-tests>`_ repository and included
+as a submodule, thus for git checkouts they must be initialized::
+
+ $ git submodule init
+ $ git submodule update
+
+If you have all compatible Python implementations available on your
+system, you can run tests on all of them using the ``tox`` utility,
+which can be found on PyPI.
+
+
+Questions?
+----------
+
+There's a mailing list available for support on Google Groups,
+`html5lib-discuss <http://groups.google.com/group/html5lib-discuss>`_,
+though you may get a quicker response asking on IRC in `#whatwg on
+irc.freenode.net <http://wiki.whatwg.org/wiki/IRC>`_.
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/debug-info.py b/chromium/third_party/catapult/third_party/html5lib-python/debug-info.py
new file mode 100644
index 00000000000..b5d2bb6a305
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/debug-info.py
@@ -0,0 +1,37 @@
+from __future__ import print_function, unicode_literals
+
+import platform
+import sys
+
+
+info = {
+ "impl": platform.python_implementation(),
+ "version": platform.python_version(),
+ "revision": platform.python_revision(),
+ "maxunicode": sys.maxunicode,
+ "maxsize": sys.maxsize
+}
+
+search_modules = ["charade", "chardet", "datrie", "genshi", "html5lib", "lxml", "six"]
+found_modules = []
+
+for m in search_modules:
+ try:
+ __import__(m)
+ except ImportError:
+ pass
+ else:
+ found_modules.append(m)
+
+info["modules"] = ", ".join(found_modules)
+
+
+print("""html5lib debug info:
+
+Python %(version)s (revision: %(revision)s)
+Implementation: %(impl)s
+
+sys.maxunicode: %(maxunicode)X
+sys.maxsize: %(maxsize)X
+
+Installed modules: %(modules)s""" % info)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/Makefile b/chromium/third_party/catapult/third_party/html5lib-python/doc/Makefile
new file mode 100644
index 00000000000..e0e58667e7d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/Makefile
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/html5lib.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/html5lib.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/html5lib"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/html5lib"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/changes.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/changes.rst
new file mode 100644
index 00000000000..ded3b705d0f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/changes.rst
@@ -0,0 +1,3 @@
+.. :changelog:
+
+.. include:: ../CHANGES.rst
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/conf.py b/chromium/third_party/catapult/third_party/html5lib-python/doc/conf.py
new file mode 100644
index 00000000000..434f21c42eb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/conf.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# html5lib documentation build configuration file, created by
+# sphinx-quickstart on Wed May 8 00:04:49 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'html5lib'
+copyright = '2006 - 2013, James Graham, Geoffrey Sneddon, and contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.0'
+# The full version, including alpha/beta/rc tags.
+sys.path.append(os.path.abspath('..'))
+from html5lib import __version__
+release = __version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = 'en'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build', 'theme']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'html5libdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'html5lib.tex', 'html5lib Documentation',
+ 'James Graham, Geoffrey Sneddon, and contributors', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'html5lib', 'html5lib Documentation',
+ ['James Graham, Geoffrey Sneddon, and contributors'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'html5lib', 'html5lib Documentation',
+ 'James Graham, Geoffrey Sneddon, and contributors', 'html5lib', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+class CExtMock(object):
+ """Required for autodoc on readthedocs.org where you cannot build C extensions."""
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def __call__(self, *args, **kwargs):
+ return CExtMock()
+
+ @classmethod
+ def __getattr__(cls, name):
+ if name in ('__file__', '__path__'):
+ return '/dev/null'
+ else:
+ return CExtMock()
+
+try:
+ import lxml # flake8: noqa
+except ImportError:
+ sys.modules['lxml'] = CExtMock()
+ sys.modules['lxml.etree'] = CExtMock()
+ print("warning: lxml modules mocked.")
+
+try:
+ import genshi # flake8: noqa
+except ImportError:
+ sys.modules['genshi'] = CExtMock()
+ sys.modules['genshi.core'] = CExtMock()
+ print("warning: genshi modules mocked.")
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.filters.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.filters.rst
new file mode 100644
index 00000000000..1fda38a735a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.filters.rst
@@ -0,0 +1,59 @@
+filters Package
+===============
+
+:mod:`_base` Module
+-------------------
+
+.. automodule:: html5lib.filters._base
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`alphabeticalattributes` Module
+------------------------------------
+
+.. automodule:: html5lib.filters.alphabeticalattributes
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`inject_meta_charset` Module
+---------------------------------
+
+.. automodule:: html5lib.filters.inject_meta_charset
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`lint` Module
+------------------
+
+.. automodule:: html5lib.filters.lint
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`optionaltags` Module
+--------------------------
+
+.. automodule:: html5lib.filters.optionaltags
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`sanitizer` Module
+-----------------------
+
+.. automodule:: html5lib.filters.sanitizer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`whitespace` Module
+------------------------
+
+.. automodule:: html5lib.filters.whitespace
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.rst
new file mode 100644
index 00000000000..d4ed12b4646
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.rst
@@ -0,0 +1,77 @@
+html5lib Package
+================
+
+:mod:`html5lib` Package
+-----------------------
+
+.. automodule:: html5lib.__init__
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`constants` Module
+-----------------------
+
+.. automodule:: html5lib.constants
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`html5parser` Module
+-------------------------
+
+.. automodule:: html5lib.html5parser
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`ihatexml` Module
+----------------------
+
+.. automodule:: html5lib.ihatexml
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`inputstream` Module
+-------------------------
+
+.. automodule:: html5lib.inputstream
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`sanitizer` Module
+-----------------------
+
+.. automodule:: html5lib.sanitizer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`tokenizer` Module
+-----------------------
+
+.. automodule:: html5lib.tokenizer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`utils` Module
+-------------------
+
+.. automodule:: html5lib.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+
+ html5lib.filters
+ html5lib.serializer
+ html5lib.treebuilders
+ html5lib.treewalkers
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst
new file mode 100644
index 00000000000..fa9547421b1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst
@@ -0,0 +1,19 @@
+serializer Package
+==================
+
+:mod:`serializer` Package
+-------------------------
+
+.. automodule:: html5lib.serializer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`htmlserializer` Module
+----------------------------
+
+.. automodule:: html5lib.serializer.htmlserializer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst
new file mode 100644
index 00000000000..9911983948d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst
@@ -0,0 +1,43 @@
+treebuilders Package
+====================
+
+:mod:`treebuilders` Package
+---------------------------
+
+.. automodule:: html5lib.treebuilders
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`_base` Module
+-------------------
+
+.. automodule:: html5lib.treebuilders._base
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`dom` Module
+-----------------
+
+.. automodule:: html5lib.treebuilders.dom
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`etree` Module
+-------------------
+
+.. automodule:: html5lib.treebuilders.etree
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`etree_lxml` Module
+------------------------
+
+.. automodule:: html5lib.treebuilders.etree_lxml
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst
new file mode 100644
index 00000000000..80595e2d7d0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst
@@ -0,0 +1,59 @@
+treewalkers Package
+===================
+
+:mod:`treewalkers` Package
+--------------------------
+
+.. automodule:: html5lib.treewalkers
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`_base` Module
+-------------------
+
+.. automodule:: html5lib.treewalkers._base
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`dom` Module
+-----------------
+
+.. automodule:: html5lib.treewalkers.dom
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`etree` Module
+-------------------
+
+.. automodule:: html5lib.treewalkers.etree
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`genshistream` Module
+--------------------------
+
+.. automodule:: html5lib.treewalkers.genshistream
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`lxmletree` Module
+-----------------------
+
+.. automodule:: html5lib.treewalkers.lxmletree
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`pulldom` Module
+---------------------
+
+.. automodule:: html5lib.treewalkers.pulldom
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/index.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/index.rst
new file mode 100644
index 00000000000..ca2e1b969cd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/index.rst
@@ -0,0 +1,21 @@
+Overview
+========
+
+.. include:: ../README.rst
+ :start-line: 6
+
+.. toctree::
+ :maxdepth: 2
+
+ movingparts
+ changes
+ License <license>
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/license.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/license.rst
new file mode 100644
index 00000000000..7e6291f3b9b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/license.rst
@@ -0,0 +1,4 @@
+License
+=======
+
+.. include:: ../LICENSE
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/make.bat b/chromium/third_party/catapult/third_party/html5lib-python/doc/make.bat
new file mode 100644
index 00000000000..1df9d1811f6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/make.bat
@@ -0,0 +1,242 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\html5lib.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\html5lib.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+:end
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/modules.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/modules.rst
new file mode 100644
index 00000000000..59fbcc86bc1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/modules.rst
@@ -0,0 +1,7 @@
+html5lib
+========
+
+.. toctree::
+ :maxdepth: 4
+
+ html5lib
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/doc/movingparts.rst b/chromium/third_party/catapult/third_party/html5lib-python/doc/movingparts.rst
new file mode 100644
index 00000000000..36539785a7e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/doc/movingparts.rst
@@ -0,0 +1,209 @@
+The moving parts
+================
+
+html5lib consists of a number of components, which are responsible for
+handling its features.
+
+
+Tree builders
+-------------
+
+The parser reads HTML by tokenizing the content and building a tree that
+the user can later access. There are three main types of trees that
+html5lib can build:
+
+* ``etree`` - this is the default; builds a tree based on ``xml.etree``,
+ which can be found in the standard library. Whenever possible, the
+ accelerated ``ElementTree`` implementation (i.e.
+ ``xml.etree.cElementTree`` on Python 2.x) is used.
+
+* ``dom`` - builds a tree based on ``xml.dom.minidom``.
+
+* ``lxml.etree`` - uses lxml's implementation of the ``ElementTree``
+ API. The performance gains are relatively small compared to using the
+ accelerated ``ElementTree`` module.
+
+You can specify the builder by name when using the shorthand API:
+
+.. code-block:: python
+
+ import html5lib
+ with open("mydocument.html", "rb") as f:
+ lxml_etree_document = html5lib.parse(f, treebuilder="lxml")
+
+When instantiating a parser object, you have to pass a tree builder
+class in the ``tree`` keyword attribute:
+
+.. code-block:: python
+
+ import html5lib
+ parser = html5lib.HTMLParser(tree=SomeTreeBuilder)
+ document = parser.parse("<p>Hello World!")
+
+To get a builder class by name, use the ``getTreeBuilder`` function:
+
+.. code-block:: python
+
+ import html5lib
+ parser = html5lib.HTMLParser(tree=html5lib.getTreeBuilder("dom"))
+ minidom_document = parser.parse("<p>Hello World!")
+
+The implementation of builders can be found in `html5lib/treebuilders/
+<https://github.com/html5lib/html5lib-python/tree/master/html5lib/treebuilders>`_.
+
+
+Tree walkers
+------------
+
+Once a tree is ready, you can work on it either manually, or using
+a tree walker, which provides a streaming view of the tree. html5lib
+provides walkers for all three supported types of trees (``etree``,
+``dom`` and ``lxml``).
+
+The implementation of walkers can be found in `html5lib/treewalkers/
+<https://github.com/html5lib/html5lib-python/tree/master/html5lib/treewalkers>`_.
+
+Walkers make consuming HTML easier. html5lib uses them to provide you
+with has a couple of handy tools.
+
+
+HTMLSerializer
+~~~~~~~~~~~~~~
+
+The serializer lets you write HTML back as a stream of bytes.
+
+.. code-block:: pycon
+
+ >>> import html5lib
+ >>> element = html5lib.parse('<p xml:lang="pl">Witam wszystkich')
+ >>> walker = html5lib.getTreeWalker("etree")
+ >>> stream = walker(element)
+ >>> s = html5lib.serializer.HTMLSerializer()
+ >>> output = s.serialize(stream)
+ >>> for item in output:
+ ... print("%r" % item)
+ '<p'
+ ' '
+ 'xml:lang'
+ '='
+ 'pl'
+ '>'
+ 'Witam wszystkich'
+
+You can customize the serializer behaviour in a variety of ways, consult
+the :class:`~html5lib.serializer.htmlserializer.HTMLSerializer`
+documentation.
+
+
+Filters
+~~~~~~~
+
+You can alter the stream content with filters provided by html5lib:
+
+* :class:`alphabeticalattributes.Filter
+ <html5lib.filters.alphabeticalattributes.Filter>` sorts attributes on
+ tags to be in alphabetical order
+
+* :class:`inject_meta_charset.Filter
+ <html5lib.filters.inject_meta_charset.Filter>` sets a user-specified
+ encoding in the correct ``<meta>`` tag in the ``<head>`` section of
+ the document
+
+* :class:`lint.Filter <html5lib.filters.lint.Filter>` raises
+ ``LintError`` exceptions on invalid tag and attribute names, invalid
+ PCDATA, etc.
+
+* :class:`optionaltags.Filter <html5lib.filters.optionaltags.Filter>`
+ removes tags from the stream which are not necessary to produce valid
+ HTML
+
+* :class:`sanitizer.Filter <html5lib.filters.sanitizer.Filter>` removes
+ unsafe markup and CSS. Elements that are known to be safe are passed
+ through and the rest is converted to visible text. The default
+ configuration of the sanitizer follows the `WHATWG Sanitization Rules
+ <http://wiki.whatwg.org/wiki/Sanitization_rules>`_.
+
+* :class:`whitespace.Filter <html5lib.filters.whitespace.Filter>`
+ collapses all whitespace characters to single spaces unless they're in
+ ``<pre/>`` or ``textarea`` tags.
+
+To use a filter, simply wrap it around a stream:
+
+.. code-block:: python
+
+ >>> import html5lib
+ >>> from html5lib.filters import sanitizer
+ >>> dom = html5lib.parse("<p><script>alert('Boo!')", treebuilder="dom")
+ >>> walker = html5lib.getTreeWalker("dom")
+ >>> stream = walker(dom)
+ >>> sane_stream = sanitizer.Filter(stream) clean_stream = sanitizer.Filter(stream)
+
+
+Tree adapters
+-------------
+
+Used to translate one type of tree to another. More documentation
+pending, sorry.
+
+
+Encoding discovery
+------------------
+
+Parsed trees are always Unicode. However a large variety of input
+encodings are supported. The encoding of the document is determined in
+the following way:
+
+* The encoding may be explicitly specified by passing the name of the
+ encoding as the encoding parameter to the
+ :meth:`~html5lib.html5parser.HTMLParser.parse` method on
+ ``HTMLParser`` objects.
+
+* If no encoding is specified, the parser will attempt to detect the
+ encoding from a ``<meta>`` element in the first 512 bytes of the
+ document (this is only a partial implementation of the current HTML
+ 5 specification).
+
+* If no encoding can be found and the chardet library is available, an
+ attempt will be made to sniff the encoding from the byte pattern.
+
+* If all else fails, the default encoding will be used. This is usually
+ `Windows-1252 <http://en.wikipedia.org/wiki/Windows-1252>`_, which is
+ a common fallback used by Web browsers.
+
+
+Tokenizers
+----------
+
+The part of the parser responsible for translating a raw input stream
+into meaningful tokens is the tokenizer. Currently html5lib provides
+two.
+
+To set up a tokenizer, simply pass it when instantiating
+a :class:`~html5lib.html5parser.HTMLParser`:
+
+.. code-block:: python
+
+ import html5lib
+ from html5lib import sanitizer
+
+ p = html5lib.HTMLParser(tokenizer=sanitizer.HTMLSanitizer)
+ p.parse("<p>Surprise!<script>alert('Boo!');</script>")
+
+HTMLTokenizer
+~~~~~~~~~~~~~
+
+This is the default tokenizer, the heart of html5lib. The implementation
+can be found in `html5lib/tokenizer.py
+<https://github.com/html5lib/html5lib-python/blob/master/html5lib/tokenizer.py>`_.
+
+HTMLSanitizer
+~~~~~~~~~~~~~
+
+This is a tokenizer that removes unsafe markup and CSS styles from the
+input. Elements that are known to be safe are passed through and the
+rest is converted to visible text. The default configuration of the
+sanitizer follows the `WHATWG Sanitization Rules
+<http://wiki.whatwg.org/wiki/Sanitization_rules>`_.
+
+The implementation can be found in `html5lib/sanitizer.py
+<https://github.com/html5lib/html5lib-python/blob/master/html5lib/sanitizer.py>`_.
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/flake8-run.sh b/chromium/third_party/catapult/third_party/html5lib-python/flake8-run.sh
new file mode 100755
index 00000000000..d1a587d3506
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/flake8-run.sh
@@ -0,0 +1,14 @@
+#!/bin/bash -e
+
+if [[ ! -x $(which flake8) ]]; then
+ echo "fatal: flake8 not found on $PATH. Exiting."
+ exit 1
+fi
+
+if [[ $TRAVIS != "true" || $FLAKE == "true" ]]; then
+ find html5lib/ -name '*.py' -and -not -name 'constants.py' -print0 | xargs -0 flake8 --ignore=E501
+ flake1=$?
+ flake8 --max-line-length=99 --ignore=E126 html5lib/constants.py
+ flake2=$?
+ exit $[$flake1 || $flake2]
+fi
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/__init__.py
new file mode 100644
index 00000000000..3765c676149
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/__init__.py
@@ -0,0 +1,25 @@
+"""
+HTML parsing library based on the WHATWG "HTML5"
+specification. The parser is designed to be compatible with existing
+HTML found in the wild and implements well-defined error recovery that
+is largely compatible with modern desktop web browsers.
+
+Example usage:
+
+import html5lib
+f = open("my_document.html")
+tree = html5lib.parse(f)
+"""
+
+from __future__ import absolute_import, division, unicode_literals
+
+from .html5parser import HTMLParser, parse, parseFragment
+from .treebuilders import getTreeBuilder
+from .treewalkers import getTreeWalker
+from .serializer import serialize
+
+__all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder",
+ "getTreeWalker", "serialize"]
+
+# this has to be at the top level, see how setup.py parses this
+__version__ = "0.9999999-dev"
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/constants.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/constants.py
new file mode 100644
index 00000000000..d938e0ae666
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/constants.py
@@ -0,0 +1,3102 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import string
+
+EOF = None
+
+E = {
+ "null-character":
+ "Null character in input stream, replaced with U+FFFD.",
+ "invalid-codepoint":
+ "Invalid codepoint in stream.",
+ "incorrectly-placed-solidus":
+ "Solidus (/) incorrectly placed in tag.",
+ "incorrect-cr-newline-entity":
+ "Incorrect CR newline entity, replaced with LF.",
+ "illegal-windows-1252-entity":
+ "Entity used with illegal number (windows-1252 reference).",
+ "cant-convert-numeric-entity":
+ "Numeric entity couldn't be converted to character "
+ "(codepoint U+%(charAsInt)08x).",
+ "illegal-codepoint-for-numeric-entity":
+ "Numeric entity represents an illegal codepoint: "
+ "U+%(charAsInt)08x.",
+ "numeric-entity-without-semicolon":
+ "Numeric entity didn't end with ';'.",
+ "expected-numeric-entity-but-got-eof":
+ "Numeric entity expected. Got end of file instead.",
+ "expected-numeric-entity":
+ "Numeric entity expected but none found.",
+ "named-entity-without-semicolon":
+ "Named entity didn't end with ';'.",
+ "expected-named-entity":
+ "Named entity expected. Got none.",
+ "attributes-in-end-tag":
+ "End tag contains unexpected attributes.",
+ 'self-closing-flag-on-end-tag':
+ "End tag contains unexpected self-closing flag.",
+ "expected-tag-name-but-got-right-bracket":
+ "Expected tag name. Got '>' instead.",
+ "expected-tag-name-but-got-question-mark":
+ "Expected tag name. Got '?' instead. (HTML doesn't "
+ "support processing instructions.)",
+ "expected-tag-name":
+ "Expected tag name. Got something else instead",
+ "expected-closing-tag-but-got-right-bracket":
+ "Expected closing tag. Got '>' instead. Ignoring '</>'.",
+ "expected-closing-tag-but-got-eof":
+ "Expected closing tag. Unexpected end of file.",
+ "expected-closing-tag-but-got-char":
+ "Expected closing tag. Unexpected character '%(data)s' found.",
+ "eof-in-tag-name":
+ "Unexpected end of file in the tag name.",
+ "expected-attribute-name-but-got-eof":
+ "Unexpected end of file. Expected attribute name instead.",
+ "eof-in-attribute-name":
+ "Unexpected end of file in attribute name.",
+ "invalid-character-in-attribute-name":
+ "Invalid character in attribute name",
+ "duplicate-attribute":
+ "Dropped duplicate attribute on tag.",
+ "expected-end-of-tag-name-but-got-eof":
+ "Unexpected end of file. Expected = or end of tag.",
+ "expected-attribute-value-but-got-eof":
+ "Unexpected end of file. Expected attribute value.",
+ "expected-attribute-value-but-got-right-bracket":
+ "Expected attribute value. Got '>' instead.",
+ 'equals-in-unquoted-attribute-value':
+ "Unexpected = in unquoted attribute",
+ 'unexpected-character-in-unquoted-attribute-value':
+ "Unexpected character in unquoted attribute",
+ "invalid-character-after-attribute-name":
+ "Unexpected character after attribute name.",
+ "unexpected-character-after-attribute-value":
+ "Unexpected character after attribute value.",
+ "eof-in-attribute-value-double-quote":
+ "Unexpected end of file in attribute value (\").",
+ "eof-in-attribute-value-single-quote":
+ "Unexpected end of file in attribute value (').",
+ "eof-in-attribute-value-no-quotes":
+ "Unexpected end of file in attribute value.",
+ "unexpected-EOF-after-solidus-in-tag":
+ "Unexpected end of file in tag. Expected >",
+ "unexpected-character-after-solidus-in-tag":
+ "Unexpected character after / in tag. Expected >",
+ "expected-dashes-or-doctype":
+ "Expected '--' or 'DOCTYPE'. Not found.",
+ "unexpected-bang-after-double-dash-in-comment":
+ "Unexpected ! after -- in comment",
+ "unexpected-space-after-double-dash-in-comment":
+ "Unexpected space after -- in comment",
+ "incorrect-comment":
+ "Incorrect comment.",
+ "eof-in-comment":
+ "Unexpected end of file in comment.",
+ "eof-in-comment-end-dash":
+ "Unexpected end of file in comment (-)",
+ "unexpected-dash-after-double-dash-in-comment":
+ "Unexpected '-' after '--' found in comment.",
+ "eof-in-comment-double-dash":
+ "Unexpected end of file in comment (--).",
+ "eof-in-comment-end-space-state":
+ "Unexpected end of file in comment.",
+ "eof-in-comment-end-bang-state":
+ "Unexpected end of file in comment.",
+ "unexpected-char-in-comment":
+ "Unexpected character in comment found.",
+ "need-space-after-doctype":
+ "No space after literal string 'DOCTYPE'.",
+ "expected-doctype-name-but-got-right-bracket":
+ "Unexpected > character. Expected DOCTYPE name.",
+ "expected-doctype-name-but-got-eof":
+ "Unexpected end of file. Expected DOCTYPE name.",
+ "eof-in-doctype-name":
+ "Unexpected end of file in DOCTYPE name.",
+ "eof-in-doctype":
+ "Unexpected end of file in DOCTYPE.",
+ "expected-space-or-right-bracket-in-doctype":
+ "Expected space or '>'. Got '%(data)s'",
+ "unexpected-end-of-doctype":
+ "Unexpected end of DOCTYPE.",
+ "unexpected-char-in-doctype":
+ "Unexpected character in DOCTYPE.",
+ "eof-in-innerhtml":
+ "XXX innerHTML EOF",
+ "unexpected-doctype":
+ "Unexpected DOCTYPE. Ignored.",
+ "non-html-root":
+ "html needs to be the first start tag.",
+ "expected-doctype-but-got-eof":
+ "Unexpected End of file. Expected DOCTYPE.",
+ "unknown-doctype":
+ "Erroneous DOCTYPE.",
+ "expected-doctype-but-got-chars":
+ "Unexpected non-space characters. Expected DOCTYPE.",
+ "expected-doctype-but-got-start-tag":
+ "Unexpected start tag (%(name)s). Expected DOCTYPE.",
+ "expected-doctype-but-got-end-tag":
+ "Unexpected end tag (%(name)s). Expected DOCTYPE.",
+ "end-tag-after-implied-root":
+ "Unexpected end tag (%(name)s) after the (implied) root element.",
+ "expected-named-closing-tag-but-got-eof":
+ "Unexpected end of file. Expected end tag (%(name)s).",
+ "two-heads-are-not-better-than-one":
+ "Unexpected start tag head in existing head. Ignored.",
+ "unexpected-end-tag":
+ "Unexpected end tag (%(name)s). Ignored.",
+ "unexpected-start-tag-out-of-my-head":
+ "Unexpected start tag (%(name)s) that can be in head. Moved.",
+ "unexpected-start-tag":
+ "Unexpected start tag (%(name)s).",
+ "missing-end-tag":
+ "Missing end tag (%(name)s).",
+ "missing-end-tags":
+ "Missing end tags (%(name)s).",
+ "unexpected-start-tag-implies-end-tag":
+ "Unexpected start tag (%(startName)s) "
+ "implies end tag (%(endName)s).",
+ "unexpected-start-tag-treated-as":
+ "Unexpected start tag (%(originalName)s). Treated as %(newName)s.",
+ "deprecated-tag":
+ "Unexpected start tag %(name)s. Don't use it!",
+ "unexpected-start-tag-ignored":
+ "Unexpected start tag %(name)s. Ignored.",
+ "expected-one-end-tag-but-got-another":
+ "Unexpected end tag (%(gotName)s). "
+ "Missing end tag (%(expectedName)s).",
+ "end-tag-too-early":
+ "End tag (%(name)s) seen too early. Expected other end tag.",
+ "end-tag-too-early-named":
+ "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).",
+ "end-tag-too-early-ignored":
+ "End tag (%(name)s) seen too early. Ignored.",
+ "adoption-agency-1.1":
+ "End tag (%(name)s) violates step 1, "
+ "paragraph 1 of the adoption agency algorithm.",
+ "adoption-agency-1.2":
+ "End tag (%(name)s) violates step 1, "
+ "paragraph 2 of the adoption agency algorithm.",
+ "adoption-agency-1.3":
+ "End tag (%(name)s) violates step 1, "
+ "paragraph 3 of the adoption agency algorithm.",
+ "adoption-agency-4.4":
+ "End tag (%(name)s) violates step 4, "
+ "paragraph 4 of the adoption agency algorithm.",
+ "unexpected-end-tag-treated-as":
+ "Unexpected end tag (%(originalName)s). Treated as %(newName)s.",
+ "no-end-tag":
+ "This element (%(name)s) has no end tag.",
+ "unexpected-implied-end-tag-in-table":
+ "Unexpected implied end tag (%(name)s) in the table phase.",
+ "unexpected-implied-end-tag-in-table-body":
+ "Unexpected implied end tag (%(name)s) in the table body phase.",
+ "unexpected-char-implies-table-voodoo":
+ "Unexpected non-space characters in "
+ "table context caused voodoo mode.",
+ "unexpected-hidden-input-in-table":
+ "Unexpected input with type hidden in table context.",
+ "unexpected-form-in-table":
+ "Unexpected form in table context.",
+ "unexpected-start-tag-implies-table-voodoo":
+ "Unexpected start tag (%(name)s) in "
+ "table context caused voodoo mode.",
+ "unexpected-end-tag-implies-table-voodoo":
+ "Unexpected end tag (%(name)s) in "
+ "table context caused voodoo mode.",
+ "unexpected-cell-in-table-body":
+ "Unexpected table cell start tag (%(name)s) "
+ "in the table body phase.",
+ "unexpected-cell-end-tag":
+ "Got table cell end tag (%(name)s) "
+ "while required end tags are missing.",
+ "unexpected-end-tag-in-table-body":
+ "Unexpected end tag (%(name)s) in the table body phase. Ignored.",
+ "unexpected-implied-end-tag-in-table-row":
+ "Unexpected implied end tag (%(name)s) in the table row phase.",
+ "unexpected-end-tag-in-table-row":
+ "Unexpected end tag (%(name)s) in the table row phase. Ignored.",
+ "unexpected-select-in-select":
+ "Unexpected select start tag in the select phase "
+ "treated as select end tag.",
+ "unexpected-input-in-select":
+ "Unexpected input start tag in the select phase.",
+ "unexpected-start-tag-in-select":
+ "Unexpected start tag token (%(name)s in the select phase. "
+ "Ignored.",
+ "unexpected-end-tag-in-select":
+ "Unexpected end tag (%(name)s) in the select phase. Ignored.",
+ "unexpected-table-element-start-tag-in-select-in-table":
+ "Unexpected table element start tag (%(name)s) in the select in table phase.",
+ "unexpected-table-element-end-tag-in-select-in-table":
+ "Unexpected table element end tag (%(name)s) in the select in table phase.",
+ "unexpected-char-after-body":
+ "Unexpected non-space characters in the after body phase.",
+ "unexpected-start-tag-after-body":
+ "Unexpected start tag token (%(name)s)"
+ " in the after body phase.",
+ "unexpected-end-tag-after-body":
+ "Unexpected end tag token (%(name)s)"
+ " in the after body phase.",
+ "unexpected-char-in-frameset":
+ "Unexpected characters in the frameset phase. Characters ignored.",
+ "unexpected-start-tag-in-frameset":
+ "Unexpected start tag token (%(name)s)"
+ " in the frameset phase. Ignored.",
+ "unexpected-frameset-in-frameset-innerhtml":
+ "Unexpected end tag token (frameset) "
+ "in the frameset phase (innerHTML).",
+ "unexpected-end-tag-in-frameset":
+ "Unexpected end tag token (%(name)s)"
+ " in the frameset phase. Ignored.",
+ "unexpected-char-after-frameset":
+ "Unexpected non-space characters in the "
+ "after frameset phase. Ignored.",
+ "unexpected-start-tag-after-frameset":
+ "Unexpected start tag (%(name)s)"
+ " in the after frameset phase. Ignored.",
+ "unexpected-end-tag-after-frameset":
+ "Unexpected end tag (%(name)s)"
+ " in the after frameset phase. Ignored.",
+ "unexpected-end-tag-after-body-innerhtml":
+ "Unexpected end tag after body(innerHtml)",
+ "expected-eof-but-got-char":
+ "Unexpected non-space characters. Expected end of file.",
+ "expected-eof-but-got-start-tag":
+ "Unexpected start tag (%(name)s)"
+ ". Expected end of file.",
+ "expected-eof-but-got-end-tag":
+ "Unexpected end tag (%(name)s)"
+ ". Expected end of file.",
+ "eof-in-table":
+ "Unexpected end of file. Expected table content.",
+ "eof-in-select":
+ "Unexpected end of file. Expected select content.",
+ "eof-in-frameset":
+ "Unexpected end of file. Expected frameset content.",
+ "eof-in-script-in-script":
+ "Unexpected end of file. Expected script content.",
+ "eof-in-foreign-lands":
+ "Unexpected end of file. Expected foreign content",
+ "non-void-element-with-trailing-solidus":
+ "Trailing solidus not allowed on element %(name)s",
+ "unexpected-html-element-in-foreign-content":
+ "Element %(name)s not allowed in a non-html context",
+ "unexpected-end-tag-before-html":
+ "Unexpected end tag (%(name)s) before html.",
+ "XXX-undefined-error":
+ "Undefined error (this sucks and should be fixed)",
+}
+
+namespaces = {
+ "html": "http://www.w3.org/1999/xhtml",
+ "mathml": "http://www.w3.org/1998/Math/MathML",
+ "svg": "http://www.w3.org/2000/svg",
+ "xlink": "http://www.w3.org/1999/xlink",
+ "xml": "http://www.w3.org/XML/1998/namespace",
+ "xmlns": "http://www.w3.org/2000/xmlns/"
+}
+
+scopingElements = frozenset([
+ (namespaces["html"], "applet"),
+ (namespaces["html"], "caption"),
+ (namespaces["html"], "html"),
+ (namespaces["html"], "marquee"),
+ (namespaces["html"], "object"),
+ (namespaces["html"], "table"),
+ (namespaces["html"], "td"),
+ (namespaces["html"], "th"),
+ (namespaces["mathml"], "mi"),
+ (namespaces["mathml"], "mo"),
+ (namespaces["mathml"], "mn"),
+ (namespaces["mathml"], "ms"),
+ (namespaces["mathml"], "mtext"),
+ (namespaces["mathml"], "annotation-xml"),
+ (namespaces["svg"], "foreignObject"),
+ (namespaces["svg"], "desc"),
+ (namespaces["svg"], "title"),
+])
+
+formattingElements = frozenset([
+ (namespaces["html"], "a"),
+ (namespaces["html"], "b"),
+ (namespaces["html"], "big"),
+ (namespaces["html"], "code"),
+ (namespaces["html"], "em"),
+ (namespaces["html"], "font"),
+ (namespaces["html"], "i"),
+ (namespaces["html"], "nobr"),
+ (namespaces["html"], "s"),
+ (namespaces["html"], "small"),
+ (namespaces["html"], "strike"),
+ (namespaces["html"], "strong"),
+ (namespaces["html"], "tt"),
+ (namespaces["html"], "u")
+])
+
+specialElements = frozenset([
+ (namespaces["html"], "address"),
+ (namespaces["html"], "applet"),
+ (namespaces["html"], "area"),
+ (namespaces["html"], "article"),
+ (namespaces["html"], "aside"),
+ (namespaces["html"], "base"),
+ (namespaces["html"], "basefont"),
+ (namespaces["html"], "bgsound"),
+ (namespaces["html"], "blockquote"),
+ (namespaces["html"], "body"),
+ (namespaces["html"], "br"),
+ (namespaces["html"], "button"),
+ (namespaces["html"], "caption"),
+ (namespaces["html"], "center"),
+ (namespaces["html"], "col"),
+ (namespaces["html"], "colgroup"),
+ (namespaces["html"], "command"),
+ (namespaces["html"], "dd"),
+ (namespaces["html"], "details"),
+ (namespaces["html"], "dir"),
+ (namespaces["html"], "div"),
+ (namespaces["html"], "dl"),
+ (namespaces["html"], "dt"),
+ (namespaces["html"], "embed"),
+ (namespaces["html"], "fieldset"),
+ (namespaces["html"], "figure"),
+ (namespaces["html"], "footer"),
+ (namespaces["html"], "form"),
+ (namespaces["html"], "frame"),
+ (namespaces["html"], "frameset"),
+ (namespaces["html"], "h1"),
+ (namespaces["html"], "h2"),
+ (namespaces["html"], "h3"),
+ (namespaces["html"], "h4"),
+ (namespaces["html"], "h5"),
+ (namespaces["html"], "h6"),
+ (namespaces["html"], "head"),
+ (namespaces["html"], "header"),
+ (namespaces["html"], "hr"),
+ (namespaces["html"], "html"),
+ (namespaces["html"], "iframe"),
+ # Note that image is commented out in the spec as "this isn't an
+ # element that can end up on the stack, so it doesn't matter,"
+ (namespaces["html"], "image"),
+ (namespaces["html"], "img"),
+ (namespaces["html"], "input"),
+ (namespaces["html"], "isindex"),
+ (namespaces["html"], "li"),
+ (namespaces["html"], "link"),
+ (namespaces["html"], "listing"),
+ (namespaces["html"], "marquee"),
+ (namespaces["html"], "menu"),
+ (namespaces["html"], "meta"),
+ (namespaces["html"], "nav"),
+ (namespaces["html"], "noembed"),
+ (namespaces["html"], "noframes"),
+ (namespaces["html"], "noscript"),
+ (namespaces["html"], "object"),
+ (namespaces["html"], "ol"),
+ (namespaces["html"], "p"),
+ (namespaces["html"], "param"),
+ (namespaces["html"], "plaintext"),
+ (namespaces["html"], "pre"),
+ (namespaces["html"], "script"),
+ (namespaces["html"], "section"),
+ (namespaces["html"], "select"),
+ (namespaces["html"], "style"),
+ (namespaces["html"], "table"),
+ (namespaces["html"], "tbody"),
+ (namespaces["html"], "td"),
+ (namespaces["html"], "textarea"),
+ (namespaces["html"], "tfoot"),
+ (namespaces["html"], "th"),
+ (namespaces["html"], "thead"),
+ (namespaces["html"], "title"),
+ (namespaces["html"], "tr"),
+ (namespaces["html"], "ul"),
+ (namespaces["html"], "wbr"),
+ (namespaces["html"], "xmp"),
+ (namespaces["svg"], "foreignObject")
+])
+
+htmlIntegrationPointElements = frozenset([
+ (namespaces["mathml"], "annotaion-xml"),
+ (namespaces["svg"], "foreignObject"),
+ (namespaces["svg"], "desc"),
+ (namespaces["svg"], "title")
+])
+
+mathmlTextIntegrationPointElements = frozenset([
+ (namespaces["mathml"], "mi"),
+ (namespaces["mathml"], "mo"),
+ (namespaces["mathml"], "mn"),
+ (namespaces["mathml"], "ms"),
+ (namespaces["mathml"], "mtext")
+])
+
+adjustForeignAttributes = {
+ "xlink:actuate": ("xlink", "actuate", namespaces["xlink"]),
+ "xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]),
+ "xlink:href": ("xlink", "href", namespaces["xlink"]),
+ "xlink:role": ("xlink", "role", namespaces["xlink"]),
+ "xlink:show": ("xlink", "show", namespaces["xlink"]),
+ "xlink:title": ("xlink", "title", namespaces["xlink"]),
+ "xlink:type": ("xlink", "type", namespaces["xlink"]),
+ "xml:base": ("xml", "base", namespaces["xml"]),
+ "xml:lang": ("xml", "lang", namespaces["xml"]),
+ "xml:space": ("xml", "space", namespaces["xml"]),
+ "xmlns": (None, "xmlns", namespaces["xmlns"]),
+ "xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"])
+}
+
+unadjustForeignAttributes = dict([((ns, local), qname) for qname, (prefix, local, ns) in
+ adjustForeignAttributes.items()])
+
+spaceCharacters = frozenset([
+ "\t",
+ "\n",
+ "\u000C",
+ " ",
+ "\r"
+])
+
+tableInsertModeElements = frozenset([
+ "table",
+ "tbody",
+ "tfoot",
+ "thead",
+ "tr"
+])
+
+asciiLowercase = frozenset(string.ascii_lowercase)
+asciiUppercase = frozenset(string.ascii_uppercase)
+asciiLetters = frozenset(string.ascii_letters)
+digits = frozenset(string.digits)
+hexDigits = frozenset(string.hexdigits)
+
+asciiUpper2Lower = dict([(ord(c), ord(c.lower()))
+ for c in string.ascii_uppercase])
+
+# Heading elements need to be ordered
+headingElements = (
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6"
+)
+
+voidElements = frozenset([
+ "base",
+ "command",
+ "event-source",
+ "link",
+ "meta",
+ "hr",
+ "br",
+ "img",
+ "embed",
+ "param",
+ "area",
+ "col",
+ "input",
+ "source",
+ "track"
+])
+
+cdataElements = frozenset(['title', 'textarea'])
+
+rcdataElements = frozenset([
+ 'style',
+ 'script',
+ 'xmp',
+ 'iframe',
+ 'noembed',
+ 'noframes',
+ 'noscript'
+])
+
+booleanAttributes = {
+ "": frozenset(["irrelevant"]),
+ "style": frozenset(["scoped"]),
+ "img": frozenset(["ismap"]),
+ "audio": frozenset(["autoplay", "controls"]),
+ "video": frozenset(["autoplay", "controls"]),
+ "script": frozenset(["defer", "async"]),
+ "details": frozenset(["open"]),
+ "datagrid": frozenset(["multiple", "disabled"]),
+ "command": frozenset(["hidden", "disabled", "checked", "default"]),
+ "hr": frozenset(["noshade"]),
+ "menu": frozenset(["autosubmit"]),
+ "fieldset": frozenset(["disabled", "readonly"]),
+ "option": frozenset(["disabled", "readonly", "selected"]),
+ "optgroup": frozenset(["disabled", "readonly"]),
+ "button": frozenset(["disabled", "autofocus"]),
+ "input": frozenset(["disabled", "readonly", "required", "autofocus", "checked", "ismap"]),
+ "select": frozenset(["disabled", "readonly", "autofocus", "multiple"]),
+ "output": frozenset(["disabled", "readonly"]),
+}
+
+# entitiesWindows1252 has to be _ordered_ and needs to have an index. It
+# therefore can't be a frozenset.
+entitiesWindows1252 = (
+ 8364, # 0x80 0x20AC EURO SIGN
+ 65533, # 0x81 UNDEFINED
+ 8218, # 0x82 0x201A SINGLE LOW-9 QUOTATION MARK
+ 402, # 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK
+ 8222, # 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK
+ 8230, # 0x85 0x2026 HORIZONTAL ELLIPSIS
+ 8224, # 0x86 0x2020 DAGGER
+ 8225, # 0x87 0x2021 DOUBLE DAGGER
+ 710, # 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT
+ 8240, # 0x89 0x2030 PER MILLE SIGN
+ 352, # 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON
+ 8249, # 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 338, # 0x8C 0x0152 LATIN CAPITAL LIGATURE OE
+ 65533, # 0x8D UNDEFINED
+ 381, # 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON
+ 65533, # 0x8F UNDEFINED
+ 65533, # 0x90 UNDEFINED
+ 8216, # 0x91 0x2018 LEFT SINGLE QUOTATION MARK
+ 8217, # 0x92 0x2019 RIGHT SINGLE QUOTATION MARK
+ 8220, # 0x93 0x201C LEFT DOUBLE QUOTATION MARK
+ 8221, # 0x94 0x201D RIGHT DOUBLE QUOTATION MARK
+ 8226, # 0x95 0x2022 BULLET
+ 8211, # 0x96 0x2013 EN DASH
+ 8212, # 0x97 0x2014 EM DASH
+ 732, # 0x98 0x02DC SMALL TILDE
+ 8482, # 0x99 0x2122 TRADE MARK SIGN
+ 353, # 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON
+ 8250, # 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 339, # 0x9C 0x0153 LATIN SMALL LIGATURE OE
+ 65533, # 0x9D UNDEFINED
+ 382, # 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON
+ 376 # 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS
+)
+
+xmlEntities = frozenset(['lt;', 'gt;', 'amp;', 'apos;', 'quot;'])
+
+entities = {
+ "AElig": "\xc6",
+ "AElig;": "\xc6",
+ "AMP": "&",
+ "AMP;": "&",
+ "Aacute": "\xc1",
+ "Aacute;": "\xc1",
+ "Abreve;": "\u0102",
+ "Acirc": "\xc2",
+ "Acirc;": "\xc2",
+ "Acy;": "\u0410",
+ "Afr;": "\U0001d504",
+ "Agrave": "\xc0",
+ "Agrave;": "\xc0",
+ "Alpha;": "\u0391",
+ "Amacr;": "\u0100",
+ "And;": "\u2a53",
+ "Aogon;": "\u0104",
+ "Aopf;": "\U0001d538",
+ "ApplyFunction;": "\u2061",
+ "Aring": "\xc5",
+ "Aring;": "\xc5",
+ "Ascr;": "\U0001d49c",
+ "Assign;": "\u2254",
+ "Atilde": "\xc3",
+ "Atilde;": "\xc3",
+ "Auml": "\xc4",
+ "Auml;": "\xc4",
+ "Backslash;": "\u2216",
+ "Barv;": "\u2ae7",
+ "Barwed;": "\u2306",
+ "Bcy;": "\u0411",
+ "Because;": "\u2235",
+ "Bernoullis;": "\u212c",
+ "Beta;": "\u0392",
+ "Bfr;": "\U0001d505",
+ "Bopf;": "\U0001d539",
+ "Breve;": "\u02d8",
+ "Bscr;": "\u212c",
+ "Bumpeq;": "\u224e",
+ "CHcy;": "\u0427",
+ "COPY": "\xa9",
+ "COPY;": "\xa9",
+ "Cacute;": "\u0106",
+ "Cap;": "\u22d2",
+ "CapitalDifferentialD;": "\u2145",
+ "Cayleys;": "\u212d",
+ "Ccaron;": "\u010c",
+ "Ccedil": "\xc7",
+ "Ccedil;": "\xc7",
+ "Ccirc;": "\u0108",
+ "Cconint;": "\u2230",
+ "Cdot;": "\u010a",
+ "Cedilla;": "\xb8",
+ "CenterDot;": "\xb7",
+ "Cfr;": "\u212d",
+ "Chi;": "\u03a7",
+ "CircleDot;": "\u2299",
+ "CircleMinus;": "\u2296",
+ "CirclePlus;": "\u2295",
+ "CircleTimes;": "\u2297",
+ "ClockwiseContourIntegral;": "\u2232",
+ "CloseCurlyDoubleQuote;": "\u201d",
+ "CloseCurlyQuote;": "\u2019",
+ "Colon;": "\u2237",
+ "Colone;": "\u2a74",
+ "Congruent;": "\u2261",
+ "Conint;": "\u222f",
+ "ContourIntegral;": "\u222e",
+ "Copf;": "\u2102",
+ "Coproduct;": "\u2210",
+ "CounterClockwiseContourIntegral;": "\u2233",
+ "Cross;": "\u2a2f",
+ "Cscr;": "\U0001d49e",
+ "Cup;": "\u22d3",
+ "CupCap;": "\u224d",
+ "DD;": "\u2145",
+ "DDotrahd;": "\u2911",
+ "DJcy;": "\u0402",
+ "DScy;": "\u0405",
+ "DZcy;": "\u040f",
+ "Dagger;": "\u2021",
+ "Darr;": "\u21a1",
+ "Dashv;": "\u2ae4",
+ "Dcaron;": "\u010e",
+ "Dcy;": "\u0414",
+ "Del;": "\u2207",
+ "Delta;": "\u0394",
+ "Dfr;": "\U0001d507",
+ "DiacriticalAcute;": "\xb4",
+ "DiacriticalDot;": "\u02d9",
+ "DiacriticalDoubleAcute;": "\u02dd",
+ "DiacriticalGrave;": "`",
+ "DiacriticalTilde;": "\u02dc",
+ "Diamond;": "\u22c4",
+ "DifferentialD;": "\u2146",
+ "Dopf;": "\U0001d53b",
+ "Dot;": "\xa8",
+ "DotDot;": "\u20dc",
+ "DotEqual;": "\u2250",
+ "DoubleContourIntegral;": "\u222f",
+ "DoubleDot;": "\xa8",
+ "DoubleDownArrow;": "\u21d3",
+ "DoubleLeftArrow;": "\u21d0",
+ "DoubleLeftRightArrow;": "\u21d4",
+ "DoubleLeftTee;": "\u2ae4",
+ "DoubleLongLeftArrow;": "\u27f8",
+ "DoubleLongLeftRightArrow;": "\u27fa",
+ "DoubleLongRightArrow;": "\u27f9",
+ "DoubleRightArrow;": "\u21d2",
+ "DoubleRightTee;": "\u22a8",
+ "DoubleUpArrow;": "\u21d1",
+ "DoubleUpDownArrow;": "\u21d5",
+ "DoubleVerticalBar;": "\u2225",
+ "DownArrow;": "\u2193",
+ "DownArrowBar;": "\u2913",
+ "DownArrowUpArrow;": "\u21f5",
+ "DownBreve;": "\u0311",
+ "DownLeftRightVector;": "\u2950",
+ "DownLeftTeeVector;": "\u295e",
+ "DownLeftVector;": "\u21bd",
+ "DownLeftVectorBar;": "\u2956",
+ "DownRightTeeVector;": "\u295f",
+ "DownRightVector;": "\u21c1",
+ "DownRightVectorBar;": "\u2957",
+ "DownTee;": "\u22a4",
+ "DownTeeArrow;": "\u21a7",
+ "Downarrow;": "\u21d3",
+ "Dscr;": "\U0001d49f",
+ "Dstrok;": "\u0110",
+ "ENG;": "\u014a",
+ "ETH": "\xd0",
+ "ETH;": "\xd0",
+ "Eacute": "\xc9",
+ "Eacute;": "\xc9",
+ "Ecaron;": "\u011a",
+ "Ecirc": "\xca",
+ "Ecirc;": "\xca",
+ "Ecy;": "\u042d",
+ "Edot;": "\u0116",
+ "Efr;": "\U0001d508",
+ "Egrave": "\xc8",
+ "Egrave;": "\xc8",
+ "Element;": "\u2208",
+ "Emacr;": "\u0112",
+ "EmptySmallSquare;": "\u25fb",
+ "EmptyVerySmallSquare;": "\u25ab",
+ "Eogon;": "\u0118",
+ "Eopf;": "\U0001d53c",
+ "Epsilon;": "\u0395",
+ "Equal;": "\u2a75",
+ "EqualTilde;": "\u2242",
+ "Equilibrium;": "\u21cc",
+ "Escr;": "\u2130",
+ "Esim;": "\u2a73",
+ "Eta;": "\u0397",
+ "Euml": "\xcb",
+ "Euml;": "\xcb",
+ "Exists;": "\u2203",
+ "ExponentialE;": "\u2147",
+ "Fcy;": "\u0424",
+ "Ffr;": "\U0001d509",
+ "FilledSmallSquare;": "\u25fc",
+ "FilledVerySmallSquare;": "\u25aa",
+ "Fopf;": "\U0001d53d",
+ "ForAll;": "\u2200",
+ "Fouriertrf;": "\u2131",
+ "Fscr;": "\u2131",
+ "GJcy;": "\u0403",
+ "GT": ">",
+ "GT;": ">",
+ "Gamma;": "\u0393",
+ "Gammad;": "\u03dc",
+ "Gbreve;": "\u011e",
+ "Gcedil;": "\u0122",
+ "Gcirc;": "\u011c",
+ "Gcy;": "\u0413",
+ "Gdot;": "\u0120",
+ "Gfr;": "\U0001d50a",
+ "Gg;": "\u22d9",
+ "Gopf;": "\U0001d53e",
+ "GreaterEqual;": "\u2265",
+ "GreaterEqualLess;": "\u22db",
+ "GreaterFullEqual;": "\u2267",
+ "GreaterGreater;": "\u2aa2",
+ "GreaterLess;": "\u2277",
+ "GreaterSlantEqual;": "\u2a7e",
+ "GreaterTilde;": "\u2273",
+ "Gscr;": "\U0001d4a2",
+ "Gt;": "\u226b",
+ "HARDcy;": "\u042a",
+ "Hacek;": "\u02c7",
+ "Hat;": "^",
+ "Hcirc;": "\u0124",
+ "Hfr;": "\u210c",
+ "HilbertSpace;": "\u210b",
+ "Hopf;": "\u210d",
+ "HorizontalLine;": "\u2500",
+ "Hscr;": "\u210b",
+ "Hstrok;": "\u0126",
+ "HumpDownHump;": "\u224e",
+ "HumpEqual;": "\u224f",
+ "IEcy;": "\u0415",
+ "IJlig;": "\u0132",
+ "IOcy;": "\u0401",
+ "Iacute": "\xcd",
+ "Iacute;": "\xcd",
+ "Icirc": "\xce",
+ "Icirc;": "\xce",
+ "Icy;": "\u0418",
+ "Idot;": "\u0130",
+ "Ifr;": "\u2111",
+ "Igrave": "\xcc",
+ "Igrave;": "\xcc",
+ "Im;": "\u2111",
+ "Imacr;": "\u012a",
+ "ImaginaryI;": "\u2148",
+ "Implies;": "\u21d2",
+ "Int;": "\u222c",
+ "Integral;": "\u222b",
+ "Intersection;": "\u22c2",
+ "InvisibleComma;": "\u2063",
+ "InvisibleTimes;": "\u2062",
+ "Iogon;": "\u012e",
+ "Iopf;": "\U0001d540",
+ "Iota;": "\u0399",
+ "Iscr;": "\u2110",
+ "Itilde;": "\u0128",
+ "Iukcy;": "\u0406",
+ "Iuml": "\xcf",
+ "Iuml;": "\xcf",
+ "Jcirc;": "\u0134",
+ "Jcy;": "\u0419",
+ "Jfr;": "\U0001d50d",
+ "Jopf;": "\U0001d541",
+ "Jscr;": "\U0001d4a5",
+ "Jsercy;": "\u0408",
+ "Jukcy;": "\u0404",
+ "KHcy;": "\u0425",
+ "KJcy;": "\u040c",
+ "Kappa;": "\u039a",
+ "Kcedil;": "\u0136",
+ "Kcy;": "\u041a",
+ "Kfr;": "\U0001d50e",
+ "Kopf;": "\U0001d542",
+ "Kscr;": "\U0001d4a6",
+ "LJcy;": "\u0409",
+ "LT": "<",
+ "LT;": "<",
+ "Lacute;": "\u0139",
+ "Lambda;": "\u039b",
+ "Lang;": "\u27ea",
+ "Laplacetrf;": "\u2112",
+ "Larr;": "\u219e",
+ "Lcaron;": "\u013d",
+ "Lcedil;": "\u013b",
+ "Lcy;": "\u041b",
+ "LeftAngleBracket;": "\u27e8",
+ "LeftArrow;": "\u2190",
+ "LeftArrowBar;": "\u21e4",
+ "LeftArrowRightArrow;": "\u21c6",
+ "LeftCeiling;": "\u2308",
+ "LeftDoubleBracket;": "\u27e6",
+ "LeftDownTeeVector;": "\u2961",
+ "LeftDownVector;": "\u21c3",
+ "LeftDownVectorBar;": "\u2959",
+ "LeftFloor;": "\u230a",
+ "LeftRightArrow;": "\u2194",
+ "LeftRightVector;": "\u294e",
+ "LeftTee;": "\u22a3",
+ "LeftTeeArrow;": "\u21a4",
+ "LeftTeeVector;": "\u295a",
+ "LeftTriangle;": "\u22b2",
+ "LeftTriangleBar;": "\u29cf",
+ "LeftTriangleEqual;": "\u22b4",
+ "LeftUpDownVector;": "\u2951",
+ "LeftUpTeeVector;": "\u2960",
+ "LeftUpVector;": "\u21bf",
+ "LeftUpVectorBar;": "\u2958",
+ "LeftVector;": "\u21bc",
+ "LeftVectorBar;": "\u2952",
+ "Leftarrow;": "\u21d0",
+ "Leftrightarrow;": "\u21d4",
+ "LessEqualGreater;": "\u22da",
+ "LessFullEqual;": "\u2266",
+ "LessGreater;": "\u2276",
+ "LessLess;": "\u2aa1",
+ "LessSlantEqual;": "\u2a7d",
+ "LessTilde;": "\u2272",
+ "Lfr;": "\U0001d50f",
+ "Ll;": "\u22d8",
+ "Lleftarrow;": "\u21da",
+ "Lmidot;": "\u013f",
+ "LongLeftArrow;": "\u27f5",
+ "LongLeftRightArrow;": "\u27f7",
+ "LongRightArrow;": "\u27f6",
+ "Longleftarrow;": "\u27f8",
+ "Longleftrightarrow;": "\u27fa",
+ "Longrightarrow;": "\u27f9",
+ "Lopf;": "\U0001d543",
+ "LowerLeftArrow;": "\u2199",
+ "LowerRightArrow;": "\u2198",
+ "Lscr;": "\u2112",
+ "Lsh;": "\u21b0",
+ "Lstrok;": "\u0141",
+ "Lt;": "\u226a",
+ "Map;": "\u2905",
+ "Mcy;": "\u041c",
+ "MediumSpace;": "\u205f",
+ "Mellintrf;": "\u2133",
+ "Mfr;": "\U0001d510",
+ "MinusPlus;": "\u2213",
+ "Mopf;": "\U0001d544",
+ "Mscr;": "\u2133",
+ "Mu;": "\u039c",
+ "NJcy;": "\u040a",
+ "Nacute;": "\u0143",
+ "Ncaron;": "\u0147",
+ "Ncedil;": "\u0145",
+ "Ncy;": "\u041d",
+ "NegativeMediumSpace;": "\u200b",
+ "NegativeThickSpace;": "\u200b",
+ "NegativeThinSpace;": "\u200b",
+ "NegativeVeryThinSpace;": "\u200b",
+ "NestedGreaterGreater;": "\u226b",
+ "NestedLessLess;": "\u226a",
+ "NewLine;": "\n",
+ "Nfr;": "\U0001d511",
+ "NoBreak;": "\u2060",
+ "NonBreakingSpace;": "\xa0",
+ "Nopf;": "\u2115",
+ "Not;": "\u2aec",
+ "NotCongruent;": "\u2262",
+ "NotCupCap;": "\u226d",
+ "NotDoubleVerticalBar;": "\u2226",
+ "NotElement;": "\u2209",
+ "NotEqual;": "\u2260",
+ "NotEqualTilde;": "\u2242\u0338",
+ "NotExists;": "\u2204",
+ "NotGreater;": "\u226f",
+ "NotGreaterEqual;": "\u2271",
+ "NotGreaterFullEqual;": "\u2267\u0338",
+ "NotGreaterGreater;": "\u226b\u0338",
+ "NotGreaterLess;": "\u2279",
+ "NotGreaterSlantEqual;": "\u2a7e\u0338",
+ "NotGreaterTilde;": "\u2275",
+ "NotHumpDownHump;": "\u224e\u0338",
+ "NotHumpEqual;": "\u224f\u0338",
+ "NotLeftTriangle;": "\u22ea",
+ "NotLeftTriangleBar;": "\u29cf\u0338",
+ "NotLeftTriangleEqual;": "\u22ec",
+ "NotLess;": "\u226e",
+ "NotLessEqual;": "\u2270",
+ "NotLessGreater;": "\u2278",
+ "NotLessLess;": "\u226a\u0338",
+ "NotLessSlantEqual;": "\u2a7d\u0338",
+ "NotLessTilde;": "\u2274",
+ "NotNestedGreaterGreater;": "\u2aa2\u0338",
+ "NotNestedLessLess;": "\u2aa1\u0338",
+ "NotPrecedes;": "\u2280",
+ "NotPrecedesEqual;": "\u2aaf\u0338",
+ "NotPrecedesSlantEqual;": "\u22e0",
+ "NotReverseElement;": "\u220c",
+ "NotRightTriangle;": "\u22eb",
+ "NotRightTriangleBar;": "\u29d0\u0338",
+ "NotRightTriangleEqual;": "\u22ed",
+ "NotSquareSubset;": "\u228f\u0338",
+ "NotSquareSubsetEqual;": "\u22e2",
+ "NotSquareSuperset;": "\u2290\u0338",
+ "NotSquareSupersetEqual;": "\u22e3",
+ "NotSubset;": "\u2282\u20d2",
+ "NotSubsetEqual;": "\u2288",
+ "NotSucceeds;": "\u2281",
+ "NotSucceedsEqual;": "\u2ab0\u0338",
+ "NotSucceedsSlantEqual;": "\u22e1",
+ "NotSucceedsTilde;": "\u227f\u0338",
+ "NotSuperset;": "\u2283\u20d2",
+ "NotSupersetEqual;": "\u2289",
+ "NotTilde;": "\u2241",
+ "NotTildeEqual;": "\u2244",
+ "NotTildeFullEqual;": "\u2247",
+ "NotTildeTilde;": "\u2249",
+ "NotVerticalBar;": "\u2224",
+ "Nscr;": "\U0001d4a9",
+ "Ntilde": "\xd1",
+ "Ntilde;": "\xd1",
+ "Nu;": "\u039d",
+ "OElig;": "\u0152",
+ "Oacute": "\xd3",
+ "Oacute;": "\xd3",
+ "Ocirc": "\xd4",
+ "Ocirc;": "\xd4",
+ "Ocy;": "\u041e",
+ "Odblac;": "\u0150",
+ "Ofr;": "\U0001d512",
+ "Ograve": "\xd2",
+ "Ograve;": "\xd2",
+ "Omacr;": "\u014c",
+ "Omega;": "\u03a9",
+ "Omicron;": "\u039f",
+ "Oopf;": "\U0001d546",
+ "OpenCurlyDoubleQuote;": "\u201c",
+ "OpenCurlyQuote;": "\u2018",
+ "Or;": "\u2a54",
+ "Oscr;": "\U0001d4aa",
+ "Oslash": "\xd8",
+ "Oslash;": "\xd8",
+ "Otilde": "\xd5",
+ "Otilde;": "\xd5",
+ "Otimes;": "\u2a37",
+ "Ouml": "\xd6",
+ "Ouml;": "\xd6",
+ "OverBar;": "\u203e",
+ "OverBrace;": "\u23de",
+ "OverBracket;": "\u23b4",
+ "OverParenthesis;": "\u23dc",
+ "PartialD;": "\u2202",
+ "Pcy;": "\u041f",
+ "Pfr;": "\U0001d513",
+ "Phi;": "\u03a6",
+ "Pi;": "\u03a0",
+ "PlusMinus;": "\xb1",
+ "Poincareplane;": "\u210c",
+ "Popf;": "\u2119",
+ "Pr;": "\u2abb",
+ "Precedes;": "\u227a",
+ "PrecedesEqual;": "\u2aaf",
+ "PrecedesSlantEqual;": "\u227c",
+ "PrecedesTilde;": "\u227e",
+ "Prime;": "\u2033",
+ "Product;": "\u220f",
+ "Proportion;": "\u2237",
+ "Proportional;": "\u221d",
+ "Pscr;": "\U0001d4ab",
+ "Psi;": "\u03a8",
+ "QUOT": "\"",
+ "QUOT;": "\"",
+ "Qfr;": "\U0001d514",
+ "Qopf;": "\u211a",
+ "Qscr;": "\U0001d4ac",
+ "RBarr;": "\u2910",
+ "REG": "\xae",
+ "REG;": "\xae",
+ "Racute;": "\u0154",
+ "Rang;": "\u27eb",
+ "Rarr;": "\u21a0",
+ "Rarrtl;": "\u2916",
+ "Rcaron;": "\u0158",
+ "Rcedil;": "\u0156",
+ "Rcy;": "\u0420",
+ "Re;": "\u211c",
+ "ReverseElement;": "\u220b",
+ "ReverseEquilibrium;": "\u21cb",
+ "ReverseUpEquilibrium;": "\u296f",
+ "Rfr;": "\u211c",
+ "Rho;": "\u03a1",
+ "RightAngleBracket;": "\u27e9",
+ "RightArrow;": "\u2192",
+ "RightArrowBar;": "\u21e5",
+ "RightArrowLeftArrow;": "\u21c4",
+ "RightCeiling;": "\u2309",
+ "RightDoubleBracket;": "\u27e7",
+ "RightDownTeeVector;": "\u295d",
+ "RightDownVector;": "\u21c2",
+ "RightDownVectorBar;": "\u2955",
+ "RightFloor;": "\u230b",
+ "RightTee;": "\u22a2",
+ "RightTeeArrow;": "\u21a6",
+ "RightTeeVector;": "\u295b",
+ "RightTriangle;": "\u22b3",
+ "RightTriangleBar;": "\u29d0",
+ "RightTriangleEqual;": "\u22b5",
+ "RightUpDownVector;": "\u294f",
+ "RightUpTeeVector;": "\u295c",
+ "RightUpVector;": "\u21be",
+ "RightUpVectorBar;": "\u2954",
+ "RightVector;": "\u21c0",
+ "RightVectorBar;": "\u2953",
+ "Rightarrow;": "\u21d2",
+ "Ropf;": "\u211d",
+ "RoundImplies;": "\u2970",
+ "Rrightarrow;": "\u21db",
+ "Rscr;": "\u211b",
+ "Rsh;": "\u21b1",
+ "RuleDelayed;": "\u29f4",
+ "SHCHcy;": "\u0429",
+ "SHcy;": "\u0428",
+ "SOFTcy;": "\u042c",
+ "Sacute;": "\u015a",
+ "Sc;": "\u2abc",
+ "Scaron;": "\u0160",
+ "Scedil;": "\u015e",
+ "Scirc;": "\u015c",
+ "Scy;": "\u0421",
+ "Sfr;": "\U0001d516",
+ "ShortDownArrow;": "\u2193",
+ "ShortLeftArrow;": "\u2190",
+ "ShortRightArrow;": "\u2192",
+ "ShortUpArrow;": "\u2191",
+ "Sigma;": "\u03a3",
+ "SmallCircle;": "\u2218",
+ "Sopf;": "\U0001d54a",
+ "Sqrt;": "\u221a",
+ "Square;": "\u25a1",
+ "SquareIntersection;": "\u2293",
+ "SquareSubset;": "\u228f",
+ "SquareSubsetEqual;": "\u2291",
+ "SquareSuperset;": "\u2290",
+ "SquareSupersetEqual;": "\u2292",
+ "SquareUnion;": "\u2294",
+ "Sscr;": "\U0001d4ae",
+ "Star;": "\u22c6",
+ "Sub;": "\u22d0",
+ "Subset;": "\u22d0",
+ "SubsetEqual;": "\u2286",
+ "Succeeds;": "\u227b",
+ "SucceedsEqual;": "\u2ab0",
+ "SucceedsSlantEqual;": "\u227d",
+ "SucceedsTilde;": "\u227f",
+ "SuchThat;": "\u220b",
+ "Sum;": "\u2211",
+ "Sup;": "\u22d1",
+ "Superset;": "\u2283",
+ "SupersetEqual;": "\u2287",
+ "Supset;": "\u22d1",
+ "THORN": "\xde",
+ "THORN;": "\xde",
+ "TRADE;": "\u2122",
+ "TSHcy;": "\u040b",
+ "TScy;": "\u0426",
+ "Tab;": "\t",
+ "Tau;": "\u03a4",
+ "Tcaron;": "\u0164",
+ "Tcedil;": "\u0162",
+ "Tcy;": "\u0422",
+ "Tfr;": "\U0001d517",
+ "Therefore;": "\u2234",
+ "Theta;": "\u0398",
+ "ThickSpace;": "\u205f\u200a",
+ "ThinSpace;": "\u2009",
+ "Tilde;": "\u223c",
+ "TildeEqual;": "\u2243",
+ "TildeFullEqual;": "\u2245",
+ "TildeTilde;": "\u2248",
+ "Topf;": "\U0001d54b",
+ "TripleDot;": "\u20db",
+ "Tscr;": "\U0001d4af",
+ "Tstrok;": "\u0166",
+ "Uacute": "\xda",
+ "Uacute;": "\xda",
+ "Uarr;": "\u219f",
+ "Uarrocir;": "\u2949",
+ "Ubrcy;": "\u040e",
+ "Ubreve;": "\u016c",
+ "Ucirc": "\xdb",
+ "Ucirc;": "\xdb",
+ "Ucy;": "\u0423",
+ "Udblac;": "\u0170",
+ "Ufr;": "\U0001d518",
+ "Ugrave": "\xd9",
+ "Ugrave;": "\xd9",
+ "Umacr;": "\u016a",
+ "UnderBar;": "_",
+ "UnderBrace;": "\u23df",
+ "UnderBracket;": "\u23b5",
+ "UnderParenthesis;": "\u23dd",
+ "Union;": "\u22c3",
+ "UnionPlus;": "\u228e",
+ "Uogon;": "\u0172",
+ "Uopf;": "\U0001d54c",
+ "UpArrow;": "\u2191",
+ "UpArrowBar;": "\u2912",
+ "UpArrowDownArrow;": "\u21c5",
+ "UpDownArrow;": "\u2195",
+ "UpEquilibrium;": "\u296e",
+ "UpTee;": "\u22a5",
+ "UpTeeArrow;": "\u21a5",
+ "Uparrow;": "\u21d1",
+ "Updownarrow;": "\u21d5",
+ "UpperLeftArrow;": "\u2196",
+ "UpperRightArrow;": "\u2197",
+ "Upsi;": "\u03d2",
+ "Upsilon;": "\u03a5",
+ "Uring;": "\u016e",
+ "Uscr;": "\U0001d4b0",
+ "Utilde;": "\u0168",
+ "Uuml": "\xdc",
+ "Uuml;": "\xdc",
+ "VDash;": "\u22ab",
+ "Vbar;": "\u2aeb",
+ "Vcy;": "\u0412",
+ "Vdash;": "\u22a9",
+ "Vdashl;": "\u2ae6",
+ "Vee;": "\u22c1",
+ "Verbar;": "\u2016",
+ "Vert;": "\u2016",
+ "VerticalBar;": "\u2223",
+ "VerticalLine;": "|",
+ "VerticalSeparator;": "\u2758",
+ "VerticalTilde;": "\u2240",
+ "VeryThinSpace;": "\u200a",
+ "Vfr;": "\U0001d519",
+ "Vopf;": "\U0001d54d",
+ "Vscr;": "\U0001d4b1",
+ "Vvdash;": "\u22aa",
+ "Wcirc;": "\u0174",
+ "Wedge;": "\u22c0",
+ "Wfr;": "\U0001d51a",
+ "Wopf;": "\U0001d54e",
+ "Wscr;": "\U0001d4b2",
+ "Xfr;": "\U0001d51b",
+ "Xi;": "\u039e",
+ "Xopf;": "\U0001d54f",
+ "Xscr;": "\U0001d4b3",
+ "YAcy;": "\u042f",
+ "YIcy;": "\u0407",
+ "YUcy;": "\u042e",
+ "Yacute": "\xdd",
+ "Yacute;": "\xdd",
+ "Ycirc;": "\u0176",
+ "Ycy;": "\u042b",
+ "Yfr;": "\U0001d51c",
+ "Yopf;": "\U0001d550",
+ "Yscr;": "\U0001d4b4",
+ "Yuml;": "\u0178",
+ "ZHcy;": "\u0416",
+ "Zacute;": "\u0179",
+ "Zcaron;": "\u017d",
+ "Zcy;": "\u0417",
+ "Zdot;": "\u017b",
+ "ZeroWidthSpace;": "\u200b",
+ "Zeta;": "\u0396",
+ "Zfr;": "\u2128",
+ "Zopf;": "\u2124",
+ "Zscr;": "\U0001d4b5",
+ "aacute": "\xe1",
+ "aacute;": "\xe1",
+ "abreve;": "\u0103",
+ "ac;": "\u223e",
+ "acE;": "\u223e\u0333",
+ "acd;": "\u223f",
+ "acirc": "\xe2",
+ "acirc;": "\xe2",
+ "acute": "\xb4",
+ "acute;": "\xb4",
+ "acy;": "\u0430",
+ "aelig": "\xe6",
+ "aelig;": "\xe6",
+ "af;": "\u2061",
+ "afr;": "\U0001d51e",
+ "agrave": "\xe0",
+ "agrave;": "\xe0",
+ "alefsym;": "\u2135",
+ "aleph;": "\u2135",
+ "alpha;": "\u03b1",
+ "amacr;": "\u0101",
+ "amalg;": "\u2a3f",
+ "amp": "&",
+ "amp;": "&",
+ "and;": "\u2227",
+ "andand;": "\u2a55",
+ "andd;": "\u2a5c",
+ "andslope;": "\u2a58",
+ "andv;": "\u2a5a",
+ "ang;": "\u2220",
+ "ange;": "\u29a4",
+ "angle;": "\u2220",
+ "angmsd;": "\u2221",
+ "angmsdaa;": "\u29a8",
+ "angmsdab;": "\u29a9",
+ "angmsdac;": "\u29aa",
+ "angmsdad;": "\u29ab",
+ "angmsdae;": "\u29ac",
+ "angmsdaf;": "\u29ad",
+ "angmsdag;": "\u29ae",
+ "angmsdah;": "\u29af",
+ "angrt;": "\u221f",
+ "angrtvb;": "\u22be",
+ "angrtvbd;": "\u299d",
+ "angsph;": "\u2222",
+ "angst;": "\xc5",
+ "angzarr;": "\u237c",
+ "aogon;": "\u0105",
+ "aopf;": "\U0001d552",
+ "ap;": "\u2248",
+ "apE;": "\u2a70",
+ "apacir;": "\u2a6f",
+ "ape;": "\u224a",
+ "apid;": "\u224b",
+ "apos;": "'",
+ "approx;": "\u2248",
+ "approxeq;": "\u224a",
+ "aring": "\xe5",
+ "aring;": "\xe5",
+ "ascr;": "\U0001d4b6",
+ "ast;": "*",
+ "asymp;": "\u2248",
+ "asympeq;": "\u224d",
+ "atilde": "\xe3",
+ "atilde;": "\xe3",
+ "auml": "\xe4",
+ "auml;": "\xe4",
+ "awconint;": "\u2233",
+ "awint;": "\u2a11",
+ "bNot;": "\u2aed",
+ "backcong;": "\u224c",
+ "backepsilon;": "\u03f6",
+ "backprime;": "\u2035",
+ "backsim;": "\u223d",
+ "backsimeq;": "\u22cd",
+ "barvee;": "\u22bd",
+ "barwed;": "\u2305",
+ "barwedge;": "\u2305",
+ "bbrk;": "\u23b5",
+ "bbrktbrk;": "\u23b6",
+ "bcong;": "\u224c",
+ "bcy;": "\u0431",
+ "bdquo;": "\u201e",
+ "becaus;": "\u2235",
+ "because;": "\u2235",
+ "bemptyv;": "\u29b0",
+ "bepsi;": "\u03f6",
+ "bernou;": "\u212c",
+ "beta;": "\u03b2",
+ "beth;": "\u2136",
+ "between;": "\u226c",
+ "bfr;": "\U0001d51f",
+ "bigcap;": "\u22c2",
+ "bigcirc;": "\u25ef",
+ "bigcup;": "\u22c3",
+ "bigodot;": "\u2a00",
+ "bigoplus;": "\u2a01",
+ "bigotimes;": "\u2a02",
+ "bigsqcup;": "\u2a06",
+ "bigstar;": "\u2605",
+ "bigtriangledown;": "\u25bd",
+ "bigtriangleup;": "\u25b3",
+ "biguplus;": "\u2a04",
+ "bigvee;": "\u22c1",
+ "bigwedge;": "\u22c0",
+ "bkarow;": "\u290d",
+ "blacklozenge;": "\u29eb",
+ "blacksquare;": "\u25aa",
+ "blacktriangle;": "\u25b4",
+ "blacktriangledown;": "\u25be",
+ "blacktriangleleft;": "\u25c2",
+ "blacktriangleright;": "\u25b8",
+ "blank;": "\u2423",
+ "blk12;": "\u2592",
+ "blk14;": "\u2591",
+ "blk34;": "\u2593",
+ "block;": "\u2588",
+ "bne;": "=\u20e5",
+ "bnequiv;": "\u2261\u20e5",
+ "bnot;": "\u2310",
+ "bopf;": "\U0001d553",
+ "bot;": "\u22a5",
+ "bottom;": "\u22a5",
+ "bowtie;": "\u22c8",
+ "boxDL;": "\u2557",
+ "boxDR;": "\u2554",
+ "boxDl;": "\u2556",
+ "boxDr;": "\u2553",
+ "boxH;": "\u2550",
+ "boxHD;": "\u2566",
+ "boxHU;": "\u2569",
+ "boxHd;": "\u2564",
+ "boxHu;": "\u2567",
+ "boxUL;": "\u255d",
+ "boxUR;": "\u255a",
+ "boxUl;": "\u255c",
+ "boxUr;": "\u2559",
+ "boxV;": "\u2551",
+ "boxVH;": "\u256c",
+ "boxVL;": "\u2563",
+ "boxVR;": "\u2560",
+ "boxVh;": "\u256b",
+ "boxVl;": "\u2562",
+ "boxVr;": "\u255f",
+ "boxbox;": "\u29c9",
+ "boxdL;": "\u2555",
+ "boxdR;": "\u2552",
+ "boxdl;": "\u2510",
+ "boxdr;": "\u250c",
+ "boxh;": "\u2500",
+ "boxhD;": "\u2565",
+ "boxhU;": "\u2568",
+ "boxhd;": "\u252c",
+ "boxhu;": "\u2534",
+ "boxminus;": "\u229f",
+ "boxplus;": "\u229e",
+ "boxtimes;": "\u22a0",
+ "boxuL;": "\u255b",
+ "boxuR;": "\u2558",
+ "boxul;": "\u2518",
+ "boxur;": "\u2514",
+ "boxv;": "\u2502",
+ "boxvH;": "\u256a",
+ "boxvL;": "\u2561",
+ "boxvR;": "\u255e",
+ "boxvh;": "\u253c",
+ "boxvl;": "\u2524",
+ "boxvr;": "\u251c",
+ "bprime;": "\u2035",
+ "breve;": "\u02d8",
+ "brvbar": "\xa6",
+ "brvbar;": "\xa6",
+ "bscr;": "\U0001d4b7",
+ "bsemi;": "\u204f",
+ "bsim;": "\u223d",
+ "bsime;": "\u22cd",
+ "bsol;": "\\",
+ "bsolb;": "\u29c5",
+ "bsolhsub;": "\u27c8",
+ "bull;": "\u2022",
+ "bullet;": "\u2022",
+ "bump;": "\u224e",
+ "bumpE;": "\u2aae",
+ "bumpe;": "\u224f",
+ "bumpeq;": "\u224f",
+ "cacute;": "\u0107",
+ "cap;": "\u2229",
+ "capand;": "\u2a44",
+ "capbrcup;": "\u2a49",
+ "capcap;": "\u2a4b",
+ "capcup;": "\u2a47",
+ "capdot;": "\u2a40",
+ "caps;": "\u2229\ufe00",
+ "caret;": "\u2041",
+ "caron;": "\u02c7",
+ "ccaps;": "\u2a4d",
+ "ccaron;": "\u010d",
+ "ccedil": "\xe7",
+ "ccedil;": "\xe7",
+ "ccirc;": "\u0109",
+ "ccups;": "\u2a4c",
+ "ccupssm;": "\u2a50",
+ "cdot;": "\u010b",
+ "cedil": "\xb8",
+ "cedil;": "\xb8",
+ "cemptyv;": "\u29b2",
+ "cent": "\xa2",
+ "cent;": "\xa2",
+ "centerdot;": "\xb7",
+ "cfr;": "\U0001d520",
+ "chcy;": "\u0447",
+ "check;": "\u2713",
+ "checkmark;": "\u2713",
+ "chi;": "\u03c7",
+ "cir;": "\u25cb",
+ "cirE;": "\u29c3",
+ "circ;": "\u02c6",
+ "circeq;": "\u2257",
+ "circlearrowleft;": "\u21ba",
+ "circlearrowright;": "\u21bb",
+ "circledR;": "\xae",
+ "circledS;": "\u24c8",
+ "circledast;": "\u229b",
+ "circledcirc;": "\u229a",
+ "circleddash;": "\u229d",
+ "cire;": "\u2257",
+ "cirfnint;": "\u2a10",
+ "cirmid;": "\u2aef",
+ "cirscir;": "\u29c2",
+ "clubs;": "\u2663",
+ "clubsuit;": "\u2663",
+ "colon;": ":",
+ "colone;": "\u2254",
+ "coloneq;": "\u2254",
+ "comma;": ",",
+ "commat;": "@",
+ "comp;": "\u2201",
+ "compfn;": "\u2218",
+ "complement;": "\u2201",
+ "complexes;": "\u2102",
+ "cong;": "\u2245",
+ "congdot;": "\u2a6d",
+ "conint;": "\u222e",
+ "copf;": "\U0001d554",
+ "coprod;": "\u2210",
+ "copy": "\xa9",
+ "copy;": "\xa9",
+ "copysr;": "\u2117",
+ "crarr;": "\u21b5",
+ "cross;": "\u2717",
+ "cscr;": "\U0001d4b8",
+ "csub;": "\u2acf",
+ "csube;": "\u2ad1",
+ "csup;": "\u2ad0",
+ "csupe;": "\u2ad2",
+ "ctdot;": "\u22ef",
+ "cudarrl;": "\u2938",
+ "cudarrr;": "\u2935",
+ "cuepr;": "\u22de",
+ "cuesc;": "\u22df",
+ "cularr;": "\u21b6",
+ "cularrp;": "\u293d",
+ "cup;": "\u222a",
+ "cupbrcap;": "\u2a48",
+ "cupcap;": "\u2a46",
+ "cupcup;": "\u2a4a",
+ "cupdot;": "\u228d",
+ "cupor;": "\u2a45",
+ "cups;": "\u222a\ufe00",
+ "curarr;": "\u21b7",
+ "curarrm;": "\u293c",
+ "curlyeqprec;": "\u22de",
+ "curlyeqsucc;": "\u22df",
+ "curlyvee;": "\u22ce",
+ "curlywedge;": "\u22cf",
+ "curren": "\xa4",
+ "curren;": "\xa4",
+ "curvearrowleft;": "\u21b6",
+ "curvearrowright;": "\u21b7",
+ "cuvee;": "\u22ce",
+ "cuwed;": "\u22cf",
+ "cwconint;": "\u2232",
+ "cwint;": "\u2231",
+ "cylcty;": "\u232d",
+ "dArr;": "\u21d3",
+ "dHar;": "\u2965",
+ "dagger;": "\u2020",
+ "daleth;": "\u2138",
+ "darr;": "\u2193",
+ "dash;": "\u2010",
+ "dashv;": "\u22a3",
+ "dbkarow;": "\u290f",
+ "dblac;": "\u02dd",
+ "dcaron;": "\u010f",
+ "dcy;": "\u0434",
+ "dd;": "\u2146",
+ "ddagger;": "\u2021",
+ "ddarr;": "\u21ca",
+ "ddotseq;": "\u2a77",
+ "deg": "\xb0",
+ "deg;": "\xb0",
+ "delta;": "\u03b4",
+ "demptyv;": "\u29b1",
+ "dfisht;": "\u297f",
+ "dfr;": "\U0001d521",
+ "dharl;": "\u21c3",
+ "dharr;": "\u21c2",
+ "diam;": "\u22c4",
+ "diamond;": "\u22c4",
+ "diamondsuit;": "\u2666",
+ "diams;": "\u2666",
+ "die;": "\xa8",
+ "digamma;": "\u03dd",
+ "disin;": "\u22f2",
+ "div;": "\xf7",
+ "divide": "\xf7",
+ "divide;": "\xf7",
+ "divideontimes;": "\u22c7",
+ "divonx;": "\u22c7",
+ "djcy;": "\u0452",
+ "dlcorn;": "\u231e",
+ "dlcrop;": "\u230d",
+ "dollar;": "$",
+ "dopf;": "\U0001d555",
+ "dot;": "\u02d9",
+ "doteq;": "\u2250",
+ "doteqdot;": "\u2251",
+ "dotminus;": "\u2238",
+ "dotplus;": "\u2214",
+ "dotsquare;": "\u22a1",
+ "doublebarwedge;": "\u2306",
+ "downarrow;": "\u2193",
+ "downdownarrows;": "\u21ca",
+ "downharpoonleft;": "\u21c3",
+ "downharpoonright;": "\u21c2",
+ "drbkarow;": "\u2910",
+ "drcorn;": "\u231f",
+ "drcrop;": "\u230c",
+ "dscr;": "\U0001d4b9",
+ "dscy;": "\u0455",
+ "dsol;": "\u29f6",
+ "dstrok;": "\u0111",
+ "dtdot;": "\u22f1",
+ "dtri;": "\u25bf",
+ "dtrif;": "\u25be",
+ "duarr;": "\u21f5",
+ "duhar;": "\u296f",
+ "dwangle;": "\u29a6",
+ "dzcy;": "\u045f",
+ "dzigrarr;": "\u27ff",
+ "eDDot;": "\u2a77",
+ "eDot;": "\u2251",
+ "eacute": "\xe9",
+ "eacute;": "\xe9",
+ "easter;": "\u2a6e",
+ "ecaron;": "\u011b",
+ "ecir;": "\u2256",
+ "ecirc": "\xea",
+ "ecirc;": "\xea",
+ "ecolon;": "\u2255",
+ "ecy;": "\u044d",
+ "edot;": "\u0117",
+ "ee;": "\u2147",
+ "efDot;": "\u2252",
+ "efr;": "\U0001d522",
+ "eg;": "\u2a9a",
+ "egrave": "\xe8",
+ "egrave;": "\xe8",
+ "egs;": "\u2a96",
+ "egsdot;": "\u2a98",
+ "el;": "\u2a99",
+ "elinters;": "\u23e7",
+ "ell;": "\u2113",
+ "els;": "\u2a95",
+ "elsdot;": "\u2a97",
+ "emacr;": "\u0113",
+ "empty;": "\u2205",
+ "emptyset;": "\u2205",
+ "emptyv;": "\u2205",
+ "emsp13;": "\u2004",
+ "emsp14;": "\u2005",
+ "emsp;": "\u2003",
+ "eng;": "\u014b",
+ "ensp;": "\u2002",
+ "eogon;": "\u0119",
+ "eopf;": "\U0001d556",
+ "epar;": "\u22d5",
+ "eparsl;": "\u29e3",
+ "eplus;": "\u2a71",
+ "epsi;": "\u03b5",
+ "epsilon;": "\u03b5",
+ "epsiv;": "\u03f5",
+ "eqcirc;": "\u2256",
+ "eqcolon;": "\u2255",
+ "eqsim;": "\u2242",
+ "eqslantgtr;": "\u2a96",
+ "eqslantless;": "\u2a95",
+ "equals;": "=",
+ "equest;": "\u225f",
+ "equiv;": "\u2261",
+ "equivDD;": "\u2a78",
+ "eqvparsl;": "\u29e5",
+ "erDot;": "\u2253",
+ "erarr;": "\u2971",
+ "escr;": "\u212f",
+ "esdot;": "\u2250",
+ "esim;": "\u2242",
+ "eta;": "\u03b7",
+ "eth": "\xf0",
+ "eth;": "\xf0",
+ "euml": "\xeb",
+ "euml;": "\xeb",
+ "euro;": "\u20ac",
+ "excl;": "!",
+ "exist;": "\u2203",
+ "expectation;": "\u2130",
+ "exponentiale;": "\u2147",
+ "fallingdotseq;": "\u2252",
+ "fcy;": "\u0444",
+ "female;": "\u2640",
+ "ffilig;": "\ufb03",
+ "fflig;": "\ufb00",
+ "ffllig;": "\ufb04",
+ "ffr;": "\U0001d523",
+ "filig;": "\ufb01",
+ "fjlig;": "fj",
+ "flat;": "\u266d",
+ "fllig;": "\ufb02",
+ "fltns;": "\u25b1",
+ "fnof;": "\u0192",
+ "fopf;": "\U0001d557",
+ "forall;": "\u2200",
+ "fork;": "\u22d4",
+ "forkv;": "\u2ad9",
+ "fpartint;": "\u2a0d",
+ "frac12": "\xbd",
+ "frac12;": "\xbd",
+ "frac13;": "\u2153",
+ "frac14": "\xbc",
+ "frac14;": "\xbc",
+ "frac15;": "\u2155",
+ "frac16;": "\u2159",
+ "frac18;": "\u215b",
+ "frac23;": "\u2154",
+ "frac25;": "\u2156",
+ "frac34": "\xbe",
+ "frac34;": "\xbe",
+ "frac35;": "\u2157",
+ "frac38;": "\u215c",
+ "frac45;": "\u2158",
+ "frac56;": "\u215a",
+ "frac58;": "\u215d",
+ "frac78;": "\u215e",
+ "frasl;": "\u2044",
+ "frown;": "\u2322",
+ "fscr;": "\U0001d4bb",
+ "gE;": "\u2267",
+ "gEl;": "\u2a8c",
+ "gacute;": "\u01f5",
+ "gamma;": "\u03b3",
+ "gammad;": "\u03dd",
+ "gap;": "\u2a86",
+ "gbreve;": "\u011f",
+ "gcirc;": "\u011d",
+ "gcy;": "\u0433",
+ "gdot;": "\u0121",
+ "ge;": "\u2265",
+ "gel;": "\u22db",
+ "geq;": "\u2265",
+ "geqq;": "\u2267",
+ "geqslant;": "\u2a7e",
+ "ges;": "\u2a7e",
+ "gescc;": "\u2aa9",
+ "gesdot;": "\u2a80",
+ "gesdoto;": "\u2a82",
+ "gesdotol;": "\u2a84",
+ "gesl;": "\u22db\ufe00",
+ "gesles;": "\u2a94",
+ "gfr;": "\U0001d524",
+ "gg;": "\u226b",
+ "ggg;": "\u22d9",
+ "gimel;": "\u2137",
+ "gjcy;": "\u0453",
+ "gl;": "\u2277",
+ "glE;": "\u2a92",
+ "gla;": "\u2aa5",
+ "glj;": "\u2aa4",
+ "gnE;": "\u2269",
+ "gnap;": "\u2a8a",
+ "gnapprox;": "\u2a8a",
+ "gne;": "\u2a88",
+ "gneq;": "\u2a88",
+ "gneqq;": "\u2269",
+ "gnsim;": "\u22e7",
+ "gopf;": "\U0001d558",
+ "grave;": "`",
+ "gscr;": "\u210a",
+ "gsim;": "\u2273",
+ "gsime;": "\u2a8e",
+ "gsiml;": "\u2a90",
+ "gt": ">",
+ "gt;": ">",
+ "gtcc;": "\u2aa7",
+ "gtcir;": "\u2a7a",
+ "gtdot;": "\u22d7",
+ "gtlPar;": "\u2995",
+ "gtquest;": "\u2a7c",
+ "gtrapprox;": "\u2a86",
+ "gtrarr;": "\u2978",
+ "gtrdot;": "\u22d7",
+ "gtreqless;": "\u22db",
+ "gtreqqless;": "\u2a8c",
+ "gtrless;": "\u2277",
+ "gtrsim;": "\u2273",
+ "gvertneqq;": "\u2269\ufe00",
+ "gvnE;": "\u2269\ufe00",
+ "hArr;": "\u21d4",
+ "hairsp;": "\u200a",
+ "half;": "\xbd",
+ "hamilt;": "\u210b",
+ "hardcy;": "\u044a",
+ "harr;": "\u2194",
+ "harrcir;": "\u2948",
+ "harrw;": "\u21ad",
+ "hbar;": "\u210f",
+ "hcirc;": "\u0125",
+ "hearts;": "\u2665",
+ "heartsuit;": "\u2665",
+ "hellip;": "\u2026",
+ "hercon;": "\u22b9",
+ "hfr;": "\U0001d525",
+ "hksearow;": "\u2925",
+ "hkswarow;": "\u2926",
+ "hoarr;": "\u21ff",
+ "homtht;": "\u223b",
+ "hookleftarrow;": "\u21a9",
+ "hookrightarrow;": "\u21aa",
+ "hopf;": "\U0001d559",
+ "horbar;": "\u2015",
+ "hscr;": "\U0001d4bd",
+ "hslash;": "\u210f",
+ "hstrok;": "\u0127",
+ "hybull;": "\u2043",
+ "hyphen;": "\u2010",
+ "iacute": "\xed",
+ "iacute;": "\xed",
+ "ic;": "\u2063",
+ "icirc": "\xee",
+ "icirc;": "\xee",
+ "icy;": "\u0438",
+ "iecy;": "\u0435",
+ "iexcl": "\xa1",
+ "iexcl;": "\xa1",
+ "iff;": "\u21d4",
+ "ifr;": "\U0001d526",
+ "igrave": "\xec",
+ "igrave;": "\xec",
+ "ii;": "\u2148",
+ "iiiint;": "\u2a0c",
+ "iiint;": "\u222d",
+ "iinfin;": "\u29dc",
+ "iiota;": "\u2129",
+ "ijlig;": "\u0133",
+ "imacr;": "\u012b",
+ "image;": "\u2111",
+ "imagline;": "\u2110",
+ "imagpart;": "\u2111",
+ "imath;": "\u0131",
+ "imof;": "\u22b7",
+ "imped;": "\u01b5",
+ "in;": "\u2208",
+ "incare;": "\u2105",
+ "infin;": "\u221e",
+ "infintie;": "\u29dd",
+ "inodot;": "\u0131",
+ "int;": "\u222b",
+ "intcal;": "\u22ba",
+ "integers;": "\u2124",
+ "intercal;": "\u22ba",
+ "intlarhk;": "\u2a17",
+ "intprod;": "\u2a3c",
+ "iocy;": "\u0451",
+ "iogon;": "\u012f",
+ "iopf;": "\U0001d55a",
+ "iota;": "\u03b9",
+ "iprod;": "\u2a3c",
+ "iquest": "\xbf",
+ "iquest;": "\xbf",
+ "iscr;": "\U0001d4be",
+ "isin;": "\u2208",
+ "isinE;": "\u22f9",
+ "isindot;": "\u22f5",
+ "isins;": "\u22f4",
+ "isinsv;": "\u22f3",
+ "isinv;": "\u2208",
+ "it;": "\u2062",
+ "itilde;": "\u0129",
+ "iukcy;": "\u0456",
+ "iuml": "\xef",
+ "iuml;": "\xef",
+ "jcirc;": "\u0135",
+ "jcy;": "\u0439",
+ "jfr;": "\U0001d527",
+ "jmath;": "\u0237",
+ "jopf;": "\U0001d55b",
+ "jscr;": "\U0001d4bf",
+ "jsercy;": "\u0458",
+ "jukcy;": "\u0454",
+ "kappa;": "\u03ba",
+ "kappav;": "\u03f0",
+ "kcedil;": "\u0137",
+ "kcy;": "\u043a",
+ "kfr;": "\U0001d528",
+ "kgreen;": "\u0138",
+ "khcy;": "\u0445",
+ "kjcy;": "\u045c",
+ "kopf;": "\U0001d55c",
+ "kscr;": "\U0001d4c0",
+ "lAarr;": "\u21da",
+ "lArr;": "\u21d0",
+ "lAtail;": "\u291b",
+ "lBarr;": "\u290e",
+ "lE;": "\u2266",
+ "lEg;": "\u2a8b",
+ "lHar;": "\u2962",
+ "lacute;": "\u013a",
+ "laemptyv;": "\u29b4",
+ "lagran;": "\u2112",
+ "lambda;": "\u03bb",
+ "lang;": "\u27e8",
+ "langd;": "\u2991",
+ "langle;": "\u27e8",
+ "lap;": "\u2a85",
+ "laquo": "\xab",
+ "laquo;": "\xab",
+ "larr;": "\u2190",
+ "larrb;": "\u21e4",
+ "larrbfs;": "\u291f",
+ "larrfs;": "\u291d",
+ "larrhk;": "\u21a9",
+ "larrlp;": "\u21ab",
+ "larrpl;": "\u2939",
+ "larrsim;": "\u2973",
+ "larrtl;": "\u21a2",
+ "lat;": "\u2aab",
+ "latail;": "\u2919",
+ "late;": "\u2aad",
+ "lates;": "\u2aad\ufe00",
+ "lbarr;": "\u290c",
+ "lbbrk;": "\u2772",
+ "lbrace;": "{",
+ "lbrack;": "[",
+ "lbrke;": "\u298b",
+ "lbrksld;": "\u298f",
+ "lbrkslu;": "\u298d",
+ "lcaron;": "\u013e",
+ "lcedil;": "\u013c",
+ "lceil;": "\u2308",
+ "lcub;": "{",
+ "lcy;": "\u043b",
+ "ldca;": "\u2936",
+ "ldquo;": "\u201c",
+ "ldquor;": "\u201e",
+ "ldrdhar;": "\u2967",
+ "ldrushar;": "\u294b",
+ "ldsh;": "\u21b2",
+ "le;": "\u2264",
+ "leftarrow;": "\u2190",
+ "leftarrowtail;": "\u21a2",
+ "leftharpoondown;": "\u21bd",
+ "leftharpoonup;": "\u21bc",
+ "leftleftarrows;": "\u21c7",
+ "leftrightarrow;": "\u2194",
+ "leftrightarrows;": "\u21c6",
+ "leftrightharpoons;": "\u21cb",
+ "leftrightsquigarrow;": "\u21ad",
+ "leftthreetimes;": "\u22cb",
+ "leg;": "\u22da",
+ "leq;": "\u2264",
+ "leqq;": "\u2266",
+ "leqslant;": "\u2a7d",
+ "les;": "\u2a7d",
+ "lescc;": "\u2aa8",
+ "lesdot;": "\u2a7f",
+ "lesdoto;": "\u2a81",
+ "lesdotor;": "\u2a83",
+ "lesg;": "\u22da\ufe00",
+ "lesges;": "\u2a93",
+ "lessapprox;": "\u2a85",
+ "lessdot;": "\u22d6",
+ "lesseqgtr;": "\u22da",
+ "lesseqqgtr;": "\u2a8b",
+ "lessgtr;": "\u2276",
+ "lesssim;": "\u2272",
+ "lfisht;": "\u297c",
+ "lfloor;": "\u230a",
+ "lfr;": "\U0001d529",
+ "lg;": "\u2276",
+ "lgE;": "\u2a91",
+ "lhard;": "\u21bd",
+ "lharu;": "\u21bc",
+ "lharul;": "\u296a",
+ "lhblk;": "\u2584",
+ "ljcy;": "\u0459",
+ "ll;": "\u226a",
+ "llarr;": "\u21c7",
+ "llcorner;": "\u231e",
+ "llhard;": "\u296b",
+ "lltri;": "\u25fa",
+ "lmidot;": "\u0140",
+ "lmoust;": "\u23b0",
+ "lmoustache;": "\u23b0",
+ "lnE;": "\u2268",
+ "lnap;": "\u2a89",
+ "lnapprox;": "\u2a89",
+ "lne;": "\u2a87",
+ "lneq;": "\u2a87",
+ "lneqq;": "\u2268",
+ "lnsim;": "\u22e6",
+ "loang;": "\u27ec",
+ "loarr;": "\u21fd",
+ "lobrk;": "\u27e6",
+ "longleftarrow;": "\u27f5",
+ "longleftrightarrow;": "\u27f7",
+ "longmapsto;": "\u27fc",
+ "longrightarrow;": "\u27f6",
+ "looparrowleft;": "\u21ab",
+ "looparrowright;": "\u21ac",
+ "lopar;": "\u2985",
+ "lopf;": "\U0001d55d",
+ "loplus;": "\u2a2d",
+ "lotimes;": "\u2a34",
+ "lowast;": "\u2217",
+ "lowbar;": "_",
+ "loz;": "\u25ca",
+ "lozenge;": "\u25ca",
+ "lozf;": "\u29eb",
+ "lpar;": "(",
+ "lparlt;": "\u2993",
+ "lrarr;": "\u21c6",
+ "lrcorner;": "\u231f",
+ "lrhar;": "\u21cb",
+ "lrhard;": "\u296d",
+ "lrm;": "\u200e",
+ "lrtri;": "\u22bf",
+ "lsaquo;": "\u2039",
+ "lscr;": "\U0001d4c1",
+ "lsh;": "\u21b0",
+ "lsim;": "\u2272",
+ "lsime;": "\u2a8d",
+ "lsimg;": "\u2a8f",
+ "lsqb;": "[",
+ "lsquo;": "\u2018",
+ "lsquor;": "\u201a",
+ "lstrok;": "\u0142",
+ "lt": "<",
+ "lt;": "<",
+ "ltcc;": "\u2aa6",
+ "ltcir;": "\u2a79",
+ "ltdot;": "\u22d6",
+ "lthree;": "\u22cb",
+ "ltimes;": "\u22c9",
+ "ltlarr;": "\u2976",
+ "ltquest;": "\u2a7b",
+ "ltrPar;": "\u2996",
+ "ltri;": "\u25c3",
+ "ltrie;": "\u22b4",
+ "ltrif;": "\u25c2",
+ "lurdshar;": "\u294a",
+ "luruhar;": "\u2966",
+ "lvertneqq;": "\u2268\ufe00",
+ "lvnE;": "\u2268\ufe00",
+ "mDDot;": "\u223a",
+ "macr": "\xaf",
+ "macr;": "\xaf",
+ "male;": "\u2642",
+ "malt;": "\u2720",
+ "maltese;": "\u2720",
+ "map;": "\u21a6",
+ "mapsto;": "\u21a6",
+ "mapstodown;": "\u21a7",
+ "mapstoleft;": "\u21a4",
+ "mapstoup;": "\u21a5",
+ "marker;": "\u25ae",
+ "mcomma;": "\u2a29",
+ "mcy;": "\u043c",
+ "mdash;": "\u2014",
+ "measuredangle;": "\u2221",
+ "mfr;": "\U0001d52a",
+ "mho;": "\u2127",
+ "micro": "\xb5",
+ "micro;": "\xb5",
+ "mid;": "\u2223",
+ "midast;": "*",
+ "midcir;": "\u2af0",
+ "middot": "\xb7",
+ "middot;": "\xb7",
+ "minus;": "\u2212",
+ "minusb;": "\u229f",
+ "minusd;": "\u2238",
+ "minusdu;": "\u2a2a",
+ "mlcp;": "\u2adb",
+ "mldr;": "\u2026",
+ "mnplus;": "\u2213",
+ "models;": "\u22a7",
+ "mopf;": "\U0001d55e",
+ "mp;": "\u2213",
+ "mscr;": "\U0001d4c2",
+ "mstpos;": "\u223e",
+ "mu;": "\u03bc",
+ "multimap;": "\u22b8",
+ "mumap;": "\u22b8",
+ "nGg;": "\u22d9\u0338",
+ "nGt;": "\u226b\u20d2",
+ "nGtv;": "\u226b\u0338",
+ "nLeftarrow;": "\u21cd",
+ "nLeftrightarrow;": "\u21ce",
+ "nLl;": "\u22d8\u0338",
+ "nLt;": "\u226a\u20d2",
+ "nLtv;": "\u226a\u0338",
+ "nRightarrow;": "\u21cf",
+ "nVDash;": "\u22af",
+ "nVdash;": "\u22ae",
+ "nabla;": "\u2207",
+ "nacute;": "\u0144",
+ "nang;": "\u2220\u20d2",
+ "nap;": "\u2249",
+ "napE;": "\u2a70\u0338",
+ "napid;": "\u224b\u0338",
+ "napos;": "\u0149",
+ "napprox;": "\u2249",
+ "natur;": "\u266e",
+ "natural;": "\u266e",
+ "naturals;": "\u2115",
+ "nbsp": "\xa0",
+ "nbsp;": "\xa0",
+ "nbump;": "\u224e\u0338",
+ "nbumpe;": "\u224f\u0338",
+ "ncap;": "\u2a43",
+ "ncaron;": "\u0148",
+ "ncedil;": "\u0146",
+ "ncong;": "\u2247",
+ "ncongdot;": "\u2a6d\u0338",
+ "ncup;": "\u2a42",
+ "ncy;": "\u043d",
+ "ndash;": "\u2013",
+ "ne;": "\u2260",
+ "neArr;": "\u21d7",
+ "nearhk;": "\u2924",
+ "nearr;": "\u2197",
+ "nearrow;": "\u2197",
+ "nedot;": "\u2250\u0338",
+ "nequiv;": "\u2262",
+ "nesear;": "\u2928",
+ "nesim;": "\u2242\u0338",
+ "nexist;": "\u2204",
+ "nexists;": "\u2204",
+ "nfr;": "\U0001d52b",
+ "ngE;": "\u2267\u0338",
+ "nge;": "\u2271",
+ "ngeq;": "\u2271",
+ "ngeqq;": "\u2267\u0338",
+ "ngeqslant;": "\u2a7e\u0338",
+ "nges;": "\u2a7e\u0338",
+ "ngsim;": "\u2275",
+ "ngt;": "\u226f",
+ "ngtr;": "\u226f",
+ "nhArr;": "\u21ce",
+ "nharr;": "\u21ae",
+ "nhpar;": "\u2af2",
+ "ni;": "\u220b",
+ "nis;": "\u22fc",
+ "nisd;": "\u22fa",
+ "niv;": "\u220b",
+ "njcy;": "\u045a",
+ "nlArr;": "\u21cd",
+ "nlE;": "\u2266\u0338",
+ "nlarr;": "\u219a",
+ "nldr;": "\u2025",
+ "nle;": "\u2270",
+ "nleftarrow;": "\u219a",
+ "nleftrightarrow;": "\u21ae",
+ "nleq;": "\u2270",
+ "nleqq;": "\u2266\u0338",
+ "nleqslant;": "\u2a7d\u0338",
+ "nles;": "\u2a7d\u0338",
+ "nless;": "\u226e",
+ "nlsim;": "\u2274",
+ "nlt;": "\u226e",
+ "nltri;": "\u22ea",
+ "nltrie;": "\u22ec",
+ "nmid;": "\u2224",
+ "nopf;": "\U0001d55f",
+ "not": "\xac",
+ "not;": "\xac",
+ "notin;": "\u2209",
+ "notinE;": "\u22f9\u0338",
+ "notindot;": "\u22f5\u0338",
+ "notinva;": "\u2209",
+ "notinvb;": "\u22f7",
+ "notinvc;": "\u22f6",
+ "notni;": "\u220c",
+ "notniva;": "\u220c",
+ "notnivb;": "\u22fe",
+ "notnivc;": "\u22fd",
+ "npar;": "\u2226",
+ "nparallel;": "\u2226",
+ "nparsl;": "\u2afd\u20e5",
+ "npart;": "\u2202\u0338",
+ "npolint;": "\u2a14",
+ "npr;": "\u2280",
+ "nprcue;": "\u22e0",
+ "npre;": "\u2aaf\u0338",
+ "nprec;": "\u2280",
+ "npreceq;": "\u2aaf\u0338",
+ "nrArr;": "\u21cf",
+ "nrarr;": "\u219b",
+ "nrarrc;": "\u2933\u0338",
+ "nrarrw;": "\u219d\u0338",
+ "nrightarrow;": "\u219b",
+ "nrtri;": "\u22eb",
+ "nrtrie;": "\u22ed",
+ "nsc;": "\u2281",
+ "nsccue;": "\u22e1",
+ "nsce;": "\u2ab0\u0338",
+ "nscr;": "\U0001d4c3",
+ "nshortmid;": "\u2224",
+ "nshortparallel;": "\u2226",
+ "nsim;": "\u2241",
+ "nsime;": "\u2244",
+ "nsimeq;": "\u2244",
+ "nsmid;": "\u2224",
+ "nspar;": "\u2226",
+ "nsqsube;": "\u22e2",
+ "nsqsupe;": "\u22e3",
+ "nsub;": "\u2284",
+ "nsubE;": "\u2ac5\u0338",
+ "nsube;": "\u2288",
+ "nsubset;": "\u2282\u20d2",
+ "nsubseteq;": "\u2288",
+ "nsubseteqq;": "\u2ac5\u0338",
+ "nsucc;": "\u2281",
+ "nsucceq;": "\u2ab0\u0338",
+ "nsup;": "\u2285",
+ "nsupE;": "\u2ac6\u0338",
+ "nsupe;": "\u2289",
+ "nsupset;": "\u2283\u20d2",
+ "nsupseteq;": "\u2289",
+ "nsupseteqq;": "\u2ac6\u0338",
+ "ntgl;": "\u2279",
+ "ntilde": "\xf1",
+ "ntilde;": "\xf1",
+ "ntlg;": "\u2278",
+ "ntriangleleft;": "\u22ea",
+ "ntrianglelefteq;": "\u22ec",
+ "ntriangleright;": "\u22eb",
+ "ntrianglerighteq;": "\u22ed",
+ "nu;": "\u03bd",
+ "num;": "#",
+ "numero;": "\u2116",
+ "numsp;": "\u2007",
+ "nvDash;": "\u22ad",
+ "nvHarr;": "\u2904",
+ "nvap;": "\u224d\u20d2",
+ "nvdash;": "\u22ac",
+ "nvge;": "\u2265\u20d2",
+ "nvgt;": ">\u20d2",
+ "nvinfin;": "\u29de",
+ "nvlArr;": "\u2902",
+ "nvle;": "\u2264\u20d2",
+ "nvlt;": "<\u20d2",
+ "nvltrie;": "\u22b4\u20d2",
+ "nvrArr;": "\u2903",
+ "nvrtrie;": "\u22b5\u20d2",
+ "nvsim;": "\u223c\u20d2",
+ "nwArr;": "\u21d6",
+ "nwarhk;": "\u2923",
+ "nwarr;": "\u2196",
+ "nwarrow;": "\u2196",
+ "nwnear;": "\u2927",
+ "oS;": "\u24c8",
+ "oacute": "\xf3",
+ "oacute;": "\xf3",
+ "oast;": "\u229b",
+ "ocir;": "\u229a",
+ "ocirc": "\xf4",
+ "ocirc;": "\xf4",
+ "ocy;": "\u043e",
+ "odash;": "\u229d",
+ "odblac;": "\u0151",
+ "odiv;": "\u2a38",
+ "odot;": "\u2299",
+ "odsold;": "\u29bc",
+ "oelig;": "\u0153",
+ "ofcir;": "\u29bf",
+ "ofr;": "\U0001d52c",
+ "ogon;": "\u02db",
+ "ograve": "\xf2",
+ "ograve;": "\xf2",
+ "ogt;": "\u29c1",
+ "ohbar;": "\u29b5",
+ "ohm;": "\u03a9",
+ "oint;": "\u222e",
+ "olarr;": "\u21ba",
+ "olcir;": "\u29be",
+ "olcross;": "\u29bb",
+ "oline;": "\u203e",
+ "olt;": "\u29c0",
+ "omacr;": "\u014d",
+ "omega;": "\u03c9",
+ "omicron;": "\u03bf",
+ "omid;": "\u29b6",
+ "ominus;": "\u2296",
+ "oopf;": "\U0001d560",
+ "opar;": "\u29b7",
+ "operp;": "\u29b9",
+ "oplus;": "\u2295",
+ "or;": "\u2228",
+ "orarr;": "\u21bb",
+ "ord;": "\u2a5d",
+ "order;": "\u2134",
+ "orderof;": "\u2134",
+ "ordf": "\xaa",
+ "ordf;": "\xaa",
+ "ordm": "\xba",
+ "ordm;": "\xba",
+ "origof;": "\u22b6",
+ "oror;": "\u2a56",
+ "orslope;": "\u2a57",
+ "orv;": "\u2a5b",
+ "oscr;": "\u2134",
+ "oslash": "\xf8",
+ "oslash;": "\xf8",
+ "osol;": "\u2298",
+ "otilde": "\xf5",
+ "otilde;": "\xf5",
+ "otimes;": "\u2297",
+ "otimesas;": "\u2a36",
+ "ouml": "\xf6",
+ "ouml;": "\xf6",
+ "ovbar;": "\u233d",
+ "par;": "\u2225",
+ "para": "\xb6",
+ "para;": "\xb6",
+ "parallel;": "\u2225",
+ "parsim;": "\u2af3",
+ "parsl;": "\u2afd",
+ "part;": "\u2202",
+ "pcy;": "\u043f",
+ "percnt;": "%",
+ "period;": ".",
+ "permil;": "\u2030",
+ "perp;": "\u22a5",
+ "pertenk;": "\u2031",
+ "pfr;": "\U0001d52d",
+ "phi;": "\u03c6",
+ "phiv;": "\u03d5",
+ "phmmat;": "\u2133",
+ "phone;": "\u260e",
+ "pi;": "\u03c0",
+ "pitchfork;": "\u22d4",
+ "piv;": "\u03d6",
+ "planck;": "\u210f",
+ "planckh;": "\u210e",
+ "plankv;": "\u210f",
+ "plus;": "+",
+ "plusacir;": "\u2a23",
+ "plusb;": "\u229e",
+ "pluscir;": "\u2a22",
+ "plusdo;": "\u2214",
+ "plusdu;": "\u2a25",
+ "pluse;": "\u2a72",
+ "plusmn": "\xb1",
+ "plusmn;": "\xb1",
+ "plussim;": "\u2a26",
+ "plustwo;": "\u2a27",
+ "pm;": "\xb1",
+ "pointint;": "\u2a15",
+ "popf;": "\U0001d561",
+ "pound": "\xa3",
+ "pound;": "\xa3",
+ "pr;": "\u227a",
+ "prE;": "\u2ab3",
+ "prap;": "\u2ab7",
+ "prcue;": "\u227c",
+ "pre;": "\u2aaf",
+ "prec;": "\u227a",
+ "precapprox;": "\u2ab7",
+ "preccurlyeq;": "\u227c",
+ "preceq;": "\u2aaf",
+ "precnapprox;": "\u2ab9",
+ "precneqq;": "\u2ab5",
+ "precnsim;": "\u22e8",
+ "precsim;": "\u227e",
+ "prime;": "\u2032",
+ "primes;": "\u2119",
+ "prnE;": "\u2ab5",
+ "prnap;": "\u2ab9",
+ "prnsim;": "\u22e8",
+ "prod;": "\u220f",
+ "profalar;": "\u232e",
+ "profline;": "\u2312",
+ "profsurf;": "\u2313",
+ "prop;": "\u221d",
+ "propto;": "\u221d",
+ "prsim;": "\u227e",
+ "prurel;": "\u22b0",
+ "pscr;": "\U0001d4c5",
+ "psi;": "\u03c8",
+ "puncsp;": "\u2008",
+ "qfr;": "\U0001d52e",
+ "qint;": "\u2a0c",
+ "qopf;": "\U0001d562",
+ "qprime;": "\u2057",
+ "qscr;": "\U0001d4c6",
+ "quaternions;": "\u210d",
+ "quatint;": "\u2a16",
+ "quest;": "?",
+ "questeq;": "\u225f",
+ "quot": "\"",
+ "quot;": "\"",
+ "rAarr;": "\u21db",
+ "rArr;": "\u21d2",
+ "rAtail;": "\u291c",
+ "rBarr;": "\u290f",
+ "rHar;": "\u2964",
+ "race;": "\u223d\u0331",
+ "racute;": "\u0155",
+ "radic;": "\u221a",
+ "raemptyv;": "\u29b3",
+ "rang;": "\u27e9",
+ "rangd;": "\u2992",
+ "range;": "\u29a5",
+ "rangle;": "\u27e9",
+ "raquo": "\xbb",
+ "raquo;": "\xbb",
+ "rarr;": "\u2192",
+ "rarrap;": "\u2975",
+ "rarrb;": "\u21e5",
+ "rarrbfs;": "\u2920",
+ "rarrc;": "\u2933",
+ "rarrfs;": "\u291e",
+ "rarrhk;": "\u21aa",
+ "rarrlp;": "\u21ac",
+ "rarrpl;": "\u2945",
+ "rarrsim;": "\u2974",
+ "rarrtl;": "\u21a3",
+ "rarrw;": "\u219d",
+ "ratail;": "\u291a",
+ "ratio;": "\u2236",
+ "rationals;": "\u211a",
+ "rbarr;": "\u290d",
+ "rbbrk;": "\u2773",
+ "rbrace;": "}",
+ "rbrack;": "]",
+ "rbrke;": "\u298c",
+ "rbrksld;": "\u298e",
+ "rbrkslu;": "\u2990",
+ "rcaron;": "\u0159",
+ "rcedil;": "\u0157",
+ "rceil;": "\u2309",
+ "rcub;": "}",
+ "rcy;": "\u0440",
+ "rdca;": "\u2937",
+ "rdldhar;": "\u2969",
+ "rdquo;": "\u201d",
+ "rdquor;": "\u201d",
+ "rdsh;": "\u21b3",
+ "real;": "\u211c",
+ "realine;": "\u211b",
+ "realpart;": "\u211c",
+ "reals;": "\u211d",
+ "rect;": "\u25ad",
+ "reg": "\xae",
+ "reg;": "\xae",
+ "rfisht;": "\u297d",
+ "rfloor;": "\u230b",
+ "rfr;": "\U0001d52f",
+ "rhard;": "\u21c1",
+ "rharu;": "\u21c0",
+ "rharul;": "\u296c",
+ "rho;": "\u03c1",
+ "rhov;": "\u03f1",
+ "rightarrow;": "\u2192",
+ "rightarrowtail;": "\u21a3",
+ "rightharpoondown;": "\u21c1",
+ "rightharpoonup;": "\u21c0",
+ "rightleftarrows;": "\u21c4",
+ "rightleftharpoons;": "\u21cc",
+ "rightrightarrows;": "\u21c9",
+ "rightsquigarrow;": "\u219d",
+ "rightthreetimes;": "\u22cc",
+ "ring;": "\u02da",
+ "risingdotseq;": "\u2253",
+ "rlarr;": "\u21c4",
+ "rlhar;": "\u21cc",
+ "rlm;": "\u200f",
+ "rmoust;": "\u23b1",
+ "rmoustache;": "\u23b1",
+ "rnmid;": "\u2aee",
+ "roang;": "\u27ed",
+ "roarr;": "\u21fe",
+ "robrk;": "\u27e7",
+ "ropar;": "\u2986",
+ "ropf;": "\U0001d563",
+ "roplus;": "\u2a2e",
+ "rotimes;": "\u2a35",
+ "rpar;": ")",
+ "rpargt;": "\u2994",
+ "rppolint;": "\u2a12",
+ "rrarr;": "\u21c9",
+ "rsaquo;": "\u203a",
+ "rscr;": "\U0001d4c7",
+ "rsh;": "\u21b1",
+ "rsqb;": "]",
+ "rsquo;": "\u2019",
+ "rsquor;": "\u2019",
+ "rthree;": "\u22cc",
+ "rtimes;": "\u22ca",
+ "rtri;": "\u25b9",
+ "rtrie;": "\u22b5",
+ "rtrif;": "\u25b8",
+ "rtriltri;": "\u29ce",
+ "ruluhar;": "\u2968",
+ "rx;": "\u211e",
+ "sacute;": "\u015b",
+ "sbquo;": "\u201a",
+ "sc;": "\u227b",
+ "scE;": "\u2ab4",
+ "scap;": "\u2ab8",
+ "scaron;": "\u0161",
+ "sccue;": "\u227d",
+ "sce;": "\u2ab0",
+ "scedil;": "\u015f",
+ "scirc;": "\u015d",
+ "scnE;": "\u2ab6",
+ "scnap;": "\u2aba",
+ "scnsim;": "\u22e9",
+ "scpolint;": "\u2a13",
+ "scsim;": "\u227f",
+ "scy;": "\u0441",
+ "sdot;": "\u22c5",
+ "sdotb;": "\u22a1",
+ "sdote;": "\u2a66",
+ "seArr;": "\u21d8",
+ "searhk;": "\u2925",
+ "searr;": "\u2198",
+ "searrow;": "\u2198",
+ "sect": "\xa7",
+ "sect;": "\xa7",
+ "semi;": ";",
+ "seswar;": "\u2929",
+ "setminus;": "\u2216",
+ "setmn;": "\u2216",
+ "sext;": "\u2736",
+ "sfr;": "\U0001d530",
+ "sfrown;": "\u2322",
+ "sharp;": "\u266f",
+ "shchcy;": "\u0449",
+ "shcy;": "\u0448",
+ "shortmid;": "\u2223",
+ "shortparallel;": "\u2225",
+ "shy": "\xad",
+ "shy;": "\xad",
+ "sigma;": "\u03c3",
+ "sigmaf;": "\u03c2",
+ "sigmav;": "\u03c2",
+ "sim;": "\u223c",
+ "simdot;": "\u2a6a",
+ "sime;": "\u2243",
+ "simeq;": "\u2243",
+ "simg;": "\u2a9e",
+ "simgE;": "\u2aa0",
+ "siml;": "\u2a9d",
+ "simlE;": "\u2a9f",
+ "simne;": "\u2246",
+ "simplus;": "\u2a24",
+ "simrarr;": "\u2972",
+ "slarr;": "\u2190",
+ "smallsetminus;": "\u2216",
+ "smashp;": "\u2a33",
+ "smeparsl;": "\u29e4",
+ "smid;": "\u2223",
+ "smile;": "\u2323",
+ "smt;": "\u2aaa",
+ "smte;": "\u2aac",
+ "smtes;": "\u2aac\ufe00",
+ "softcy;": "\u044c",
+ "sol;": "/",
+ "solb;": "\u29c4",
+ "solbar;": "\u233f",
+ "sopf;": "\U0001d564",
+ "spades;": "\u2660",
+ "spadesuit;": "\u2660",
+ "spar;": "\u2225",
+ "sqcap;": "\u2293",
+ "sqcaps;": "\u2293\ufe00",
+ "sqcup;": "\u2294",
+ "sqcups;": "\u2294\ufe00",
+ "sqsub;": "\u228f",
+ "sqsube;": "\u2291",
+ "sqsubset;": "\u228f",
+ "sqsubseteq;": "\u2291",
+ "sqsup;": "\u2290",
+ "sqsupe;": "\u2292",
+ "sqsupset;": "\u2290",
+ "sqsupseteq;": "\u2292",
+ "squ;": "\u25a1",
+ "square;": "\u25a1",
+ "squarf;": "\u25aa",
+ "squf;": "\u25aa",
+ "srarr;": "\u2192",
+ "sscr;": "\U0001d4c8",
+ "ssetmn;": "\u2216",
+ "ssmile;": "\u2323",
+ "sstarf;": "\u22c6",
+ "star;": "\u2606",
+ "starf;": "\u2605",
+ "straightepsilon;": "\u03f5",
+ "straightphi;": "\u03d5",
+ "strns;": "\xaf",
+ "sub;": "\u2282",
+ "subE;": "\u2ac5",
+ "subdot;": "\u2abd",
+ "sube;": "\u2286",
+ "subedot;": "\u2ac3",
+ "submult;": "\u2ac1",
+ "subnE;": "\u2acb",
+ "subne;": "\u228a",
+ "subplus;": "\u2abf",
+ "subrarr;": "\u2979",
+ "subset;": "\u2282",
+ "subseteq;": "\u2286",
+ "subseteqq;": "\u2ac5",
+ "subsetneq;": "\u228a",
+ "subsetneqq;": "\u2acb",
+ "subsim;": "\u2ac7",
+ "subsub;": "\u2ad5",
+ "subsup;": "\u2ad3",
+ "succ;": "\u227b",
+ "succapprox;": "\u2ab8",
+ "succcurlyeq;": "\u227d",
+ "succeq;": "\u2ab0",
+ "succnapprox;": "\u2aba",
+ "succneqq;": "\u2ab6",
+ "succnsim;": "\u22e9",
+ "succsim;": "\u227f",
+ "sum;": "\u2211",
+ "sung;": "\u266a",
+ "sup1": "\xb9",
+ "sup1;": "\xb9",
+ "sup2": "\xb2",
+ "sup2;": "\xb2",
+ "sup3": "\xb3",
+ "sup3;": "\xb3",
+ "sup;": "\u2283",
+ "supE;": "\u2ac6",
+ "supdot;": "\u2abe",
+ "supdsub;": "\u2ad8",
+ "supe;": "\u2287",
+ "supedot;": "\u2ac4",
+ "suphsol;": "\u27c9",
+ "suphsub;": "\u2ad7",
+ "suplarr;": "\u297b",
+ "supmult;": "\u2ac2",
+ "supnE;": "\u2acc",
+ "supne;": "\u228b",
+ "supplus;": "\u2ac0",
+ "supset;": "\u2283",
+ "supseteq;": "\u2287",
+ "supseteqq;": "\u2ac6",
+ "supsetneq;": "\u228b",
+ "supsetneqq;": "\u2acc",
+ "supsim;": "\u2ac8",
+ "supsub;": "\u2ad4",
+ "supsup;": "\u2ad6",
+ "swArr;": "\u21d9",
+ "swarhk;": "\u2926",
+ "swarr;": "\u2199",
+ "swarrow;": "\u2199",
+ "swnwar;": "\u292a",
+ "szlig": "\xdf",
+ "szlig;": "\xdf",
+ "target;": "\u2316",
+ "tau;": "\u03c4",
+ "tbrk;": "\u23b4",
+ "tcaron;": "\u0165",
+ "tcedil;": "\u0163",
+ "tcy;": "\u0442",
+ "tdot;": "\u20db",
+ "telrec;": "\u2315",
+ "tfr;": "\U0001d531",
+ "there4;": "\u2234",
+ "therefore;": "\u2234",
+ "theta;": "\u03b8",
+ "thetasym;": "\u03d1",
+ "thetav;": "\u03d1",
+ "thickapprox;": "\u2248",
+ "thicksim;": "\u223c",
+ "thinsp;": "\u2009",
+ "thkap;": "\u2248",
+ "thksim;": "\u223c",
+ "thorn": "\xfe",
+ "thorn;": "\xfe",
+ "tilde;": "\u02dc",
+ "times": "\xd7",
+ "times;": "\xd7",
+ "timesb;": "\u22a0",
+ "timesbar;": "\u2a31",
+ "timesd;": "\u2a30",
+ "tint;": "\u222d",
+ "toea;": "\u2928",
+ "top;": "\u22a4",
+ "topbot;": "\u2336",
+ "topcir;": "\u2af1",
+ "topf;": "\U0001d565",
+ "topfork;": "\u2ada",
+ "tosa;": "\u2929",
+ "tprime;": "\u2034",
+ "trade;": "\u2122",
+ "triangle;": "\u25b5",
+ "triangledown;": "\u25bf",
+ "triangleleft;": "\u25c3",
+ "trianglelefteq;": "\u22b4",
+ "triangleq;": "\u225c",
+ "triangleright;": "\u25b9",
+ "trianglerighteq;": "\u22b5",
+ "tridot;": "\u25ec",
+ "trie;": "\u225c",
+ "triminus;": "\u2a3a",
+ "triplus;": "\u2a39",
+ "trisb;": "\u29cd",
+ "tritime;": "\u2a3b",
+ "trpezium;": "\u23e2",
+ "tscr;": "\U0001d4c9",
+ "tscy;": "\u0446",
+ "tshcy;": "\u045b",
+ "tstrok;": "\u0167",
+ "twixt;": "\u226c",
+ "twoheadleftarrow;": "\u219e",
+ "twoheadrightarrow;": "\u21a0",
+ "uArr;": "\u21d1",
+ "uHar;": "\u2963",
+ "uacute": "\xfa",
+ "uacute;": "\xfa",
+ "uarr;": "\u2191",
+ "ubrcy;": "\u045e",
+ "ubreve;": "\u016d",
+ "ucirc": "\xfb",
+ "ucirc;": "\xfb",
+ "ucy;": "\u0443",
+ "udarr;": "\u21c5",
+ "udblac;": "\u0171",
+ "udhar;": "\u296e",
+ "ufisht;": "\u297e",
+ "ufr;": "\U0001d532",
+ "ugrave": "\xf9",
+ "ugrave;": "\xf9",
+ "uharl;": "\u21bf",
+ "uharr;": "\u21be",
+ "uhblk;": "\u2580",
+ "ulcorn;": "\u231c",
+ "ulcorner;": "\u231c",
+ "ulcrop;": "\u230f",
+ "ultri;": "\u25f8",
+ "umacr;": "\u016b",
+ "uml": "\xa8",
+ "uml;": "\xa8",
+ "uogon;": "\u0173",
+ "uopf;": "\U0001d566",
+ "uparrow;": "\u2191",
+ "updownarrow;": "\u2195",
+ "upharpoonleft;": "\u21bf",
+ "upharpoonright;": "\u21be",
+ "uplus;": "\u228e",
+ "upsi;": "\u03c5",
+ "upsih;": "\u03d2",
+ "upsilon;": "\u03c5",
+ "upuparrows;": "\u21c8",
+ "urcorn;": "\u231d",
+ "urcorner;": "\u231d",
+ "urcrop;": "\u230e",
+ "uring;": "\u016f",
+ "urtri;": "\u25f9",
+ "uscr;": "\U0001d4ca",
+ "utdot;": "\u22f0",
+ "utilde;": "\u0169",
+ "utri;": "\u25b5",
+ "utrif;": "\u25b4",
+ "uuarr;": "\u21c8",
+ "uuml": "\xfc",
+ "uuml;": "\xfc",
+ "uwangle;": "\u29a7",
+ "vArr;": "\u21d5",
+ "vBar;": "\u2ae8",
+ "vBarv;": "\u2ae9",
+ "vDash;": "\u22a8",
+ "vangrt;": "\u299c",
+ "varepsilon;": "\u03f5",
+ "varkappa;": "\u03f0",
+ "varnothing;": "\u2205",
+ "varphi;": "\u03d5",
+ "varpi;": "\u03d6",
+ "varpropto;": "\u221d",
+ "varr;": "\u2195",
+ "varrho;": "\u03f1",
+ "varsigma;": "\u03c2",
+ "varsubsetneq;": "\u228a\ufe00",
+ "varsubsetneqq;": "\u2acb\ufe00",
+ "varsupsetneq;": "\u228b\ufe00",
+ "varsupsetneqq;": "\u2acc\ufe00",
+ "vartheta;": "\u03d1",
+ "vartriangleleft;": "\u22b2",
+ "vartriangleright;": "\u22b3",
+ "vcy;": "\u0432",
+ "vdash;": "\u22a2",
+ "vee;": "\u2228",
+ "veebar;": "\u22bb",
+ "veeeq;": "\u225a",
+ "vellip;": "\u22ee",
+ "verbar;": "|",
+ "vert;": "|",
+ "vfr;": "\U0001d533",
+ "vltri;": "\u22b2",
+ "vnsub;": "\u2282\u20d2",
+ "vnsup;": "\u2283\u20d2",
+ "vopf;": "\U0001d567",
+ "vprop;": "\u221d",
+ "vrtri;": "\u22b3",
+ "vscr;": "\U0001d4cb",
+ "vsubnE;": "\u2acb\ufe00",
+ "vsubne;": "\u228a\ufe00",
+ "vsupnE;": "\u2acc\ufe00",
+ "vsupne;": "\u228b\ufe00",
+ "vzigzag;": "\u299a",
+ "wcirc;": "\u0175",
+ "wedbar;": "\u2a5f",
+ "wedge;": "\u2227",
+ "wedgeq;": "\u2259",
+ "weierp;": "\u2118",
+ "wfr;": "\U0001d534",
+ "wopf;": "\U0001d568",
+ "wp;": "\u2118",
+ "wr;": "\u2240",
+ "wreath;": "\u2240",
+ "wscr;": "\U0001d4cc",
+ "xcap;": "\u22c2",
+ "xcirc;": "\u25ef",
+ "xcup;": "\u22c3",
+ "xdtri;": "\u25bd",
+ "xfr;": "\U0001d535",
+ "xhArr;": "\u27fa",
+ "xharr;": "\u27f7",
+ "xi;": "\u03be",
+ "xlArr;": "\u27f8",
+ "xlarr;": "\u27f5",
+ "xmap;": "\u27fc",
+ "xnis;": "\u22fb",
+ "xodot;": "\u2a00",
+ "xopf;": "\U0001d569",
+ "xoplus;": "\u2a01",
+ "xotime;": "\u2a02",
+ "xrArr;": "\u27f9",
+ "xrarr;": "\u27f6",
+ "xscr;": "\U0001d4cd",
+ "xsqcup;": "\u2a06",
+ "xuplus;": "\u2a04",
+ "xutri;": "\u25b3",
+ "xvee;": "\u22c1",
+ "xwedge;": "\u22c0",
+ "yacute": "\xfd",
+ "yacute;": "\xfd",
+ "yacy;": "\u044f",
+ "ycirc;": "\u0177",
+ "ycy;": "\u044b",
+ "yen": "\xa5",
+ "yen;": "\xa5",
+ "yfr;": "\U0001d536",
+ "yicy;": "\u0457",
+ "yopf;": "\U0001d56a",
+ "yscr;": "\U0001d4ce",
+ "yucy;": "\u044e",
+ "yuml": "\xff",
+ "yuml;": "\xff",
+ "zacute;": "\u017a",
+ "zcaron;": "\u017e",
+ "zcy;": "\u0437",
+ "zdot;": "\u017c",
+ "zeetrf;": "\u2128",
+ "zeta;": "\u03b6",
+ "zfr;": "\U0001d537",
+ "zhcy;": "\u0436",
+ "zigrarr;": "\u21dd",
+ "zopf;": "\U0001d56b",
+ "zscr;": "\U0001d4cf",
+ "zwj;": "\u200d",
+ "zwnj;": "\u200c",
+}
+
+replacementCharacters = {
+ 0x0: "\uFFFD",
+ 0x0d: "\u000D",
+ 0x80: "\u20AC",
+ 0x81: "\u0081",
+ 0x81: "\u0081",
+ 0x82: "\u201A",
+ 0x83: "\u0192",
+ 0x84: "\u201E",
+ 0x85: "\u2026",
+ 0x86: "\u2020",
+ 0x87: "\u2021",
+ 0x88: "\u02C6",
+ 0x89: "\u2030",
+ 0x8A: "\u0160",
+ 0x8B: "\u2039",
+ 0x8C: "\u0152",
+ 0x8D: "\u008D",
+ 0x8E: "\u017D",
+ 0x8F: "\u008F",
+ 0x90: "\u0090",
+ 0x91: "\u2018",
+ 0x92: "\u2019",
+ 0x93: "\u201C",
+ 0x94: "\u201D",
+ 0x95: "\u2022",
+ 0x96: "\u2013",
+ 0x97: "\u2014",
+ 0x98: "\u02DC",
+ 0x99: "\u2122",
+ 0x9A: "\u0161",
+ 0x9B: "\u203A",
+ 0x9C: "\u0153",
+ 0x9D: "\u009D",
+ 0x9E: "\u017E",
+ 0x9F: "\u0178",
+}
+
+encodings = {
+ '437': 'cp437',
+ '850': 'cp850',
+ '852': 'cp852',
+ '855': 'cp855',
+ '857': 'cp857',
+ '860': 'cp860',
+ '861': 'cp861',
+ '862': 'cp862',
+ '863': 'cp863',
+ '865': 'cp865',
+ '866': 'cp866',
+ '869': 'cp869',
+ 'ansix341968': 'ascii',
+ 'ansix341986': 'ascii',
+ 'arabic': 'iso8859-6',
+ 'ascii': 'ascii',
+ 'asmo708': 'iso8859-6',
+ 'big5': 'big5',
+ 'big5hkscs': 'big5hkscs',
+ 'chinese': 'gbk',
+ 'cp037': 'cp037',
+ 'cp1026': 'cp1026',
+ 'cp154': 'ptcp154',
+ 'cp367': 'ascii',
+ 'cp424': 'cp424',
+ 'cp437': 'cp437',
+ 'cp500': 'cp500',
+ 'cp775': 'cp775',
+ 'cp819': 'windows-1252',
+ 'cp850': 'cp850',
+ 'cp852': 'cp852',
+ 'cp855': 'cp855',
+ 'cp857': 'cp857',
+ 'cp860': 'cp860',
+ 'cp861': 'cp861',
+ 'cp862': 'cp862',
+ 'cp863': 'cp863',
+ 'cp864': 'cp864',
+ 'cp865': 'cp865',
+ 'cp866': 'cp866',
+ 'cp869': 'cp869',
+ 'cp936': 'gbk',
+ 'cpgr': 'cp869',
+ 'cpis': 'cp861',
+ 'csascii': 'ascii',
+ 'csbig5': 'big5',
+ 'cseuckr': 'cp949',
+ 'cseucpkdfmtjapanese': 'euc_jp',
+ 'csgb2312': 'gbk',
+ 'cshproman8': 'hp-roman8',
+ 'csibm037': 'cp037',
+ 'csibm1026': 'cp1026',
+ 'csibm424': 'cp424',
+ 'csibm500': 'cp500',
+ 'csibm855': 'cp855',
+ 'csibm857': 'cp857',
+ 'csibm860': 'cp860',
+ 'csibm861': 'cp861',
+ 'csibm863': 'cp863',
+ 'csibm864': 'cp864',
+ 'csibm865': 'cp865',
+ 'csibm866': 'cp866',
+ 'csibm869': 'cp869',
+ 'csiso2022jp': 'iso2022_jp',
+ 'csiso2022jp2': 'iso2022_jp_2',
+ 'csiso2022kr': 'iso2022_kr',
+ 'csiso58gb231280': 'gbk',
+ 'csisolatin1': 'windows-1252',
+ 'csisolatin2': 'iso8859-2',
+ 'csisolatin3': 'iso8859-3',
+ 'csisolatin4': 'iso8859-4',
+ 'csisolatin5': 'windows-1254',
+ 'csisolatin6': 'iso8859-10',
+ 'csisolatinarabic': 'iso8859-6',
+ 'csisolatincyrillic': 'iso8859-5',
+ 'csisolatingreek': 'iso8859-7',
+ 'csisolatinhebrew': 'iso8859-8',
+ 'cskoi8r': 'koi8-r',
+ 'csksc56011987': 'cp949',
+ 'cspc775baltic': 'cp775',
+ 'cspc850multilingual': 'cp850',
+ 'cspc862latinhebrew': 'cp862',
+ 'cspc8codepage437': 'cp437',
+ 'cspcp852': 'cp852',
+ 'csptcp154': 'ptcp154',
+ 'csshiftjis': 'shift_jis',
+ 'csunicode11utf7': 'utf-7',
+ 'cyrillic': 'iso8859-5',
+ 'cyrillicasian': 'ptcp154',
+ 'ebcdiccpbe': 'cp500',
+ 'ebcdiccpca': 'cp037',
+ 'ebcdiccpch': 'cp500',
+ 'ebcdiccphe': 'cp424',
+ 'ebcdiccpnl': 'cp037',
+ 'ebcdiccpus': 'cp037',
+ 'ebcdiccpwt': 'cp037',
+ 'ecma114': 'iso8859-6',
+ 'ecma118': 'iso8859-7',
+ 'elot928': 'iso8859-7',
+ 'eucjp': 'euc_jp',
+ 'euckr': 'cp949',
+ 'extendedunixcodepackedformatforjapanese': 'euc_jp',
+ 'gb18030': 'gb18030',
+ 'gb2312': 'gbk',
+ 'gb231280': 'gbk',
+ 'gbk': 'gbk',
+ 'greek': 'iso8859-7',
+ 'greek8': 'iso8859-7',
+ 'hebrew': 'iso8859-8',
+ 'hproman8': 'hp-roman8',
+ 'hzgb2312': 'hz',
+ 'ibm037': 'cp037',
+ 'ibm1026': 'cp1026',
+ 'ibm367': 'ascii',
+ 'ibm424': 'cp424',
+ 'ibm437': 'cp437',
+ 'ibm500': 'cp500',
+ 'ibm775': 'cp775',
+ 'ibm819': 'windows-1252',
+ 'ibm850': 'cp850',
+ 'ibm852': 'cp852',
+ 'ibm855': 'cp855',
+ 'ibm857': 'cp857',
+ 'ibm860': 'cp860',
+ 'ibm861': 'cp861',
+ 'ibm862': 'cp862',
+ 'ibm863': 'cp863',
+ 'ibm864': 'cp864',
+ 'ibm865': 'cp865',
+ 'ibm866': 'cp866',
+ 'ibm869': 'cp869',
+ 'iso2022jp': 'iso2022_jp',
+ 'iso2022jp2': 'iso2022_jp_2',
+ 'iso2022kr': 'iso2022_kr',
+ 'iso646irv1991': 'ascii',
+ 'iso646us': 'ascii',
+ 'iso88591': 'windows-1252',
+ 'iso885910': 'iso8859-10',
+ 'iso8859101992': 'iso8859-10',
+ 'iso885911987': 'windows-1252',
+ 'iso885913': 'iso8859-13',
+ 'iso885914': 'iso8859-14',
+ 'iso8859141998': 'iso8859-14',
+ 'iso885915': 'iso8859-15',
+ 'iso885916': 'iso8859-16',
+ 'iso8859162001': 'iso8859-16',
+ 'iso88592': 'iso8859-2',
+ 'iso885921987': 'iso8859-2',
+ 'iso88593': 'iso8859-3',
+ 'iso885931988': 'iso8859-3',
+ 'iso88594': 'iso8859-4',
+ 'iso885941988': 'iso8859-4',
+ 'iso88595': 'iso8859-5',
+ 'iso885951988': 'iso8859-5',
+ 'iso88596': 'iso8859-6',
+ 'iso885961987': 'iso8859-6',
+ 'iso88597': 'iso8859-7',
+ 'iso885971987': 'iso8859-7',
+ 'iso88598': 'iso8859-8',
+ 'iso885981988': 'iso8859-8',
+ 'iso88599': 'windows-1254',
+ 'iso885991989': 'windows-1254',
+ 'isoceltic': 'iso8859-14',
+ 'isoir100': 'windows-1252',
+ 'isoir101': 'iso8859-2',
+ 'isoir109': 'iso8859-3',
+ 'isoir110': 'iso8859-4',
+ 'isoir126': 'iso8859-7',
+ 'isoir127': 'iso8859-6',
+ 'isoir138': 'iso8859-8',
+ 'isoir144': 'iso8859-5',
+ 'isoir148': 'windows-1254',
+ 'isoir149': 'cp949',
+ 'isoir157': 'iso8859-10',
+ 'isoir199': 'iso8859-14',
+ 'isoir226': 'iso8859-16',
+ 'isoir58': 'gbk',
+ 'isoir6': 'ascii',
+ 'koi8r': 'koi8-r',
+ 'koi8u': 'koi8-u',
+ 'korean': 'cp949',
+ 'ksc5601': 'cp949',
+ 'ksc56011987': 'cp949',
+ 'ksc56011989': 'cp949',
+ 'l1': 'windows-1252',
+ 'l10': 'iso8859-16',
+ 'l2': 'iso8859-2',
+ 'l3': 'iso8859-3',
+ 'l4': 'iso8859-4',
+ 'l5': 'windows-1254',
+ 'l6': 'iso8859-10',
+ 'l8': 'iso8859-14',
+ 'latin1': 'windows-1252',
+ 'latin10': 'iso8859-16',
+ 'latin2': 'iso8859-2',
+ 'latin3': 'iso8859-3',
+ 'latin4': 'iso8859-4',
+ 'latin5': 'windows-1254',
+ 'latin6': 'iso8859-10',
+ 'latin8': 'iso8859-14',
+ 'latin9': 'iso8859-15',
+ 'ms936': 'gbk',
+ 'mskanji': 'shift_jis',
+ 'pt154': 'ptcp154',
+ 'ptcp154': 'ptcp154',
+ 'r8': 'hp-roman8',
+ 'roman8': 'hp-roman8',
+ 'shiftjis': 'shift_jis',
+ 'tis620': 'cp874',
+ 'unicode11utf7': 'utf-7',
+ 'us': 'ascii',
+ 'usascii': 'ascii',
+ 'utf16': 'utf-16',
+ 'utf16be': 'utf-16-be',
+ 'utf16le': 'utf-16-le',
+ 'utf8': 'utf-8',
+ 'windows1250': 'cp1250',
+ 'windows1251': 'cp1251',
+ 'windows1252': 'cp1252',
+ 'windows1253': 'cp1253',
+ 'windows1254': 'cp1254',
+ 'windows1255': 'cp1255',
+ 'windows1256': 'cp1256',
+ 'windows1257': 'cp1257',
+ 'windows1258': 'cp1258',
+ 'windows936': 'gbk',
+ 'x-x-big5': 'big5'}
+
+tokenTypes = {
+ "Doctype": 0,
+ "Characters": 1,
+ "SpaceCharacters": 2,
+ "StartTag": 3,
+ "EndTag": 4,
+ "EmptyTag": 5,
+ "Comment": 6,
+ "ParseError": 7
+}
+
+tagTokenTypes = frozenset([tokenTypes["StartTag"], tokenTypes["EndTag"],
+ tokenTypes["EmptyTag"]])
+
+
+prefixes = dict([(v, k) for k, v in namespaces.items()])
+prefixes["http://www.w3.org/1998/Math/MathML"] = "math"
+
+
+class DataLossWarning(UserWarning):
+ pass
+
+
+class ReparseException(Exception):
+ pass
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/__init__.py
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/_base.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/_base.py
new file mode 100644
index 00000000000..c7dbaed0fab
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/_base.py
@@ -0,0 +1,12 @@
+from __future__ import absolute_import, division, unicode_literals
+
+
+class Filter(object):
+ def __init__(self, source):
+ self.source = source
+
+ def __iter__(self):
+ return iter(self.source)
+
+ def __getattr__(self, name):
+ return getattr(self.source, name)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py
new file mode 100644
index 00000000000..fed6996c1d9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py
@@ -0,0 +1,20 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import _base
+
+try:
+ from collections import OrderedDict
+except ImportError:
+ from ordereddict import OrderedDict
+
+
+class Filter(_base.Filter):
+ def __iter__(self):
+ for token in _base.Filter.__iter__(self):
+ if token["type"] in ("StartTag", "EmptyTag"):
+ attrs = OrderedDict()
+ for name, value in sorted(token["data"].items(),
+ key=lambda x: x[0]):
+ attrs[name] = value
+ token["data"] = attrs
+ yield token
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py
new file mode 100644
index 00000000000..ca33b70b530
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py
@@ -0,0 +1,65 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import _base
+
+
+class Filter(_base.Filter):
+ def __init__(self, source, encoding):
+ _base.Filter.__init__(self, source)
+ self.encoding = encoding
+
+ def __iter__(self):
+ state = "pre_head"
+ meta_found = (self.encoding is None)
+ pending = []
+
+ for token in _base.Filter.__iter__(self):
+ type = token["type"]
+ if type == "StartTag":
+ if token["name"].lower() == "head":
+ state = "in_head"
+
+ elif type == "EmptyTag":
+ if token["name"].lower() == "meta":
+ # replace charset with actual encoding
+ has_http_equiv_content_type = False
+ for (namespace, name), value in token["data"].items():
+ if namespace is not None:
+ continue
+ elif name.lower() == 'charset':
+ token["data"][(namespace, name)] = self.encoding
+ meta_found = True
+ break
+ elif name == 'http-equiv' and value.lower() == 'content-type':
+ has_http_equiv_content_type = True
+ else:
+ if has_http_equiv_content_type and (None, "content") in token["data"]:
+ token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding
+ meta_found = True
+
+ elif token["name"].lower() == "head" and not meta_found:
+ # insert meta into empty head
+ yield {"type": "StartTag", "name": "head",
+ "data": token["data"]}
+ yield {"type": "EmptyTag", "name": "meta",
+ "data": {(None, "charset"): self.encoding}}
+ yield {"type": "EndTag", "name": "head"}
+ meta_found = True
+ continue
+
+ elif type == "EndTag":
+ if token["name"].lower() == "head" and pending:
+ # insert meta into head (if necessary) and flush pending queue
+ yield pending.pop(0)
+ if not meta_found:
+ yield {"type": "EmptyTag", "name": "meta",
+ "data": {(None, "charset"): self.encoding}}
+ while pending:
+ yield pending.pop(0)
+ meta_found = True
+ state = "post_head"
+
+ if state == "in_head":
+ pending.append(token)
+ else:
+ yield token
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/lint.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/lint.py
new file mode 100644
index 00000000000..8884696dc51
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/lint.py
@@ -0,0 +1,90 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import _base
+from ..constants import cdataElements, rcdataElements, voidElements
+
+from ..constants import spaceCharacters
+spaceCharacters = "".join(spaceCharacters)
+
+
+class LintError(Exception):
+ pass
+
+
+class Filter(_base.Filter):
+ def __iter__(self):
+ open_elements = []
+ contentModelFlag = "PCDATA"
+ for token in _base.Filter.__iter__(self):
+ type = token["type"]
+ if type in ("StartTag", "EmptyTag"):
+ name = token["name"]
+ if contentModelFlag != "PCDATA":
+ raise LintError("StartTag not in PCDATA content model flag: %(tag)s" % {"tag": name})
+ if not isinstance(name, str):
+ raise LintError("Tag name is not a string: %(tag)r" % {"tag": name})
+ if not name:
+ raise LintError("Empty tag name")
+ if type == "StartTag" and name in voidElements:
+ raise LintError("Void element reported as StartTag token: %(tag)s" % {"tag": name})
+ elif type == "EmptyTag" and name not in voidElements:
+ raise LintError("Non-void element reported as EmptyTag token: %(tag)s" % {"tag": token["name"]})
+ if type == "StartTag":
+ open_elements.append(name)
+ for name, value in token["data"]:
+ if not isinstance(name, str):
+ raise LintError("Attribute name is not a string: %(name)r" % {"name": name})
+ if not name:
+ raise LintError("Empty attribute name")
+ if not isinstance(value, str):
+ raise LintError("Attribute value is not a string: %(value)r" % {"value": value})
+ if name in cdataElements:
+ contentModelFlag = "CDATA"
+ elif name in rcdataElements:
+ contentModelFlag = "RCDATA"
+ elif name == "plaintext":
+ contentModelFlag = "PLAINTEXT"
+
+ elif type == "EndTag":
+ name = token["name"]
+ if not isinstance(name, str):
+ raise LintError("Tag name is not a string: %(tag)r" % {"tag": name})
+ if not name:
+ raise LintError("Empty tag name")
+ if name in voidElements:
+ raise LintError("Void element reported as EndTag token: %(tag)s" % {"tag": name})
+ start_name = open_elements.pop()
+ if start_name != name:
+ raise LintError("EndTag (%(end)s) does not match StartTag (%(start)s)" % {"end": name, "start": start_name})
+ contentModelFlag = "PCDATA"
+
+ elif type == "Comment":
+ if contentModelFlag != "PCDATA":
+ raise LintError("Comment not in PCDATA content model flag")
+
+ elif type in ("Characters", "SpaceCharacters"):
+ data = token["data"]
+ if not isinstance(data, str):
+ raise LintError("Attribute name is not a string: %(name)r" % {"name": data})
+ if not data:
+ raise LintError("%(type)s token with empty data" % {"type": type})
+ if type == "SpaceCharacters":
+ data = data.strip(spaceCharacters)
+ if data:
+ raise LintError("Non-space character(s) found in SpaceCharacters token: %(token)r" % {"token": data})
+
+ elif type == "Doctype":
+ name = token["name"]
+ if contentModelFlag != "PCDATA":
+ raise LintError("Doctype not in PCDATA content model flag: %(name)s" % {"name": name})
+ if not isinstance(name, str):
+ raise LintError("Tag name is not a string: %(tag)r" % {"tag": name})
+ # XXX: what to do with token["data"] ?
+
+ elif type in ("ParseError", "SerializeError"):
+ pass
+
+ else:
+ raise LintError("Unknown token type: %(type)s" % {"type": type})
+
+ yield token
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py
new file mode 100644
index 00000000000..fefe0b3097b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py
@@ -0,0 +1,205 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import _base
+
+
+class Filter(_base.Filter):
+ def slider(self):
+ previous1 = previous2 = None
+ for token in self.source:
+ if previous1 is not None:
+ yield previous2, previous1, token
+ previous2 = previous1
+ previous1 = token
+ yield previous2, previous1, None
+
+ def __iter__(self):
+ for previous, token, next in self.slider():
+ type = token["type"]
+ if type == "StartTag":
+ if (token["data"] or
+ not self.is_optional_start(token["name"], previous, next)):
+ yield token
+ elif type == "EndTag":
+ if not self.is_optional_end(token["name"], next):
+ yield token
+ else:
+ yield token
+
+ def is_optional_start(self, tagname, previous, next):
+ type = next and next["type"] or None
+ if tagname in 'html':
+ # An html element's start tag may be omitted if the first thing
+ # inside the html element is not a space character or a comment.
+ return type not in ("Comment", "SpaceCharacters")
+ elif tagname == 'head':
+ # A head element's start tag may be omitted if the first thing
+ # inside the head element is an element.
+ # XXX: we also omit the start tag if the head element is empty
+ if type in ("StartTag", "EmptyTag"):
+ return True
+ elif type == "EndTag":
+ return next["name"] == "head"
+ elif tagname == 'body':
+ # A body element's start tag may be omitted if the first thing
+ # inside the body element is not a space character or a comment,
+ # except if the first thing inside the body element is a script
+ # or style element and the node immediately preceding the body
+ # element is a head element whose end tag has been omitted.
+ if type in ("Comment", "SpaceCharacters"):
+ return False
+ elif type == "StartTag":
+ # XXX: we do not look at the preceding event, so we never omit
+ # the body element's start tag if it's followed by a script or
+ # a style element.
+ return next["name"] not in ('script', 'style')
+ else:
+ return True
+ elif tagname == 'colgroup':
+ # A colgroup element's start tag may be omitted if the first thing
+ # inside the colgroup element is a col element, and if the element
+ # is not immediately preceeded by another colgroup element whose
+ # end tag has been omitted.
+ if type in ("StartTag", "EmptyTag"):
+ # XXX: we do not look at the preceding event, so instead we never
+ # omit the colgroup element's end tag when it is immediately
+ # followed by another colgroup element. See is_optional_end.
+ return next["name"] == "col"
+ else:
+ return False
+ elif tagname == 'tbody':
+ # A tbody element's start tag may be omitted if the first thing
+ # inside the tbody element is a tr element, and if the element is
+ # not immediately preceeded by a tbody, thead, or tfoot element
+ # whose end tag has been omitted.
+ if type == "StartTag":
+ # omit the thead and tfoot elements' end tag when they are
+ # immediately followed by a tbody element. See is_optional_end.
+ if previous and previous['type'] == 'EndTag' and \
+ previous['name'] in ('tbody', 'thead', 'tfoot'):
+ return False
+ return next["name"] == 'tr'
+ else:
+ return False
+ return False
+
+ def is_optional_end(self, tagname, next):
+ type = next and next["type"] or None
+ if tagname in ('html', 'head', 'body'):
+ # An html element's end tag may be omitted if the html element
+ # is not immediately followed by a space character or a comment.
+ return type not in ("Comment", "SpaceCharacters")
+ elif tagname in ('li', 'optgroup', 'tr'):
+ # A li element's end tag may be omitted if the li element is
+ # immediately followed by another li element or if there is
+ # no more content in the parent element.
+ # An optgroup element's end tag may be omitted if the optgroup
+ # element is immediately followed by another optgroup element,
+ # or if there is no more content in the parent element.
+ # A tr element's end tag may be omitted if the tr element is
+ # immediately followed by another tr element, or if there is
+ # no more content in the parent element.
+ if type == "StartTag":
+ return next["name"] == tagname
+ else:
+ return type == "EndTag" or type is None
+ elif tagname in ('dt', 'dd'):
+ # A dt element's end tag may be omitted if the dt element is
+ # immediately followed by another dt element or a dd element.
+ # A dd element's end tag may be omitted if the dd element is
+ # immediately followed by another dd element or a dt element,
+ # or if there is no more content in the parent element.
+ if type == "StartTag":
+ return next["name"] in ('dt', 'dd')
+ elif tagname == 'dd':
+ return type == "EndTag" or type is None
+ else:
+ return False
+ elif tagname == 'p':
+ # A p element's end tag may be omitted if the p element is
+ # immediately followed by an address, article, aside,
+ # blockquote, datagrid, dialog, dir, div, dl, fieldset,
+ # footer, form, h1, h2, h3, h4, h5, h6, header, hr, menu,
+ # nav, ol, p, pre, section, table, or ul, element, or if
+ # there is no more content in the parent element.
+ if type in ("StartTag", "EmptyTag"):
+ return next["name"] in ('address', 'article', 'aside',
+ 'blockquote', 'datagrid', 'dialog',
+ 'dir', 'div', 'dl', 'fieldset', 'footer',
+ 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+ 'header', 'hr', 'menu', 'nav', 'ol',
+ 'p', 'pre', 'section', 'table', 'ul')
+ else:
+ return type == "EndTag" or type is None
+ elif tagname == 'option':
+ # An option element's end tag may be omitted if the option
+ # element is immediately followed by another option element,
+ # or if it is immediately followed by an <code>optgroup</code>
+ # element, or if there is no more content in the parent
+ # element.
+ if type == "StartTag":
+ return next["name"] in ('option', 'optgroup')
+ else:
+ return type == "EndTag" or type is None
+ elif tagname in ('rt', 'rp'):
+ # An rt element's end tag may be omitted if the rt element is
+ # immediately followed by an rt or rp element, or if there is
+ # no more content in the parent element.
+ # An rp element's end tag may be omitted if the rp element is
+ # immediately followed by an rt or rp element, or if there is
+ # no more content in the parent element.
+ if type == "StartTag":
+ return next["name"] in ('rt', 'rp')
+ else:
+ return type == "EndTag" or type is None
+ elif tagname == 'colgroup':
+ # A colgroup element's end tag may be omitted if the colgroup
+ # element is not immediately followed by a space character or
+ # a comment.
+ if type in ("Comment", "SpaceCharacters"):
+ return False
+ elif type == "StartTag":
+ # XXX: we also look for an immediately following colgroup
+ # element. See is_optional_start.
+ return next["name"] != 'colgroup'
+ else:
+ return True
+ elif tagname in ('thead', 'tbody'):
+ # A thead element's end tag may be omitted if the thead element
+ # is immediately followed by a tbody or tfoot element.
+ # A tbody element's end tag may be omitted if the tbody element
+ # is immediately followed by a tbody or tfoot element, or if
+ # there is no more content in the parent element.
+ # A tfoot element's end tag may be omitted if the tfoot element
+ # is immediately followed by a tbody element, or if there is no
+ # more content in the parent element.
+ # XXX: we never omit the end tag when the following element is
+ # a tbody. See is_optional_start.
+ if type == "StartTag":
+ return next["name"] in ['tbody', 'tfoot']
+ elif tagname == 'tbody':
+ return type == "EndTag" or type is None
+ else:
+ return False
+ elif tagname == 'tfoot':
+ # A tfoot element's end tag may be omitted if the tfoot element
+ # is immediately followed by a tbody element, or if there is no
+ # more content in the parent element.
+ # XXX: we never omit the end tag when the following element is
+ # a tbody. See is_optional_start.
+ if type == "StartTag":
+ return next["name"] == 'tbody'
+ else:
+ return type == "EndTag" or type is None
+ elif tagname in ('td', 'th'):
+ # A td element's end tag may be omitted if the td element is
+ # immediately followed by a td or th element, or if there is
+ # no more content in the parent element.
+ # A th element's end tag may be omitted if the th element is
+ # immediately followed by a td or th element, or if there is
+ # no more content in the parent element.
+ if type == "StartTag":
+ return next["name"] in ('td', 'th')
+ else:
+ return type == "EndTag" or type is None
+ return False
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py
new file mode 100644
index 00000000000..b206b54e7a7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py
@@ -0,0 +1,12 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import _base
+from ..sanitizer import HTMLSanitizerMixin
+
+
+class Filter(_base.Filter, HTMLSanitizerMixin):
+ def __iter__(self):
+ for token in _base.Filter.__iter__(self):
+ token = self.sanitize_token(token)
+ if token:
+ yield token
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py
new file mode 100644
index 00000000000..dfc60eebd35
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py
@@ -0,0 +1,38 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import re
+
+from . import _base
+from ..constants import rcdataElements, spaceCharacters
+spaceCharacters = "".join(spaceCharacters)
+
+SPACES_REGEX = re.compile("[%s]+" % spaceCharacters)
+
+
+class Filter(_base.Filter):
+
+ spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements))
+
+ def __iter__(self):
+ preserve = 0
+ for token in _base.Filter.__iter__(self):
+ type = token["type"]
+ if type == "StartTag" \
+ and (preserve or token["name"] in self.spacePreserveElements):
+ preserve += 1
+
+ elif type == "EndTag" and preserve:
+ preserve -= 1
+
+ elif not preserve and type == "SpaceCharacters" and token["data"]:
+ # Test on token["data"] above to not introduce spaces where there were not
+ token["data"] = " "
+
+ elif not preserve and type == "Characters":
+ token["data"] = collapse_spaces(token["data"])
+
+ yield token
+
+
+def collapse_spaces(text):
+ return SPACES_REGEX.sub(' ', text)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/html5parser.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/html5parser.py
new file mode 100644
index 00000000000..12aa6a35e1a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/html5parser.py
@@ -0,0 +1,2724 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import with_metaclass
+
+import types
+
+from . import inputstream
+from . import tokenizer
+
+from . import treebuilders
+from .treebuilders._base import Marker
+
+from . import utils
+from . import constants
+from .constants import spaceCharacters, asciiUpper2Lower
+from .constants import specialElements
+from .constants import headingElements
+from .constants import cdataElements, rcdataElements
+from .constants import tokenTypes, ReparseException, namespaces
+from .constants import htmlIntegrationPointElements, mathmlTextIntegrationPointElements
+from .constants import adjustForeignAttributes as adjustForeignAttributesMap
+from .constants import E
+
+
+def parse(doc, treebuilder="etree", encoding=None,
+ namespaceHTMLElements=True):
+ """Parse a string or file-like object into a tree"""
+ tb = treebuilders.getTreeBuilder(treebuilder)
+ p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements)
+ return p.parse(doc, encoding=encoding)
+
+
+def parseFragment(doc, container="div", treebuilder="etree", encoding=None,
+ namespaceHTMLElements=True):
+ tb = treebuilders.getTreeBuilder(treebuilder)
+ p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements)
+ return p.parseFragment(doc, container=container, encoding=encoding)
+
+
+def method_decorator_metaclass(function):
+ class Decorated(type):
+ def __new__(meta, classname, bases, classDict):
+ for attributeName, attribute in classDict.items():
+ if isinstance(attribute, types.FunctionType):
+ attribute = function(attribute)
+
+ classDict[attributeName] = attribute
+ return type.__new__(meta, classname, bases, classDict)
+ return Decorated
+
+
+class HTMLParser(object):
+ """HTML parser. Generates a tree structure from a stream of (possibly
+ malformed) HTML"""
+
+ def __init__(self, tree=None, tokenizer=tokenizer.HTMLTokenizer,
+ strict=False, namespaceHTMLElements=True, debug=False):
+ """
+ strict - raise an exception when a parse error is encountered
+
+ tree - a treebuilder class controlling the type of tree that will be
+ returned. Built in treebuilders can be accessed through
+ html5lib.treebuilders.getTreeBuilder(treeType)
+
+ tokenizer - a class that provides a stream of tokens to the treebuilder.
+ This may be replaced for e.g. a sanitizer which converts some tags to
+ text
+ """
+
+ # Raise an exception on the first error encountered
+ self.strict = strict
+
+ if tree is None:
+ tree = treebuilders.getTreeBuilder("etree")
+ self.tree = tree(namespaceHTMLElements)
+ self.tokenizer_class = tokenizer
+ self.errors = []
+
+ self.phases = dict([(name, cls(self, self.tree)) for name, cls in
+ getPhases(debug).items()])
+
+ def _parse(self, stream, innerHTML=False, container="div",
+ encoding=None, parseMeta=True, useChardet=True, **kwargs):
+
+ self.innerHTMLMode = innerHTML
+ self.container = container
+ self.tokenizer = self.tokenizer_class(stream, encoding=encoding,
+ parseMeta=parseMeta,
+ useChardet=useChardet,
+ parser=self, **kwargs)
+ self.reset()
+
+ while True:
+ try:
+ self.mainLoop()
+ break
+ except ReparseException:
+ self.reset()
+
+ def reset(self):
+ self.tree.reset()
+ self.firstStartTag = False
+ self.errors = []
+ self.log = [] # only used with debug mode
+ # "quirks" / "limited quirks" / "no quirks"
+ self.compatMode = "no quirks"
+
+ if self.innerHTMLMode:
+ self.innerHTML = self.container.lower()
+
+ if self.innerHTML in cdataElements:
+ self.tokenizer.state = self.tokenizer.rcdataState
+ elif self.innerHTML in rcdataElements:
+ self.tokenizer.state = self.tokenizer.rawtextState
+ elif self.innerHTML == 'plaintext':
+ self.tokenizer.state = self.tokenizer.plaintextState
+ else:
+ # state already is data state
+ # self.tokenizer.state = self.tokenizer.dataState
+ pass
+ self.phase = self.phases["beforeHtml"]
+ self.phase.insertHtmlElement()
+ self.resetInsertionMode()
+ else:
+ self.innerHTML = False
+ self.phase = self.phases["initial"]
+
+ self.lastPhase = None
+
+ self.beforeRCDataPhase = None
+
+ self.framesetOK = True
+
+ @property
+ def documentEncoding(self):
+ """The name of the character encoding
+ that was used to decode the input stream,
+ or :obj:`None` if that is not determined yet.
+
+ """
+ if not hasattr(self, 'tokenizer'):
+ return None
+ return self.tokenizer.stream.charEncoding[0]
+
+ def isHTMLIntegrationPoint(self, element):
+ if (element.name == "annotation-xml" and
+ element.namespace == namespaces["mathml"]):
+ return ("encoding" in element.attributes and
+ element.attributes["encoding"].translate(
+ asciiUpper2Lower) in
+ ("text/html", "application/xhtml+xml"))
+ else:
+ return (element.namespace, element.name) in htmlIntegrationPointElements
+
+ def isMathMLTextIntegrationPoint(self, element):
+ return (element.namespace, element.name) in mathmlTextIntegrationPointElements
+
+ def mainLoop(self):
+ CharactersToken = tokenTypes["Characters"]
+ SpaceCharactersToken = tokenTypes["SpaceCharacters"]
+ StartTagToken = tokenTypes["StartTag"]
+ EndTagToken = tokenTypes["EndTag"]
+ CommentToken = tokenTypes["Comment"]
+ DoctypeToken = tokenTypes["Doctype"]
+ ParseErrorToken = tokenTypes["ParseError"]
+
+ for token in self.normalizedTokens():
+ new_token = token
+ while new_token is not None:
+ currentNode = self.tree.openElements[-1] if self.tree.openElements else None
+ currentNodeNamespace = currentNode.namespace if currentNode else None
+ currentNodeName = currentNode.name if currentNode else None
+
+ type = new_token["type"]
+
+ if type == ParseErrorToken:
+ self.parseError(new_token["data"], new_token.get("datavars", {}))
+ new_token = None
+ else:
+ if (len(self.tree.openElements) == 0 or
+ currentNodeNamespace == self.tree.defaultNamespace or
+ (self.isMathMLTextIntegrationPoint(currentNode) and
+ ((type == StartTagToken and
+ token["name"] not in frozenset(["mglyph", "malignmark"])) or
+ type in (CharactersToken, SpaceCharactersToken))) or
+ (currentNodeNamespace == namespaces["mathml"] and
+ currentNodeName == "annotation-xml" and
+ token["name"] == "svg") or
+ (self.isHTMLIntegrationPoint(currentNode) and
+ type in (StartTagToken, CharactersToken, SpaceCharactersToken))):
+ phase = self.phase
+ else:
+ phase = self.phases["inForeignContent"]
+
+ if type == CharactersToken:
+ new_token = phase.processCharacters(new_token)
+ elif type == SpaceCharactersToken:
+ new_token = phase.processSpaceCharacters(new_token)
+ elif type == StartTagToken:
+ new_token = phase.processStartTag(new_token)
+ elif type == EndTagToken:
+ new_token = phase.processEndTag(new_token)
+ elif type == CommentToken:
+ new_token = phase.processComment(new_token)
+ elif type == DoctypeToken:
+ new_token = phase.processDoctype(new_token)
+
+ if (type == StartTagToken and token["selfClosing"]
+ and not token["selfClosingAcknowledged"]):
+ self.parseError("non-void-element-with-trailing-solidus",
+ {"name": token["name"]})
+
+ # When the loop finishes it's EOF
+ reprocess = True
+ phases = []
+ while reprocess:
+ phases.append(self.phase)
+ reprocess = self.phase.processEOF()
+ if reprocess:
+ assert self.phase not in phases
+
+ def normalizedTokens(self):
+ for token in self.tokenizer:
+ yield self.normalizeToken(token)
+
+ def parse(self, stream, encoding=None, parseMeta=True, useChardet=True):
+ """Parse a HTML document into a well-formed tree
+
+ stream - a filelike object or string containing the HTML to be parsed
+
+ The optional encoding parameter must be a string that indicates
+ the encoding. If specified, that encoding will be used,
+ regardless of any BOM or later declaration (such as in a meta
+ element)
+ """
+ self._parse(stream, innerHTML=False, encoding=encoding,
+ parseMeta=parseMeta, useChardet=useChardet)
+ return self.tree.getDocument()
+
+ def parseFragment(self, stream, container="div", encoding=None,
+ parseMeta=False, useChardet=True):
+ """Parse a HTML fragment into a well-formed tree fragment
+
+ container - name of the element we're setting the innerHTML property
+ if set to None, default to 'div'
+
+ stream - a filelike object or string containing the HTML to be parsed
+
+ The optional encoding parameter must be a string that indicates
+ the encoding. If specified, that encoding will be used,
+ regardless of any BOM or later declaration (such as in a meta
+ element)
+ """
+ self._parse(stream, True, container=container, encoding=encoding)
+ return self.tree.getFragment()
+
+ def parseError(self, errorcode="XXX-undefined-error", datavars={}):
+ # XXX The idea is to make errorcode mandatory.
+ self.errors.append((self.tokenizer.stream.position(), errorcode, datavars))
+ if self.strict:
+ raise ParseError(E[errorcode] % datavars)
+
+ def normalizeToken(self, token):
+ """ HTML5 specific normalizations to the token stream """
+
+ if token["type"] == tokenTypes["StartTag"]:
+ token["data"] = dict(token["data"][::-1])
+
+ return token
+
+ def adjustMathMLAttributes(self, token):
+ replacements = {"definitionurl": "definitionURL"}
+ for k, v in replacements.items():
+ if k in token["data"]:
+ token["data"][v] = token["data"][k]
+ del token["data"][k]
+
+ def adjustSVGAttributes(self, token):
+ replacements = {
+ "attributename": "attributeName",
+ "attributetype": "attributeType",
+ "basefrequency": "baseFrequency",
+ "baseprofile": "baseProfile",
+ "calcmode": "calcMode",
+ "clippathunits": "clipPathUnits",
+ "contentscripttype": "contentScriptType",
+ "contentstyletype": "contentStyleType",
+ "diffuseconstant": "diffuseConstant",
+ "edgemode": "edgeMode",
+ "externalresourcesrequired": "externalResourcesRequired",
+ "filterres": "filterRes",
+ "filterunits": "filterUnits",
+ "glyphref": "glyphRef",
+ "gradienttransform": "gradientTransform",
+ "gradientunits": "gradientUnits",
+ "kernelmatrix": "kernelMatrix",
+ "kernelunitlength": "kernelUnitLength",
+ "keypoints": "keyPoints",
+ "keysplines": "keySplines",
+ "keytimes": "keyTimes",
+ "lengthadjust": "lengthAdjust",
+ "limitingconeangle": "limitingConeAngle",
+ "markerheight": "markerHeight",
+ "markerunits": "markerUnits",
+ "markerwidth": "markerWidth",
+ "maskcontentunits": "maskContentUnits",
+ "maskunits": "maskUnits",
+ "numoctaves": "numOctaves",
+ "pathlength": "pathLength",
+ "patterncontentunits": "patternContentUnits",
+ "patterntransform": "patternTransform",
+ "patternunits": "patternUnits",
+ "pointsatx": "pointsAtX",
+ "pointsaty": "pointsAtY",
+ "pointsatz": "pointsAtZ",
+ "preservealpha": "preserveAlpha",
+ "preserveaspectratio": "preserveAspectRatio",
+ "primitiveunits": "primitiveUnits",
+ "refx": "refX",
+ "refy": "refY",
+ "repeatcount": "repeatCount",
+ "repeatdur": "repeatDur",
+ "requiredextensions": "requiredExtensions",
+ "requiredfeatures": "requiredFeatures",
+ "specularconstant": "specularConstant",
+ "specularexponent": "specularExponent",
+ "spreadmethod": "spreadMethod",
+ "startoffset": "startOffset",
+ "stddeviation": "stdDeviation",
+ "stitchtiles": "stitchTiles",
+ "surfacescale": "surfaceScale",
+ "systemlanguage": "systemLanguage",
+ "tablevalues": "tableValues",
+ "targetx": "targetX",
+ "targety": "targetY",
+ "textlength": "textLength",
+ "viewbox": "viewBox",
+ "viewtarget": "viewTarget",
+ "xchannelselector": "xChannelSelector",
+ "ychannelselector": "yChannelSelector",
+ "zoomandpan": "zoomAndPan"
+ }
+ for originalName in list(token["data"].keys()):
+ if originalName in replacements:
+ svgName = replacements[originalName]
+ token["data"][svgName] = token["data"][originalName]
+ del token["data"][originalName]
+
+ def adjustForeignAttributes(self, token):
+ replacements = adjustForeignAttributesMap
+
+ for originalName in token["data"].keys():
+ if originalName in replacements:
+ foreignName = replacements[originalName]
+ token["data"][foreignName] = token["data"][originalName]
+ del token["data"][originalName]
+
+ def reparseTokenNormal(self, token):
+ self.parser.phase()
+
+ def resetInsertionMode(self):
+ # The name of this method is mostly historical. (It's also used in the
+ # specification.)
+ last = False
+ newModes = {
+ "select": "inSelect",
+ "td": "inCell",
+ "th": "inCell",
+ "tr": "inRow",
+ "tbody": "inTableBody",
+ "thead": "inTableBody",
+ "tfoot": "inTableBody",
+ "caption": "inCaption",
+ "colgroup": "inColumnGroup",
+ "table": "inTable",
+ "head": "inBody",
+ "body": "inBody",
+ "frameset": "inFrameset",
+ "html": "beforeHead"
+ }
+ for node in self.tree.openElements[::-1]:
+ nodeName = node.name
+ new_phase = None
+ if node == self.tree.openElements[0]:
+ assert self.innerHTML
+ last = True
+ nodeName = self.innerHTML
+ # Check for conditions that should only happen in the innerHTML
+ # case
+ if nodeName in ("select", "colgroup", "head", "html"):
+ assert self.innerHTML
+
+ if not last and node.namespace != self.tree.defaultNamespace:
+ continue
+
+ if nodeName in newModes:
+ new_phase = self.phases[newModes[nodeName]]
+ break
+ elif last:
+ new_phase = self.phases["inBody"]
+ break
+
+ self.phase = new_phase
+
+ def parseRCDataRawtext(self, token, contentType):
+ """Generic RCDATA/RAWTEXT Parsing algorithm
+ contentType - RCDATA or RAWTEXT
+ """
+ assert contentType in ("RAWTEXT", "RCDATA")
+
+ self.tree.insertElement(token)
+
+ if contentType == "RAWTEXT":
+ self.tokenizer.state = self.tokenizer.rawtextState
+ else:
+ self.tokenizer.state = self.tokenizer.rcdataState
+
+ self.originalPhase = self.phase
+
+ self.phase = self.phases["text"]
+
+
+def getPhases(debug):
+ def log(function):
+ """Logger that records which phase processes each token"""
+ type_names = dict((value, key) for key, value in
+ constants.tokenTypes.items())
+
+ def wrapped(self, *args, **kwargs):
+ if function.__name__.startswith("process") and len(args) > 0:
+ token = args[0]
+ try:
+ info = {"type": type_names[token['type']]}
+ except:
+ raise
+ if token['type'] in constants.tagTokenTypes:
+ info["name"] = token['name']
+
+ self.parser.log.append((self.parser.tokenizer.state.__name__,
+ self.parser.phase.__class__.__name__,
+ self.__class__.__name__,
+ function.__name__,
+ info))
+ return function(self, *args, **kwargs)
+ else:
+ return function(self, *args, **kwargs)
+ return wrapped
+
+ def getMetaclass(use_metaclass, metaclass_func):
+ if use_metaclass:
+ return method_decorator_metaclass(metaclass_func)
+ else:
+ return type
+
+ class Phase(with_metaclass(getMetaclass(debug, log))):
+ """Base class for helper object that implements each phase of processing
+ """
+
+ def __init__(self, parser, tree):
+ self.parser = parser
+ self.tree = tree
+
+ def processEOF(self):
+ raise NotImplementedError
+
+ def processComment(self, token):
+ # For most phases the following is correct. Where it's not it will be
+ # overridden.
+ self.tree.insertComment(token, self.tree.openElements[-1])
+
+ def processDoctype(self, token):
+ self.parser.parseError("unexpected-doctype")
+
+ def processCharacters(self, token):
+ self.tree.insertText(token["data"])
+
+ def processSpaceCharacters(self, token):
+ self.tree.insertText(token["data"])
+
+ def processStartTag(self, token):
+ return self.startTagHandler[token["name"]](token)
+
+ def startTagHtml(self, token):
+ if not self.parser.firstStartTag and token["name"] == "html":
+ self.parser.parseError("non-html-root")
+ # XXX Need a check here to see if the first start tag token emitted is
+ # this token... If it's not, invoke self.parser.parseError().
+ for attr, value in token["data"].items():
+ if attr not in self.tree.openElements[0].attributes:
+ self.tree.openElements[0].attributes[attr] = value
+ self.parser.firstStartTag = False
+
+ def processEndTag(self, token):
+ return self.endTagHandler[token["name"]](token)
+
+ class InitialPhase(Phase):
+ def processSpaceCharacters(self, token):
+ pass
+
+ def processComment(self, token):
+ self.tree.insertComment(token, self.tree.document)
+
+ def processDoctype(self, token):
+ name = token["name"]
+ publicId = token["publicId"]
+ systemId = token["systemId"]
+ correct = token["correct"]
+
+ if (name != "html" or publicId is not None or
+ systemId is not None and systemId != "about:legacy-compat"):
+ self.parser.parseError("unknown-doctype")
+
+ if publicId is None:
+ publicId = ""
+
+ self.tree.insertDoctype(token)
+
+ if publicId != "":
+ publicId = publicId.translate(asciiUpper2Lower)
+
+ if (not correct or token["name"] != "html"
+ or publicId.startswith(
+ ("+//silmaril//dtd html pro v0r11 19970101//",
+ "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
+ "-//as//dtd html 3.0 aswedit + extensions//",
+ "-//ietf//dtd html 2.0 level 1//",
+ "-//ietf//dtd html 2.0 level 2//",
+ "-//ietf//dtd html 2.0 strict level 1//",
+ "-//ietf//dtd html 2.0 strict level 2//",
+ "-//ietf//dtd html 2.0 strict//",
+ "-//ietf//dtd html 2.0//",
+ "-//ietf//dtd html 2.1e//",
+ "-//ietf//dtd html 3.0//",
+ "-//ietf//dtd html 3.2 final//",
+ "-//ietf//dtd html 3.2//",
+ "-//ietf//dtd html 3//",
+ "-//ietf//dtd html level 0//",
+ "-//ietf//dtd html level 1//",
+ "-//ietf//dtd html level 2//",
+ "-//ietf//dtd html level 3//",
+ "-//ietf//dtd html strict level 0//",
+ "-//ietf//dtd html strict level 1//",
+ "-//ietf//dtd html strict level 2//",
+ "-//ietf//dtd html strict level 3//",
+ "-//ietf//dtd html strict//",
+ "-//ietf//dtd html//",
+ "-//metrius//dtd metrius presentational//",
+ "-//microsoft//dtd internet explorer 2.0 html strict//",
+ "-//microsoft//dtd internet explorer 2.0 html//",
+ "-//microsoft//dtd internet explorer 2.0 tables//",
+ "-//microsoft//dtd internet explorer 3.0 html strict//",
+ "-//microsoft//dtd internet explorer 3.0 html//",
+ "-//microsoft//dtd internet explorer 3.0 tables//",
+ "-//netscape comm. corp.//dtd html//",
+ "-//netscape comm. corp.//dtd strict html//",
+ "-//o'reilly and associates//dtd html 2.0//",
+ "-//o'reilly and associates//dtd html extended 1.0//",
+ "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+ "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
+ "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
+ "-//spyglass//dtd html 2.0 extended//",
+ "-//sq//dtd html 2.0 hotmetal + extensions//",
+ "-//sun microsystems corp.//dtd hotjava html//",
+ "-//sun microsystems corp.//dtd hotjava strict html//",
+ "-//w3c//dtd html 3 1995-03-24//",
+ "-//w3c//dtd html 3.2 draft//",
+ "-//w3c//dtd html 3.2 final//",
+ "-//w3c//dtd html 3.2//",
+ "-//w3c//dtd html 3.2s draft//",
+ "-//w3c//dtd html 4.0 frameset//",
+ "-//w3c//dtd html 4.0 transitional//",
+ "-//w3c//dtd html experimental 19960712//",
+ "-//w3c//dtd html experimental 970421//",
+ "-//w3c//dtd w3 html//",
+ "-//w3o//dtd w3 html 3.0//",
+ "-//webtechs//dtd mozilla html 2.0//",
+ "-//webtechs//dtd mozilla html//"))
+ or publicId in
+ ("-//w3o//dtd w3 html strict 3.0//en//",
+ "-/w3c/dtd html 4.0 transitional/en",
+ "html")
+ or publicId.startswith(
+ ("-//w3c//dtd html 4.01 frameset//",
+ "-//w3c//dtd html 4.01 transitional//")) and
+ systemId is None
+ or systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"):
+ self.parser.compatMode = "quirks"
+ elif (publicId.startswith(
+ ("-//w3c//dtd xhtml 1.0 frameset//",
+ "-//w3c//dtd xhtml 1.0 transitional//"))
+ or publicId.startswith(
+ ("-//w3c//dtd html 4.01 frameset//",
+ "-//w3c//dtd html 4.01 transitional//")) and
+ systemId is not None):
+ self.parser.compatMode = "limited quirks"
+
+ self.parser.phase = self.parser.phases["beforeHtml"]
+
+ def anythingElse(self):
+ self.parser.compatMode = "quirks"
+ self.parser.phase = self.parser.phases["beforeHtml"]
+
+ def processCharacters(self, token):
+ self.parser.parseError("expected-doctype-but-got-chars")
+ self.anythingElse()
+ return token
+
+ def processStartTag(self, token):
+ self.parser.parseError("expected-doctype-but-got-start-tag",
+ {"name": token["name"]})
+ self.anythingElse()
+ return token
+
+ def processEndTag(self, token):
+ self.parser.parseError("expected-doctype-but-got-end-tag",
+ {"name": token["name"]})
+ self.anythingElse()
+ return token
+
+ def processEOF(self):
+ self.parser.parseError("expected-doctype-but-got-eof")
+ self.anythingElse()
+ return True
+
+ class BeforeHtmlPhase(Phase):
+ # helper methods
+ def insertHtmlElement(self):
+ self.tree.insertRoot(impliedTagToken("html", "StartTag"))
+ self.parser.phase = self.parser.phases["beforeHead"]
+
+ # other
+ def processEOF(self):
+ self.insertHtmlElement()
+ return True
+
+ def processComment(self, token):
+ self.tree.insertComment(token, self.tree.document)
+
+ def processSpaceCharacters(self, token):
+ pass
+
+ def processCharacters(self, token):
+ self.insertHtmlElement()
+ return token
+
+ def processStartTag(self, token):
+ if token["name"] == "html":
+ self.parser.firstStartTag = True
+ self.insertHtmlElement()
+ return token
+
+ def processEndTag(self, token):
+ if token["name"] not in ("head", "body", "html", "br"):
+ self.parser.parseError("unexpected-end-tag-before-html",
+ {"name": token["name"]})
+ else:
+ self.insertHtmlElement()
+ return token
+
+ class BeforeHeadPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("head", self.startTagHead)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ (("head", "body", "html", "br"), self.endTagImplyHead)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ self.startTagHead(impliedTagToken("head", "StartTag"))
+ return True
+
+ def processSpaceCharacters(self, token):
+ pass
+
+ def processCharacters(self, token):
+ self.startTagHead(impliedTagToken("head", "StartTag"))
+ return token
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagHead(self, token):
+ self.tree.insertElement(token)
+ self.tree.headPointer = self.tree.openElements[-1]
+ self.parser.phase = self.parser.phases["inHead"]
+
+ def startTagOther(self, token):
+ self.startTagHead(impliedTagToken("head", "StartTag"))
+ return token
+
+ def endTagImplyHead(self, token):
+ self.startTagHead(impliedTagToken("head", "StartTag"))
+ return token
+
+ def endTagOther(self, token):
+ self.parser.parseError("end-tag-after-implied-root",
+ {"name": token["name"]})
+
+ class InHeadPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("title", self.startTagTitle),
+ (("noscript", "noframes", "style"), self.startTagNoScriptNoFramesStyle),
+ ("script", self.startTagScript),
+ (("base", "basefont", "bgsound", "command", "link"),
+ self.startTagBaseLinkCommand),
+ ("meta", self.startTagMeta),
+ ("head", self.startTagHead)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self. endTagHandler = utils.MethodDispatcher([
+ ("head", self.endTagHead),
+ (("br", "html", "body"), self.endTagHtmlBodyBr)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # the real thing
+ def processEOF(self):
+ self.anythingElse()
+ return True
+
+ def processCharacters(self, token):
+ self.anythingElse()
+ return token
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagHead(self, token):
+ self.parser.parseError("two-heads-are-not-better-than-one")
+
+ def startTagBaseLinkCommand(self, token):
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ def startTagMeta(self, token):
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ attributes = token["data"]
+ if self.parser.tokenizer.stream.charEncoding[1] == "tentative":
+ if "charset" in attributes:
+ self.parser.tokenizer.stream.changeEncoding(attributes["charset"])
+ elif ("content" in attributes and
+ "http-equiv" in attributes and
+ attributes["http-equiv"].lower() == "content-type"):
+ # Encoding it as UTF-8 here is a hack, as really we should pass
+ # the abstract Unicode string, and just use the
+ # ContentAttrParser on that, but using UTF-8 allows all chars
+ # to be encoded and as a ASCII-superset works.
+ data = inputstream.EncodingBytes(attributes["content"].encode("utf-8"))
+ parser = inputstream.ContentAttrParser(data)
+ codec = parser.parse()
+ self.parser.tokenizer.stream.changeEncoding(codec)
+
+ def startTagTitle(self, token):
+ self.parser.parseRCDataRawtext(token, "RCDATA")
+
+ def startTagNoScriptNoFramesStyle(self, token):
+ # Need to decide whether to implement the scripting-disabled case
+ self.parser.parseRCDataRawtext(token, "RAWTEXT")
+
+ def startTagScript(self, token):
+ self.tree.insertElement(token)
+ self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState
+ self.parser.originalPhase = self.parser.phase
+ self.parser.phase = self.parser.phases["text"]
+
+ def startTagOther(self, token):
+ self.anythingElse()
+ return token
+
+ def endTagHead(self, token):
+ node = self.parser.tree.openElements.pop()
+ assert node.name == "head", "Expected head got %s" % node.name
+ self.parser.phase = self.parser.phases["afterHead"]
+
+ def endTagHtmlBodyBr(self, token):
+ self.anythingElse()
+ return token
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def anythingElse(self):
+ self.endTagHead(impliedTagToken("head"))
+
+ # XXX If we implement a parser for which scripting is disabled we need to
+ # implement this phase.
+ #
+ # class InHeadNoScriptPhase(Phase):
+ class AfterHeadPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("body", self.startTagBody),
+ ("frameset", self.startTagFrameset),
+ (("base", "basefont", "bgsound", "link", "meta", "noframes", "script",
+ "style", "title"),
+ self.startTagFromHead),
+ ("head", self.startTagHead)
+ ])
+ self.startTagHandler.default = self.startTagOther
+ self.endTagHandler = utils.MethodDispatcher([(("body", "html", "br"),
+ self.endTagHtmlBodyBr)])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ self.anythingElse()
+ return True
+
+ def processCharacters(self, token):
+ self.anythingElse()
+ return token
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagBody(self, token):
+ self.parser.framesetOK = False
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inBody"]
+
+ def startTagFrameset(self, token):
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inFrameset"]
+
+ def startTagFromHead(self, token):
+ self.parser.parseError("unexpected-start-tag-out-of-my-head",
+ {"name": token["name"]})
+ self.tree.openElements.append(self.tree.headPointer)
+ self.parser.phases["inHead"].processStartTag(token)
+ for node in self.tree.openElements[::-1]:
+ if node.name == "head":
+ self.tree.openElements.remove(node)
+ break
+
+ def startTagHead(self, token):
+ self.parser.parseError("unexpected-start-tag", {"name": token["name"]})
+
+ def startTagOther(self, token):
+ self.anythingElse()
+ return token
+
+ def endTagHtmlBodyBr(self, token):
+ self.anythingElse()
+ return token
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def anythingElse(self):
+ self.tree.insertElement(impliedTagToken("body", "StartTag"))
+ self.parser.phase = self.parser.phases["inBody"]
+ self.parser.framesetOK = True
+
+ class InBodyPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody
+ # the really-really-really-very crazy mode
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ # Keep a ref to this for special handling of whitespace in <pre>
+ self.processSpaceCharactersNonPre = self.processSpaceCharacters
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ (("base", "basefont", "bgsound", "command", "link", "meta",
+ "script", "style", "title"),
+ self.startTagProcessInHead),
+ ("body", self.startTagBody),
+ ("frameset", self.startTagFrameset),
+ (("address", "article", "aside", "blockquote", "center", "details",
+ "details", "dir", "div", "dl", "fieldset", "figcaption", "figure",
+ "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p",
+ "section", "summary", "ul"),
+ self.startTagCloseP),
+ (headingElements, self.startTagHeading),
+ (("pre", "listing"), self.startTagPreListing),
+ ("form", self.startTagForm),
+ (("li", "dd", "dt"), self.startTagListItem),
+ ("plaintext", self.startTagPlaintext),
+ ("a", self.startTagA),
+ (("b", "big", "code", "em", "font", "i", "s", "small", "strike",
+ "strong", "tt", "u"), self.startTagFormatting),
+ ("nobr", self.startTagNobr),
+ ("button", self.startTagButton),
+ (("applet", "marquee", "object"), self.startTagAppletMarqueeObject),
+ ("xmp", self.startTagXmp),
+ ("table", self.startTagTable),
+ (("area", "br", "embed", "img", "keygen", "wbr"),
+ self.startTagVoidFormatting),
+ (("param", "source", "track"), self.startTagParamSource),
+ ("input", self.startTagInput),
+ ("hr", self.startTagHr),
+ ("image", self.startTagImage),
+ ("isindex", self.startTagIsIndex),
+ ("textarea", self.startTagTextarea),
+ ("iframe", self.startTagIFrame),
+ (("noembed", "noframes", "noscript"), self.startTagRawtext),
+ ("select", self.startTagSelect),
+ (("rp", "rt"), self.startTagRpRt),
+ (("option", "optgroup"), self.startTagOpt),
+ (("math"), self.startTagMath),
+ (("svg"), self.startTagSvg),
+ (("caption", "col", "colgroup", "frame", "head",
+ "tbody", "td", "tfoot", "th", "thead",
+ "tr"), self.startTagMisplaced)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("body", self.endTagBody),
+ ("html", self.endTagHtml),
+ (("address", "article", "aside", "blockquote", "button", "center",
+ "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure",
+ "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre",
+ "section", "summary", "ul"), self.endTagBlock),
+ ("form", self.endTagForm),
+ ("p", self.endTagP),
+ (("dd", "dt", "li"), self.endTagListItem),
+ (headingElements, self.endTagHeading),
+ (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small",
+ "strike", "strong", "tt", "u"), self.endTagFormatting),
+ (("applet", "marquee", "object"), self.endTagAppletMarqueeObject),
+ ("br", self.endTagBr),
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def isMatchingFormattingElement(self, node1, node2):
+ if node1.name != node2.name or node1.namespace != node2.namespace:
+ return False
+ elif len(node1.attributes) != len(node2.attributes):
+ return False
+ else:
+ attributes1 = sorted(node1.attributes.items())
+ attributes2 = sorted(node2.attributes.items())
+ for attr1, attr2 in zip(attributes1, attributes2):
+ if attr1 != attr2:
+ return False
+ return True
+
+ # helper
+ def addFormattingElement(self, token):
+ self.tree.insertElement(token)
+ element = self.tree.openElements[-1]
+
+ matchingElements = []
+ for node in self.tree.activeFormattingElements[::-1]:
+ if node is Marker:
+ break
+ elif self.isMatchingFormattingElement(node, element):
+ matchingElements.append(node)
+
+ assert len(matchingElements) <= 3
+ if len(matchingElements) == 3:
+ self.tree.activeFormattingElements.remove(matchingElements[-1])
+ self.tree.activeFormattingElements.append(element)
+
+ # the real deal
+ def processEOF(self):
+ allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td",
+ "tfoot", "th", "thead", "tr", "body",
+ "html"))
+ for node in self.tree.openElements[::-1]:
+ if node.name not in allowed_elements:
+ self.parser.parseError("expected-closing-tag-but-got-eof")
+ break
+ # Stop parsing
+
+ def processSpaceCharactersDropNewline(self, token):
+ # Sometimes (start of <pre>, <listing>, and <textarea> blocks) we
+ # want to drop leading newlines
+ data = token["data"]
+ self.processSpaceCharacters = self.processSpaceCharactersNonPre
+ if (data.startswith("\n") and
+ self.tree.openElements[-1].name in ("pre", "listing", "textarea")
+ and not self.tree.openElements[-1].hasContent()):
+ data = data[1:]
+ if data:
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertText(data)
+
+ def processCharacters(self, token):
+ if token["data"] == "\u0000":
+ # The tokenizer should always emit null on its own
+ return
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertText(token["data"])
+ # This must be bad for performance
+ if (self.parser.framesetOK and
+ any([char not in spaceCharacters
+ for char in token["data"]])):
+ self.parser.framesetOK = False
+
+ def processSpaceCharacters(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertText(token["data"])
+
+ def startTagProcessInHead(self, token):
+ return self.parser.phases["inHead"].processStartTag(token)
+
+ def startTagBody(self, token):
+ self.parser.parseError("unexpected-start-tag", {"name": "body"})
+ if (len(self.tree.openElements) == 1
+ or self.tree.openElements[1].name != "body"):
+ assert self.parser.innerHTML
+ else:
+ self.parser.framesetOK = False
+ for attr, value in token["data"].items():
+ if attr not in self.tree.openElements[1].attributes:
+ self.tree.openElements[1].attributes[attr] = value
+
+ def startTagFrameset(self, token):
+ self.parser.parseError("unexpected-start-tag", {"name": "frameset"})
+ if (len(self.tree.openElements) == 1 or self.tree.openElements[1].name != "body"):
+ assert self.parser.innerHTML
+ elif not self.parser.framesetOK:
+ pass
+ else:
+ if self.tree.openElements[1].parent:
+ self.tree.openElements[1].parent.removeChild(self.tree.openElements[1])
+ while self.tree.openElements[-1].name != "html":
+ self.tree.openElements.pop()
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inFrameset"]
+
+ def startTagCloseP(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.insertElement(token)
+
+ def startTagPreListing(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.insertElement(token)
+ self.parser.framesetOK = False
+ self.processSpaceCharacters = self.processSpaceCharactersDropNewline
+
+ def startTagForm(self, token):
+ if self.tree.formPointer:
+ self.parser.parseError("unexpected-start-tag", {"name": "form"})
+ else:
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.insertElement(token)
+ self.tree.formPointer = self.tree.openElements[-1]
+
+ def startTagListItem(self, token):
+ self.parser.framesetOK = False
+
+ stopNamesMap = {"li": ["li"],
+ "dt": ["dt", "dd"],
+ "dd": ["dt", "dd"]}
+ stopNames = stopNamesMap[token["name"]]
+ for node in reversed(self.tree.openElements):
+ if node.name in stopNames:
+ self.parser.phase.processEndTag(
+ impliedTagToken(node.name, "EndTag"))
+ break
+ if (node.nameTuple in specialElements and
+ node.name not in ("address", "div", "p")):
+ break
+
+ if self.tree.elementInScope("p", variant="button"):
+ self.parser.phase.processEndTag(
+ impliedTagToken("p", "EndTag"))
+
+ self.tree.insertElement(token)
+
+ def startTagPlaintext(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.insertElement(token)
+ self.parser.tokenizer.state = self.parser.tokenizer.plaintextState
+
+ def startTagHeading(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ if self.tree.openElements[-1].name in headingElements:
+ self.parser.parseError("unexpected-start-tag", {"name": token["name"]})
+ self.tree.openElements.pop()
+ self.tree.insertElement(token)
+
+ def startTagA(self, token):
+ afeAElement = self.tree.elementInActiveFormattingElements("a")
+ if afeAElement:
+ self.parser.parseError("unexpected-start-tag-implies-end-tag",
+ {"startName": "a", "endName": "a"})
+ self.endTagFormatting(impliedTagToken("a"))
+ if afeAElement in self.tree.openElements:
+ self.tree.openElements.remove(afeAElement)
+ if afeAElement in self.tree.activeFormattingElements:
+ self.tree.activeFormattingElements.remove(afeAElement)
+ self.tree.reconstructActiveFormattingElements()
+ self.addFormattingElement(token)
+
+ def startTagFormatting(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.addFormattingElement(token)
+
+ def startTagNobr(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ if self.tree.elementInScope("nobr"):
+ self.parser.parseError("unexpected-start-tag-implies-end-tag",
+ {"startName": "nobr", "endName": "nobr"})
+ self.processEndTag(impliedTagToken("nobr"))
+ # XXX Need tests that trigger the following
+ self.tree.reconstructActiveFormattingElements()
+ self.addFormattingElement(token)
+
+ def startTagButton(self, token):
+ if self.tree.elementInScope("button"):
+ self.parser.parseError("unexpected-start-tag-implies-end-tag",
+ {"startName": "button", "endName": "button"})
+ self.processEndTag(impliedTagToken("button"))
+ return token
+ else:
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(token)
+ self.parser.framesetOK = False
+
+ def startTagAppletMarqueeObject(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(token)
+ self.tree.activeFormattingElements.append(Marker)
+ self.parser.framesetOK = False
+
+ def startTagXmp(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.reconstructActiveFormattingElements()
+ self.parser.framesetOK = False
+ self.parser.parseRCDataRawtext(token, "RAWTEXT")
+
+ def startTagTable(self, token):
+ if self.parser.compatMode != "quirks":
+ if self.tree.elementInScope("p", variant="button"):
+ self.processEndTag(impliedTagToken("p"))
+ self.tree.insertElement(token)
+ self.parser.framesetOK = False
+ self.parser.phase = self.parser.phases["inTable"]
+
+ def startTagVoidFormatting(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+ self.parser.framesetOK = False
+
+ def startTagInput(self, token):
+ framesetOK = self.parser.framesetOK
+ self.startTagVoidFormatting(token)
+ if ("type" in token["data"] and
+ token["data"]["type"].translate(asciiUpper2Lower) == "hidden"):
+ # input type=hidden doesn't change framesetOK
+ self.parser.framesetOK = framesetOK
+
+ def startTagParamSource(self, token):
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ def startTagHr(self, token):
+ if self.tree.elementInScope("p", variant="button"):
+ self.endTagP(impliedTagToken("p"))
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+ self.parser.framesetOK = False
+
+ def startTagImage(self, token):
+ # No really...
+ self.parser.parseError("unexpected-start-tag-treated-as",
+ {"originalName": "image", "newName": "img"})
+ self.processStartTag(impliedTagToken("img", "StartTag",
+ attributes=token["data"],
+ selfClosing=token["selfClosing"]))
+
+ def startTagIsIndex(self, token):
+ self.parser.parseError("deprecated-tag", {"name": "isindex"})
+ if self.tree.formPointer:
+ return
+ form_attrs = {}
+ if "action" in token["data"]:
+ form_attrs["action"] = token["data"]["action"]
+ self.processStartTag(impliedTagToken("form", "StartTag",
+ attributes=form_attrs))
+ self.processStartTag(impliedTagToken("hr", "StartTag"))
+ self.processStartTag(impliedTagToken("label", "StartTag"))
+ # XXX Localization ...
+ if "prompt" in token["data"]:
+ prompt = token["data"]["prompt"]
+ else:
+ prompt = "This is a searchable index. Enter search keywords: "
+ self.processCharacters(
+ {"type": tokenTypes["Characters"], "data": prompt})
+ attributes = token["data"].copy()
+ if "action" in attributes:
+ del attributes["action"]
+ if "prompt" in attributes:
+ del attributes["prompt"]
+ attributes["name"] = "isindex"
+ self.processStartTag(impliedTagToken("input", "StartTag",
+ attributes=attributes,
+ selfClosing=token["selfClosing"]))
+ self.processEndTag(impliedTagToken("label"))
+ self.processStartTag(impliedTagToken("hr", "StartTag"))
+ self.processEndTag(impliedTagToken("form"))
+
+ def startTagTextarea(self, token):
+ self.tree.insertElement(token)
+ self.parser.tokenizer.state = self.parser.tokenizer.rcdataState
+ self.processSpaceCharacters = self.processSpaceCharactersDropNewline
+ self.parser.framesetOK = False
+
+ def startTagIFrame(self, token):
+ self.parser.framesetOK = False
+ self.startTagRawtext(token)
+
+ def startTagRawtext(self, token):
+ """iframe, noembed noframes, noscript(if scripting enabled)"""
+ self.parser.parseRCDataRawtext(token, "RAWTEXT")
+
+ def startTagOpt(self, token):
+ if self.tree.openElements[-1].name == "option":
+ self.parser.phase.processEndTag(impliedTagToken("option"))
+ self.tree.reconstructActiveFormattingElements()
+ self.parser.tree.insertElement(token)
+
+ def startTagSelect(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(token)
+ self.parser.framesetOK = False
+ if self.parser.phase in (self.parser.phases["inTable"],
+ self.parser.phases["inCaption"],
+ self.parser.phases["inColumnGroup"],
+ self.parser.phases["inTableBody"],
+ self.parser.phases["inRow"],
+ self.parser.phases["inCell"]):
+ self.parser.phase = self.parser.phases["inSelectInTable"]
+ else:
+ self.parser.phase = self.parser.phases["inSelect"]
+
+ def startTagRpRt(self, token):
+ if self.tree.elementInScope("ruby"):
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1].name != "ruby":
+ self.parser.parseError()
+ self.tree.insertElement(token)
+
+ def startTagMath(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.parser.adjustMathMLAttributes(token)
+ self.parser.adjustForeignAttributes(token)
+ token["namespace"] = namespaces["mathml"]
+ self.tree.insertElement(token)
+ # Need to get the parse error right for the case where the token
+ # has a namespace not equal to the xmlns attribute
+ if token["selfClosing"]:
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ def startTagSvg(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.parser.adjustSVGAttributes(token)
+ self.parser.adjustForeignAttributes(token)
+ token["namespace"] = namespaces["svg"]
+ self.tree.insertElement(token)
+ # Need to get the parse error right for the case where the token
+ # has a namespace not equal to the xmlns attribute
+ if token["selfClosing"]:
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ def startTagMisplaced(self, token):
+ """ Elements that should be children of other elements that have a
+ different insertion mode; here they are ignored
+ "caption", "col", "colgroup", "frame", "frameset", "head",
+ "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
+ "tr", "noscript"
+ """
+ self.parser.parseError("unexpected-start-tag-ignored", {"name": token["name"]})
+
+ def startTagOther(self, token):
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(token)
+
+ def endTagP(self, token):
+ if not self.tree.elementInScope("p", variant="button"):
+ self.startTagCloseP(impliedTagToken("p", "StartTag"))
+ self.parser.parseError("unexpected-end-tag", {"name": "p"})
+ self.endTagP(impliedTagToken("p", "EndTag"))
+ else:
+ self.tree.generateImpliedEndTags("p")
+ if self.tree.openElements[-1].name != "p":
+ self.parser.parseError("unexpected-end-tag", {"name": "p"})
+ node = self.tree.openElements.pop()
+ while node.name != "p":
+ node = self.tree.openElements.pop()
+
+ def endTagBody(self, token):
+ if not self.tree.elementInScope("body"):
+ self.parser.parseError()
+ return
+ elif self.tree.openElements[-1].name != "body":
+ for node in self.tree.openElements[2:]:
+ if node.name not in frozenset(("dd", "dt", "li", "optgroup",
+ "option", "p", "rp", "rt",
+ "tbody", "td", "tfoot",
+ "th", "thead", "tr", "body",
+ "html")):
+ # Not sure this is the correct name for the parse error
+ self.parser.parseError(
+ "expected-one-end-tag-but-got-another",
+ {"expectedName": "body", "gotName": node.name})
+ break
+ self.parser.phase = self.parser.phases["afterBody"]
+
+ def endTagHtml(self, token):
+ # We repeat the test for the body end tag token being ignored here
+ if self.tree.elementInScope("body"):
+ self.endTagBody(impliedTagToken("body"))
+ return token
+
+ def endTagBlock(self, token):
+ # Put us back in the right whitespace handling mode
+ if token["name"] == "pre":
+ self.processSpaceCharacters = self.processSpaceCharactersNonPre
+ inScope = self.tree.elementInScope(token["name"])
+ if inScope:
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError("end-tag-too-early", {"name": token["name"]})
+ if inScope:
+ node = self.tree.openElements.pop()
+ while node.name != token["name"]:
+ node = self.tree.openElements.pop()
+
+ def endTagForm(self, token):
+ node = self.tree.formPointer
+ self.tree.formPointer = None
+ if node is None or not self.tree.elementInScope(node):
+ self.parser.parseError("unexpected-end-tag",
+ {"name": "form"})
+ else:
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1] != node:
+ self.parser.parseError("end-tag-too-early-ignored",
+ {"name": "form"})
+ self.tree.openElements.remove(node)
+
+ def endTagListItem(self, token):
+ if token["name"] == "li":
+ variant = "list"
+ else:
+ variant = None
+ if not self.tree.elementInScope(token["name"], variant=variant):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+ else:
+ self.tree.generateImpliedEndTags(exclude=token["name"])
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError(
+ "end-tag-too-early",
+ {"name": token["name"]})
+ node = self.tree.openElements.pop()
+ while node.name != token["name"]:
+ node = self.tree.openElements.pop()
+
+ def endTagHeading(self, token):
+ for item in headingElements:
+ if self.tree.elementInScope(item):
+ self.tree.generateImpliedEndTags()
+ break
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError("end-tag-too-early", {"name": token["name"]})
+
+ for item in headingElements:
+ if self.tree.elementInScope(item):
+ item = self.tree.openElements.pop()
+ while item.name not in headingElements:
+ item = self.tree.openElements.pop()
+ break
+
+ def endTagFormatting(self, token):
+ """The much-feared adoption agency algorithm"""
+ # http://svn.whatwg.org/webapps/complete.html#adoptionAgency revision 7867
+ # XXX Better parseError messages appreciated.
+
+ # Step 1
+ outerLoopCounter = 0
+
+ # Step 2
+ while outerLoopCounter < 8:
+
+ # Step 3
+ outerLoopCounter += 1
+
+ # Step 4:
+
+ # Let the formatting element be the last element in
+ # the list of active formatting elements that:
+ # - is between the end of the list and the last scope
+ # marker in the list, if any, or the start of the list
+ # otherwise, and
+ # - has the same tag name as the token.
+ formattingElement = self.tree.elementInActiveFormattingElements(
+ token["name"])
+ if (not formattingElement or
+ (formattingElement in self.tree.openElements and
+ not self.tree.elementInScope(formattingElement.name))):
+ # If there is no such node, then abort these steps
+ # and instead act as described in the "any other
+ # end tag" entry below.
+ self.endTagOther(token)
+ return
+
+ # Otherwise, if there is such a node, but that node is
+ # not in the stack of open elements, then this is a
+ # parse error; remove the element from the list, and
+ # abort these steps.
+ elif formattingElement not in self.tree.openElements:
+ self.parser.parseError("adoption-agency-1.2", {"name": token["name"]})
+ self.tree.activeFormattingElements.remove(formattingElement)
+ return
+
+ # Otherwise, if there is such a node, and that node is
+ # also in the stack of open elements, but the element
+ # is not in scope, then this is a parse error; ignore
+ # the token, and abort these steps.
+ elif not self.tree.elementInScope(formattingElement.name):
+ self.parser.parseError("adoption-agency-4.4", {"name": token["name"]})
+ return
+
+ # Otherwise, there is a formatting element and that
+ # element is in the stack and is in scope. If the
+ # element is not the current node, this is a parse
+ # error. In any case, proceed with the algorithm as
+ # written in the following steps.
+ else:
+ if formattingElement != self.tree.openElements[-1]:
+ self.parser.parseError("adoption-agency-1.3", {"name": token["name"]})
+
+ # Step 5:
+
+ # Let the furthest block be the topmost node in the
+ # stack of open elements that is lower in the stack
+ # than the formatting element, and is an element in
+ # the special category. There might not be one.
+ afeIndex = self.tree.openElements.index(formattingElement)
+ furthestBlock = None
+ for element in self.tree.openElements[afeIndex:]:
+ if element.nameTuple in specialElements:
+ furthestBlock = element
+ break
+
+ # Step 6:
+
+ # If there is no furthest block, then the UA must
+ # first pop all the nodes from the bottom of the stack
+ # of open elements, from the current node up to and
+ # including the formatting element, then remove the
+ # formatting element from the list of active
+ # formatting elements, and finally abort these steps.
+ if furthestBlock is None:
+ element = self.tree.openElements.pop()
+ while element != formattingElement:
+ element = self.tree.openElements.pop()
+ self.tree.activeFormattingElements.remove(element)
+ return
+
+ # Step 7
+ commonAncestor = self.tree.openElements[afeIndex - 1]
+
+ # Step 8:
+ # The bookmark is supposed to help us identify where to reinsert
+ # nodes in step 15. We have to ensure that we reinsert nodes after
+ # the node before the active formatting element. Note the bookmark
+ # can move in step 9.7
+ bookmark = self.tree.activeFormattingElements.index(formattingElement)
+
+ # Step 9
+ lastNode = node = furthestBlock
+ innerLoopCounter = 0
+
+ index = self.tree.openElements.index(node)
+ while innerLoopCounter < 3:
+ innerLoopCounter += 1
+ # Node is element before node in open elements
+ index -= 1
+ node = self.tree.openElements[index]
+ if node not in self.tree.activeFormattingElements:
+ self.tree.openElements.remove(node)
+ continue
+ # Step 9.6
+ if node == formattingElement:
+ break
+ # Step 9.7
+ if lastNode == furthestBlock:
+ bookmark = self.tree.activeFormattingElements.index(node) + 1
+ # Step 9.8
+ clone = node.cloneNode()
+ # Replace node with clone
+ self.tree.activeFormattingElements[
+ self.tree.activeFormattingElements.index(node)] = clone
+ self.tree.openElements[
+ self.tree.openElements.index(node)] = clone
+ node = clone
+ # Step 9.9
+ # Remove lastNode from its parents, if any
+ if lastNode.parent:
+ lastNode.parent.removeChild(lastNode)
+ node.appendChild(lastNode)
+ # Step 9.10
+ lastNode = node
+
+ # Step 10
+ # Foster parent lastNode if commonAncestor is a
+ # table, tbody, tfoot, thead, or tr we need to foster
+ # parent the lastNode
+ if lastNode.parent:
+ lastNode.parent.removeChild(lastNode)
+
+ if commonAncestor.name in frozenset(("table", "tbody", "tfoot", "thead", "tr")):
+ parent, insertBefore = self.tree.getTableMisnestedNodePosition()
+ parent.insertBefore(lastNode, insertBefore)
+ else:
+ commonAncestor.appendChild(lastNode)
+
+ # Step 11
+ clone = formattingElement.cloneNode()
+
+ # Step 12
+ furthestBlock.reparentChildren(clone)
+
+ # Step 13
+ furthestBlock.appendChild(clone)
+
+ # Step 14
+ self.tree.activeFormattingElements.remove(formattingElement)
+ self.tree.activeFormattingElements.insert(bookmark, clone)
+
+ # Step 15
+ self.tree.openElements.remove(formattingElement)
+ self.tree.openElements.insert(
+ self.tree.openElements.index(furthestBlock) + 1, clone)
+
+ def endTagAppletMarqueeObject(self, token):
+ if self.tree.elementInScope(token["name"]):
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError("end-tag-too-early", {"name": token["name"]})
+
+ if self.tree.elementInScope(token["name"]):
+ element = self.tree.openElements.pop()
+ while element.name != token["name"]:
+ element = self.tree.openElements.pop()
+ self.tree.clearActiveFormattingElements()
+
+ def endTagBr(self, token):
+ self.parser.parseError("unexpected-end-tag-treated-as",
+ {"originalName": "br", "newName": "br element"})
+ self.tree.reconstructActiveFormattingElements()
+ self.tree.insertElement(impliedTagToken("br", "StartTag"))
+ self.tree.openElements.pop()
+
+ def endTagOther(self, token):
+ for node in self.tree.openElements[::-1]:
+ if node.name == token["name"]:
+ self.tree.generateImpliedEndTags(exclude=token["name"])
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+ while self.tree.openElements.pop() != node:
+ pass
+ break
+ else:
+ if node.nameTuple in specialElements:
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+ break
+
+ class TextPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.startTagHandler = utils.MethodDispatcher([])
+ self.startTagHandler.default = self.startTagOther
+ self.endTagHandler = utils.MethodDispatcher([
+ ("script", self.endTagScript)])
+ self.endTagHandler.default = self.endTagOther
+
+ def processCharacters(self, token):
+ self.tree.insertText(token["data"])
+
+ def processEOF(self):
+ self.parser.parseError("expected-named-closing-tag-but-got-eof",
+ {"name": self.tree.openElements[-1].name})
+ self.tree.openElements.pop()
+ self.parser.phase = self.parser.originalPhase
+ return True
+
+ def startTagOther(self, token):
+ assert False, "Tried to process start tag %s in RCDATA/RAWTEXT mode" % token['name']
+
+ def endTagScript(self, token):
+ node = self.tree.openElements.pop()
+ assert node.name == "script"
+ self.parser.phase = self.parser.originalPhase
+ # The rest of this method is all stuff that only happens if
+ # document.write works
+
+ def endTagOther(self, token):
+ self.tree.openElements.pop()
+ self.parser.phase = self.parser.originalPhase
+
+ class InTablePhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-table
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("caption", self.startTagCaption),
+ ("colgroup", self.startTagColgroup),
+ ("col", self.startTagCol),
+ (("tbody", "tfoot", "thead"), self.startTagRowGroup),
+ (("td", "th", "tr"), self.startTagImplyTbody),
+ ("table", self.startTagTable),
+ (("style", "script"), self.startTagStyleScript),
+ ("input", self.startTagInput),
+ ("form", self.startTagForm)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("table", self.endTagTable),
+ (("body", "caption", "col", "colgroup", "html", "tbody", "td",
+ "tfoot", "th", "thead", "tr"), self.endTagIgnore)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # helper methods
+ def clearStackToTableContext(self):
+ # "clear the stack back to a table context"
+ while self.tree.openElements[-1].name not in ("table", "html"):
+ # self.parser.parseError("unexpected-implied-end-tag-in-table",
+ # {"name": self.tree.openElements[-1].name})
+ self.tree.openElements.pop()
+ # When the current node is <html> it's an innerHTML case
+
+ # processing methods
+ def processEOF(self):
+ if self.tree.openElements[-1].name != "html":
+ self.parser.parseError("eof-in-table")
+ else:
+ assert self.parser.innerHTML
+ # Stop parsing
+
+ def processSpaceCharacters(self, token):
+ originalPhase = self.parser.phase
+ self.parser.phase = self.parser.phases["inTableText"]
+ self.parser.phase.originalPhase = originalPhase
+ self.parser.phase.processSpaceCharacters(token)
+
+ def processCharacters(self, token):
+ originalPhase = self.parser.phase
+ self.parser.phase = self.parser.phases["inTableText"]
+ self.parser.phase.originalPhase = originalPhase
+ self.parser.phase.processCharacters(token)
+
+ def insertText(self, token):
+ # If we get here there must be at least one non-whitespace character
+ # Do the table magic!
+ self.tree.insertFromTable = True
+ self.parser.phases["inBody"].processCharacters(token)
+ self.tree.insertFromTable = False
+
+ def startTagCaption(self, token):
+ self.clearStackToTableContext()
+ self.tree.activeFormattingElements.append(Marker)
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inCaption"]
+
+ def startTagColgroup(self, token):
+ self.clearStackToTableContext()
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inColumnGroup"]
+
+ def startTagCol(self, token):
+ self.startTagColgroup(impliedTagToken("colgroup", "StartTag"))
+ return token
+
+ def startTagRowGroup(self, token):
+ self.clearStackToTableContext()
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inTableBody"]
+
+ def startTagImplyTbody(self, token):
+ self.startTagRowGroup(impliedTagToken("tbody", "StartTag"))
+ return token
+
+ def startTagTable(self, token):
+ self.parser.parseError("unexpected-start-tag-implies-end-tag",
+ {"startName": "table", "endName": "table"})
+ self.parser.phase.processEndTag(impliedTagToken("table"))
+ if not self.parser.innerHTML:
+ return token
+
+ def startTagStyleScript(self, token):
+ return self.parser.phases["inHead"].processStartTag(token)
+
+ def startTagInput(self, token):
+ if ("type" in token["data"] and
+ token["data"]["type"].translate(asciiUpper2Lower) == "hidden"):
+ self.parser.parseError("unexpected-hidden-input-in-table")
+ self.tree.insertElement(token)
+ # XXX associate with form
+ self.tree.openElements.pop()
+ else:
+ self.startTagOther(token)
+
+ def startTagForm(self, token):
+ self.parser.parseError("unexpected-form-in-table")
+ if self.tree.formPointer is None:
+ self.tree.insertElement(token)
+ self.tree.formPointer = self.tree.openElements[-1]
+ self.tree.openElements.pop()
+
+ def startTagOther(self, token):
+ self.parser.parseError("unexpected-start-tag-implies-table-voodoo", {"name": token["name"]})
+ # Do the table magic!
+ self.tree.insertFromTable = True
+ self.parser.phases["inBody"].processStartTag(token)
+ self.tree.insertFromTable = False
+
+ def endTagTable(self, token):
+ if self.tree.elementInScope("table", variant="table"):
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1].name != "table":
+ self.parser.parseError("end-tag-too-early-named",
+ {"gotName": "table",
+ "expectedName": self.tree.openElements[-1].name})
+ while self.tree.openElements[-1].name != "table":
+ self.tree.openElements.pop()
+ self.tree.openElements.pop()
+ self.parser.resetInsertionMode()
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def endTagIgnore(self, token):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag-implies-table-voodoo", {"name": token["name"]})
+ # Do the table magic!
+ self.tree.insertFromTable = True
+ self.parser.phases["inBody"].processEndTag(token)
+ self.tree.insertFromTable = False
+
+ class InTableTextPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.originalPhase = None
+ self.characterTokens = []
+
+ def flushCharacters(self):
+ data = "".join([item["data"] for item in self.characterTokens])
+ if any([item not in spaceCharacters for item in data]):
+ token = {"type": tokenTypes["Characters"], "data": data}
+ self.parser.phases["inTable"].insertText(token)
+ elif data:
+ self.tree.insertText(data)
+ self.characterTokens = []
+
+ def processComment(self, token):
+ self.flushCharacters()
+ self.parser.phase = self.originalPhase
+ return token
+
+ def processEOF(self):
+ self.flushCharacters()
+ self.parser.phase = self.originalPhase
+ return True
+
+ def processCharacters(self, token):
+ if token["data"] == "\u0000":
+ return
+ self.characterTokens.append(token)
+
+ def processSpaceCharacters(self, token):
+ # pretty sure we should never reach here
+ self.characterTokens.append(token)
+ # assert False
+
+ def processStartTag(self, token):
+ self.flushCharacters()
+ self.parser.phase = self.originalPhase
+ return token
+
+ def processEndTag(self, token):
+ self.flushCharacters()
+ self.parser.phase = self.originalPhase
+ return token
+
+ class InCaptionPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-caption
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), self.startTagTableElement)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("caption", self.endTagCaption),
+ ("table", self.endTagTable),
+ (("body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), self.endTagIgnore)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def ignoreEndTagCaption(self):
+ return not self.tree.elementInScope("caption", variant="table")
+
+ def processEOF(self):
+ self.parser.phases["inBody"].processEOF()
+
+ def processCharacters(self, token):
+ return self.parser.phases["inBody"].processCharacters(token)
+
+ def startTagTableElement(self, token):
+ self.parser.parseError()
+ # XXX Have to duplicate logic here to find out if the tag is ignored
+ ignoreEndTag = self.ignoreEndTagCaption()
+ self.parser.phase.processEndTag(impliedTagToken("caption"))
+ if not ignoreEndTag:
+ return token
+
+ def startTagOther(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def endTagCaption(self, token):
+ if not self.ignoreEndTagCaption():
+ # AT this code is quite similar to endTagTable in "InTable"
+ self.tree.generateImpliedEndTags()
+ if self.tree.openElements[-1].name != "caption":
+ self.parser.parseError("expected-one-end-tag-but-got-another",
+ {"gotName": "caption",
+ "expectedName": self.tree.openElements[-1].name})
+ while self.tree.openElements[-1].name != "caption":
+ self.tree.openElements.pop()
+ self.tree.openElements.pop()
+ self.tree.clearActiveFormattingElements()
+ self.parser.phase = self.parser.phases["inTable"]
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def endTagTable(self, token):
+ self.parser.parseError()
+ ignoreEndTag = self.ignoreEndTagCaption()
+ self.parser.phase.processEndTag(impliedTagToken("caption"))
+ if not ignoreEndTag:
+ return token
+
+ def endTagIgnore(self, token):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def endTagOther(self, token):
+ return self.parser.phases["inBody"].processEndTag(token)
+
+ class InColumnGroupPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-column
+
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("col", self.startTagCol)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("colgroup", self.endTagColgroup),
+ ("col", self.endTagCol)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def ignoreEndTagColgroup(self):
+ return self.tree.openElements[-1].name == "html"
+
+ def processEOF(self):
+ if self.tree.openElements[-1].name == "html":
+ assert self.parser.innerHTML
+ return
+ else:
+ ignoreEndTag = self.ignoreEndTagColgroup()
+ self.endTagColgroup(impliedTagToken("colgroup"))
+ if not ignoreEndTag:
+ return True
+
+ def processCharacters(self, token):
+ ignoreEndTag = self.ignoreEndTagColgroup()
+ self.endTagColgroup(impliedTagToken("colgroup"))
+ if not ignoreEndTag:
+ return token
+
+ def startTagCol(self, token):
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+
+ def startTagOther(self, token):
+ ignoreEndTag = self.ignoreEndTagColgroup()
+ self.endTagColgroup(impliedTagToken("colgroup"))
+ if not ignoreEndTag:
+ return token
+
+ def endTagColgroup(self, token):
+ if self.ignoreEndTagColgroup():
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+ else:
+ self.tree.openElements.pop()
+ self.parser.phase = self.parser.phases["inTable"]
+
+ def endTagCol(self, token):
+ self.parser.parseError("no-end-tag", {"name": "col"})
+
+ def endTagOther(self, token):
+ ignoreEndTag = self.ignoreEndTagColgroup()
+ self.endTagColgroup(impliedTagToken("colgroup"))
+ if not ignoreEndTag:
+ return token
+
+ class InTableBodyPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-table0
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("tr", self.startTagTr),
+ (("td", "th"), self.startTagTableCell),
+ (("caption", "col", "colgroup", "tbody", "tfoot", "thead"),
+ self.startTagTableOther)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ (("tbody", "tfoot", "thead"), self.endTagTableRowGroup),
+ ("table", self.endTagTable),
+ (("body", "caption", "col", "colgroup", "html", "td", "th",
+ "tr"), self.endTagIgnore)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # helper methods
+ def clearStackToTableBodyContext(self):
+ while self.tree.openElements[-1].name not in ("tbody", "tfoot",
+ "thead", "html"):
+ # self.parser.parseError("unexpected-implied-end-tag-in-table",
+ # {"name": self.tree.openElements[-1].name})
+ self.tree.openElements.pop()
+ if self.tree.openElements[-1].name == "html":
+ assert self.parser.innerHTML
+
+ # the rest
+ def processEOF(self):
+ self.parser.phases["inTable"].processEOF()
+
+ def processSpaceCharacters(self, token):
+ return self.parser.phases["inTable"].processSpaceCharacters(token)
+
+ def processCharacters(self, token):
+ return self.parser.phases["inTable"].processCharacters(token)
+
+ def startTagTr(self, token):
+ self.clearStackToTableBodyContext()
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inRow"]
+
+ def startTagTableCell(self, token):
+ self.parser.parseError("unexpected-cell-in-table-body",
+ {"name": token["name"]})
+ self.startTagTr(impliedTagToken("tr", "StartTag"))
+ return token
+
+ def startTagTableOther(self, token):
+ # XXX AT Any ideas on how to share this with endTagTable?
+ if (self.tree.elementInScope("tbody", variant="table") or
+ self.tree.elementInScope("thead", variant="table") or
+ self.tree.elementInScope("tfoot", variant="table")):
+ self.clearStackToTableBodyContext()
+ self.endTagTableRowGroup(
+ impliedTagToken(self.tree.openElements[-1].name))
+ return token
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def startTagOther(self, token):
+ return self.parser.phases["inTable"].processStartTag(token)
+
+ def endTagTableRowGroup(self, token):
+ if self.tree.elementInScope(token["name"], variant="table"):
+ self.clearStackToTableBodyContext()
+ self.tree.openElements.pop()
+ self.parser.phase = self.parser.phases["inTable"]
+ else:
+ self.parser.parseError("unexpected-end-tag-in-table-body",
+ {"name": token["name"]})
+
+ def endTagTable(self, token):
+ if (self.tree.elementInScope("tbody", variant="table") or
+ self.tree.elementInScope("thead", variant="table") or
+ self.tree.elementInScope("tfoot", variant="table")):
+ self.clearStackToTableBodyContext()
+ self.endTagTableRowGroup(
+ impliedTagToken(self.tree.openElements[-1].name))
+ return token
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def endTagIgnore(self, token):
+ self.parser.parseError("unexpected-end-tag-in-table-body",
+ {"name": token["name"]})
+
+ def endTagOther(self, token):
+ return self.parser.phases["inTable"].processEndTag(token)
+
+ class InRowPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-row
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ (("td", "th"), self.startTagTableCell),
+ (("caption", "col", "colgroup", "tbody", "tfoot", "thead",
+ "tr"), self.startTagTableOther)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("tr", self.endTagTr),
+ ("table", self.endTagTable),
+ (("tbody", "tfoot", "thead"), self.endTagTableRowGroup),
+ (("body", "caption", "col", "colgroup", "html", "td", "th"),
+ self.endTagIgnore)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # helper methods (XXX unify this with other table helper methods)
+ def clearStackToTableRowContext(self):
+ while self.tree.openElements[-1].name not in ("tr", "html"):
+ self.parser.parseError("unexpected-implied-end-tag-in-table-row",
+ {"name": self.tree.openElements[-1].name})
+ self.tree.openElements.pop()
+
+ def ignoreEndTagTr(self):
+ return not self.tree.elementInScope("tr", variant="table")
+
+ # the rest
+ def processEOF(self):
+ self.parser.phases["inTable"].processEOF()
+
+ def processSpaceCharacters(self, token):
+ return self.parser.phases["inTable"].processSpaceCharacters(token)
+
+ def processCharacters(self, token):
+ return self.parser.phases["inTable"].processCharacters(token)
+
+ def startTagTableCell(self, token):
+ self.clearStackToTableRowContext()
+ self.tree.insertElement(token)
+ self.parser.phase = self.parser.phases["inCell"]
+ self.tree.activeFormattingElements.append(Marker)
+
+ def startTagTableOther(self, token):
+ ignoreEndTag = self.ignoreEndTagTr()
+ self.endTagTr(impliedTagToken("tr"))
+ # XXX how are we sure it's always ignored in the innerHTML case?
+ if not ignoreEndTag:
+ return token
+
+ def startTagOther(self, token):
+ return self.parser.phases["inTable"].processStartTag(token)
+
+ def endTagTr(self, token):
+ if not self.ignoreEndTagTr():
+ self.clearStackToTableRowContext()
+ self.tree.openElements.pop()
+ self.parser.phase = self.parser.phases["inTableBody"]
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def endTagTable(self, token):
+ ignoreEndTag = self.ignoreEndTagTr()
+ self.endTagTr(impliedTagToken("tr"))
+ # Reprocess the current tag if the tr end tag was not ignored
+ # XXX how are we sure it's always ignored in the innerHTML case?
+ if not ignoreEndTag:
+ return token
+
+ def endTagTableRowGroup(self, token):
+ if self.tree.elementInScope(token["name"], variant="table"):
+ self.endTagTr(impliedTagToken("tr"))
+ return token
+ else:
+ self.parser.parseError()
+
+ def endTagIgnore(self, token):
+ self.parser.parseError("unexpected-end-tag-in-table-row",
+ {"name": token["name"]})
+
+ def endTagOther(self, token):
+ return self.parser.phases["inTable"].processEndTag(token)
+
+ class InCellPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-cell
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), self.startTagTableOther)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ (("td", "th"), self.endTagTableCell),
+ (("body", "caption", "col", "colgroup", "html"), self.endTagIgnore),
+ (("table", "tbody", "tfoot", "thead", "tr"), self.endTagImply)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # helper
+ def closeCell(self):
+ if self.tree.elementInScope("td", variant="table"):
+ self.endTagTableCell(impliedTagToken("td"))
+ elif self.tree.elementInScope("th", variant="table"):
+ self.endTagTableCell(impliedTagToken("th"))
+
+ # the rest
+ def processEOF(self):
+ self.parser.phases["inBody"].processEOF()
+
+ def processCharacters(self, token):
+ return self.parser.phases["inBody"].processCharacters(token)
+
+ def startTagTableOther(self, token):
+ if (self.tree.elementInScope("td", variant="table") or
+ self.tree.elementInScope("th", variant="table")):
+ self.closeCell()
+ return token
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def startTagOther(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def endTagTableCell(self, token):
+ if self.tree.elementInScope(token["name"], variant="table"):
+ self.tree.generateImpliedEndTags(token["name"])
+ if self.tree.openElements[-1].name != token["name"]:
+ self.parser.parseError("unexpected-cell-end-tag",
+ {"name": token["name"]})
+ while True:
+ node = self.tree.openElements.pop()
+ if node.name == token["name"]:
+ break
+ else:
+ self.tree.openElements.pop()
+ self.tree.clearActiveFormattingElements()
+ self.parser.phase = self.parser.phases["inRow"]
+ else:
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def endTagIgnore(self, token):
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ def endTagImply(self, token):
+ if self.tree.elementInScope(token["name"], variant="table"):
+ self.closeCell()
+ return token
+ else:
+ # sometimes innerHTML case
+ self.parser.parseError()
+
+ def endTagOther(self, token):
+ return self.parser.phases["inBody"].processEndTag(token)
+
+ class InSelectPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("option", self.startTagOption),
+ ("optgroup", self.startTagOptgroup),
+ ("select", self.startTagSelect),
+ (("input", "keygen", "textarea"), self.startTagInput),
+ ("script", self.startTagScript)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("option", self.endTagOption),
+ ("optgroup", self.endTagOptgroup),
+ ("select", self.endTagSelect)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-select
+ def processEOF(self):
+ if self.tree.openElements[-1].name != "html":
+ self.parser.parseError("eof-in-select")
+ else:
+ assert self.parser.innerHTML
+
+ def processCharacters(self, token):
+ if token["data"] == "\u0000":
+ return
+ self.tree.insertText(token["data"])
+
+ def startTagOption(self, token):
+ # We need to imply </option> if <option> is the current node.
+ if self.tree.openElements[-1].name == "option":
+ self.tree.openElements.pop()
+ self.tree.insertElement(token)
+
+ def startTagOptgroup(self, token):
+ if self.tree.openElements[-1].name == "option":
+ self.tree.openElements.pop()
+ if self.tree.openElements[-1].name == "optgroup":
+ self.tree.openElements.pop()
+ self.tree.insertElement(token)
+
+ def startTagSelect(self, token):
+ self.parser.parseError("unexpected-select-in-select")
+ self.endTagSelect(impliedTagToken("select"))
+
+ def startTagInput(self, token):
+ self.parser.parseError("unexpected-input-in-select")
+ if self.tree.elementInScope("select", variant="select"):
+ self.endTagSelect(impliedTagToken("select"))
+ return token
+ else:
+ assert self.parser.innerHTML
+
+ def startTagScript(self, token):
+ return self.parser.phases["inHead"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("unexpected-start-tag-in-select",
+ {"name": token["name"]})
+
+ def endTagOption(self, token):
+ if self.tree.openElements[-1].name == "option":
+ self.tree.openElements.pop()
+ else:
+ self.parser.parseError("unexpected-end-tag-in-select",
+ {"name": "option"})
+
+ def endTagOptgroup(self, token):
+ # </optgroup> implicitly closes <option>
+ if (self.tree.openElements[-1].name == "option" and
+ self.tree.openElements[-2].name == "optgroup"):
+ self.tree.openElements.pop()
+ # It also closes </optgroup>
+ if self.tree.openElements[-1].name == "optgroup":
+ self.tree.openElements.pop()
+ # But nothing else
+ else:
+ self.parser.parseError("unexpected-end-tag-in-select",
+ {"name": "optgroup"})
+
+ def endTagSelect(self, token):
+ if self.tree.elementInScope("select", variant="select"):
+ node = self.tree.openElements.pop()
+ while node.name != "select":
+ node = self.tree.openElements.pop()
+ self.parser.resetInsertionMode()
+ else:
+ # innerHTML case
+ assert self.parser.innerHTML
+ self.parser.parseError()
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag-in-select",
+ {"name": token["name"]})
+
+ class InSelectInTablePhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
+ self.startTagTable)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
+ self.endTagTable)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ self.parser.phases["inSelect"].processEOF()
+
+ def processCharacters(self, token):
+ return self.parser.phases["inSelect"].processCharacters(token)
+
+ def startTagTable(self, token):
+ self.parser.parseError("unexpected-table-element-start-tag-in-select-in-table", {"name": token["name"]})
+ self.endTagOther(impliedTagToken("select"))
+ return token
+
+ def startTagOther(self, token):
+ return self.parser.phases["inSelect"].processStartTag(token)
+
+ def endTagTable(self, token):
+ self.parser.parseError("unexpected-table-element-end-tag-in-select-in-table", {"name": token["name"]})
+ if self.tree.elementInScope(token["name"], variant="table"):
+ self.endTagOther(impliedTagToken("select"))
+ return token
+
+ def endTagOther(self, token):
+ return self.parser.phases["inSelect"].processEndTag(token)
+
+ class InForeignContentPhase(Phase):
+ breakoutElements = frozenset(["b", "big", "blockquote", "body", "br",
+ "center", "code", "dd", "div", "dl", "dt",
+ "em", "embed", "h1", "h2", "h3",
+ "h4", "h5", "h6", "head", "hr", "i", "img",
+ "li", "listing", "menu", "meta", "nobr",
+ "ol", "p", "pre", "ruby", "s", "small",
+ "span", "strong", "strike", "sub", "sup",
+ "table", "tt", "u", "ul", "var"])
+
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ def adjustSVGTagNames(self, token):
+ replacements = {"altglyph": "altGlyph",
+ "altglyphdef": "altGlyphDef",
+ "altglyphitem": "altGlyphItem",
+ "animatecolor": "animateColor",
+ "animatemotion": "animateMotion",
+ "animatetransform": "animateTransform",
+ "clippath": "clipPath",
+ "feblend": "feBlend",
+ "fecolormatrix": "feColorMatrix",
+ "fecomponenttransfer": "feComponentTransfer",
+ "fecomposite": "feComposite",
+ "feconvolvematrix": "feConvolveMatrix",
+ "fediffuselighting": "feDiffuseLighting",
+ "fedisplacementmap": "feDisplacementMap",
+ "fedistantlight": "feDistantLight",
+ "feflood": "feFlood",
+ "fefunca": "feFuncA",
+ "fefuncb": "feFuncB",
+ "fefuncg": "feFuncG",
+ "fefuncr": "feFuncR",
+ "fegaussianblur": "feGaussianBlur",
+ "feimage": "feImage",
+ "femerge": "feMerge",
+ "femergenode": "feMergeNode",
+ "femorphology": "feMorphology",
+ "feoffset": "feOffset",
+ "fepointlight": "fePointLight",
+ "fespecularlighting": "feSpecularLighting",
+ "fespotlight": "feSpotLight",
+ "fetile": "feTile",
+ "feturbulence": "feTurbulence",
+ "foreignobject": "foreignObject",
+ "glyphref": "glyphRef",
+ "lineargradient": "linearGradient",
+ "radialgradient": "radialGradient",
+ "textpath": "textPath"}
+
+ if token["name"] in replacements:
+ token["name"] = replacements[token["name"]]
+
+ def processCharacters(self, token):
+ if token["data"] == "\u0000":
+ token["data"] = "\uFFFD"
+ elif (self.parser.framesetOK and
+ any(char not in spaceCharacters for char in token["data"])):
+ self.parser.framesetOK = False
+ Phase.processCharacters(self, token)
+
+ def processStartTag(self, token):
+ currentNode = self.tree.openElements[-1]
+ if (token["name"] in self.breakoutElements or
+ (token["name"] == "font" and
+ set(token["data"].keys()) & set(["color", "face", "size"]))):
+ self.parser.parseError("unexpected-html-element-in-foreign-content",
+ {"name": token["name"]})
+ while (self.tree.openElements[-1].namespace !=
+ self.tree.defaultNamespace and
+ not self.parser.isHTMLIntegrationPoint(self.tree.openElements[-1]) and
+ not self.parser.isMathMLTextIntegrationPoint(self.tree.openElements[-1])):
+ self.tree.openElements.pop()
+ return token
+
+ else:
+ if currentNode.namespace == namespaces["mathml"]:
+ self.parser.adjustMathMLAttributes(token)
+ elif currentNode.namespace == namespaces["svg"]:
+ self.adjustSVGTagNames(token)
+ self.parser.adjustSVGAttributes(token)
+ self.parser.adjustForeignAttributes(token)
+ token["namespace"] = currentNode.namespace
+ self.tree.insertElement(token)
+ if token["selfClosing"]:
+ self.tree.openElements.pop()
+ token["selfClosingAcknowledged"] = True
+
+ def processEndTag(self, token):
+ nodeIndex = len(self.tree.openElements) - 1
+ node = self.tree.openElements[-1]
+ if node.name != token["name"]:
+ self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
+
+ while True:
+ if node.name.translate(asciiUpper2Lower) == token["name"]:
+ # XXX this isn't in the spec but it seems necessary
+ if self.parser.phase == self.parser.phases["inTableText"]:
+ self.parser.phase.flushCharacters()
+ self.parser.phase = self.parser.phase.originalPhase
+ while self.tree.openElements.pop() != node:
+ assert self.tree.openElements
+ new_token = None
+ break
+ nodeIndex -= 1
+
+ node = self.tree.openElements[nodeIndex]
+ if node.namespace != self.tree.defaultNamespace:
+ continue
+ else:
+ new_token = self.parser.phase.processEndTag(token)
+ break
+ return new_token
+
+ class AfterBodyPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([("html", self.endTagHtml)])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ # Stop parsing
+ pass
+
+ def processComment(self, token):
+ # This is needed because data is to be appended to the <html> element
+ # here and not to whatever is currently open.
+ self.tree.insertComment(token, self.tree.openElements[0])
+
+ def processCharacters(self, token):
+ self.parser.parseError("unexpected-char-after-body")
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("unexpected-start-tag-after-body",
+ {"name": token["name"]})
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ def endTagHtml(self, name):
+ if self.parser.innerHTML:
+ self.parser.parseError("unexpected-end-tag-after-body-innerhtml")
+ else:
+ self.parser.phase = self.parser.phases["afterAfterBody"]
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag-after-body",
+ {"name": token["name"]})
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ class InFramesetPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#in-frameset
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("frameset", self.startTagFrameset),
+ ("frame", self.startTagFrame),
+ ("noframes", self.startTagNoframes)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("frameset", self.endTagFrameset)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ if self.tree.openElements[-1].name != "html":
+ self.parser.parseError("eof-in-frameset")
+ else:
+ assert self.parser.innerHTML
+
+ def processCharacters(self, token):
+ self.parser.parseError("unexpected-char-in-frameset")
+
+ def startTagFrameset(self, token):
+ self.tree.insertElement(token)
+
+ def startTagFrame(self, token):
+ self.tree.insertElement(token)
+ self.tree.openElements.pop()
+
+ def startTagNoframes(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("unexpected-start-tag-in-frameset",
+ {"name": token["name"]})
+
+ def endTagFrameset(self, token):
+ if self.tree.openElements[-1].name == "html":
+ # innerHTML case
+ self.parser.parseError("unexpected-frameset-in-frameset-innerhtml")
+ else:
+ self.tree.openElements.pop()
+ if (not self.parser.innerHTML and
+ self.tree.openElements[-1].name != "frameset"):
+ # If we're not in innerHTML mode and the the current node is not a
+ # "frameset" element (anymore) then switch.
+ self.parser.phase = self.parser.phases["afterFrameset"]
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag-in-frameset",
+ {"name": token["name"]})
+
+ class AfterFramesetPhase(Phase):
+ # http://www.whatwg.org/specs/web-apps/current-work/#after3
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("noframes", self.startTagNoframes)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ self.endTagHandler = utils.MethodDispatcher([
+ ("html", self.endTagHtml)
+ ])
+ self.endTagHandler.default = self.endTagOther
+
+ def processEOF(self):
+ # Stop parsing
+ pass
+
+ def processCharacters(self, token):
+ self.parser.parseError("unexpected-char-after-frameset")
+
+ def startTagNoframes(self, token):
+ return self.parser.phases["inHead"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("unexpected-start-tag-after-frameset",
+ {"name": token["name"]})
+
+ def endTagHtml(self, token):
+ self.parser.phase = self.parser.phases["afterAfterFrameset"]
+
+ def endTagOther(self, token):
+ self.parser.parseError("unexpected-end-tag-after-frameset",
+ {"name": token["name"]})
+
+ class AfterAfterBodyPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ def processEOF(self):
+ pass
+
+ def processComment(self, token):
+ self.tree.insertComment(token, self.tree.document)
+
+ def processSpaceCharacters(self, token):
+ return self.parser.phases["inBody"].processSpaceCharacters(token)
+
+ def processCharacters(self, token):
+ self.parser.parseError("expected-eof-but-got-char")
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("expected-eof-but-got-start-tag",
+ {"name": token["name"]})
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ def processEndTag(self, token):
+ self.parser.parseError("expected-eof-but-got-end-tag",
+ {"name": token["name"]})
+ self.parser.phase = self.parser.phases["inBody"]
+ return token
+
+ class AfterAfterFramesetPhase(Phase):
+ def __init__(self, parser, tree):
+ Phase.__init__(self, parser, tree)
+
+ self.startTagHandler = utils.MethodDispatcher([
+ ("html", self.startTagHtml),
+ ("noframes", self.startTagNoFrames)
+ ])
+ self.startTagHandler.default = self.startTagOther
+
+ def processEOF(self):
+ pass
+
+ def processComment(self, token):
+ self.tree.insertComment(token, self.tree.document)
+
+ def processSpaceCharacters(self, token):
+ return self.parser.phases["inBody"].processSpaceCharacters(token)
+
+ def processCharacters(self, token):
+ self.parser.parseError("expected-eof-but-got-char")
+
+ def startTagHtml(self, token):
+ return self.parser.phases["inBody"].processStartTag(token)
+
+ def startTagNoFrames(self, token):
+ return self.parser.phases["inHead"].processStartTag(token)
+
+ def startTagOther(self, token):
+ self.parser.parseError("expected-eof-but-got-start-tag",
+ {"name": token["name"]})
+
+ def processEndTag(self, token):
+ self.parser.parseError("expected-eof-but-got-end-tag",
+ {"name": token["name"]})
+
+ return {
+ "initial": InitialPhase,
+ "beforeHtml": BeforeHtmlPhase,
+ "beforeHead": BeforeHeadPhase,
+ "inHead": InHeadPhase,
+ # XXX "inHeadNoscript": InHeadNoScriptPhase,
+ "afterHead": AfterHeadPhase,
+ "inBody": InBodyPhase,
+ "text": TextPhase,
+ "inTable": InTablePhase,
+ "inTableText": InTableTextPhase,
+ "inCaption": InCaptionPhase,
+ "inColumnGroup": InColumnGroupPhase,
+ "inTableBody": InTableBodyPhase,
+ "inRow": InRowPhase,
+ "inCell": InCellPhase,
+ "inSelect": InSelectPhase,
+ "inSelectInTable": InSelectInTablePhase,
+ "inForeignContent": InForeignContentPhase,
+ "afterBody": AfterBodyPhase,
+ "inFrameset": InFramesetPhase,
+ "afterFrameset": AfterFramesetPhase,
+ "afterAfterBody": AfterAfterBodyPhase,
+ "afterAfterFrameset": AfterAfterFramesetPhase,
+ # XXX after after frameset
+ }
+
+
+def impliedTagToken(name, type="EndTag", attributes=None,
+ selfClosing=False):
+ if attributes is None:
+ attributes = {}
+ return {"type": tokenTypes[type], "name": name, "data": attributes,
+ "selfClosing": selfClosing}
+
+
+class ParseError(Exception):
+ """Error in parsed document"""
+ pass
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/ihatexml.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/ihatexml.py
new file mode 100644
index 00000000000..0fc79308ef4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/ihatexml.py
@@ -0,0 +1,285 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import re
+import warnings
+
+from .constants import DataLossWarning
+
+baseChar = """
+[#x0041-#x005A] | [#x0061-#x007A] | [#x00C0-#x00D6] | [#x00D8-#x00F6] |
+[#x00F8-#x00FF] | [#x0100-#x0131] | [#x0134-#x013E] | [#x0141-#x0148] |
+[#x014A-#x017E] | [#x0180-#x01C3] | [#x01CD-#x01F0] | [#x01F4-#x01F5] |
+[#x01FA-#x0217] | [#x0250-#x02A8] | [#x02BB-#x02C1] | #x0386 |
+[#x0388-#x038A] | #x038C | [#x038E-#x03A1] | [#x03A3-#x03CE] |
+[#x03D0-#x03D6] | #x03DA | #x03DC | #x03DE | #x03E0 | [#x03E2-#x03F3] |
+[#x0401-#x040C] | [#x040E-#x044F] | [#x0451-#x045C] | [#x045E-#x0481] |
+[#x0490-#x04C4] | [#x04C7-#x04C8] | [#x04CB-#x04CC] | [#x04D0-#x04EB] |
+[#x04EE-#x04F5] | [#x04F8-#x04F9] | [#x0531-#x0556] | #x0559 |
+[#x0561-#x0586] | [#x05D0-#x05EA] | [#x05F0-#x05F2] | [#x0621-#x063A] |
+[#x0641-#x064A] | [#x0671-#x06B7] | [#x06BA-#x06BE] | [#x06C0-#x06CE] |
+[#x06D0-#x06D3] | #x06D5 | [#x06E5-#x06E6] | [#x0905-#x0939] | #x093D |
+[#x0958-#x0961] | [#x0985-#x098C] | [#x098F-#x0990] | [#x0993-#x09A8] |
+[#x09AA-#x09B0] | #x09B2 | [#x09B6-#x09B9] | [#x09DC-#x09DD] |
+[#x09DF-#x09E1] | [#x09F0-#x09F1] | [#x0A05-#x0A0A] | [#x0A0F-#x0A10] |
+[#x0A13-#x0A28] | [#x0A2A-#x0A30] | [#x0A32-#x0A33] | [#x0A35-#x0A36] |
+[#x0A38-#x0A39] | [#x0A59-#x0A5C] | #x0A5E | [#x0A72-#x0A74] |
+[#x0A85-#x0A8B] | #x0A8D | [#x0A8F-#x0A91] | [#x0A93-#x0AA8] |
+[#x0AAA-#x0AB0] | [#x0AB2-#x0AB3] | [#x0AB5-#x0AB9] | #x0ABD | #x0AE0 |
+[#x0B05-#x0B0C] | [#x0B0F-#x0B10] | [#x0B13-#x0B28] | [#x0B2A-#x0B30] |
+[#x0B32-#x0B33] | [#x0B36-#x0B39] | #x0B3D | [#x0B5C-#x0B5D] |
+[#x0B5F-#x0B61] | [#x0B85-#x0B8A] | [#x0B8E-#x0B90] | [#x0B92-#x0B95] |
+[#x0B99-#x0B9A] | #x0B9C | [#x0B9E-#x0B9F] | [#x0BA3-#x0BA4] |
+[#x0BA8-#x0BAA] | [#x0BAE-#x0BB5] | [#x0BB7-#x0BB9] | [#x0C05-#x0C0C] |
+[#x0C0E-#x0C10] | [#x0C12-#x0C28] | [#x0C2A-#x0C33] | [#x0C35-#x0C39] |
+[#x0C60-#x0C61] | [#x0C85-#x0C8C] | [#x0C8E-#x0C90] | [#x0C92-#x0CA8] |
+[#x0CAA-#x0CB3] | [#x0CB5-#x0CB9] | #x0CDE | [#x0CE0-#x0CE1] |
+[#x0D05-#x0D0C] | [#x0D0E-#x0D10] | [#x0D12-#x0D28] | [#x0D2A-#x0D39] |
+[#x0D60-#x0D61] | [#x0E01-#x0E2E] | #x0E30 | [#x0E32-#x0E33] |
+[#x0E40-#x0E45] | [#x0E81-#x0E82] | #x0E84 | [#x0E87-#x0E88] | #x0E8A |
+#x0E8D | [#x0E94-#x0E97] | [#x0E99-#x0E9F] | [#x0EA1-#x0EA3] | #x0EA5 |
+#x0EA7 | [#x0EAA-#x0EAB] | [#x0EAD-#x0EAE] | #x0EB0 | [#x0EB2-#x0EB3] |
+#x0EBD | [#x0EC0-#x0EC4] | [#x0F40-#x0F47] | [#x0F49-#x0F69] |
+[#x10A0-#x10C5] | [#x10D0-#x10F6] | #x1100 | [#x1102-#x1103] |
+[#x1105-#x1107] | #x1109 | [#x110B-#x110C] | [#x110E-#x1112] | #x113C |
+#x113E | #x1140 | #x114C | #x114E | #x1150 | [#x1154-#x1155] | #x1159 |
+[#x115F-#x1161] | #x1163 | #x1165 | #x1167 | #x1169 | [#x116D-#x116E] |
+[#x1172-#x1173] | #x1175 | #x119E | #x11A8 | #x11AB | [#x11AE-#x11AF] |
+[#x11B7-#x11B8] | #x11BA | [#x11BC-#x11C2] | #x11EB | #x11F0 | #x11F9 |
+[#x1E00-#x1E9B] | [#x1EA0-#x1EF9] | [#x1F00-#x1F15] | [#x1F18-#x1F1D] |
+[#x1F20-#x1F45] | [#x1F48-#x1F4D] | [#x1F50-#x1F57] | #x1F59 | #x1F5B |
+#x1F5D | [#x1F5F-#x1F7D] | [#x1F80-#x1FB4] | [#x1FB6-#x1FBC] | #x1FBE |
+[#x1FC2-#x1FC4] | [#x1FC6-#x1FCC] | [#x1FD0-#x1FD3] | [#x1FD6-#x1FDB] |
+[#x1FE0-#x1FEC] | [#x1FF2-#x1FF4] | [#x1FF6-#x1FFC] | #x2126 |
+[#x212A-#x212B] | #x212E | [#x2180-#x2182] | [#x3041-#x3094] |
+[#x30A1-#x30FA] | [#x3105-#x312C] | [#xAC00-#xD7A3]"""
+
+ideographic = """[#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]"""
+
+combiningCharacter = """
+[#x0300-#x0345] | [#x0360-#x0361] | [#x0483-#x0486] | [#x0591-#x05A1] |
+[#x05A3-#x05B9] | [#x05BB-#x05BD] | #x05BF | [#x05C1-#x05C2] | #x05C4 |
+[#x064B-#x0652] | #x0670 | [#x06D6-#x06DC] | [#x06DD-#x06DF] |
+[#x06E0-#x06E4] | [#x06E7-#x06E8] | [#x06EA-#x06ED] | [#x0901-#x0903] |
+#x093C | [#x093E-#x094C] | #x094D | [#x0951-#x0954] | [#x0962-#x0963] |
+[#x0981-#x0983] | #x09BC | #x09BE | #x09BF | [#x09C0-#x09C4] |
+[#x09C7-#x09C8] | [#x09CB-#x09CD] | #x09D7 | [#x09E2-#x09E3] | #x0A02 |
+#x0A3C | #x0A3E | #x0A3F | [#x0A40-#x0A42] | [#x0A47-#x0A48] |
+[#x0A4B-#x0A4D] | [#x0A70-#x0A71] | [#x0A81-#x0A83] | #x0ABC |
+[#x0ABE-#x0AC5] | [#x0AC7-#x0AC9] | [#x0ACB-#x0ACD] | [#x0B01-#x0B03] |
+#x0B3C | [#x0B3E-#x0B43] | [#x0B47-#x0B48] | [#x0B4B-#x0B4D] |
+[#x0B56-#x0B57] | [#x0B82-#x0B83] | [#x0BBE-#x0BC2] | [#x0BC6-#x0BC8] |
+[#x0BCA-#x0BCD] | #x0BD7 | [#x0C01-#x0C03] | [#x0C3E-#x0C44] |
+[#x0C46-#x0C48] | [#x0C4A-#x0C4D] | [#x0C55-#x0C56] | [#x0C82-#x0C83] |
+[#x0CBE-#x0CC4] | [#x0CC6-#x0CC8] | [#x0CCA-#x0CCD] | [#x0CD5-#x0CD6] |
+[#x0D02-#x0D03] | [#x0D3E-#x0D43] | [#x0D46-#x0D48] | [#x0D4A-#x0D4D] |
+#x0D57 | #x0E31 | [#x0E34-#x0E3A] | [#x0E47-#x0E4E] | #x0EB1 |
+[#x0EB4-#x0EB9] | [#x0EBB-#x0EBC] | [#x0EC8-#x0ECD] | [#x0F18-#x0F19] |
+#x0F35 | #x0F37 | #x0F39 | #x0F3E | #x0F3F | [#x0F71-#x0F84] |
+[#x0F86-#x0F8B] | [#x0F90-#x0F95] | #x0F97 | [#x0F99-#x0FAD] |
+[#x0FB1-#x0FB7] | #x0FB9 | [#x20D0-#x20DC] | #x20E1 | [#x302A-#x302F] |
+#x3099 | #x309A"""
+
+digit = """
+[#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] |
+[#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] |
+[#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] |
+[#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29]"""
+
+extender = """
+#x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 |
+#[#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE]"""
+
+letter = " | ".join([baseChar, ideographic])
+
+# Without the
+name = " | ".join([letter, digit, ".", "-", "_", combiningCharacter,
+ extender])
+nameFirst = " | ".join([letter, "_"])
+
+reChar = re.compile(r"#x([\d|A-F]{4,4})")
+reCharRange = re.compile(r"\[#x([\d|A-F]{4,4})-#x([\d|A-F]{4,4})\]")
+
+
+def charStringToList(chars):
+ charRanges = [item.strip() for item in chars.split(" | ")]
+ rv = []
+ for item in charRanges:
+ foundMatch = False
+ for regexp in (reChar, reCharRange):
+ match = regexp.match(item)
+ if match is not None:
+ rv.append([hexToInt(item) for item in match.groups()])
+ if len(rv[-1]) == 1:
+ rv[-1] = rv[-1] * 2
+ foundMatch = True
+ break
+ if not foundMatch:
+ assert len(item) == 1
+
+ rv.append([ord(item)] * 2)
+ rv = normaliseCharList(rv)
+ return rv
+
+
+def normaliseCharList(charList):
+ charList = sorted(charList)
+ for item in charList:
+ assert item[1] >= item[0]
+ rv = []
+ i = 0
+ while i < len(charList):
+ j = 1
+ rv.append(charList[i])
+ while i + j < len(charList) and charList[i + j][0] <= rv[-1][1] + 1:
+ rv[-1][1] = charList[i + j][1]
+ j += 1
+ i += j
+ return rv
+
+# We don't really support characters above the BMP :(
+max_unicode = int("FFFF", 16)
+
+
+def missingRanges(charList):
+ rv = []
+ if charList[0] != 0:
+ rv.append([0, charList[0][0] - 1])
+ for i, item in enumerate(charList[:-1]):
+ rv.append([item[1] + 1, charList[i + 1][0] - 1])
+ if charList[-1][1] != max_unicode:
+ rv.append([charList[-1][1] + 1, max_unicode])
+ return rv
+
+
+def listToRegexpStr(charList):
+ rv = []
+ for item in charList:
+ if item[0] == item[1]:
+ rv.append(escapeRegexp(chr(item[0])))
+ else:
+ rv.append(escapeRegexp(chr(item[0])) + "-" +
+ escapeRegexp(chr(item[1])))
+ return "[%s]" % "".join(rv)
+
+
+def hexToInt(hex_str):
+ return int(hex_str, 16)
+
+
+def escapeRegexp(string):
+ specialCharacters = (".", "^", "$", "*", "+", "?", "{", "}",
+ "[", "]", "|", "(", ")", "-")
+ for char in specialCharacters:
+ string = string.replace(char, "\\" + char)
+
+ return string
+
+# output from the above
+nonXmlNameBMPRegexp = re.compile('[\x00-,/:-@\\[-\\^`\\{-\xb6\xb8-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u02cf\u02d2-\u02ff\u0346-\u035f\u0362-\u0385\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482\u0487-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u0590\u05a2\u05ba\u05be\u05c0\u05c3\u05c5-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u063f\u0653-\u065f\u066a-\u066f\u06b8-\u06b9\u06bf\u06cf\u06d4\u06e9\u06ee-\u06ef\u06fa-\u0900\u0904\u093a-\u093b\u094e-\u0950\u0955-\u0957\u0964-\u0965\u0970-\u0980\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09bb\u09bd\u09c5-\u09c6\u09c9-\u09ca\u09ce-\u09d6\u09d8-\u09db\u09de\u09e4-\u09e5\u09f2-\u0a01\u0a03-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a3b\u0a3d\u0a43-\u0a46\u0a49-\u0a4a\u0a4e-\u0a58\u0a5d\u0a5f-\u0a65\u0a75-\u0a80\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abb\u0ac6\u0aca\u0ace-\u0adf\u0ae1-\u0ae5\u0af0-\u0b00\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3b\u0b44-\u0b46\u0b49-\u0b4a\u0b4e-\u0b55\u0b58-\u0b5b\u0b5e\u0b62-\u0b65\u0b70-\u0b81\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0bbd\u0bc3-\u0bc5\u0bc9\u0bce-\u0bd6\u0bd8-\u0be6\u0bf0-\u0c00\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c3d\u0c45\u0c49\u0c4e-\u0c54\u0c57-\u0c5f\u0c62-\u0c65\u0c70-\u0c81\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cbd\u0cc5\u0cc9\u0cce-\u0cd4\u0cd7-\u0cdd\u0cdf\u0ce2-\u0ce5\u0cf0-\u0d01\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d3d\u0d44-\u0d45\u0d49\u0d4e-\u0d56\u0d58-\u0d5f\u0d62-\u0d65\u0d70-\u0e00\u0e2f\u0e3b-\u0e3f\u0e4f\u0e5a-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eba\u0ebe-\u0ebf\u0ec5\u0ec7\u0ece-\u0ecf\u0eda-\u0f17\u0f1a-\u0f1f\u0f2a-\u0f34\u0f36\u0f38\u0f3a-\u0f3d\u0f48\u0f6a-\u0f70\u0f85\u0f8c-\u0f8f\u0f96\u0f98\u0fae-\u0fb0\u0fb8\u0fba-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u20cf\u20dd-\u20e0\u20e2-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3004\u3006\u3008-\u3020\u3030\u3036-\u3040\u3095-\u3098\u309b-\u309c\u309f-\u30a0\u30fb\u30ff-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]')
+
+nonXmlNameFirstBMPRegexp = re.compile('[\x00-@\\[-\\^`\\{-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u0385\u0387\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u0640\u064b-\u0670\u06b8-\u06b9\u06bf\u06cf\u06d4\u06d6-\u06e4\u06e7-\u0904\u093a-\u093c\u093e-\u0957\u0962-\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09db\u09de\u09e2-\u09ef\u09f2-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a58\u0a5d\u0a5f-\u0a71\u0a75-\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abc\u0abe-\u0adf\u0ae1-\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3c\u0b3e-\u0b5b\u0b5e\u0b62-\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c5f\u0c62-\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cdd\u0cdf\u0ce2-\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d5f\u0d62-\u0e00\u0e2f\u0e31\u0e34-\u0e3f\u0e46-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eb1\u0eb4-\u0ebc\u0ebe-\u0ebf\u0ec5-\u0f3f\u0f48\u0f6a-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3006\u3008-\u3020\u302a-\u3040\u3095-\u30a0\u30fb-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]')
+
+# Simpler things
+nonPubidCharRegexp = re.compile("[^\x20\x0D\x0Aa-zA-Z0-9\-\'()+,./:=?;!*#@$_%]")
+
+
+class InfosetFilter(object):
+ replacementRegexp = re.compile(r"U[\dA-F]{5,5}")
+
+ def __init__(self, replaceChars=None,
+ dropXmlnsLocalName=False,
+ dropXmlnsAttrNs=False,
+ preventDoubleDashComments=False,
+ preventDashAtCommentEnd=False,
+ replaceFormFeedCharacters=True,
+ preventSingleQuotePubid=False):
+
+ self.dropXmlnsLocalName = dropXmlnsLocalName
+ self.dropXmlnsAttrNs = dropXmlnsAttrNs
+
+ self.preventDoubleDashComments = preventDoubleDashComments
+ self.preventDashAtCommentEnd = preventDashAtCommentEnd
+
+ self.replaceFormFeedCharacters = replaceFormFeedCharacters
+
+ self.preventSingleQuotePubid = preventSingleQuotePubid
+
+ self.replaceCache = {}
+
+ def coerceAttribute(self, name, namespace=None):
+ if self.dropXmlnsLocalName and name.startswith("xmlns:"):
+ warnings.warn("Attributes cannot begin with xmlns", DataLossWarning)
+ return None
+ elif (self.dropXmlnsAttrNs and
+ namespace == "http://www.w3.org/2000/xmlns/"):
+ warnings.warn("Attributes cannot be in the xml namespace", DataLossWarning)
+ return None
+ else:
+ return self.toXmlName(name)
+
+ def coerceElement(self, name, namespace=None):
+ return self.toXmlName(name)
+
+ def coerceComment(self, data):
+ if self.preventDoubleDashComments:
+ while "--" in data:
+ warnings.warn("Comments cannot contain adjacent dashes", DataLossWarning)
+ data = data.replace("--", "- -")
+ return data
+
+ def coerceCharacters(self, data):
+ if self.replaceFormFeedCharacters:
+ for i in range(data.count("\x0C")):
+ warnings.warn("Text cannot contain U+000C", DataLossWarning)
+ data = data.replace("\x0C", " ")
+ # Other non-xml characters
+ return data
+
+ def coercePubid(self, data):
+ dataOutput = data
+ for char in nonPubidCharRegexp.findall(data):
+ warnings.warn("Coercing non-XML pubid", DataLossWarning)
+ replacement = self.getReplacementCharacter(char)
+ dataOutput = dataOutput.replace(char, replacement)
+ if self.preventSingleQuotePubid and dataOutput.find("'") >= 0:
+ warnings.warn("Pubid cannot contain single quote", DataLossWarning)
+ dataOutput = dataOutput.replace("'", self.getReplacementCharacter("'"))
+ return dataOutput
+
+ def toXmlName(self, name):
+ nameFirst = name[0]
+ nameRest = name[1:]
+ m = nonXmlNameFirstBMPRegexp.match(nameFirst)
+ if m:
+ warnings.warn("Coercing non-XML name", DataLossWarning)
+ nameFirstOutput = self.getReplacementCharacter(nameFirst)
+ else:
+ nameFirstOutput = nameFirst
+
+ nameRestOutput = nameRest
+ replaceChars = set(nonXmlNameBMPRegexp.findall(nameRest))
+ for char in replaceChars:
+ warnings.warn("Coercing non-XML name", DataLossWarning)
+ replacement = self.getReplacementCharacter(char)
+ nameRestOutput = nameRestOutput.replace(char, replacement)
+ return nameFirstOutput + nameRestOutput
+
+ def getReplacementCharacter(self, char):
+ if char in self.replaceCache:
+ replacement = self.replaceCache[char]
+ else:
+ replacement = self.escapeChar(char)
+ return replacement
+
+ def fromXmlName(self, name):
+ for item in set(self.replacementRegexp.findall(name)):
+ name = name.replace(item, self.unescapeChar(item))
+ return name
+
+ def escapeChar(self, char):
+ replacement = "U%05X" % ord(char)
+ self.replaceCache[char] = replacement
+ return replacement
+
+ def unescapeChar(self, charcode):
+ return chr(int(charcode[1:], 16))
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/inputstream.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/inputstream.py
new file mode 100644
index 00000000000..7020aa60f6a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/inputstream.py
@@ -0,0 +1,903 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+from six.moves import http_client
+
+import codecs
+import re
+
+from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase
+from .constants import encodings, ReparseException
+from . import utils
+
+from io import StringIO
+
+try:
+ from io import BytesIO
+except ImportError:
+ BytesIO = StringIO
+
+try:
+ from io import BufferedIOBase
+except ImportError:
+ class BufferedIOBase(object):
+ pass
+
+# Non-unicode versions of constants for use in the pre-parser
+spaceCharactersBytes = frozenset([item.encode("ascii") for item in spaceCharacters])
+asciiLettersBytes = frozenset([item.encode("ascii") for item in asciiLetters])
+asciiUppercaseBytes = frozenset([item.encode("ascii") for item in asciiUppercase])
+spacesAngleBrackets = spaceCharactersBytes | frozenset([b">", b"<"])
+
+
+invalid_unicode_no_surrogate = "[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]"
+
+if utils.supports_lone_surrogates:
+ # Use one extra step of indirection and create surrogates with
+ # unichr. Not using this indirection would introduce an illegal
+ # unicode literal on platforms not supporting such lone
+ # surrogates.
+ invalid_unicode_re = re.compile(invalid_unicode_no_surrogate +
+ eval('"\\uD800-\\uDFFF"'))
+else:
+ invalid_unicode_re = re.compile(invalid_unicode_no_surrogate)
+
+non_bmp_invalid_codepoints = set([0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
+ 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF,
+ 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE,
+ 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF,
+ 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
+ 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF,
+ 0x10FFFE, 0x10FFFF])
+
+ascii_punctuation_re = re.compile("[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]")
+
+# Cache for charsUntil()
+charsUntilRegEx = {}
+
+
+class BufferedStream(object):
+ """Buffering for streams that do not have buffering of their own
+
+ The buffer is implemented as a list of chunks on the assumption that
+ joining many strings will be slow since it is O(n**2)
+ """
+
+ def __init__(self, stream):
+ self.stream = stream
+ self.buffer = []
+ self.position = [-1, 0] # chunk number, offset
+
+ def tell(self):
+ pos = 0
+ for chunk in self.buffer[:self.position[0]]:
+ pos += len(chunk)
+ pos += self.position[1]
+ return pos
+
+ def seek(self, pos):
+ assert pos <= self._bufferedBytes()
+ offset = pos
+ i = 0
+ while len(self.buffer[i]) < offset:
+ offset -= len(self.buffer[i])
+ i += 1
+ self.position = [i, offset]
+
+ def read(self, bytes):
+ if not self.buffer:
+ return self._readStream(bytes)
+ elif (self.position[0] == len(self.buffer) and
+ self.position[1] == len(self.buffer[-1])):
+ return self._readStream(bytes)
+ else:
+ return self._readFromBuffer(bytes)
+
+ def _bufferedBytes(self):
+ return sum([len(item) for item in self.buffer])
+
+ def _readStream(self, bytes):
+ data = self.stream.read(bytes)
+ self.buffer.append(data)
+ self.position[0] += 1
+ self.position[1] = len(data)
+ return data
+
+ def _readFromBuffer(self, bytes):
+ remainingBytes = bytes
+ rv = []
+ bufferIndex = self.position[0]
+ bufferOffset = self.position[1]
+ while bufferIndex < len(self.buffer) and remainingBytes != 0:
+ assert remainingBytes > 0
+ bufferedData = self.buffer[bufferIndex]
+
+ if remainingBytes <= len(bufferedData) - bufferOffset:
+ bytesToRead = remainingBytes
+ self.position = [bufferIndex, bufferOffset + bytesToRead]
+ else:
+ bytesToRead = len(bufferedData) - bufferOffset
+ self.position = [bufferIndex, len(bufferedData)]
+ bufferIndex += 1
+ rv.append(bufferedData[bufferOffset:bufferOffset + bytesToRead])
+ remainingBytes -= bytesToRead
+
+ bufferOffset = 0
+
+ if remainingBytes:
+ rv.append(self._readStream(remainingBytes))
+
+ return b"".join(rv)
+
+
+def HTMLInputStream(source, encoding=None, parseMeta=True, chardet=True):
+ if isinstance(source, http_client.HTTPResponse):
+ # Work around Python bug #20007: read(0) closes the connection.
+ # http://bugs.python.org/issue20007
+ isUnicode = False
+ elif hasattr(source, "read"):
+ isUnicode = isinstance(source.read(0), text_type)
+ else:
+ isUnicode = isinstance(source, text_type)
+
+ if isUnicode:
+ if encoding is not None:
+ raise TypeError("Cannot explicitly set an encoding with a unicode string")
+
+ return HTMLUnicodeInputStream(source)
+ else:
+ return HTMLBinaryInputStream(source, encoding, parseMeta, chardet)
+
+
+class HTMLUnicodeInputStream(object):
+ """Provides a unicode stream of characters to the HTMLTokenizer.
+
+ This class takes care of character encoding and removing or replacing
+ incorrect byte-sequences and also provides column and line tracking.
+
+ """
+
+ _defaultChunkSize = 10240
+
+ def __init__(self, source):
+ """Initialises the HTMLInputStream.
+
+ HTMLInputStream(source, [encoding]) -> Normalized stream from source
+ for use by html5lib.
+
+ source can be either a file-object, local filename or a string.
+
+ The optional encoding parameter must be a string that indicates
+ the encoding. If specified, that encoding will be used,
+ regardless of any BOM or later declaration (such as in a meta
+ element)
+
+ parseMeta - Look for a <meta> element containing encoding information
+
+ """
+
+ if not utils.supports_lone_surrogates:
+ # Such platforms will have already checked for such
+ # surrogate errors, so no need to do this checking.
+ self.reportCharacterErrors = None
+ self.replaceCharactersRegexp = None
+ elif len("\U0010FFFF") == 1:
+ self.reportCharacterErrors = self.characterErrorsUCS4
+ self.replaceCharactersRegexp = re.compile(eval('"[\\uD800-\\uDFFF]"'))
+ else:
+ self.reportCharacterErrors = self.characterErrorsUCS2
+ self.replaceCharactersRegexp = re.compile(
+ eval('"([\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF])"'))
+
+ # List of where new lines occur
+ self.newLines = [0]
+
+ self.charEncoding = ("utf-8", "certain")
+ self.dataStream = self.openStream(source)
+
+ self.reset()
+
+ def reset(self):
+ self.chunk = ""
+ self.chunkSize = 0
+ self.chunkOffset = 0
+ self.errors = []
+
+ # number of (complete) lines in previous chunks
+ self.prevNumLines = 0
+ # number of columns in the last line of the previous chunk
+ self.prevNumCols = 0
+
+ # Deal with CR LF and surrogates split over chunk boundaries
+ self._bufferedCharacter = None
+
+ def openStream(self, source):
+ """Produces a file object from source.
+
+ source can be either a file object, local filename or a string.
+
+ """
+ # Already a file object
+ if hasattr(source, 'read'):
+ stream = source
+ else:
+ stream = StringIO(source)
+
+ return stream
+
+ def _position(self, offset):
+ chunk = self.chunk
+ nLines = chunk.count('\n', 0, offset)
+ positionLine = self.prevNumLines + nLines
+ lastLinePos = chunk.rfind('\n', 0, offset)
+ if lastLinePos == -1:
+ positionColumn = self.prevNumCols + offset
+ else:
+ positionColumn = offset - (lastLinePos + 1)
+ return (positionLine, positionColumn)
+
+ def position(self):
+ """Returns (line, col) of the current position in the stream."""
+ line, col = self._position(self.chunkOffset)
+ return (line + 1, col)
+
+ def char(self):
+ """ Read one character from the stream or queue if available. Return
+ EOF when EOF is reached.
+ """
+ # Read a new chunk from the input stream if necessary
+ if self.chunkOffset >= self.chunkSize:
+ if not self.readChunk():
+ return EOF
+
+ chunkOffset = self.chunkOffset
+ char = self.chunk[chunkOffset]
+ self.chunkOffset = chunkOffset + 1
+
+ return char
+
+ def readChunk(self, chunkSize=None):
+ if chunkSize is None:
+ chunkSize = self._defaultChunkSize
+
+ self.prevNumLines, self.prevNumCols = self._position(self.chunkSize)
+
+ self.chunk = ""
+ self.chunkSize = 0
+ self.chunkOffset = 0
+
+ data = self.dataStream.read(chunkSize)
+
+ # Deal with CR LF and surrogates broken across chunks
+ if self._bufferedCharacter:
+ data = self._bufferedCharacter + data
+ self._bufferedCharacter = None
+ elif not data:
+ # We have no more data, bye-bye stream
+ return False
+
+ if len(data) > 1:
+ lastv = ord(data[-1])
+ if lastv == 0x0D or 0xD800 <= lastv <= 0xDBFF:
+ self._bufferedCharacter = data[-1]
+ data = data[:-1]
+
+ if self.reportCharacterErrors:
+ self.reportCharacterErrors(data)
+
+ # Replace invalid characters
+ # Note U+0000 is dealt with in the tokenizer
+ data = self.replaceCharactersRegexp.sub("\ufffd", data)
+
+ data = data.replace("\r\n", "\n")
+ data = data.replace("\r", "\n")
+
+ self.chunk = data
+ self.chunkSize = len(data)
+
+ return True
+
+ def characterErrorsUCS4(self, data):
+ for i in range(len(invalid_unicode_re.findall(data))):
+ self.errors.append("invalid-codepoint")
+
+ def characterErrorsUCS2(self, data):
+ # Someone picked the wrong compile option
+ # You lose
+ skip = False
+ for match in invalid_unicode_re.finditer(data):
+ if skip:
+ continue
+ codepoint = ord(match.group())
+ pos = match.start()
+ # Pretty sure there should be endianness issues here
+ if utils.isSurrogatePair(data[pos:pos + 2]):
+ # We have a surrogate pair!
+ char_val = utils.surrogatePairToCodepoint(data[pos:pos + 2])
+ if char_val in non_bmp_invalid_codepoints:
+ self.errors.append("invalid-codepoint")
+ skip = True
+ elif (codepoint >= 0xD800 and codepoint <= 0xDFFF and
+ pos == len(data) - 1):
+ self.errors.append("invalid-codepoint")
+ else:
+ skip = False
+ self.errors.append("invalid-codepoint")
+
+ def charsUntil(self, characters, opposite=False):
+ """ Returns a string of characters from the stream up to but not
+ including any character in 'characters' or EOF. 'characters' must be
+ a container that supports the 'in' method and iteration over its
+ characters.
+ """
+
+ # Use a cache of regexps to find the required characters
+ try:
+ chars = charsUntilRegEx[(characters, opposite)]
+ except KeyError:
+ if __debug__:
+ for c in characters:
+ assert(ord(c) < 128)
+ regex = "".join(["\\x%02x" % ord(c) for c in characters])
+ if not opposite:
+ regex = "^%s" % regex
+ chars = charsUntilRegEx[(characters, opposite)] = re.compile("[%s]+" % regex)
+
+ rv = []
+
+ while True:
+ # Find the longest matching prefix
+ m = chars.match(self.chunk, self.chunkOffset)
+ if m is None:
+ # If nothing matched, and it wasn't because we ran out of chunk,
+ # then stop
+ if self.chunkOffset != self.chunkSize:
+ break
+ else:
+ end = m.end()
+ # If not the whole chunk matched, return everything
+ # up to the part that didn't match
+ if end != self.chunkSize:
+ rv.append(self.chunk[self.chunkOffset:end])
+ self.chunkOffset = end
+ break
+ # If the whole remainder of the chunk matched,
+ # use it all and read the next chunk
+ rv.append(self.chunk[self.chunkOffset:])
+ if not self.readChunk():
+ # Reached EOF
+ break
+
+ r = "".join(rv)
+ return r
+
+ def unget(self, char):
+ # Only one character is allowed to be ungotten at once - it must
+ # be consumed again before any further call to unget
+ if char is not None:
+ if self.chunkOffset == 0:
+ # unget is called quite rarely, so it's a good idea to do
+ # more work here if it saves a bit of work in the frequently
+ # called char and charsUntil.
+ # So, just prepend the ungotten character onto the current
+ # chunk:
+ self.chunk = char + self.chunk
+ self.chunkSize += 1
+ else:
+ self.chunkOffset -= 1
+ assert self.chunk[self.chunkOffset] == char
+
+
+class HTMLBinaryInputStream(HTMLUnicodeInputStream):
+ """Provides a unicode stream of characters to the HTMLTokenizer.
+
+ This class takes care of character encoding and removing or replacing
+ incorrect byte-sequences and also provides column and line tracking.
+
+ """
+
+ def __init__(self, source, encoding=None, parseMeta=True, chardet=True):
+ """Initialises the HTMLInputStream.
+
+ HTMLInputStream(source, [encoding]) -> Normalized stream from source
+ for use by html5lib.
+
+ source can be either a file-object, local filename or a string.
+
+ The optional encoding parameter must be a string that indicates
+ the encoding. If specified, that encoding will be used,
+ regardless of any BOM or later declaration (such as in a meta
+ element)
+
+ parseMeta - Look for a <meta> element containing encoding information
+
+ """
+ # Raw Stream - for unicode objects this will encode to utf-8 and set
+ # self.charEncoding as appropriate
+ self.rawStream = self.openStream(source)
+
+ HTMLUnicodeInputStream.__init__(self, self.rawStream)
+
+ self.charEncoding = (codecName(encoding), "certain")
+
+ # Encoding Information
+ # Number of bytes to use when looking for a meta element with
+ # encoding information
+ self.numBytesMeta = 512
+ # Number of bytes to use when using detecting encoding using chardet
+ self.numBytesChardet = 100
+ # Encoding to use if no other information can be found
+ self.defaultEncoding = "windows-1252"
+
+ # Detect encoding iff no explicit "transport level" encoding is supplied
+ if (self.charEncoding[0] is None):
+ self.charEncoding = self.detectEncoding(parseMeta, chardet)
+
+ # Call superclass
+ self.reset()
+
+ def reset(self):
+ self.dataStream = codecs.getreader(self.charEncoding[0])(self.rawStream,
+ 'replace')
+ HTMLUnicodeInputStream.reset(self)
+
+ def openStream(self, source):
+ """Produces a file object from source.
+
+ source can be either a file object, local filename or a string.
+
+ """
+ # Already a file object
+ if hasattr(source, 'read'):
+ stream = source
+ else:
+ stream = BytesIO(source)
+
+ try:
+ stream.seek(stream.tell())
+ except:
+ stream = BufferedStream(stream)
+
+ return stream
+
+ def detectEncoding(self, parseMeta=True, chardet=True):
+ # First look for a BOM
+ # This will also read past the BOM if present
+ encoding = self.detectBOM()
+ confidence = "certain"
+ # If there is no BOM need to look for meta elements with encoding
+ # information
+ if encoding is None and parseMeta:
+ encoding = self.detectEncodingMeta()
+ confidence = "tentative"
+ # Guess with chardet, if avaliable
+ if encoding is None and chardet:
+ confidence = "tentative"
+ try:
+ try:
+ from charade.universaldetector import UniversalDetector
+ except ImportError:
+ from chardet.universaldetector import UniversalDetector
+ buffers = []
+ detector = UniversalDetector()
+ while not detector.done:
+ buffer = self.rawStream.read(self.numBytesChardet)
+ assert isinstance(buffer, bytes)
+ if not buffer:
+ break
+ buffers.append(buffer)
+ detector.feed(buffer)
+ detector.close()
+ encoding = detector.result['encoding']
+ self.rawStream.seek(0)
+ except ImportError:
+ pass
+ # If all else fails use the default encoding
+ if encoding is None:
+ confidence = "tentative"
+ encoding = self.defaultEncoding
+
+ # Substitute for equivalent encodings:
+ encodingSub = {"iso-8859-1": "windows-1252"}
+
+ if encoding.lower() in encodingSub:
+ encoding = encodingSub[encoding.lower()]
+
+ return encoding, confidence
+
+ def changeEncoding(self, newEncoding):
+ assert self.charEncoding[1] != "certain"
+ newEncoding = codecName(newEncoding)
+ if newEncoding in ("utf-16", "utf-16-be", "utf-16-le"):
+ newEncoding = "utf-8"
+ if newEncoding is None:
+ return
+ elif newEncoding == self.charEncoding[0]:
+ self.charEncoding = (self.charEncoding[0], "certain")
+ else:
+ self.rawStream.seek(0)
+ self.reset()
+ self.charEncoding = (newEncoding, "certain")
+ raise ReparseException("Encoding changed from %s to %s" % (self.charEncoding[0], newEncoding))
+
+ def detectBOM(self):
+ """Attempts to detect at BOM at the start of the stream. If
+ an encoding can be determined from the BOM return the name of the
+ encoding otherwise return None"""
+ bomDict = {
+ codecs.BOM_UTF8: 'utf-8',
+ codecs.BOM_UTF16_LE: 'utf-16-le', codecs.BOM_UTF16_BE: 'utf-16-be',
+ codecs.BOM_UTF32_LE: 'utf-32-le', codecs.BOM_UTF32_BE: 'utf-32-be'
+ }
+
+ # Go to beginning of file and read in 4 bytes
+ string = self.rawStream.read(4)
+ assert isinstance(string, bytes)
+
+ # Try detecting the BOM using bytes from the string
+ encoding = bomDict.get(string[:3]) # UTF-8
+ seek = 3
+ if not encoding:
+ # Need to detect UTF-32 before UTF-16
+ encoding = bomDict.get(string) # UTF-32
+ seek = 4
+ if not encoding:
+ encoding = bomDict.get(string[:2]) # UTF-16
+ seek = 2
+
+ # Set the read position past the BOM if one was found, otherwise
+ # set it to the start of the stream
+ self.rawStream.seek(encoding and seek or 0)
+
+ return encoding
+
+ def detectEncodingMeta(self):
+ """Report the encoding declared by the meta element
+ """
+ buffer = self.rawStream.read(self.numBytesMeta)
+ assert isinstance(buffer, bytes)
+ parser = EncodingParser(buffer)
+ self.rawStream.seek(0)
+ encoding = parser.getEncoding()
+
+ if encoding in ("utf-16", "utf-16-be", "utf-16-le"):
+ encoding = "utf-8"
+
+ return encoding
+
+
+class EncodingBytes(bytes):
+ """String-like object with an associated position and various extra methods
+ If the position is ever greater than the string length then an exception is
+ raised"""
+ def __new__(self, value):
+ assert isinstance(value, bytes)
+ return bytes.__new__(self, value.lower())
+
+ def __init__(self, value):
+ self._position = -1
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ p = self._position = self._position + 1
+ if p >= len(self):
+ raise StopIteration
+ elif p < 0:
+ raise TypeError
+ return self[p:p + 1]
+
+ def next(self):
+ # Py2 compat
+ return self.__next__()
+
+ def previous(self):
+ p = self._position
+ if p >= len(self):
+ raise StopIteration
+ elif p < 0:
+ raise TypeError
+ self._position = p = p - 1
+ return self[p:p + 1]
+
+ def setPosition(self, position):
+ if self._position >= len(self):
+ raise StopIteration
+ self._position = position
+
+ def getPosition(self):
+ if self._position >= len(self):
+ raise StopIteration
+ if self._position >= 0:
+ return self._position
+ else:
+ return None
+
+ position = property(getPosition, setPosition)
+
+ def getCurrentByte(self):
+ return self[self.position:self.position + 1]
+
+ currentByte = property(getCurrentByte)
+
+ def skip(self, chars=spaceCharactersBytes):
+ """Skip past a list of characters"""
+ p = self.position # use property for the error-checking
+ while p < len(self):
+ c = self[p:p + 1]
+ if c not in chars:
+ self._position = p
+ return c
+ p += 1
+ self._position = p
+ return None
+
+ def skipUntil(self, chars):
+ p = self.position
+ while p < len(self):
+ c = self[p:p + 1]
+ if c in chars:
+ self._position = p
+ return c
+ p += 1
+ self._position = p
+ return None
+
+ def matchBytes(self, bytes):
+ """Look for a sequence of bytes at the start of a string. If the bytes
+ are found return True and advance the position to the byte after the
+ match. Otherwise return False and leave the position alone"""
+ p = self.position
+ data = self[p:p + len(bytes)]
+ rv = data.startswith(bytes)
+ if rv:
+ self.position += len(bytes)
+ return rv
+
+ def jumpTo(self, bytes):
+ """Look for the next sequence of bytes matching a given sequence. If
+ a match is found advance the position to the last byte of the match"""
+ newPosition = self[self.position:].find(bytes)
+ if newPosition > -1:
+ # XXX: This is ugly, but I can't see a nicer way to fix this.
+ if self._position == -1:
+ self._position = 0
+ self._position += (newPosition + len(bytes) - 1)
+ return True
+ else:
+ raise StopIteration
+
+
+class EncodingParser(object):
+ """Mini parser for detecting character encoding from meta elements"""
+
+ def __init__(self, data):
+ """string - the data to work on for encoding detection"""
+ self.data = EncodingBytes(data)
+ self.encoding = None
+
+ def getEncoding(self):
+ methodDispatch = (
+ (b"<!--", self.handleComment),
+ (b"<meta", self.handleMeta),
+ (b"</", self.handlePossibleEndTag),
+ (b"<!", self.handleOther),
+ (b"<?", self.handleOther),
+ (b"<", self.handlePossibleStartTag))
+ for byte in self.data:
+ keepParsing = True
+ for key, method in methodDispatch:
+ if self.data.matchBytes(key):
+ try:
+ keepParsing = method()
+ break
+ except StopIteration:
+ keepParsing = False
+ break
+ if not keepParsing:
+ break
+
+ return self.encoding
+
+ def handleComment(self):
+ """Skip over comments"""
+ return self.data.jumpTo(b"-->")
+
+ def handleMeta(self):
+ if self.data.currentByte not in spaceCharactersBytes:
+ # if we have <meta not followed by a space so just keep going
+ return True
+ # We have a valid meta element we want to search for attributes
+ hasPragma = False
+ pendingEncoding = None
+ while True:
+ # Try to find the next attribute after the current position
+ attr = self.getAttribute()
+ if attr is None:
+ return True
+ else:
+ if attr[0] == b"http-equiv":
+ hasPragma = attr[1] == b"content-type"
+ if hasPragma and pendingEncoding is not None:
+ self.encoding = pendingEncoding
+ return False
+ elif attr[0] == b"charset":
+ tentativeEncoding = attr[1]
+ codec = codecName(tentativeEncoding)
+ if codec is not None:
+ self.encoding = codec
+ return False
+ elif attr[0] == b"content":
+ contentParser = ContentAttrParser(EncodingBytes(attr[1]))
+ tentativeEncoding = contentParser.parse()
+ if tentativeEncoding is not None:
+ codec = codecName(tentativeEncoding)
+ if codec is not None:
+ if hasPragma:
+ self.encoding = codec
+ return False
+ else:
+ pendingEncoding = codec
+
+ def handlePossibleStartTag(self):
+ return self.handlePossibleTag(False)
+
+ def handlePossibleEndTag(self):
+ next(self.data)
+ return self.handlePossibleTag(True)
+
+ def handlePossibleTag(self, endTag):
+ data = self.data
+ if data.currentByte not in asciiLettersBytes:
+ # If the next byte is not an ascii letter either ignore this
+ # fragment (possible start tag case) or treat it according to
+ # handleOther
+ if endTag:
+ data.previous()
+ self.handleOther()
+ return True
+
+ c = data.skipUntil(spacesAngleBrackets)
+ if c == b"<":
+ # return to the first step in the overall "two step" algorithm
+ # reprocessing the < byte
+ data.previous()
+ else:
+ # Read all attributes
+ attr = self.getAttribute()
+ while attr is not None:
+ attr = self.getAttribute()
+ return True
+
+ def handleOther(self):
+ return self.data.jumpTo(b">")
+
+ def getAttribute(self):
+ """Return a name,value pair for the next attribute in the stream,
+ if one is found, or None"""
+ data = self.data
+ # Step 1 (skip chars)
+ c = data.skip(spaceCharactersBytes | frozenset([b"/"]))
+ assert c is None or len(c) == 1
+ # Step 2
+ if c in (b">", None):
+ return None
+ # Step 3
+ attrName = []
+ attrValue = []
+ # Step 4 attribute name
+ while True:
+ if c == b"=" and attrName:
+ break
+ elif c in spaceCharactersBytes:
+ # Step 6!
+ c = data.skip()
+ break
+ elif c in (b"/", b">"):
+ return b"".join(attrName), b""
+ elif c in asciiUppercaseBytes:
+ attrName.append(c.lower())
+ elif c is None:
+ return None
+ else:
+ attrName.append(c)
+ # Step 5
+ c = next(data)
+ # Step 7
+ if c != b"=":
+ data.previous()
+ return b"".join(attrName), b""
+ # Step 8
+ next(data)
+ # Step 9
+ c = data.skip()
+ # Step 10
+ if c in (b"'", b'"'):
+ # 10.1
+ quoteChar = c
+ while True:
+ # 10.2
+ c = next(data)
+ # 10.3
+ if c == quoteChar:
+ next(data)
+ return b"".join(attrName), b"".join(attrValue)
+ # 10.4
+ elif c in asciiUppercaseBytes:
+ attrValue.append(c.lower())
+ # 10.5
+ else:
+ attrValue.append(c)
+ elif c == b">":
+ return b"".join(attrName), b""
+ elif c in asciiUppercaseBytes:
+ attrValue.append(c.lower())
+ elif c is None:
+ return None
+ else:
+ attrValue.append(c)
+ # Step 11
+ while True:
+ c = next(data)
+ if c in spacesAngleBrackets:
+ return b"".join(attrName), b"".join(attrValue)
+ elif c in asciiUppercaseBytes:
+ attrValue.append(c.lower())
+ elif c is None:
+ return None
+ else:
+ attrValue.append(c)
+
+
+class ContentAttrParser(object):
+ def __init__(self, data):
+ assert isinstance(data, bytes)
+ self.data = data
+
+ def parse(self):
+ try:
+ # Check if the attr name is charset
+ # otherwise return
+ self.data.jumpTo(b"charset")
+ self.data.position += 1
+ self.data.skip()
+ if not self.data.currentByte == b"=":
+ # If there is no = sign keep looking for attrs
+ return None
+ self.data.position += 1
+ self.data.skip()
+ # Look for an encoding between matching quote marks
+ if self.data.currentByte in (b'"', b"'"):
+ quoteMark = self.data.currentByte
+ self.data.position += 1
+ oldPosition = self.data.position
+ if self.data.jumpTo(quoteMark):
+ return self.data[oldPosition:self.data.position]
+ else:
+ return None
+ else:
+ # Unquoted value
+ oldPosition = self.data.position
+ try:
+ self.data.skipUntil(spaceCharactersBytes)
+ return self.data[oldPosition:self.data.position]
+ except StopIteration:
+ # Return the whole remaining value
+ return self.data[oldPosition:]
+ except StopIteration:
+ return None
+
+
+def codecName(encoding):
+ """Return the python codec name corresponding to an encoding or None if the
+ string doesn't correspond to a valid encoding."""
+ if isinstance(encoding, bytes):
+ try:
+ encoding = encoding.decode("ascii")
+ except UnicodeDecodeError:
+ return None
+ if encoding:
+ canonicalName = ascii_punctuation_re.sub("", encoding).lower()
+ return encodings.get(canonicalName, None)
+ else:
+ return None
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/sanitizer.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/sanitizer.py
new file mode 100644
index 00000000000..2cef2655544
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/sanitizer.py
@@ -0,0 +1,296 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import re
+from xml.sax.saxutils import escape, unescape
+from six.moves import urllib_parse as urlparse
+
+from .tokenizer import HTMLTokenizer
+from .constants import tokenTypes
+
+
+content_type_rgx = re.compile(r'''
+ ^
+ # Match a content type <application>/<type>
+ (?P<content_type>[-a-zA-Z0-9.]+/[-a-zA-Z0-9.]+)
+ # Match any character set and encoding
+ (?:(?:;charset=(?:[-a-zA-Z0-9]+)(?:;(?:base64))?)
+ |(?:;(?:base64))?(?:;charset=(?:[-a-zA-Z0-9]+))?)
+ # Assume the rest is data
+ ,.*
+ $
+ ''',
+ re.VERBOSE)
+
+
+class HTMLSanitizerMixin(object):
+ """ sanitization of XHTML+MathML+SVG and of inline style attributes."""
+
+ acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area',
+ 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button',
+ 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup',
+ 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn',
+ 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset',
+ 'figcaption', 'figure', 'footer', 'font', 'form', 'header', 'h1',
+ 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', 'ins',
+ 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter',
+ 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option',
+ 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select',
+ 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong',
+ 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot',
+ 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video']
+
+ mathml_elements = ['maction', 'math', 'merror', 'mfrac', 'mi',
+ 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom',
+ 'mprescripts', 'mroot', 'mrow', 'mspace', 'msqrt', 'mstyle', 'msub',
+ 'msubsup', 'msup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder',
+ 'munderover', 'none']
+
+ svg_elements = ['a', 'animate', 'animateColor', 'animateMotion',
+ 'animateTransform', 'clipPath', 'circle', 'defs', 'desc', 'ellipse',
+ 'font-face', 'font-face-name', 'font-face-src', 'g', 'glyph', 'hkern',
+ 'linearGradient', 'line', 'marker', 'metadata', 'missing-glyph',
+ 'mpath', 'path', 'polygon', 'polyline', 'radialGradient', 'rect',
+ 'set', 'stop', 'svg', 'switch', 'text', 'title', 'tspan', 'use']
+
+ acceptable_attributes = ['abbr', 'accept', 'accept-charset', 'accesskey',
+ 'action', 'align', 'alt', 'autocomplete', 'autofocus', 'axis',
+ 'background', 'balance', 'bgcolor', 'bgproperties', 'border',
+ 'bordercolor', 'bordercolordark', 'bordercolorlight', 'bottompadding',
+ 'cellpadding', 'cellspacing', 'ch', 'challenge', 'char', 'charoff',
+ 'choff', 'charset', 'checked', 'cite', 'class', 'clear', 'color',
+ 'cols', 'colspan', 'compact', 'contenteditable', 'controls', 'coords',
+ 'data', 'datafld', 'datapagesize', 'datasrc', 'datetime', 'default',
+ 'delay', 'dir', 'disabled', 'draggable', 'dynsrc', 'enctype', 'end',
+ 'face', 'for', 'form', 'frame', 'galleryimg', 'gutter', 'headers',
+ 'height', 'hidefocus', 'hidden', 'high', 'href', 'hreflang', 'hspace',
+ 'icon', 'id', 'inputmode', 'ismap', 'keytype', 'label', 'leftspacing',
+ 'lang', 'list', 'longdesc', 'loop', 'loopcount', 'loopend',
+ 'loopstart', 'low', 'lowsrc', 'max', 'maxlength', 'media', 'method',
+ 'min', 'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'open',
+ 'optimum', 'pattern', 'ping', 'point-size', 'poster', 'pqg', 'preload',
+ 'prompt', 'radiogroup', 'readonly', 'rel', 'repeat-max', 'repeat-min',
+ 'replace', 'required', 'rev', 'rightspacing', 'rows', 'rowspan',
+ 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'src', 'start',
+ 'step', 'style', 'summary', 'suppress', 'tabindex', 'target',
+ 'template', 'title', 'toppadding', 'type', 'unselectable', 'usemap',
+ 'urn', 'valign', 'value', 'variable', 'volume', 'vspace', 'vrml',
+ 'width', 'wrap', 'xml:lang']
+
+ mathml_attributes = ['actiontype', 'align', 'columnalign', 'columnalign',
+ 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'depth',
+ 'display', 'displaystyle', 'equalcolumns', 'equalrows', 'fence',
+ 'fontstyle', 'fontweight', 'frame', 'height', 'linethickness', 'lspace',
+ 'mathbackground', 'mathcolor', 'mathvariant', 'mathvariant', 'maxsize',
+ 'minsize', 'other', 'rowalign', 'rowalign', 'rowalign', 'rowlines',
+ 'rowspacing', 'rowspan', 'rspace', 'scriptlevel', 'selection',
+ 'separator', 'stretchy', 'width', 'width', 'xlink:href', 'xlink:show',
+ 'xlink:type', 'xmlns', 'xmlns:xlink']
+
+ svg_attributes = ['accent-height', 'accumulate', 'additive', 'alphabetic',
+ 'arabic-form', 'ascent', 'attributeName', 'attributeType',
+ 'baseProfile', 'bbox', 'begin', 'by', 'calcMode', 'cap-height',
+ 'class', 'clip-path', 'color', 'color-rendering', 'content', 'cx',
+ 'cy', 'd', 'dx', 'dy', 'descent', 'display', 'dur', 'end', 'fill',
+ 'fill-opacity', 'fill-rule', 'font-family', 'font-size',
+ 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'from',
+ 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'gradientUnits', 'hanging',
+ 'height', 'horiz-adv-x', 'horiz-origin-x', 'id', 'ideographic', 'k',
+ 'keyPoints', 'keySplines', 'keyTimes', 'lang', 'marker-end',
+ 'marker-mid', 'marker-start', 'markerHeight', 'markerUnits',
+ 'markerWidth', 'mathematical', 'max', 'min', 'name', 'offset',
+ 'opacity', 'orient', 'origin', 'overline-position',
+ 'overline-thickness', 'panose-1', 'path', 'pathLength', 'points',
+ 'preserveAspectRatio', 'r', 'refX', 'refY', 'repeatCount',
+ 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'restart',
+ 'rotate', 'rx', 'ry', 'slope', 'stemh', 'stemv', 'stop-color',
+ 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness',
+ 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap',
+ 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity',
+ 'stroke-width', 'systemLanguage', 'target', 'text-anchor', 'to',
+ 'transform', 'type', 'u1', 'u2', 'underline-position',
+ 'underline-thickness', 'unicode', 'unicode-range', 'units-per-em',
+ 'values', 'version', 'viewBox', 'visibility', 'width', 'widths', 'x',
+ 'x-height', 'x1', 'x2', 'xlink:actuate', 'xlink:arcrole',
+ 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type',
+ 'xml:base', 'xml:lang', 'xml:space', 'xmlns', 'xmlns:xlink', 'y',
+ 'y1', 'y2', 'zoomAndPan']
+
+ attr_val_is_uri = ['href', 'src', 'cite', 'action', 'longdesc', 'poster', 'background', 'datasrc',
+ 'dynsrc', 'lowsrc', 'ping', 'poster', 'xlink:href', 'xml:base']
+
+ svg_attr_val_allows_ref = ['clip-path', 'color-profile', 'cursor', 'fill',
+ 'filter', 'marker', 'marker-start', 'marker-mid', 'marker-end',
+ 'mask', 'stroke']
+
+ svg_allow_local_href = ['altGlyph', 'animate', 'animateColor',
+ 'animateMotion', 'animateTransform', 'cursor', 'feImage', 'filter',
+ 'linearGradient', 'pattern', 'radialGradient', 'textpath', 'tref',
+ 'set', 'use']
+
+ acceptable_css_properties = ['azimuth', 'background-color',
+ 'border-bottom-color', 'border-collapse', 'border-color',
+ 'border-left-color', 'border-right-color', 'border-top-color', 'clear',
+ 'color', 'cursor', 'direction', 'display', 'elevation', 'float', 'font',
+ 'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight',
+ 'height', 'letter-spacing', 'line-height', 'overflow', 'pause',
+ 'pause-after', 'pause-before', 'pitch', 'pitch-range', 'richness',
+ 'speak', 'speak-header', 'speak-numeral', 'speak-punctuation',
+ 'speech-rate', 'stress', 'text-align', 'text-decoration', 'text-indent',
+ 'unicode-bidi', 'vertical-align', 'voice-family', 'volume',
+ 'white-space', 'width']
+
+ acceptable_css_keywords = ['auto', 'aqua', 'black', 'block', 'blue',
+ 'bold', 'both', 'bottom', 'brown', 'center', 'collapse', 'dashed',
+ 'dotted', 'fuchsia', 'gray', 'green', '!important', 'italic', 'left',
+ 'lime', 'maroon', 'medium', 'none', 'navy', 'normal', 'nowrap', 'olive',
+ 'pointer', 'purple', 'red', 'right', 'solid', 'silver', 'teal', 'top',
+ 'transparent', 'underline', 'white', 'yellow']
+
+ acceptable_svg_properties = ['fill', 'fill-opacity', 'fill-rule',
+ 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin',
+ 'stroke-opacity']
+
+ acceptable_protocols = ['ed2k', 'ftp', 'http', 'https', 'irc',
+ 'mailto', 'news', 'gopher', 'nntp', 'telnet', 'webcal',
+ 'xmpp', 'callto', 'feed', 'urn', 'aim', 'rsync', 'tag',
+ 'ssh', 'sftp', 'rtsp', 'afs', 'data']
+
+ acceptable_content_types = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/bmp', 'text/plain']
+
+ # subclasses may define their own versions of these constants
+ allowed_elements = acceptable_elements + mathml_elements + svg_elements
+ allowed_attributes = acceptable_attributes + mathml_attributes + svg_attributes
+ allowed_css_properties = acceptable_css_properties
+ allowed_css_keywords = acceptable_css_keywords
+ allowed_svg_properties = acceptable_svg_properties
+ allowed_protocols = acceptable_protocols
+ allowed_content_types = acceptable_content_types
+
+ # Sanitize the +html+, escaping all elements not in ALLOWED_ELEMENTS, and
+ # stripping out all # attributes not in ALLOWED_ATTRIBUTES. Style
+ # attributes are parsed, and a restricted set, # specified by
+ # ALLOWED_CSS_PROPERTIES and ALLOWED_CSS_KEYWORDS, are allowed through.
+ # attributes in ATTR_VAL_IS_URI are scanned, and only URI schemes specified
+ # in ALLOWED_PROTOCOLS are allowed.
+ #
+ # sanitize_html('<script> do_nasty_stuff() </script>')
+ # => &lt;script> do_nasty_stuff() &lt;/script>
+ # sanitize_html('<a href="javascript: sucker();">Click here for $100</a>')
+ # => <a>Click here for $100</a>
+ def sanitize_token(self, token):
+
+ # accommodate filters which use token_type differently
+ token_type = token["type"]
+ if token_type in list(tokenTypes.keys()):
+ token_type = tokenTypes[token_type]
+
+ if token_type in (tokenTypes["StartTag"], tokenTypes["EndTag"],
+ tokenTypes["EmptyTag"]):
+ if token["name"] in self.allowed_elements:
+ return self.allowed_token(token, token_type)
+ else:
+ return self.disallowed_token(token, token_type)
+ elif token_type == tokenTypes["Comment"]:
+ pass
+ else:
+ return token
+
+ def allowed_token(self, token, token_type):
+ if "data" in token:
+ attrs = dict([(name, val) for name, val in
+ token["data"][::-1]
+ if name in self.allowed_attributes])
+ for attr in self.attr_val_is_uri:
+ if attr not in attrs:
+ continue
+ val_unescaped = re.sub("[`\000-\040\177-\240\s]+", '',
+ unescape(attrs[attr])).lower()
+ # remove replacement characters from unescaped characters
+ val_unescaped = val_unescaped.replace("\ufffd", "")
+ uri = urlparse.urlparse(val_unescaped)
+ if uri and uri.scheme:
+ if uri.scheme not in self.allowed_protocols:
+ del attrs[attr]
+ if uri.scheme == 'data':
+ m = content_type_rgx.match(uri.path)
+ if not m:
+ del attrs[attr]
+ elif m.group('content_type') not in self.allowed_content_types:
+ del attrs[attr]
+
+ for attr in self.svg_attr_val_allows_ref:
+ if attr in attrs:
+ attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)',
+ ' ',
+ unescape(attrs[attr]))
+ if (token["name"] in self.svg_allow_local_href and
+ 'xlink:href' in attrs and re.search('^\s*[^#\s].*',
+ attrs['xlink:href'])):
+ del attrs['xlink:href']
+ if 'style' in attrs:
+ attrs['style'] = self.sanitize_css(attrs['style'])
+ token["data"] = [[name, val] for name, val in list(attrs.items())]
+ return token
+
+ def disallowed_token(self, token, token_type):
+ if token_type == tokenTypes["EndTag"]:
+ token["data"] = "</%s>" % token["name"]
+ elif token["data"]:
+ attrs = ''.join([' %s="%s"' % (k, escape(v)) for k, v in token["data"]])
+ token["data"] = "<%s%s>" % (token["name"], attrs)
+ else:
+ token["data"] = "<%s>" % token["name"]
+ if token.get("selfClosing"):
+ token["data"] = token["data"][:-1] + "/>"
+
+ if token["type"] in list(tokenTypes.keys()):
+ token["type"] = "Characters"
+ else:
+ token["type"] = tokenTypes["Characters"]
+
+ del token["name"]
+ return token
+
+ def sanitize_css(self, style):
+ # disallow urls
+ style = re.compile('url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style)
+
+ # gauntlet
+ if not re.match("""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style):
+ return ''
+ if not re.match("^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style):
+ return ''
+
+ clean = []
+ for prop, value in re.findall("([-\w]+)\s*:\s*([^:;]*)", style):
+ if not value:
+ continue
+ if prop.lower() in self.allowed_css_properties:
+ clean.append(prop + ': ' + value + ';')
+ elif prop.split('-')[0].lower() in ['background', 'border', 'margin',
+ 'padding']:
+ for keyword in value.split():
+ if keyword not in self.acceptable_css_keywords and \
+ not re.match("^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword):
+ break
+ else:
+ clean.append(prop + ': ' + value + ';')
+ elif prop.lower() in self.allowed_svg_properties:
+ clean.append(prop + ': ' + value + ';')
+
+ return ' '.join(clean)
+
+
+class HTMLSanitizer(HTMLTokenizer, HTMLSanitizerMixin):
+ def __init__(self, stream, encoding=None, parseMeta=True, useChardet=True,
+ lowercaseElementName=False, lowercaseAttrName=False, parser=None):
+ # Change case matching defaults as we only output lowercase html anyway
+ # This solution doesn't seem ideal...
+ HTMLTokenizer.__init__(self, stream, encoding, parseMeta, useChardet,
+ lowercaseElementName, lowercaseAttrName, parser=parser)
+
+ def __iter__(self):
+ for token in HTMLTokenizer.__iter__(self):
+ token = self.sanitize_token(token)
+ if token:
+ yield token
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py
new file mode 100644
index 00000000000..8380839a6d3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py
@@ -0,0 +1,16 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from .. import treewalkers
+
+from .htmlserializer import HTMLSerializer
+
+
+def serialize(input, tree="etree", format="html", encoding=None,
+ **serializer_opts):
+ # XXX: Should we cache this?
+ walker = treewalkers.getTreeWalker(tree)
+ if format == "html":
+ s = HTMLSerializer(**serializer_opts)
+ else:
+ raise ValueError("type must be html")
+ return s.render(walker(input), encoding)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py
new file mode 100644
index 00000000000..be4d6344119
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py
@@ -0,0 +1,317 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+
+try:
+ from functools import reduce
+except ImportError:
+ pass
+
+from ..constants import voidElements, booleanAttributes, spaceCharacters
+from ..constants import rcdataElements, entities, xmlEntities
+from .. import utils
+from xml.sax.saxutils import escape
+
+spaceCharacters = "".join(spaceCharacters)
+
+try:
+ from codecs import register_error, xmlcharrefreplace_errors
+except ImportError:
+ unicode_encode_errors = "strict"
+else:
+ unicode_encode_errors = "htmlentityreplace"
+
+ encode_entity_map = {}
+ is_ucs4 = len("\U0010FFFF") == 1
+ for k, v in list(entities.items()):
+ # skip multi-character entities
+ if ((is_ucs4 and len(v) > 1) or
+ (not is_ucs4 and len(v) > 2)):
+ continue
+ if v != "&":
+ if len(v) == 2:
+ v = utils.surrogatePairToCodepoint(v)
+ else:
+ v = ord(v)
+ if v not in encode_entity_map or k.islower():
+ # prefer &lt; over &LT; and similarly for &amp;, &gt;, etc.
+ encode_entity_map[v] = k
+
+ def htmlentityreplace_errors(exc):
+ if isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)):
+ res = []
+ codepoints = []
+ skip = False
+ for i, c in enumerate(exc.object[exc.start:exc.end]):
+ if skip:
+ skip = False
+ continue
+ index = i + exc.start
+ if utils.isSurrogatePair(exc.object[index:min([exc.end, index + 2])]):
+ codepoint = utils.surrogatePairToCodepoint(exc.object[index:index + 2])
+ skip = True
+ else:
+ codepoint = ord(c)
+ codepoints.append(codepoint)
+ for cp in codepoints:
+ e = encode_entity_map.get(cp)
+ if e:
+ res.append("&")
+ res.append(e)
+ if not e.endswith(";"):
+ res.append(";")
+ else:
+ res.append("&#x%s;" % (hex(cp)[2:]))
+ return ("".join(res), exc.end)
+ else:
+ return xmlcharrefreplace_errors(exc)
+
+ register_error(unicode_encode_errors, htmlentityreplace_errors)
+
+ del register_error
+
+
+class HTMLSerializer(object):
+
+ # attribute quoting options
+ quote_attr_values = False
+ quote_char = '"'
+ use_best_quote_char = True
+
+ # tag syntax options
+ omit_optional_tags = True
+ minimize_boolean_attributes = True
+ use_trailing_solidus = False
+ space_before_trailing_solidus = True
+
+ # escaping options
+ escape_lt_in_attrs = False
+ escape_rcdata = False
+ resolve_entities = True
+
+ # miscellaneous options
+ alphabetical_attributes = False
+ inject_meta_charset = True
+ strip_whitespace = False
+ sanitize = False
+
+ options = ("quote_attr_values", "quote_char", "use_best_quote_char",
+ "omit_optional_tags", "minimize_boolean_attributes",
+ "use_trailing_solidus", "space_before_trailing_solidus",
+ "escape_lt_in_attrs", "escape_rcdata", "resolve_entities",
+ "alphabetical_attributes", "inject_meta_charset",
+ "strip_whitespace", "sanitize")
+
+ def __init__(self, **kwargs):
+ """Initialize HTMLSerializer.
+
+ Keyword options (default given first unless specified) include:
+
+ inject_meta_charset=True|False
+ Whether it insert a meta element to define the character set of the
+ document.
+ quote_attr_values=True|False
+ Whether to quote attribute values that don't require quoting
+ per HTML5 parsing rules.
+ quote_char=u'"'|u"'"
+ Use given quote character for attribute quoting. Default is to
+ use double quote unless attribute value contains a double quote,
+ in which case single quotes are used instead.
+ escape_lt_in_attrs=False|True
+ Whether to escape < in attribute values.
+ escape_rcdata=False|True
+ Whether to escape characters that need to be escaped within normal
+ elements within rcdata elements such as style.
+ resolve_entities=True|False
+ Whether to resolve named character entities that appear in the
+ source tree. The XML predefined entities &lt; &gt; &amp; &quot; &apos;
+ are unaffected by this setting.
+ strip_whitespace=False|True
+ Whether to remove semantically meaningless whitespace. (This
+ compresses all whitespace to a single space except within pre.)
+ minimize_boolean_attributes=True|False
+ Shortens boolean attributes to give just the attribute value,
+ for example <input disabled="disabled"> becomes <input disabled>.
+ use_trailing_solidus=False|True
+ Includes a close-tag slash at the end of the start tag of void
+ elements (empty elements whose end tag is forbidden). E.g. <hr/>.
+ space_before_trailing_solidus=True|False
+ Places a space immediately before the closing slash in a tag
+ using a trailing solidus. E.g. <hr />. Requires use_trailing_solidus.
+ sanitize=False|True
+ Strip all unsafe or unknown constructs from output.
+ See `html5lib user documentation`_
+ omit_optional_tags=True|False
+ Omit start/end tags that are optional.
+ alphabetical_attributes=False|True
+ Reorder attributes to be in alphabetical order.
+
+ .. _html5lib user documentation: http://code.google.com/p/html5lib/wiki/UserDocumentation
+ """
+ if 'quote_char' in kwargs:
+ self.use_best_quote_char = False
+ for attr in self.options:
+ setattr(self, attr, kwargs.get(attr, getattr(self, attr)))
+ self.errors = []
+ self.strict = False
+
+ def encode(self, string):
+ assert(isinstance(string, text_type))
+ if self.encoding:
+ return string.encode(self.encoding, unicode_encode_errors)
+ else:
+ return string
+
+ def encodeStrict(self, string):
+ assert(isinstance(string, text_type))
+ if self.encoding:
+ return string.encode(self.encoding, "strict")
+ else:
+ return string
+
+ def serialize(self, treewalker, encoding=None):
+ self.encoding = encoding
+ in_cdata = False
+ self.errors = []
+
+ if encoding and self.inject_meta_charset:
+ from ..filters.inject_meta_charset import Filter
+ treewalker = Filter(treewalker, encoding)
+ # WhitespaceFilter should be used before OptionalTagFilter
+ # for maximum efficiently of this latter filter
+ if self.strip_whitespace:
+ from ..filters.whitespace import Filter
+ treewalker = Filter(treewalker)
+ if self.sanitize:
+ from ..filters.sanitizer import Filter
+ treewalker = Filter(treewalker)
+ if self.omit_optional_tags:
+ from ..filters.optionaltags import Filter
+ treewalker = Filter(treewalker)
+ # Alphabetical attributes must be last, as other filters
+ # could add attributes and alter the order
+ if self.alphabetical_attributes:
+ from ..filters.alphabeticalattributes import Filter
+ treewalker = Filter(treewalker)
+
+ for token in treewalker:
+ type = token["type"]
+ if type == "Doctype":
+ doctype = "<!DOCTYPE %s" % token["name"]
+
+ if token["publicId"]:
+ doctype += ' PUBLIC "%s"' % token["publicId"]
+ elif token["systemId"]:
+ doctype += " SYSTEM"
+ if token["systemId"]:
+ if token["systemId"].find('"') >= 0:
+ if token["systemId"].find("'") >= 0:
+ self.serializeError("System identifer contains both single and double quote characters")
+ quote_char = "'"
+ else:
+ quote_char = '"'
+ doctype += " %s%s%s" % (quote_char, token["systemId"], quote_char)
+
+ doctype += ">"
+ yield self.encodeStrict(doctype)
+
+ elif type in ("Characters", "SpaceCharacters"):
+ if type == "SpaceCharacters" or in_cdata:
+ if in_cdata and token["data"].find("</") >= 0:
+ self.serializeError("Unexpected </ in CDATA")
+ yield self.encode(token["data"])
+ else:
+ yield self.encode(escape(token["data"]))
+
+ elif type in ("StartTag", "EmptyTag"):
+ name = token["name"]
+ yield self.encodeStrict("<%s" % name)
+ if name in rcdataElements and not self.escape_rcdata:
+ in_cdata = True
+ elif in_cdata:
+ self.serializeError("Unexpected child element of a CDATA element")
+ for (attr_namespace, attr_name), attr_value in token["data"].items():
+ # TODO: Add namespace support here
+ k = attr_name
+ v = attr_value
+ yield self.encodeStrict(' ')
+
+ yield self.encodeStrict(k)
+ if not self.minimize_boolean_attributes or \
+ (k not in booleanAttributes.get(name, tuple())
+ and k not in booleanAttributes.get("", tuple())):
+ yield self.encodeStrict("=")
+ if self.quote_attr_values or not v:
+ quote_attr = True
+ else:
+ quote_attr = reduce(lambda x, y: x or (y in v),
+ spaceCharacters + ">\"'=", False)
+ v = v.replace("&", "&amp;")
+ if self.escape_lt_in_attrs:
+ v = v.replace("<", "&lt;")
+ if quote_attr:
+ quote_char = self.quote_char
+ if self.use_best_quote_char:
+ if "'" in v and '"' not in v:
+ quote_char = '"'
+ elif '"' in v and "'" not in v:
+ quote_char = "'"
+ if quote_char == "'":
+ v = v.replace("'", "&#39;")
+ else:
+ v = v.replace('"', "&quot;")
+ yield self.encodeStrict(quote_char)
+ yield self.encode(v)
+ yield self.encodeStrict(quote_char)
+ else:
+ yield self.encode(v)
+ if name in voidElements and self.use_trailing_solidus:
+ if self.space_before_trailing_solidus:
+ yield self.encodeStrict(" /")
+ else:
+ yield self.encodeStrict("/")
+ yield self.encode(">")
+
+ elif type == "EndTag":
+ name = token["name"]
+ if name in rcdataElements:
+ in_cdata = False
+ elif in_cdata:
+ self.serializeError("Unexpected child element of a CDATA element")
+ yield self.encodeStrict("</%s>" % name)
+
+ elif type == "Comment":
+ data = token["data"]
+ if data.find("--") >= 0:
+ self.serializeError("Comment contains --")
+ yield self.encodeStrict("<!--%s-->" % token["data"])
+
+ elif type == "Entity":
+ name = token["name"]
+ key = name + ";"
+ if key not in entities:
+ self.serializeError("Entity %s not recognized" % name)
+ if self.resolve_entities and key not in xmlEntities:
+ data = entities[key]
+ else:
+ data = "&%s;" % name
+ yield self.encodeStrict(data)
+
+ else:
+ self.serializeError(token["data"])
+
+ def render(self, treewalker, encoding=None):
+ if encoding:
+ return b"".join(list(self.serialize(treewalker, encoding)))
+ else:
+ return "".join(list(self.serialize(treewalker)))
+
+ def serializeError(self, data="XXX ERROR MESSAGE NEEDED"):
+ # XXX The idea is to make data mandatory.
+ self.errors.append(data)
+ if self.strict:
+ raise SerializeError
+
+
+def SerializeError(Exception):
+ """Error in serialized tree"""
+ pass
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/tokenizer.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/tokenizer.py
new file mode 100644
index 00000000000..797745787a4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/tokenizer.py
@@ -0,0 +1,1731 @@
+from __future__ import absolute_import, division, unicode_literals
+
+try:
+ chr = unichr # flake8: noqa
+except NameError:
+ pass
+
+from collections import deque
+
+from .constants import spaceCharacters
+from .constants import entities
+from .constants import asciiLetters, asciiUpper2Lower
+from .constants import digits, hexDigits, EOF
+from .constants import tokenTypes, tagTokenTypes
+from .constants import replacementCharacters
+
+from .inputstream import HTMLInputStream
+
+from .trie import Trie
+
+entitiesTrie = Trie(entities)
+
+
+class HTMLTokenizer(object):
+ """ This class takes care of tokenizing HTML.
+
+ * self.currentToken
+ Holds the token that is currently being processed.
+
+ * self.state
+ Holds a reference to the method to be invoked... XXX
+
+ * self.stream
+ Points to HTMLInputStream object.
+ """
+
+ def __init__(self, stream, encoding=None, parseMeta=True, useChardet=True,
+ lowercaseElementName=True, lowercaseAttrName=True, parser=None):
+
+ self.stream = HTMLInputStream(stream, encoding, parseMeta, useChardet)
+ self.parser = parser
+
+ # Perform case conversions?
+ self.lowercaseElementName = lowercaseElementName
+ self.lowercaseAttrName = lowercaseAttrName
+
+ # Setup the initial tokenizer state
+ self.escapeFlag = False
+ self.lastFourChars = []
+ self.state = self.dataState
+ self.escape = False
+
+ # The current token being created
+ self.currentToken = None
+ super(HTMLTokenizer, self).__init__()
+
+ def __iter__(self):
+ """ This is where the magic happens.
+
+ We do our usually processing through the states and when we have a token
+ to return we yield the token which pauses processing until the next token
+ is requested.
+ """
+ self.tokenQueue = deque([])
+ # Start processing. When EOF is reached self.state will return False
+ # instead of True and the loop will terminate.
+ while self.state():
+ while self.stream.errors:
+ yield {"type": tokenTypes["ParseError"], "data": self.stream.errors.pop(0)}
+ while self.tokenQueue:
+ yield self.tokenQueue.popleft()
+
+ def consumeNumberEntity(self, isHex):
+ """This function returns either U+FFFD or the character based on the
+ decimal or hexadecimal representation. It also discards ";" if present.
+ If not present self.tokenQueue.append({"type": tokenTypes["ParseError"]}) is invoked.
+ """
+
+ allowed = digits
+ radix = 10
+ if isHex:
+ allowed = hexDigits
+ radix = 16
+
+ charStack = []
+
+ # Consume all the characters that are in range while making sure we
+ # don't hit an EOF.
+ c = self.stream.char()
+ while c in allowed and c is not EOF:
+ charStack.append(c)
+ c = self.stream.char()
+
+ # Convert the set of characters consumed to an int.
+ charAsInt = int("".join(charStack), radix)
+
+ # Certain characters get replaced with others
+ if charAsInt in replacementCharacters:
+ char = replacementCharacters[charAsInt]
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "illegal-codepoint-for-numeric-entity",
+ "datavars": {"charAsInt": charAsInt}})
+ elif ((0xD800 <= charAsInt <= 0xDFFF) or
+ (charAsInt > 0x10FFFF)):
+ char = "\uFFFD"
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "illegal-codepoint-for-numeric-entity",
+ "datavars": {"charAsInt": charAsInt}})
+ else:
+ # Should speed up this check somehow (e.g. move the set to a constant)
+ if ((0x0001 <= charAsInt <= 0x0008) or
+ (0x000E <= charAsInt <= 0x001F) or
+ (0x007F <= charAsInt <= 0x009F) or
+ (0xFDD0 <= charAsInt <= 0xFDEF) or
+ charAsInt in frozenset([0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
+ 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
+ 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE,
+ 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
+ 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE,
+ 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE,
+ 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
+ 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE,
+ 0xFFFFF, 0x10FFFE, 0x10FFFF])):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data":
+ "illegal-codepoint-for-numeric-entity",
+ "datavars": {"charAsInt": charAsInt}})
+ try:
+ # Try/except needed as UCS-2 Python builds' unichar only works
+ # within the BMP.
+ char = chr(charAsInt)
+ except ValueError:
+ v = charAsInt - 0x10000
+ char = chr(0xD800 | (v >> 10)) + chr(0xDC00 | (v & 0x3FF))
+
+ # Discard the ; if present. Otherwise, put it back on the queue and
+ # invoke parseError on parser.
+ if c != ";":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "numeric-entity-without-semicolon"})
+ self.stream.unget(c)
+
+ return char
+
+ def consumeEntity(self, allowedChar=None, fromAttribute=False):
+ # Initialise to the default output for when no entity is matched
+ output = "&"
+
+ charStack = [self.stream.char()]
+ if (charStack[0] in spaceCharacters or charStack[0] in (EOF, "<", "&")
+ or (allowedChar is not None and allowedChar == charStack[0])):
+ self.stream.unget(charStack[0])
+
+ elif charStack[0] == "#":
+ # Read the next character to see if it's hex or decimal
+ hex = False
+ charStack.append(self.stream.char())
+ if charStack[-1] in ("x", "X"):
+ hex = True
+ charStack.append(self.stream.char())
+
+ # charStack[-1] should be the first digit
+ if (hex and charStack[-1] in hexDigits) \
+ or (not hex and charStack[-1] in digits):
+ # At least one digit found, so consume the whole number
+ self.stream.unget(charStack[-1])
+ output = self.consumeNumberEntity(hex)
+ else:
+ # No digits found
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "expected-numeric-entity"})
+ self.stream.unget(charStack.pop())
+ output = "&" + "".join(charStack)
+
+ else:
+ # At this point in the process might have named entity. Entities
+ # are stored in the global variable "entities".
+ #
+ # Consume characters and compare to these to a substring of the
+ # entity names in the list until the substring no longer matches.
+ while (charStack[-1] is not EOF):
+ if not entitiesTrie.has_keys_with_prefix("".join(charStack)):
+ break
+ charStack.append(self.stream.char())
+
+ # At this point we have a string that starts with some characters
+ # that may match an entity
+ # Try to find the longest entity the string will match to take care
+ # of &noti for instance.
+ try:
+ entityName = entitiesTrie.longest_prefix("".join(charStack[:-1]))
+ entityLength = len(entityName)
+ except KeyError:
+ entityName = None
+
+ if entityName is not None:
+ if entityName[-1] != ";":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "named-entity-without-semicolon"})
+ if (entityName[-1] != ";" and fromAttribute and
+ (charStack[entityLength] in asciiLetters or
+ charStack[entityLength] in digits or
+ charStack[entityLength] == "=")):
+ self.stream.unget(charStack.pop())
+ output = "&" + "".join(charStack)
+ else:
+ output = entities[entityName]
+ self.stream.unget(charStack.pop())
+ output += "".join(charStack[entityLength:])
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-named-entity"})
+ self.stream.unget(charStack.pop())
+ output = "&" + "".join(charStack)
+
+ if fromAttribute:
+ self.currentToken["data"][-1][1] += output
+ else:
+ if output in spaceCharacters:
+ tokenType = "SpaceCharacters"
+ else:
+ tokenType = "Characters"
+ self.tokenQueue.append({"type": tokenTypes[tokenType], "data": output})
+
+ def processEntityInAttribute(self, allowedChar):
+ """This method replaces the need for "entityInAttributeValueState".
+ """
+ self.consumeEntity(allowedChar=allowedChar, fromAttribute=True)
+
+ def emitCurrentToken(self):
+ """This method is a generic handler for emitting the tags. It also sets
+ the state to "data" because that's what's needed after a token has been
+ emitted.
+ """
+ token = self.currentToken
+ # Add token to the queue to be yielded
+ if (token["type"] in tagTokenTypes):
+ if self.lowercaseElementName:
+ token["name"] = token["name"].translate(asciiUpper2Lower)
+ if token["type"] == tokenTypes["EndTag"]:
+ if token["data"]:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "attributes-in-end-tag"})
+ if token["selfClosing"]:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "self-closing-flag-on-end-tag"})
+ self.tokenQueue.append(token)
+ self.state = self.dataState
+
+ # Below are the various tokenizer states worked out.
+ def dataState(self):
+ data = self.stream.char()
+ if data == "&":
+ self.state = self.entityDataState
+ elif data == "<":
+ self.state = self.tagOpenState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\u0000"})
+ elif data is EOF:
+ # Tokenization ends.
+ return False
+ elif data in spaceCharacters:
+ # Directly after emitting a token you switch back to the "data
+ # state". At that point spaceCharacters are important so they are
+ # emitted separately.
+ self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data":
+ data + self.stream.charsUntil(spaceCharacters, True)})
+ # No need to update lastFourChars here, since the first space will
+ # have already been appended to lastFourChars and will have broken
+ # any <!-- or --> sequences
+ else:
+ chars = self.stream.charsUntil(("&", "<", "\u0000"))
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + chars})
+ return True
+
+ def entityDataState(self):
+ self.consumeEntity()
+ self.state = self.dataState
+ return True
+
+ def rcdataState(self):
+ data = self.stream.char()
+ if data == "&":
+ self.state = self.characterReferenceInRcdata
+ elif data == "<":
+ self.state = self.rcdataLessThanSignState
+ elif data == EOF:
+ # Tokenization ends.
+ return False
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ elif data in spaceCharacters:
+ # Directly after emitting a token you switch back to the "data
+ # state". At that point spaceCharacters are important so they are
+ # emitted separately.
+ self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data":
+ data + self.stream.charsUntil(spaceCharacters, True)})
+ # No need to update lastFourChars here, since the first space will
+ # have already been appended to lastFourChars and will have broken
+ # any <!-- or --> sequences
+ else:
+ chars = self.stream.charsUntil(("&", "<", "\u0000"))
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + chars})
+ return True
+
+ def characterReferenceInRcdata(self):
+ self.consumeEntity()
+ self.state = self.rcdataState
+ return True
+
+ def rawtextState(self):
+ data = self.stream.char()
+ if data == "<":
+ self.state = self.rawtextLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ elif data == EOF:
+ # Tokenization ends.
+ return False
+ else:
+ chars = self.stream.charsUntil(("<", "\u0000"))
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + chars})
+ return True
+
+ def scriptDataState(self):
+ data = self.stream.char()
+ if data == "<":
+ self.state = self.scriptDataLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ elif data == EOF:
+ # Tokenization ends.
+ return False
+ else:
+ chars = self.stream.charsUntil(("<", "\u0000"))
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + chars})
+ return True
+
+ def plaintextState(self):
+ data = self.stream.char()
+ if data == EOF:
+ # Tokenization ends.
+ return False
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + self.stream.charsUntil("\u0000")})
+ return True
+
+ def tagOpenState(self):
+ data = self.stream.char()
+ if data == "!":
+ self.state = self.markupDeclarationOpenState
+ elif data == "/":
+ self.state = self.closeTagOpenState
+ elif data in asciiLetters:
+ self.currentToken = {"type": tokenTypes["StartTag"],
+ "name": data, "data": [],
+ "selfClosing": False,
+ "selfClosingAcknowledged": False}
+ self.state = self.tagNameState
+ elif data == ">":
+ # XXX In theory it could be something besides a tag name. But
+ # do we really care?
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-tag-name-but-got-right-bracket"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<>"})
+ self.state = self.dataState
+ elif data == "?":
+ # XXX In theory it could be something besides a tag name. But
+ # do we really care?
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-tag-name-but-got-question-mark"})
+ self.stream.unget(data)
+ self.state = self.bogusCommentState
+ else:
+ # XXX
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-tag-name"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.stream.unget(data)
+ self.state = self.dataState
+ return True
+
+ def closeTagOpenState(self):
+ data = self.stream.char()
+ if data in asciiLetters:
+ self.currentToken = {"type": tokenTypes["EndTag"], "name": data,
+ "data": [], "selfClosing": False}
+ self.state = self.tagNameState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-closing-tag-but-got-right-bracket"})
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-closing-tag-but-got-eof"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"})
+ self.state = self.dataState
+ else:
+ # XXX data can be _'_...
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-closing-tag-but-got-char",
+ "datavars": {"data": data}})
+ self.stream.unget(data)
+ self.state = self.bogusCommentState
+ return True
+
+ def tagNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeAttributeNameState
+ elif data == ">":
+ self.emitCurrentToken()
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-tag-name"})
+ self.state = self.dataState
+ elif data == "/":
+ self.state = self.selfClosingStartTagState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["name"] += "\uFFFD"
+ else:
+ self.currentToken["name"] += data
+ # (Don't use charsUntil here, because tag names are
+ # very short and it's faster to not do anything fancy)
+ return True
+
+ def rcdataLessThanSignState(self):
+ data = self.stream.char()
+ if data == "/":
+ self.temporaryBuffer = ""
+ self.state = self.rcdataEndTagOpenState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.stream.unget(data)
+ self.state = self.rcdataState
+ return True
+
+ def rcdataEndTagOpenState(self):
+ data = self.stream.char()
+ if data in asciiLetters:
+ self.temporaryBuffer += data
+ self.state = self.rcdataEndTagNameState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"})
+ self.stream.unget(data)
+ self.state = self.rcdataState
+ return True
+
+ def rcdataEndTagNameState(self):
+ appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower()
+ data = self.stream.char()
+ if data in spaceCharacters and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.beforeAttributeNameState
+ elif data == "/" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.selfClosingStartTagState
+ elif data == ">" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.emitCurrentToken()
+ self.state = self.dataState
+ elif data in asciiLetters:
+ self.temporaryBuffer += data
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "</" + self.temporaryBuffer})
+ self.stream.unget(data)
+ self.state = self.rcdataState
+ return True
+
+ def rawtextLessThanSignState(self):
+ data = self.stream.char()
+ if data == "/":
+ self.temporaryBuffer = ""
+ self.state = self.rawtextEndTagOpenState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.stream.unget(data)
+ self.state = self.rawtextState
+ return True
+
+ def rawtextEndTagOpenState(self):
+ data = self.stream.char()
+ if data in asciiLetters:
+ self.temporaryBuffer += data
+ self.state = self.rawtextEndTagNameState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"})
+ self.stream.unget(data)
+ self.state = self.rawtextState
+ return True
+
+ def rawtextEndTagNameState(self):
+ appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower()
+ data = self.stream.char()
+ if data in spaceCharacters and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.beforeAttributeNameState
+ elif data == "/" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.selfClosingStartTagState
+ elif data == ">" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.emitCurrentToken()
+ self.state = self.dataState
+ elif data in asciiLetters:
+ self.temporaryBuffer += data
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "</" + self.temporaryBuffer})
+ self.stream.unget(data)
+ self.state = self.rawtextState
+ return True
+
+ def scriptDataLessThanSignState(self):
+ data = self.stream.char()
+ if data == "/":
+ self.temporaryBuffer = ""
+ self.state = self.scriptDataEndTagOpenState
+ elif data == "!":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<!"})
+ self.state = self.scriptDataEscapeStartState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.stream.unget(data)
+ self.state = self.scriptDataState
+ return True
+
+ def scriptDataEndTagOpenState(self):
+ data = self.stream.char()
+ if data in asciiLetters:
+ self.temporaryBuffer += data
+ self.state = self.scriptDataEndTagNameState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"})
+ self.stream.unget(data)
+ self.state = self.scriptDataState
+ return True
+
+ def scriptDataEndTagNameState(self):
+ appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower()
+ data = self.stream.char()
+ if data in spaceCharacters and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.beforeAttributeNameState
+ elif data == "/" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.selfClosingStartTagState
+ elif data == ">" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.emitCurrentToken()
+ self.state = self.dataState
+ elif data in asciiLetters:
+ self.temporaryBuffer += data
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "</" + self.temporaryBuffer})
+ self.stream.unget(data)
+ self.state = self.scriptDataState
+ return True
+
+ def scriptDataEscapeStartState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataEscapeStartDashState
+ else:
+ self.stream.unget(data)
+ self.state = self.scriptDataState
+ return True
+
+ def scriptDataEscapeStartDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataEscapedDashDashState
+ else:
+ self.stream.unget(data)
+ self.state = self.scriptDataState
+ return True
+
+ def scriptDataEscapedState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataEscapedDashState
+ elif data == "<":
+ self.state = self.scriptDataEscapedLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ elif data == EOF:
+ self.state = self.dataState
+ else:
+ chars = self.stream.charsUntil(("<", "-", "\u0000"))
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data":
+ data + chars})
+ return True
+
+ def scriptDataEscapedDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataEscapedDashDashState
+ elif data == "<":
+ self.state = self.scriptDataEscapedLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ self.state = self.scriptDataEscapedState
+ elif data == EOF:
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataEscapedDashDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ elif data == "<":
+ self.state = self.scriptDataEscapedLessThanSignState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"})
+ self.state = self.scriptDataState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ self.state = self.scriptDataEscapedState
+ elif data == EOF:
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataEscapedLessThanSignState(self):
+ data = self.stream.char()
+ if data == "/":
+ self.temporaryBuffer = ""
+ self.state = self.scriptDataEscapedEndTagOpenState
+ elif data in asciiLetters:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<" + data})
+ self.temporaryBuffer = data
+ self.state = self.scriptDataDoubleEscapeStartState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.stream.unget(data)
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataEscapedEndTagOpenState(self):
+ data = self.stream.char()
+ if data in asciiLetters:
+ self.temporaryBuffer = data
+ self.state = self.scriptDataEscapedEndTagNameState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"})
+ self.stream.unget(data)
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataEscapedEndTagNameState(self):
+ appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower()
+ data = self.stream.char()
+ if data in spaceCharacters and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.beforeAttributeNameState
+ elif data == "/" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.state = self.selfClosingStartTagState
+ elif data == ">" and appropriate:
+ self.currentToken = {"type": tokenTypes["EndTag"],
+ "name": self.temporaryBuffer,
+ "data": [], "selfClosing": False}
+ self.emitCurrentToken()
+ self.state = self.dataState
+ elif data in asciiLetters:
+ self.temporaryBuffer += data
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "</" + self.temporaryBuffer})
+ self.stream.unget(data)
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataDoubleEscapeStartState(self):
+ data = self.stream.char()
+ if data in (spaceCharacters | frozenset(("/", ">"))):
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ if self.temporaryBuffer.lower() == "script":
+ self.state = self.scriptDataDoubleEscapedState
+ else:
+ self.state = self.scriptDataEscapedState
+ elif data in asciiLetters:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.temporaryBuffer += data
+ else:
+ self.stream.unget(data)
+ self.state = self.scriptDataEscapedState
+ return True
+
+ def scriptDataDoubleEscapedState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataDoubleEscapedDashState
+ elif data == "<":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.state = self.scriptDataDoubleEscapedLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ elif data == EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-script-in-script"})
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ return True
+
+ def scriptDataDoubleEscapedDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ self.state = self.scriptDataDoubleEscapedDashDashState
+ elif data == "<":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.state = self.scriptDataDoubleEscapedLessThanSignState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ self.state = self.scriptDataDoubleEscapedState
+ elif data == EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-script-in-script"})
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.state = self.scriptDataDoubleEscapedState
+ return True
+
+ def scriptDataDoubleEscapedDashDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"})
+ elif data == "<":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"})
+ self.state = self.scriptDataDoubleEscapedLessThanSignState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"})
+ self.state = self.scriptDataState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": "\uFFFD"})
+ self.state = self.scriptDataDoubleEscapedState
+ elif data == EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-script-in-script"})
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.state = self.scriptDataDoubleEscapedState
+ return True
+
+ def scriptDataDoubleEscapedLessThanSignState(self):
+ data = self.stream.char()
+ if data == "/":
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "/"})
+ self.temporaryBuffer = ""
+ self.state = self.scriptDataDoubleEscapeEndState
+ else:
+ self.stream.unget(data)
+ self.state = self.scriptDataDoubleEscapedState
+ return True
+
+ def scriptDataDoubleEscapeEndState(self):
+ data = self.stream.char()
+ if data in (spaceCharacters | frozenset(("/", ">"))):
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ if self.temporaryBuffer.lower() == "script":
+ self.state = self.scriptDataEscapedState
+ else:
+ self.state = self.scriptDataDoubleEscapedState
+ elif data in asciiLetters:
+ self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data})
+ self.temporaryBuffer += data
+ else:
+ self.stream.unget(data)
+ self.state = self.scriptDataDoubleEscapedState
+ return True
+
+ def beforeAttributeNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.stream.charsUntil(spaceCharacters, True)
+ elif data in asciiLetters:
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ elif data == ">":
+ self.emitCurrentToken()
+ elif data == "/":
+ self.state = self.selfClosingStartTagState
+ elif data in ("'", '"', "=", "<"):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "invalid-character-in-attribute-name"})
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"].append(["\uFFFD", ""])
+ self.state = self.attributeNameState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-attribute-name-but-got-eof"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ return True
+
+ def attributeNameState(self):
+ data = self.stream.char()
+ leavingThisState = True
+ emitToken = False
+ if data == "=":
+ self.state = self.beforeAttributeValueState
+ elif data in asciiLetters:
+ self.currentToken["data"][-1][0] += data +\
+ self.stream.charsUntil(asciiLetters, True)
+ leavingThisState = False
+ elif data == ">":
+ # XXX If we emit here the attributes are converted to a dict
+ # without being checked and when the code below runs we error
+ # because data is a dict not a list
+ emitToken = True
+ elif data in spaceCharacters:
+ self.state = self.afterAttributeNameState
+ elif data == "/":
+ self.state = self.selfClosingStartTagState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"][-1][0] += "\uFFFD"
+ leavingThisState = False
+ elif data in ("'", '"', "<"):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data":
+ "invalid-character-in-attribute-name"})
+ self.currentToken["data"][-1][0] += data
+ leavingThisState = False
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "eof-in-attribute-name"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"][-1][0] += data
+ leavingThisState = False
+
+ if leavingThisState:
+ # Attributes are not dropped at this stage. That happens when the
+ # start tag token is emitted so values can still be safely appended
+ # to attributes, but we do want to report the parse error in time.
+ if self.lowercaseAttrName:
+ self.currentToken["data"][-1][0] = (
+ self.currentToken["data"][-1][0].translate(asciiUpper2Lower))
+ for name, value in self.currentToken["data"][:-1]:
+ if self.currentToken["data"][-1][0] == name:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "duplicate-attribute"})
+ break
+ # XXX Fix for above XXX
+ if emitToken:
+ self.emitCurrentToken()
+ return True
+
+ def afterAttributeNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.stream.charsUntil(spaceCharacters, True)
+ elif data == "=":
+ self.state = self.beforeAttributeValueState
+ elif data == ">":
+ self.emitCurrentToken()
+ elif data in asciiLetters:
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ elif data == "/":
+ self.state = self.selfClosingStartTagState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"].append(["\uFFFD", ""])
+ self.state = self.attributeNameState
+ elif data in ("'", '"', "<"):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "invalid-character-after-attribute-name"})
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-end-of-tag-but-got-eof"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"].append([data, ""])
+ self.state = self.attributeNameState
+ return True
+
+ def beforeAttributeValueState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.stream.charsUntil(spaceCharacters, True)
+ elif data == "\"":
+ self.state = self.attributeValueDoubleQuotedState
+ elif data == "&":
+ self.state = self.attributeValueUnQuotedState
+ self.stream.unget(data)
+ elif data == "'":
+ self.state = self.attributeValueSingleQuotedState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-attribute-value-but-got-right-bracket"})
+ self.emitCurrentToken()
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"][-1][1] += "\uFFFD"
+ self.state = self.attributeValueUnQuotedState
+ elif data in ("=", "<", "`"):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "equals-in-unquoted-attribute-value"})
+ self.currentToken["data"][-1][1] += data
+ self.state = self.attributeValueUnQuotedState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-attribute-value-but-got-eof"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"][-1][1] += data
+ self.state = self.attributeValueUnQuotedState
+ return True
+
+ def attributeValueDoubleQuotedState(self):
+ data = self.stream.char()
+ if data == "\"":
+ self.state = self.afterAttributeValueState
+ elif data == "&":
+ self.processEntityInAttribute('"')
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"][-1][1] += "\uFFFD"
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-attribute-value-double-quote"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"][-1][1] += data +\
+ self.stream.charsUntil(("\"", "&", "\u0000"))
+ return True
+
+ def attributeValueSingleQuotedState(self):
+ data = self.stream.char()
+ if data == "'":
+ self.state = self.afterAttributeValueState
+ elif data == "&":
+ self.processEntityInAttribute("'")
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"][-1][1] += "\uFFFD"
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-attribute-value-single-quote"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"][-1][1] += data +\
+ self.stream.charsUntil(("'", "&", "\u0000"))
+ return True
+
+ def attributeValueUnQuotedState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeAttributeNameState
+ elif data == "&":
+ self.processEntityInAttribute(">")
+ elif data == ">":
+ self.emitCurrentToken()
+ elif data in ('"', "'", "=", "<", "`"):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-character-in-unquoted-attribute-value"})
+ self.currentToken["data"][-1][1] += data
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"][-1][1] += "\uFFFD"
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-attribute-value-no-quotes"})
+ self.state = self.dataState
+ else:
+ self.currentToken["data"][-1][1] += data + self.stream.charsUntil(
+ frozenset(("&", ">", '"', "'", "=", "<", "`", "\u0000")) | spaceCharacters)
+ return True
+
+ def afterAttributeValueState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeAttributeNameState
+ elif data == ">":
+ self.emitCurrentToken()
+ elif data == "/":
+ self.state = self.selfClosingStartTagState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-EOF-after-attribute-value"})
+ self.stream.unget(data)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-character-after-attribute-value"})
+ self.stream.unget(data)
+ self.state = self.beforeAttributeNameState
+ return True
+
+ def selfClosingStartTagState(self):
+ data = self.stream.char()
+ if data == ">":
+ self.currentToken["selfClosing"] = True
+ self.emitCurrentToken()
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data":
+ "unexpected-EOF-after-solidus-in-tag"})
+ self.stream.unget(data)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-character-after-solidus-in-tag"})
+ self.stream.unget(data)
+ self.state = self.beforeAttributeNameState
+ return True
+
+ def bogusCommentState(self):
+ # Make a new comment token and give it as value all the characters
+ # until the first > or EOF (charsUntil checks for EOF automatically)
+ # and emit it.
+ data = self.stream.charsUntil(">")
+ data = data.replace("\u0000", "\uFFFD")
+ self.tokenQueue.append(
+ {"type": tokenTypes["Comment"], "data": data})
+
+ # Eat the character directly after the bogus comment which is either a
+ # ">" or an EOF.
+ self.stream.char()
+ self.state = self.dataState
+ return True
+
+ def markupDeclarationOpenState(self):
+ charStack = [self.stream.char()]
+ if charStack[-1] == "-":
+ charStack.append(self.stream.char())
+ if charStack[-1] == "-":
+ self.currentToken = {"type": tokenTypes["Comment"], "data": ""}
+ self.state = self.commentStartState
+ return True
+ elif charStack[-1] in ('d', 'D'):
+ matched = True
+ for expected in (('o', 'O'), ('c', 'C'), ('t', 'T'),
+ ('y', 'Y'), ('p', 'P'), ('e', 'E')):
+ charStack.append(self.stream.char())
+ if charStack[-1] not in expected:
+ matched = False
+ break
+ if matched:
+ self.currentToken = {"type": tokenTypes["Doctype"],
+ "name": "",
+ "publicId": None, "systemId": None,
+ "correct": True}
+ self.state = self.doctypeState
+ return True
+ elif (charStack[-1] == "[" and
+ self.parser is not None and
+ self.parser.tree.openElements and
+ self.parser.tree.openElements[-1].namespace != self.parser.tree.defaultNamespace):
+ matched = True
+ for expected in ["C", "D", "A", "T", "A", "["]:
+ charStack.append(self.stream.char())
+ if charStack[-1] != expected:
+ matched = False
+ break
+ if matched:
+ self.state = self.cdataSectionState
+ return True
+
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-dashes-or-doctype"})
+
+ while charStack:
+ self.stream.unget(charStack.pop())
+ self.state = self.bogusCommentState
+ return True
+
+ def commentStartState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.state = self.commentStartDashState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "incorrect-comment"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-comment"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["data"] += data
+ self.state = self.commentState
+ return True
+
+ def commentStartDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.state = self.commentEndState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "-\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "incorrect-comment"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-comment"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["data"] += "-" + data
+ self.state = self.commentState
+ return True
+
+ def commentState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.state = self.commentEndDashState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "\uFFFD"
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "eof-in-comment"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["data"] += data + \
+ self.stream.charsUntil(("-", "\u0000"))
+ return True
+
+ def commentEndDashState(self):
+ data = self.stream.char()
+ if data == "-":
+ self.state = self.commentEndState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "-\uFFFD"
+ self.state = self.commentState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-comment-end-dash"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["data"] += "-" + data
+ self.state = self.commentState
+ return True
+
+ def commentEndState(self):
+ data = self.stream.char()
+ if data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "--\uFFFD"
+ self.state = self.commentState
+ elif data == "!":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-bang-after-double-dash-in-comment"})
+ self.state = self.commentEndBangState
+ elif data == "-":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-dash-after-double-dash-in-comment"})
+ self.currentToken["data"] += data
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-comment-double-dash"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ # XXX
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-comment"})
+ self.currentToken["data"] += "--" + data
+ self.state = self.commentState
+ return True
+
+ def commentEndBangState(self):
+ data = self.stream.char()
+ if data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == "-":
+ self.currentToken["data"] += "--!"
+ self.state = self.commentEndDashState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["data"] += "--!\uFFFD"
+ self.state = self.commentState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-comment-end-bang-state"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["data"] += "--!" + data
+ self.state = self.commentState
+ return True
+
+ def doctypeState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeDoctypeNameState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-doctype-name-but-got-eof"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "need-space-after-doctype"})
+ self.stream.unget(data)
+ self.state = self.beforeDoctypeNameState
+ return True
+
+ def beforeDoctypeNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-doctype-name-but-got-right-bracket"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["name"] = "\uFFFD"
+ self.state = self.doctypeNameState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-doctype-name-but-got-eof"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["name"] = data
+ self.state = self.doctypeNameState
+ return True
+
+ def doctypeNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower)
+ self.state = self.afterDoctypeNameState
+ elif data == ">":
+ self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower)
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["name"] += "\uFFFD"
+ self.state = self.doctypeNameState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype-name"})
+ self.currentToken["correct"] = False
+ self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower)
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["name"] += data
+ return True
+
+ def afterDoctypeNameState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.currentToken["correct"] = False
+ self.stream.unget(data)
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ if data in ("p", "P"):
+ matched = True
+ for expected in (("u", "U"), ("b", "B"), ("l", "L"),
+ ("i", "I"), ("c", "C")):
+ data = self.stream.char()
+ if data not in expected:
+ matched = False
+ break
+ if matched:
+ self.state = self.afterDoctypePublicKeywordState
+ return True
+ elif data in ("s", "S"):
+ matched = True
+ for expected in (("y", "Y"), ("s", "S"), ("t", "T"),
+ ("e", "E"), ("m", "M")):
+ data = self.stream.char()
+ if data not in expected:
+ matched = False
+ break
+ if matched:
+ self.state = self.afterDoctypeSystemKeywordState
+ return True
+
+ # All the characters read before the current 'data' will be
+ # [a-zA-Z], so they're garbage in the bogus doctype and can be
+ # discarded; only the latest character might be '>' or EOF
+ # and needs to be ungetted
+ self.stream.unget(data)
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "expected-space-or-right-bracket-in-doctype", "datavars":
+ {"data": data}})
+ self.currentToken["correct"] = False
+ self.state = self.bogusDoctypeState
+
+ return True
+
+ def afterDoctypePublicKeywordState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeDoctypePublicIdentifierState
+ elif data in ("'", '"'):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.stream.unget(data)
+ self.state = self.beforeDoctypePublicIdentifierState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.stream.unget(data)
+ self.state = self.beforeDoctypePublicIdentifierState
+ return True
+
+ def beforeDoctypePublicIdentifierState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == "\"":
+ self.currentToken["publicId"] = ""
+ self.state = self.doctypePublicIdentifierDoubleQuotedState
+ elif data == "'":
+ self.currentToken["publicId"] = ""
+ self.state = self.doctypePublicIdentifierSingleQuotedState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-end-of-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["correct"] = False
+ self.state = self.bogusDoctypeState
+ return True
+
+ def doctypePublicIdentifierDoubleQuotedState(self):
+ data = self.stream.char()
+ if data == "\"":
+ self.state = self.afterDoctypePublicIdentifierState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["publicId"] += "\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-end-of-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["publicId"] += data
+ return True
+
+ def doctypePublicIdentifierSingleQuotedState(self):
+ data = self.stream.char()
+ if data == "'":
+ self.state = self.afterDoctypePublicIdentifierState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["publicId"] += "\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-end-of-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["publicId"] += data
+ return True
+
+ def afterDoctypePublicIdentifierState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.betweenDoctypePublicAndSystemIdentifiersState
+ elif data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == '"':
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierDoubleQuotedState
+ elif data == "'":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierSingleQuotedState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["correct"] = False
+ self.state = self.bogusDoctypeState
+ return True
+
+ def betweenDoctypePublicAndSystemIdentifiersState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data == '"':
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierDoubleQuotedState
+ elif data == "'":
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierSingleQuotedState
+ elif data == EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["correct"] = False
+ self.state = self.bogusDoctypeState
+ return True
+
+ def afterDoctypeSystemKeywordState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ self.state = self.beforeDoctypeSystemIdentifierState
+ elif data in ("'", '"'):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.stream.unget(data)
+ self.state = self.beforeDoctypeSystemIdentifierState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.stream.unget(data)
+ self.state = self.beforeDoctypeSystemIdentifierState
+ return True
+
+ def beforeDoctypeSystemIdentifierState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == "\"":
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierDoubleQuotedState
+ elif data == "'":
+ self.currentToken["systemId"] = ""
+ self.state = self.doctypeSystemIdentifierSingleQuotedState
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.currentToken["correct"] = False
+ self.state = self.bogusDoctypeState
+ return True
+
+ def doctypeSystemIdentifierDoubleQuotedState(self):
+ data = self.stream.char()
+ if data == "\"":
+ self.state = self.afterDoctypeSystemIdentifierState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["systemId"] += "\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-end-of-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["systemId"] += data
+ return True
+
+ def doctypeSystemIdentifierSingleQuotedState(self):
+ data = self.stream.char()
+ if data == "'":
+ self.state = self.afterDoctypeSystemIdentifierState
+ elif data == "\u0000":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ self.currentToken["systemId"] += "\uFFFD"
+ elif data == ">":
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-end-of-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.currentToken["systemId"] += data
+ return True
+
+ def afterDoctypeSystemIdentifierState(self):
+ data = self.stream.char()
+ if data in spaceCharacters:
+ pass
+ elif data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "eof-in-doctype"})
+ self.currentToken["correct"] = False
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ self.tokenQueue.append({"type": tokenTypes["ParseError"], "data":
+ "unexpected-char-in-doctype"})
+ self.state = self.bogusDoctypeState
+ return True
+
+ def bogusDoctypeState(self):
+ data = self.stream.char()
+ if data == ">":
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ elif data is EOF:
+ # XXX EMIT
+ self.stream.unget(data)
+ self.tokenQueue.append(self.currentToken)
+ self.state = self.dataState
+ else:
+ pass
+ return True
+
+ def cdataSectionState(self):
+ data = []
+ while True:
+ data.append(self.stream.charsUntil("]"))
+ data.append(self.stream.charsUntil(">"))
+ char = self.stream.char()
+ if char == EOF:
+ break
+ else:
+ assert char == ">"
+ if data[-1][-2:] == "]]":
+ data[-1] = data[-1][:-2]
+ break
+ else:
+ data.append(char)
+
+ data = "".join(data)
+ # Deal with null here rather than in the parser
+ nullCount = data.count("\u0000")
+ if nullCount > 0:
+ for i in range(nullCount):
+ self.tokenQueue.append({"type": tokenTypes["ParseError"],
+ "data": "invalid-codepoint"})
+ data = data.replace("\u0000", "\uFFFD")
+ if data:
+ self.tokenQueue.append({"type": tokenTypes["Characters"],
+ "data": data})
+ self.state = self.dataState
+ return True
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py
new file mode 100644
index 00000000000..ad47df95648
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py
@@ -0,0 +1,44 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from xml.sax.xmlreader import AttributesNSImpl
+
+from ..constants import adjustForeignAttributes, unadjustForeignAttributes
+
+prefix_mapping = {}
+for prefix, localName, namespace in adjustForeignAttributes.values():
+ if prefix is not None:
+ prefix_mapping[prefix] = namespace
+
+
+def to_sax(walker, handler):
+ """Call SAX-like content handler based on treewalker walker"""
+ handler.startDocument()
+ for prefix, namespace in prefix_mapping.items():
+ handler.startPrefixMapping(prefix, namespace)
+
+ for token in walker:
+ type = token["type"]
+ if type == "Doctype":
+ continue
+ elif type in ("StartTag", "EmptyTag"):
+ attrs = AttributesNSImpl(token["data"],
+ unadjustForeignAttributes)
+ handler.startElementNS((token["namespace"], token["name"]),
+ token["name"],
+ attrs)
+ if type == "EmptyTag":
+ handler.endElementNS((token["namespace"], token["name"]),
+ token["name"])
+ elif type == "EndTag":
+ handler.endElementNS((token["namespace"], token["name"]),
+ token["name"])
+ elif type in ("Characters", "SpaceCharacters"):
+ handler.characters(token["data"])
+ elif type == "Comment":
+ pass
+ else:
+ assert False, "Unknown token type"
+
+ for prefix, namespace in prefix_mapping.items():
+ handler.endPrefixMapping(prefix)
+ handler.endDocument()
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py
new file mode 100644
index 00000000000..6a6b2a4c45c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py
@@ -0,0 +1,76 @@
+"""A collection of modules for building different kinds of tree from
+HTML documents.
+
+To create a treebuilder for a new type of tree, you need to do
+implement several things:
+
+1) A set of classes for various types of elements: Document, Doctype,
+Comment, Element. These must implement the interface of
+_base.treebuilders.Node (although comment nodes have a different
+signature for their constructor, see treebuilders.etree.Comment)
+Textual content may also be implemented as another node type, or not, as
+your tree implementation requires.
+
+2) A treebuilder object (called TreeBuilder by convention) that
+inherits from treebuilders._base.TreeBuilder. This has 4 required attributes:
+documentClass - the class to use for the bottommost node of a document
+elementClass - the class to use for HTML Elements
+commentClass - the class to use for comments
+doctypeClass - the class to use for doctypes
+It also has one required method:
+getDocument - Returns the root node of the complete document tree
+
+3) If you wish to run the unit tests, you must also create a
+testSerializer method on your treebuilder which accepts a node and
+returns a string containing Node and its children serialized according
+to the format used in the unittests
+"""
+
+from __future__ import absolute_import, division, unicode_literals
+
+from ..utils import default_etree
+
+treeBuilderCache = {}
+
+
+def getTreeBuilder(treeType, implementation=None, **kwargs):
+ """Get a TreeBuilder class for various types of tree with built-in support
+
+ treeType - the name of the tree type required (case-insensitive). Supported
+ values are:
+
+ "dom" - A generic builder for DOM implementations, defaulting to
+ a xml.dom.minidom based implementation.
+ "etree" - A generic builder for tree implementations exposing an
+ ElementTree-like interface, defaulting to
+ xml.etree.cElementTree if available and
+ xml.etree.ElementTree if not.
+ "lxml" - A etree-based builder for lxml.etree, handling
+ limitations of lxml's implementation.
+
+ implementation - (Currently applies to the "etree" and "dom" tree types). A
+ module implementing the tree type e.g.
+ xml.etree.ElementTree or xml.etree.cElementTree."""
+
+ treeType = treeType.lower()
+ if treeType not in treeBuilderCache:
+ if treeType == "dom":
+ from . import dom
+ # Come up with a sane default (pref. from the stdlib)
+ if implementation is None:
+ from xml.dom import minidom
+ implementation = minidom
+ # NEVER cache here, caching is done in the dom submodule
+ return dom.getDomModule(implementation, **kwargs).TreeBuilder
+ elif treeType == "lxml":
+ from . import etree_lxml
+ treeBuilderCache[treeType] = etree_lxml.TreeBuilder
+ elif treeType == "etree":
+ from . import etree
+ if implementation is None:
+ implementation = default_etree
+ # NEVER cache here, caching is done in the etree submodule
+ return etree.getETreeModule(implementation, **kwargs).TreeBuilder
+ else:
+ raise ValueError("""Unrecognised treebuilder "%s" """ % treeType)
+ return treeBuilderCache.get(treeType)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py
new file mode 100644
index 00000000000..8b97cc11a21
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py
@@ -0,0 +1,377 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+
+from ..constants import scopingElements, tableInsertModeElements, namespaces
+
+# The scope markers are inserted when entering object elements,
+# marquees, table cells, and table captions, and are used to prevent formatting
+# from "leaking" into tables, object elements, and marquees.
+Marker = None
+
+listElementsMap = {
+ None: (frozenset(scopingElements), False),
+ "button": (frozenset(scopingElements | set([(namespaces["html"], "button")])), False),
+ "list": (frozenset(scopingElements | set([(namespaces["html"], "ol"),
+ (namespaces["html"], "ul")])), False),
+ "table": (frozenset([(namespaces["html"], "html"),
+ (namespaces["html"], "table")]), False),
+ "select": (frozenset([(namespaces["html"], "optgroup"),
+ (namespaces["html"], "option")]), True)
+}
+
+
+class Node(object):
+ def __init__(self, name):
+ """Node representing an item in the tree.
+ name - The tag name associated with the node
+ parent - The parent of the current node (or None for the document node)
+ value - The value of the current node (applies to text nodes and
+ comments
+ attributes - a dict holding name, value pairs for attributes of the node
+ childNodes - a list of child nodes of the current node. This must
+ include all elements but not necessarily other node types
+ _flags - A list of miscellaneous flags that can be set on the node
+ """
+ self.name = name
+ self.parent = None
+ self.value = None
+ self.attributes = {}
+ self.childNodes = []
+ self._flags = []
+
+ def __str__(self):
+ attributesStr = " ".join(["%s=\"%s\"" % (name, value)
+ for name, value in
+ self.attributes.items()])
+ if attributesStr:
+ return "<%s %s>" % (self.name, attributesStr)
+ else:
+ return "<%s>" % (self.name)
+
+ def __repr__(self):
+ return "<%s>" % (self.name)
+
+ def appendChild(self, node):
+ """Insert node as a child of the current node
+ """
+ raise NotImplementedError
+
+ def insertText(self, data, insertBefore=None):
+ """Insert data as text in the current node, positioned before the
+ start of node insertBefore or to the end of the node's text.
+ """
+ raise NotImplementedError
+
+ def insertBefore(self, node, refNode):
+ """Insert node as a child of the current node, before refNode in the
+ list of child nodes. Raises ValueError if refNode is not a child of
+ the current node"""
+ raise NotImplementedError
+
+ def removeChild(self, node):
+ """Remove node from the children of the current node
+ """
+ raise NotImplementedError
+
+ def reparentChildren(self, newParent):
+ """Move all the children of the current node to newParent.
+ This is needed so that trees that don't store text as nodes move the
+ text in the correct way
+ """
+ # XXX - should this method be made more general?
+ for child in self.childNodes:
+ newParent.appendChild(child)
+ self.childNodes = []
+
+ def cloneNode(self):
+ """Return a shallow copy of the current node i.e. a node with the same
+ name and attributes but with no parent or child nodes
+ """
+ raise NotImplementedError
+
+ def hasContent(self):
+ """Return true if the node has children or text, false otherwise
+ """
+ raise NotImplementedError
+
+
+class ActiveFormattingElements(list):
+ def append(self, node):
+ equalCount = 0
+ if node != Marker:
+ for element in self[::-1]:
+ if element == Marker:
+ break
+ if self.nodesEqual(element, node):
+ equalCount += 1
+ if equalCount == 3:
+ self.remove(element)
+ break
+ list.append(self, node)
+
+ def nodesEqual(self, node1, node2):
+ if not node1.nameTuple == node2.nameTuple:
+ return False
+
+ if not node1.attributes == node2.attributes:
+ return False
+
+ return True
+
+
+class TreeBuilder(object):
+ """Base treebuilder implementation
+ documentClass - the class to use for the bottommost node of a document
+ elementClass - the class to use for HTML Elements
+ commentClass - the class to use for comments
+ doctypeClass - the class to use for doctypes
+ """
+
+ # Document class
+ documentClass = None
+
+ # The class to use for creating a node
+ elementClass = None
+
+ # The class to use for creating comments
+ commentClass = None
+
+ # The class to use for creating doctypes
+ doctypeClass = None
+
+ # Fragment class
+ fragmentClass = None
+
+ def __init__(self, namespaceHTMLElements):
+ if namespaceHTMLElements:
+ self.defaultNamespace = "http://www.w3.org/1999/xhtml"
+ else:
+ self.defaultNamespace = None
+ self.reset()
+
+ def reset(self):
+ self.openElements = []
+ self.activeFormattingElements = ActiveFormattingElements()
+
+ # XXX - rename these to headElement, formElement
+ self.headPointer = None
+ self.formPointer = None
+
+ self.insertFromTable = False
+
+ self.document = self.documentClass()
+
+ def elementInScope(self, target, variant=None):
+
+ # If we pass a node in we match that. if we pass a string
+ # match any node with that name
+ exactNode = hasattr(target, "nameTuple")
+
+ listElements, invert = listElementsMap[variant]
+
+ for node in reversed(self.openElements):
+ if (node.name == target and not exactNode or
+ node == target and exactNode):
+ return True
+ elif (invert ^ (node.nameTuple in listElements)):
+ return False
+
+ assert False # We should never reach this point
+
+ def reconstructActiveFormattingElements(self):
+ # Within this algorithm the order of steps described in the
+ # specification is not quite the same as the order of steps in the
+ # code. It should still do the same though.
+
+ # Step 1: stop the algorithm when there's nothing to do.
+ if not self.activeFormattingElements:
+ return
+
+ # Step 2 and step 3: we start with the last element. So i is -1.
+ i = len(self.activeFormattingElements) - 1
+ entry = self.activeFormattingElements[i]
+ if entry == Marker or entry in self.openElements:
+ return
+
+ # Step 6
+ while entry != Marker and entry not in self.openElements:
+ if i == 0:
+ # This will be reset to 0 below
+ i = -1
+ break
+ i -= 1
+ # Step 5: let entry be one earlier in the list.
+ entry = self.activeFormattingElements[i]
+
+ while True:
+ # Step 7
+ i += 1
+
+ # Step 8
+ entry = self.activeFormattingElements[i]
+ clone = entry.cloneNode() # Mainly to get a new copy of the attributes
+
+ # Step 9
+ element = self.insertElement({"type": "StartTag",
+ "name": clone.name,
+ "namespace": clone.namespace,
+ "data": clone.attributes})
+
+ # Step 10
+ self.activeFormattingElements[i] = element
+
+ # Step 11
+ if element == self.activeFormattingElements[-1]:
+ break
+
+ def clearActiveFormattingElements(self):
+ entry = self.activeFormattingElements.pop()
+ while self.activeFormattingElements and entry != Marker:
+ entry = self.activeFormattingElements.pop()
+
+ def elementInActiveFormattingElements(self, name):
+ """Check if an element exists between the end of the active
+ formatting elements and the last marker. If it does, return it, else
+ return false"""
+
+ for item in self.activeFormattingElements[::-1]:
+ # Check for Marker first because if it's a Marker it doesn't have a
+ # name attribute.
+ if item == Marker:
+ break
+ elif item.name == name:
+ return item
+ return False
+
+ def insertRoot(self, token):
+ element = self.createElement(token)
+ self.openElements.append(element)
+ self.document.appendChild(element)
+
+ def insertDoctype(self, token):
+ name = token["name"]
+ publicId = token["publicId"]
+ systemId = token["systemId"]
+
+ doctype = self.doctypeClass(name, publicId, systemId)
+ self.document.appendChild(doctype)
+
+ def insertComment(self, token, parent=None):
+ if parent is None:
+ parent = self.openElements[-1]
+ parent.appendChild(self.commentClass(token["data"]))
+
+ def createElement(self, token):
+ """Create an element but don't insert it anywhere"""
+ name = token["name"]
+ namespace = token.get("namespace", self.defaultNamespace)
+ element = self.elementClass(name, namespace)
+ element.attributes = token["data"]
+ return element
+
+ def _getInsertFromTable(self):
+ return self._insertFromTable
+
+ def _setInsertFromTable(self, value):
+ """Switch the function used to insert an element from the
+ normal one to the misnested table one and back again"""
+ self._insertFromTable = value
+ if value:
+ self.insertElement = self.insertElementTable
+ else:
+ self.insertElement = self.insertElementNormal
+
+ insertFromTable = property(_getInsertFromTable, _setInsertFromTable)
+
+ def insertElementNormal(self, token):
+ name = token["name"]
+ assert isinstance(name, text_type), "Element %s not unicode" % name
+ namespace = token.get("namespace", self.defaultNamespace)
+ element = self.elementClass(name, namespace)
+ element.attributes = token["data"]
+ self.openElements[-1].appendChild(element)
+ self.openElements.append(element)
+ return element
+
+ def insertElementTable(self, token):
+ """Create an element and insert it into the tree"""
+ element = self.createElement(token)
+ if self.openElements[-1].name not in tableInsertModeElements:
+ return self.insertElementNormal(token)
+ else:
+ # We should be in the InTable mode. This means we want to do
+ # special magic element rearranging
+ parent, insertBefore = self.getTableMisnestedNodePosition()
+ if insertBefore is None:
+ parent.appendChild(element)
+ else:
+ parent.insertBefore(element, insertBefore)
+ self.openElements.append(element)
+ return element
+
+ def insertText(self, data, parent=None):
+ """Insert text data."""
+ if parent is None:
+ parent = self.openElements[-1]
+
+ if (not self.insertFromTable or (self.insertFromTable and
+ self.openElements[-1].name
+ not in tableInsertModeElements)):
+ parent.insertText(data)
+ else:
+ # We should be in the InTable mode. This means we want to do
+ # special magic element rearranging
+ parent, insertBefore = self.getTableMisnestedNodePosition()
+ parent.insertText(data, insertBefore)
+
+ def getTableMisnestedNodePosition(self):
+ """Get the foster parent element, and sibling to insert before
+ (or None) when inserting a misnested table node"""
+ # The foster parent element is the one which comes before the most
+ # recently opened table element
+ # XXX - this is really inelegant
+ lastTable = None
+ fosterParent = None
+ insertBefore = None
+ for elm in self.openElements[::-1]:
+ if elm.name == "table":
+ lastTable = elm
+ break
+ if lastTable:
+ # XXX - we should really check that this parent is actually a
+ # node here
+ if lastTable.parent:
+ fosterParent = lastTable.parent
+ insertBefore = lastTable
+ else:
+ fosterParent = self.openElements[
+ self.openElements.index(lastTable) - 1]
+ else:
+ fosterParent = self.openElements[0]
+ return fosterParent, insertBefore
+
+ def generateImpliedEndTags(self, exclude=None):
+ name = self.openElements[-1].name
+ # XXX td, th and tr are not actually needed
+ if (name in frozenset(("dd", "dt", "li", "option", "optgroup", "p", "rp", "rt"))
+ and name != exclude):
+ self.openElements.pop()
+ # XXX This is not entirely what the specification says. We should
+ # investigate it more closely.
+ self.generateImpliedEndTags(exclude)
+
+ def getDocument(self):
+ "Return the final tree"
+ return self.document
+
+ def getFragment(self):
+ "Return the final fragment"
+ # assert self.innerHTML
+ fragment = self.fragmentClass()
+ self.openElements[0].reparentChildren(fragment)
+ return fragment
+
+ def testSerializer(self, node):
+ """Serialize the subtree of node in the format required by unit tests
+ node - the node from which to start serializing"""
+ raise NotImplementedError
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py
new file mode 100644
index 00000000000..234233b7932
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py
@@ -0,0 +1,227 @@
+from __future__ import absolute_import, division, unicode_literals
+
+
+from xml.dom import minidom, Node
+import weakref
+
+from . import _base
+from .. import constants
+from ..constants import namespaces
+from ..utils import moduleFactoryFactory
+
+
+def getDomBuilder(DomImplementation):
+ Dom = DomImplementation
+
+ class AttrList(object):
+ def __init__(self, element):
+ self.element = element
+
+ def __iter__(self):
+ return list(self.element.attributes.items()).__iter__()
+
+ def __setitem__(self, name, value):
+ self.element.setAttribute(name, value)
+
+ def __len__(self):
+ return len(list(self.element.attributes.items()))
+
+ def items(self):
+ return [(item[0], item[1]) for item in
+ list(self.element.attributes.items())]
+
+ def keys(self):
+ return list(self.element.attributes.keys())
+
+ def __getitem__(self, name):
+ return self.element.getAttribute(name)
+
+ def __contains__(self, name):
+ if isinstance(name, tuple):
+ raise NotImplementedError
+ else:
+ return self.element.hasAttribute(name)
+
+ class NodeBuilder(_base.Node):
+ def __init__(self, element):
+ _base.Node.__init__(self, element.nodeName)
+ self.element = element
+
+ namespace = property(lambda self: hasattr(self.element, "namespaceURI")
+ and self.element.namespaceURI or None)
+
+ def appendChild(self, node):
+ node.parent = self
+ self.element.appendChild(node.element)
+
+ def insertText(self, data, insertBefore=None):
+ text = self.element.ownerDocument.createTextNode(data)
+ if insertBefore:
+ self.element.insertBefore(text, insertBefore.element)
+ else:
+ self.element.appendChild(text)
+
+ def insertBefore(self, node, refNode):
+ self.element.insertBefore(node.element, refNode.element)
+ node.parent = self
+
+ def removeChild(self, node):
+ if node.element.parentNode == self.element:
+ self.element.removeChild(node.element)
+ node.parent = None
+
+ def reparentChildren(self, newParent):
+ while self.element.hasChildNodes():
+ child = self.element.firstChild
+ self.element.removeChild(child)
+ newParent.element.appendChild(child)
+ self.childNodes = []
+
+ def getAttributes(self):
+ return AttrList(self.element)
+
+ def setAttributes(self, attributes):
+ if attributes:
+ for name, value in list(attributes.items()):
+ if isinstance(name, tuple):
+ if name[0] is not None:
+ qualifiedName = (name[0] + ":" + name[1])
+ else:
+ qualifiedName = name[1]
+ self.element.setAttributeNS(name[2], qualifiedName,
+ value)
+ else:
+ self.element.setAttribute(
+ name, value)
+ attributes = property(getAttributes, setAttributes)
+
+ def cloneNode(self):
+ return NodeBuilder(self.element.cloneNode(False))
+
+ def hasContent(self):
+ return self.element.hasChildNodes()
+
+ def getNameTuple(self):
+ if self.namespace is None:
+ return namespaces["html"], self.name
+ else:
+ return self.namespace, self.name
+
+ nameTuple = property(getNameTuple)
+
+ class TreeBuilder(_base.TreeBuilder):
+ def documentClass(self):
+ self.dom = Dom.getDOMImplementation().createDocument(None, None, None)
+ return weakref.proxy(self)
+
+ def insertDoctype(self, token):
+ name = token["name"]
+ publicId = token["publicId"]
+ systemId = token["systemId"]
+
+ domimpl = Dom.getDOMImplementation()
+ doctype = domimpl.createDocumentType(name, publicId, systemId)
+ self.document.appendChild(NodeBuilder(doctype))
+ if Dom == minidom:
+ doctype.ownerDocument = self.dom
+
+ def elementClass(self, name, namespace=None):
+ if namespace is None and self.defaultNamespace is None:
+ node = self.dom.createElement(name)
+ else:
+ node = self.dom.createElementNS(namespace, name)
+
+ return NodeBuilder(node)
+
+ def commentClass(self, data):
+ return NodeBuilder(self.dom.createComment(data))
+
+ def fragmentClass(self):
+ return NodeBuilder(self.dom.createDocumentFragment())
+
+ def appendChild(self, node):
+ self.dom.appendChild(node.element)
+
+ def testSerializer(self, element):
+ return testSerializer(element)
+
+ def getDocument(self):
+ return self.dom
+
+ def getFragment(self):
+ return _base.TreeBuilder.getFragment(self).element
+
+ def insertText(self, data, parent=None):
+ data = data
+ if parent != self:
+ _base.TreeBuilder.insertText(self, data, parent)
+ else:
+ # HACK: allow text nodes as children of the document node
+ if hasattr(self.dom, '_child_node_types'):
+ if Node.TEXT_NODE not in self.dom._child_node_types:
+ self.dom._child_node_types = list(self.dom._child_node_types)
+ self.dom._child_node_types.append(Node.TEXT_NODE)
+ self.dom.appendChild(self.dom.createTextNode(data))
+
+ implementation = DomImplementation
+ name = None
+
+ def testSerializer(element):
+ element.normalize()
+ rv = []
+
+ def serializeElement(element, indent=0):
+ if element.nodeType == Node.DOCUMENT_TYPE_NODE:
+ if element.name:
+ if element.publicId or element.systemId:
+ publicId = element.publicId or ""
+ systemId = element.systemId or ""
+ rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" %
+ (' ' * indent, element.name, publicId, systemId))
+ else:
+ rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name))
+ else:
+ rv.append("|%s<!DOCTYPE >" % (' ' * indent,))
+ elif element.nodeType == Node.DOCUMENT_NODE:
+ rv.append("#document")
+ elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
+ rv.append("#document-fragment")
+ elif element.nodeType == Node.COMMENT_NODE:
+ rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue))
+ elif element.nodeType == Node.TEXT_NODE:
+ rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue))
+ else:
+ if (hasattr(element, "namespaceURI") and
+ element.namespaceURI is not None):
+ name = "%s %s" % (constants.prefixes[element.namespaceURI],
+ element.nodeName)
+ else:
+ name = element.nodeName
+ rv.append("|%s<%s>" % (' ' * indent, name))
+ if element.hasAttributes():
+ attributes = []
+ for i in range(len(element.attributes)):
+ attr = element.attributes.item(i)
+ name = attr.nodeName
+ value = attr.value
+ ns = attr.namespaceURI
+ if ns:
+ name = "%s %s" % (constants.prefixes[ns], attr.localName)
+ else:
+ name = attr.nodeName
+ attributes.append((name, value))
+
+ for name, value in sorted(attributes):
+ rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
+ indent += 2
+ for child in element.childNodes:
+ serializeElement(child, indent)
+ serializeElement(element, 0)
+
+ return "\n".join(rv)
+
+ return locals()
+
+
+# The actual means to get a module!
+getDomModule = moduleFactoryFactory(getDomBuilder)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py
new file mode 100644
index 00000000000..2c8ed19f8fe
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py
@@ -0,0 +1,337 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+
+import re
+
+from . import _base
+from .. import ihatexml
+from .. import constants
+from ..constants import namespaces
+from ..utils import moduleFactoryFactory
+
+tag_regexp = re.compile("{([^}]*)}(.*)")
+
+
+def getETreeBuilder(ElementTreeImplementation, fullTree=False):
+ ElementTree = ElementTreeImplementation
+ ElementTreeCommentType = ElementTree.Comment("asd").tag
+
+ class Element(_base.Node):
+ def __init__(self, name, namespace=None):
+ self._name = name
+ self._namespace = namespace
+ self._element = ElementTree.Element(self._getETreeTag(name,
+ namespace))
+ if namespace is None:
+ self.nameTuple = namespaces["html"], self._name
+ else:
+ self.nameTuple = self._namespace, self._name
+ self.parent = None
+ self._childNodes = []
+ self._flags = []
+
+ def _getETreeTag(self, name, namespace):
+ if namespace is None:
+ etree_tag = name
+ else:
+ etree_tag = "{%s}%s" % (namespace, name)
+ return etree_tag
+
+ def _setName(self, name):
+ self._name = name
+ self._element.tag = self._getETreeTag(self._name, self._namespace)
+
+ def _getName(self):
+ return self._name
+
+ name = property(_getName, _setName)
+
+ def _setNamespace(self, namespace):
+ self._namespace = namespace
+ self._element.tag = self._getETreeTag(self._name, self._namespace)
+
+ def _getNamespace(self):
+ return self._namespace
+
+ namespace = property(_getNamespace, _setNamespace)
+
+ def _getAttributes(self):
+ return self._element.attrib
+
+ def _setAttributes(self, attributes):
+ # Delete existing attributes first
+ # XXX - there may be a better way to do this...
+ for key in list(self._element.attrib.keys()):
+ del self._element.attrib[key]
+ for key, value in attributes.items():
+ if isinstance(key, tuple):
+ name = "{%s}%s" % (key[2], key[1])
+ else:
+ name = key
+ self._element.set(name, value)
+
+ attributes = property(_getAttributes, _setAttributes)
+
+ def _getChildNodes(self):
+ return self._childNodes
+
+ def _setChildNodes(self, value):
+ del self._element[:]
+ self._childNodes = []
+ for element in value:
+ self.insertChild(element)
+
+ childNodes = property(_getChildNodes, _setChildNodes)
+
+ def hasContent(self):
+ """Return true if the node has children or text"""
+ return bool(self._element.text or len(self._element))
+
+ def appendChild(self, node):
+ self._childNodes.append(node)
+ self._element.append(node._element)
+ node.parent = self
+
+ def insertBefore(self, node, refNode):
+ index = list(self._element).index(refNode._element)
+ self._element.insert(index, node._element)
+ node.parent = self
+
+ def removeChild(self, node):
+ self._element.remove(node._element)
+ node.parent = None
+
+ def insertText(self, data, insertBefore=None):
+ if not(len(self._element)):
+ if not self._element.text:
+ self._element.text = ""
+ self._element.text += data
+ elif insertBefore is None:
+ # Insert the text as the tail of the last child element
+ if not self._element[-1].tail:
+ self._element[-1].tail = ""
+ self._element[-1].tail += data
+ else:
+ # Insert the text before the specified node
+ children = list(self._element)
+ index = children.index(insertBefore._element)
+ if index > 0:
+ if not self._element[index - 1].tail:
+ self._element[index - 1].tail = ""
+ self._element[index - 1].tail += data
+ else:
+ if not self._element.text:
+ self._element.text = ""
+ self._element.text += data
+
+ def cloneNode(self):
+ element = type(self)(self.name, self.namespace)
+ for name, value in self.attributes.items():
+ element.attributes[name] = value
+ return element
+
+ def reparentChildren(self, newParent):
+ if newParent.childNodes:
+ newParent.childNodes[-1]._element.tail += self._element.text
+ else:
+ if not newParent._element.text:
+ newParent._element.text = ""
+ if self._element.text is not None:
+ newParent._element.text += self._element.text
+ self._element.text = ""
+ _base.Node.reparentChildren(self, newParent)
+
+ class Comment(Element):
+ def __init__(self, data):
+ # Use the superclass constructor to set all properties on the
+ # wrapper element
+ self._element = ElementTree.Comment(data)
+ self.parent = None
+ self._childNodes = []
+ self._flags = []
+
+ def _getData(self):
+ return self._element.text
+
+ def _setData(self, value):
+ self._element.text = value
+
+ data = property(_getData, _setData)
+
+ class DocumentType(Element):
+ def __init__(self, name, publicId, systemId):
+ Element.__init__(self, "<!DOCTYPE>")
+ self._element.text = name
+ self.publicId = publicId
+ self.systemId = systemId
+
+ def _getPublicId(self):
+ return self._element.get("publicId", "")
+
+ def _setPublicId(self, value):
+ if value is not None:
+ self._element.set("publicId", value)
+
+ publicId = property(_getPublicId, _setPublicId)
+
+ def _getSystemId(self):
+ return self._element.get("systemId", "")
+
+ def _setSystemId(self, value):
+ if value is not None:
+ self._element.set("systemId", value)
+
+ systemId = property(_getSystemId, _setSystemId)
+
+ class Document(Element):
+ def __init__(self):
+ Element.__init__(self, "DOCUMENT_ROOT")
+
+ class DocumentFragment(Element):
+ def __init__(self):
+ Element.__init__(self, "DOCUMENT_FRAGMENT")
+
+ def testSerializer(element):
+ rv = []
+
+ def serializeElement(element, indent=0):
+ if not(hasattr(element, "tag")):
+ element = element.getroot()
+ if element.tag == "<!DOCTYPE>":
+ if element.get("publicId") or element.get("systemId"):
+ publicId = element.get("publicId") or ""
+ systemId = element.get("systemId") or ""
+ rv.append("""<!DOCTYPE %s "%s" "%s">""" %
+ (element.text, publicId, systemId))
+ else:
+ rv.append("<!DOCTYPE %s>" % (element.text,))
+ elif element.tag == "DOCUMENT_ROOT":
+ rv.append("#document")
+ if element.text is not None:
+ rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text))
+ if element.tail is not None:
+ raise TypeError("Document node cannot have tail")
+ if hasattr(element, "attrib") and len(element.attrib):
+ raise TypeError("Document node cannot have attributes")
+ elif element.tag == ElementTreeCommentType:
+ rv.append("|%s<!-- %s -->" % (' ' * indent, element.text))
+ else:
+ assert isinstance(element.tag, text_type), \
+ "Expected unicode, got %s, %s" % (type(element.tag), element.tag)
+ nsmatch = tag_regexp.match(element.tag)
+
+ if nsmatch is None:
+ name = element.tag
+ else:
+ ns, name = nsmatch.groups()
+ prefix = constants.prefixes[ns]
+ name = "%s %s" % (prefix, name)
+ rv.append("|%s<%s>" % (' ' * indent, name))
+
+ if hasattr(element, "attrib"):
+ attributes = []
+ for name, value in element.attrib.items():
+ nsmatch = tag_regexp.match(name)
+ if nsmatch is not None:
+ ns, name = nsmatch.groups()
+ prefix = constants.prefixes[ns]
+ attr_string = "%s %s" % (prefix, name)
+ else:
+ attr_string = name
+ attributes.append((attr_string, value))
+
+ for name, value in sorted(attributes):
+ rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
+ if element.text:
+ rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text))
+ indent += 2
+ for child in element:
+ serializeElement(child, indent)
+ if element.tail:
+ rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail))
+ serializeElement(element, 0)
+
+ return "\n".join(rv)
+
+ def tostring(element):
+ """Serialize an element and its child nodes to a string"""
+ rv = []
+ filter = ihatexml.InfosetFilter()
+
+ def serializeElement(element):
+ if isinstance(element, ElementTree.ElementTree):
+ element = element.getroot()
+
+ if element.tag == "<!DOCTYPE>":
+ if element.get("publicId") or element.get("systemId"):
+ publicId = element.get("publicId") or ""
+ systemId = element.get("systemId") or ""
+ rv.append("""<!DOCTYPE %s PUBLIC "%s" "%s">""" %
+ (element.text, publicId, systemId))
+ else:
+ rv.append("<!DOCTYPE %s>" % (element.text,))
+ elif element.tag == "DOCUMENT_ROOT":
+ if element.text is not None:
+ rv.append(element.text)
+ if element.tail is not None:
+ raise TypeError("Document node cannot have tail")
+ if hasattr(element, "attrib") and len(element.attrib):
+ raise TypeError("Document node cannot have attributes")
+
+ for child in element:
+ serializeElement(child)
+
+ elif element.tag == ElementTreeCommentType:
+ rv.append("<!--%s-->" % (element.text,))
+ else:
+ # This is assumed to be an ordinary element
+ if not element.attrib:
+ rv.append("<%s>" % (filter.fromXmlName(element.tag),))
+ else:
+ attr = " ".join(["%s=\"%s\"" % (
+ filter.fromXmlName(name), value)
+ for name, value in element.attrib.items()])
+ rv.append("<%s %s>" % (element.tag, attr))
+ if element.text:
+ rv.append(element.text)
+
+ for child in element:
+ serializeElement(child)
+
+ rv.append("</%s>" % (element.tag,))
+
+ if element.tail:
+ rv.append(element.tail)
+
+ serializeElement(element)
+
+ return "".join(rv)
+
+ class TreeBuilder(_base.TreeBuilder):
+ documentClass = Document
+ doctypeClass = DocumentType
+ elementClass = Element
+ commentClass = Comment
+ fragmentClass = DocumentFragment
+ implementation = ElementTreeImplementation
+
+ def testSerializer(self, element):
+ return testSerializer(element)
+
+ def getDocument(self):
+ if fullTree:
+ return self.document._element
+ else:
+ if self.defaultNamespace is not None:
+ return self.document._element.find(
+ "{%s}html" % self.defaultNamespace)
+ else:
+ return self.document._element.find("html")
+
+ def getFragment(self):
+ return _base.TreeBuilder.getFragment(self)._element
+
+ return locals()
+
+
+getETreeModule = moduleFactoryFactory(getETreeBuilder)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py
new file mode 100644
index 00000000000..35d08efaa61
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py
@@ -0,0 +1,369 @@
+"""Module for supporting the lxml.etree library. The idea here is to use as much
+of the native library as possible, without using fragile hacks like custom element
+names that break between releases. The downside of this is that we cannot represent
+all possible trees; specifically the following are known to cause problems:
+
+Text or comments as siblings of the root element
+Docypes with no name
+
+When any of these things occur, we emit a DataLossWarning
+"""
+
+from __future__ import absolute_import, division, unicode_literals
+
+import warnings
+import re
+import sys
+
+from . import _base
+from ..constants import DataLossWarning
+from .. import constants
+from . import etree as etree_builders
+from .. import ihatexml
+
+import lxml.etree as etree
+
+
+fullTree = True
+tag_regexp = re.compile("{([^}]*)}(.*)")
+
+comment_type = etree.Comment("asd").tag
+
+
+class DocumentType(object):
+ def __init__(self, name, publicId, systemId):
+ self.name = name
+ self.publicId = publicId
+ self.systemId = systemId
+
+
+class Document(object):
+ def __init__(self):
+ self._elementTree = None
+ self._childNodes = []
+
+ def appendChild(self, element):
+ self._elementTree.getroot().addnext(element._element)
+
+ def _getChildNodes(self):
+ return self._childNodes
+
+ childNodes = property(_getChildNodes)
+
+
+def testSerializer(element):
+ rv = []
+ finalText = None
+ infosetFilter = ihatexml.InfosetFilter()
+
+ def serializeElement(element, indent=0):
+ if not hasattr(element, "tag"):
+ if hasattr(element, "getroot"):
+ # Full tree case
+ rv.append("#document")
+ if element.docinfo.internalDTD:
+ if not (element.docinfo.public_id or
+ element.docinfo.system_url):
+ dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name
+ else:
+ dtd_str = """<!DOCTYPE %s "%s" "%s">""" % (
+ element.docinfo.root_name,
+ element.docinfo.public_id,
+ element.docinfo.system_url)
+ rv.append("|%s%s" % (' ' * (indent + 2), dtd_str))
+ next_element = element.getroot()
+ while next_element.getprevious() is not None:
+ next_element = next_element.getprevious()
+ while next_element is not None:
+ serializeElement(next_element, indent + 2)
+ next_element = next_element.getnext()
+ elif isinstance(element, str) or isinstance(element, bytes):
+ # Text in a fragment
+ assert isinstance(element, str) or sys.version_info.major == 2
+ rv.append("|%s\"%s\"" % (' ' * indent, element))
+ else:
+ # Fragment case
+ rv.append("#document-fragment")
+ for next_element in element:
+ serializeElement(next_element, indent + 2)
+ elif element.tag == comment_type:
+ rv.append("|%s<!-- %s -->" % (' ' * indent, element.text))
+ if hasattr(element, "tail") and element.tail:
+ rv.append("|%s\"%s\"" % (' ' * indent, element.tail))
+ else:
+ assert isinstance(element, etree._Element)
+ nsmatch = etree_builders.tag_regexp.match(element.tag)
+ if nsmatch is not None:
+ ns = nsmatch.group(1)
+ tag = nsmatch.group(2)
+ prefix = constants.prefixes[ns]
+ rv.append("|%s<%s %s>" % (' ' * indent, prefix,
+ infosetFilter.fromXmlName(tag)))
+ else:
+ rv.append("|%s<%s>" % (' ' * indent,
+ infosetFilter.fromXmlName(element.tag)))
+
+ if hasattr(element, "attrib"):
+ attributes = []
+ for name, value in element.attrib.items():
+ nsmatch = tag_regexp.match(name)
+ if nsmatch is not None:
+ ns, name = nsmatch.groups()
+ name = infosetFilter.fromXmlName(name)
+ prefix = constants.prefixes[ns]
+ attr_string = "%s %s" % (prefix, name)
+ else:
+ attr_string = infosetFilter.fromXmlName(name)
+ attributes.append((attr_string, value))
+
+ for name, value in sorted(attributes):
+ rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
+
+ if element.text:
+ rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text))
+ indent += 2
+ for child in element:
+ serializeElement(child, indent)
+ if hasattr(element, "tail") and element.tail:
+ rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail))
+ serializeElement(element, 0)
+
+ if finalText is not None:
+ rv.append("|%s\"%s\"" % (' ' * 2, finalText))
+
+ return "\n".join(rv)
+
+
+def tostring(element):
+ """Serialize an element and its child nodes to a string"""
+ rv = []
+ finalText = None
+
+ def serializeElement(element):
+ if not hasattr(element, "tag"):
+ if element.docinfo.internalDTD:
+ if element.docinfo.doctype:
+ dtd_str = element.docinfo.doctype
+ else:
+ dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name
+ rv.append(dtd_str)
+ serializeElement(element.getroot())
+
+ elif element.tag == comment_type:
+ rv.append("<!--%s-->" % (element.text,))
+
+ else:
+ # This is assumed to be an ordinary element
+ if not element.attrib:
+ rv.append("<%s>" % (element.tag,))
+ else:
+ attr = " ".join(["%s=\"%s\"" % (name, value)
+ for name, value in element.attrib.items()])
+ rv.append("<%s %s>" % (element.tag, attr))
+ if element.text:
+ rv.append(element.text)
+
+ for child in element:
+ serializeElement(child)
+
+ rv.append("</%s>" % (element.tag,))
+
+ if hasattr(element, "tail") and element.tail:
+ rv.append(element.tail)
+
+ serializeElement(element)
+
+ if finalText is not None:
+ rv.append("%s\"" % (' ' * 2, finalText))
+
+ return "".join(rv)
+
+
+class TreeBuilder(_base.TreeBuilder):
+ documentClass = Document
+ doctypeClass = DocumentType
+ elementClass = None
+ commentClass = None
+ fragmentClass = Document
+ implementation = etree
+
+ def __init__(self, namespaceHTMLElements, fullTree=False):
+ builder = etree_builders.getETreeModule(etree, fullTree=fullTree)
+ infosetFilter = self.infosetFilter = ihatexml.InfosetFilter()
+ self.namespaceHTMLElements = namespaceHTMLElements
+
+ class Attributes(dict):
+ def __init__(self, element, value={}):
+ self._element = element
+ dict.__init__(self, value)
+ for key, value in self.items():
+ if isinstance(key, tuple):
+ name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1]))
+ else:
+ name = infosetFilter.coerceAttribute(key)
+ self._element._element.attrib[name] = value
+
+ def __setitem__(self, key, value):
+ dict.__setitem__(self, key, value)
+ if isinstance(key, tuple):
+ name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1]))
+ else:
+ name = infosetFilter.coerceAttribute(key)
+ self._element._element.attrib[name] = value
+
+ class Element(builder.Element):
+ def __init__(self, name, namespace):
+ name = infosetFilter.coerceElement(name)
+ builder.Element.__init__(self, name, namespace=namespace)
+ self._attributes = Attributes(self)
+
+ def _setName(self, name):
+ self._name = infosetFilter.coerceElement(name)
+ self._element.tag = self._getETreeTag(
+ self._name, self._namespace)
+
+ def _getName(self):
+ return infosetFilter.fromXmlName(self._name)
+
+ name = property(_getName, _setName)
+
+ def _getAttributes(self):
+ return self._attributes
+
+ def _setAttributes(self, attributes):
+ self._attributes = Attributes(self, attributes)
+
+ attributes = property(_getAttributes, _setAttributes)
+
+ def insertText(self, data, insertBefore=None):
+ data = infosetFilter.coerceCharacters(data)
+ builder.Element.insertText(self, data, insertBefore)
+
+ def appendChild(self, child):
+ builder.Element.appendChild(self, child)
+
+ class Comment(builder.Comment):
+ def __init__(self, data):
+ data = infosetFilter.coerceComment(data)
+ builder.Comment.__init__(self, data)
+
+ def _setData(self, data):
+ data = infosetFilter.coerceComment(data)
+ self._element.text = data
+
+ def _getData(self):
+ return self._element.text
+
+ data = property(_getData, _setData)
+
+ self.elementClass = Element
+ self.commentClass = builder.Comment
+ # self.fragmentClass = builder.DocumentFragment
+ _base.TreeBuilder.__init__(self, namespaceHTMLElements)
+
+ def reset(self):
+ _base.TreeBuilder.reset(self)
+ self.insertComment = self.insertCommentInitial
+ self.initial_comments = []
+ self.doctype = None
+
+ def testSerializer(self, element):
+ return testSerializer(element)
+
+ def getDocument(self):
+ if fullTree:
+ return self.document._elementTree
+ else:
+ return self.document._elementTree.getroot()
+
+ def getFragment(self):
+ fragment = []
+ element = self.openElements[0]._element
+ if element.text:
+ fragment.append(element.text)
+ fragment.extend(list(element))
+ if element.tail:
+ fragment.append(element.tail)
+ return fragment
+
+ def insertDoctype(self, token):
+ name = token["name"]
+ publicId = token["publicId"]
+ systemId = token["systemId"]
+
+ if not name:
+ warnings.warn("lxml cannot represent empty doctype", DataLossWarning)
+ self.doctype = None
+ else:
+ coercedName = self.infosetFilter.coerceElement(name)
+ if coercedName != name:
+ warnings.warn("lxml cannot represent non-xml doctype", DataLossWarning)
+
+ doctype = self.doctypeClass(coercedName, publicId, systemId)
+ self.doctype = doctype
+
+ def insertCommentInitial(self, data, parent=None):
+ self.initial_comments.append(data)
+
+ def insertCommentMain(self, data, parent=None):
+ if (parent == self.document and
+ self.document._elementTree.getroot()[-1].tag == comment_type):
+ warnings.warn("lxml cannot represent adjacent comments beyond the root elements", DataLossWarning)
+ super(TreeBuilder, self).insertComment(data, parent)
+
+ def insertRoot(self, token):
+ """Create the document root"""
+ # Because of the way libxml2 works, it doesn't seem to be possible to
+ # alter information like the doctype after the tree has been parsed.
+ # Therefore we need to use the built-in parser to create our iniial
+ # tree, after which we can add elements like normal
+ docStr = ""
+ if self.doctype:
+ assert self.doctype.name
+ docStr += "<!DOCTYPE %s" % self.doctype.name
+ if (self.doctype.publicId is not None or
+ self.doctype.systemId is not None):
+ docStr += (' PUBLIC "%s" ' %
+ (self.infosetFilter.coercePubid(self.doctype.publicId or "")))
+ if self.doctype.systemId:
+ sysid = self.doctype.systemId
+ if sysid.find("'") >= 0 and sysid.find('"') >= 0:
+ warnings.warn("DOCTYPE system cannot contain single and double quotes", DataLossWarning)
+ sysid = sysid.replace("'", 'U00027')
+ if sysid.find("'") >= 0:
+ docStr += '"%s"' % sysid
+ else:
+ docStr += "'%s'" % sysid
+ else:
+ docStr += "''"
+ docStr += ">"
+ if self.doctype.name != token["name"]:
+ warnings.warn("lxml cannot represent doctype with a different name to the root element", DataLossWarning)
+ docStr += "<THIS_SHOULD_NEVER_APPEAR_PUBLICLY/>"
+ root = etree.fromstring(docStr)
+
+ # Append the initial comments:
+ for comment_token in self.initial_comments:
+ root.addprevious(etree.Comment(comment_token["data"]))
+
+ # Create the root document and add the ElementTree to it
+ self.document = self.documentClass()
+ self.document._elementTree = root.getroottree()
+
+ # Give the root element the right name
+ name = token["name"]
+ namespace = token.get("namespace", self.defaultNamespace)
+ if namespace is None:
+ etree_tag = name
+ else:
+ etree_tag = "{%s}%s" % (namespace, name)
+ root.tag = etree_tag
+
+ # Add the root element to the internal child/open data structures
+ root_element = self.elementClass(name, namespace)
+ root_element._element = root
+ self.document._childNodes.append(root_element)
+ self.openElements.append(root_element)
+
+ # Reset to the default insert comment function
+ self.insertComment = self.insertCommentMain
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py
new file mode 100644
index 00000000000..20b91b114ab
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py
@@ -0,0 +1,147 @@
+"""A collection of modules for iterating through different kinds of
+tree, generating tokens identical to those produced by the tokenizer
+module.
+
+To create a tree walker for a new type of tree, you need to do
+implement a tree walker object (called TreeWalker by convention) that
+implements a 'serialize' method taking a tree as sole argument and
+returning an iterator generating tokens.
+"""
+
+from __future__ import absolute_import, division, unicode_literals
+
+__all__ = ["getTreeWalker", "pprint", "dom", "etree", "genshistream", "lxmletree",
+ "pulldom"]
+
+import sys
+
+from .. import constants
+from ..utils import default_etree
+
+treeWalkerCache = {}
+
+
+def getTreeWalker(treeType, implementation=None, **kwargs):
+ """Get a TreeWalker class for various types of tree with built-in support
+
+ treeType - the name of the tree type required (case-insensitive). Supported
+ values are:
+
+ "dom" - The xml.dom.minidom DOM implementation
+ "pulldom" - The xml.dom.pulldom event stream
+ "etree" - A generic walker for tree implementations exposing an
+ elementtree-like interface (known to work with
+ ElementTree, cElementTree and lxml.etree).
+ "lxml" - Optimized walker for lxml.etree
+ "genshi" - a Genshi stream
+
+ implementation - (Currently applies to the "etree" tree type only). A module
+ implementing the tree type e.g. xml.etree.ElementTree or
+ cElementTree."""
+
+ treeType = treeType.lower()
+ if treeType not in treeWalkerCache:
+ if treeType in ("dom", "pulldom"):
+ name = "%s.%s" % (__name__, treeType)
+ __import__(name)
+ mod = sys.modules[name]
+ treeWalkerCache[treeType] = mod.TreeWalker
+ elif treeType == "genshi":
+ from . import genshistream
+ treeWalkerCache[treeType] = genshistream.TreeWalker
+ elif treeType == "lxml":
+ from . import lxmletree
+ treeWalkerCache[treeType] = lxmletree.TreeWalker
+ elif treeType == "etree":
+ from . import etree
+ if implementation is None:
+ implementation = default_etree
+ # XXX: NEVER cache here, caching is done in the etree submodule
+ return etree.getETreeModule(implementation, **kwargs).TreeWalker
+ return treeWalkerCache.get(treeType)
+
+
+def concatenateCharacterTokens(tokens):
+ pendingCharacters = []
+ for token in tokens:
+ type = token["type"]
+ if type in ("Characters", "SpaceCharacters"):
+ pendingCharacters.append(token["data"])
+ else:
+ if pendingCharacters:
+ yield {"type": "Characters", "data": "".join(pendingCharacters)}
+ pendingCharacters = []
+ yield token
+ if pendingCharacters:
+ yield {"type": "Characters", "data": "".join(pendingCharacters)}
+
+
+def pprint(walker):
+ """Pretty printer for tree walkers"""
+ output = []
+ indent = 0
+ for token in concatenateCharacterTokens(walker):
+ type = token["type"]
+ if type in ("StartTag", "EmptyTag"):
+ # tag name
+ if token["namespace"] and token["namespace"] != constants.namespaces["html"]:
+ if token["namespace"] in constants.prefixes:
+ ns = constants.prefixes[token["namespace"]]
+ else:
+ ns = token["namespace"]
+ name = "%s %s" % (ns, token["name"])
+ else:
+ name = token["name"]
+ output.append("%s<%s>" % (" " * indent, name))
+ indent += 2
+ # attributes (sorted for consistent ordering)
+ attrs = token["data"]
+ for (namespace, localname), value in sorted(attrs.items()):
+ if namespace:
+ if namespace in constants.prefixes:
+ ns = constants.prefixes[namespace]
+ else:
+ ns = namespace
+ name = "%s %s" % (ns, localname)
+ else:
+ name = localname
+ output.append("%s%s=\"%s\"" % (" " * indent, name, value))
+ # self-closing
+ if type == "EmptyTag":
+ indent -= 2
+
+ elif type == "EndTag":
+ indent -= 2
+
+ elif type == "Comment":
+ output.append("%s<!-- %s -->" % (" " * indent, token["data"]))
+
+ elif type == "Doctype":
+ if token["name"]:
+ if token["publicId"]:
+ output.append("""%s<!DOCTYPE %s "%s" "%s">""" %
+ (" " * indent,
+ token["name"],
+ token["publicId"],
+ token["systemId"] if token["systemId"] else ""))
+ elif token["systemId"]:
+ output.append("""%s<!DOCTYPE %s "" "%s">""" %
+ (" " * indent,
+ token["name"],
+ token["systemId"]))
+ else:
+ output.append("%s<!DOCTYPE %s>" % (" " * indent,
+ token["name"]))
+ else:
+ output.append("%s<!DOCTYPE >" % (" " * indent,))
+
+ elif type == "Characters":
+ output.append("%s\"%s\"" % (" " * indent, token["data"]))
+
+ elif type == "SpaceCharacters":
+ assert False, "concatenateCharacterTokens should have got rid of all Space tokens"
+
+ else:
+ raise ValueError("Unknown token type, %s" % type)
+
+ return "\n".join(output)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py
new file mode 100644
index 00000000000..4e11cd02024
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py
@@ -0,0 +1,200 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type, string_types
+
+__all__ = ["DOCUMENT", "DOCTYPE", "TEXT", "ELEMENT", "COMMENT", "ENTITY", "UNKNOWN",
+ "TreeWalker", "NonRecursiveTreeWalker"]
+
+from xml.dom import Node
+
+DOCUMENT = Node.DOCUMENT_NODE
+DOCTYPE = Node.DOCUMENT_TYPE_NODE
+TEXT = Node.TEXT_NODE
+ELEMENT = Node.ELEMENT_NODE
+COMMENT = Node.COMMENT_NODE
+ENTITY = Node.ENTITY_NODE
+UNKNOWN = "<#UNKNOWN#>"
+
+from ..constants import voidElements, spaceCharacters
+spaceCharacters = "".join(spaceCharacters)
+
+
+def to_text(s, blank_if_none=True):
+ """Wrapper around six.text_type to convert None to empty string"""
+ if s is None:
+ if blank_if_none:
+ return ""
+ else:
+ return None
+ elif isinstance(s, text_type):
+ return s
+ else:
+ return text_type(s)
+
+
+def is_text_or_none(string):
+ """Wrapper around isinstance(string_types) or is None"""
+ return string is None or isinstance(string, string_types)
+
+
+class TreeWalker(object):
+ def __init__(self, tree):
+ self.tree = tree
+
+ def __iter__(self):
+ raise NotImplementedError
+
+ def error(self, msg):
+ return {"type": "SerializeError", "data": msg}
+
+ def emptyTag(self, namespace, name, attrs, hasChildren=False):
+ assert namespace is None or isinstance(namespace, string_types), type(namespace)
+ assert isinstance(name, string_types), type(name)
+ assert all((namespace is None or isinstance(namespace, string_types)) and
+ isinstance(name, string_types) and
+ isinstance(value, string_types)
+ for (namespace, name), value in attrs.items())
+
+ yield {"type": "EmptyTag", "name": to_text(name, False),
+ "namespace": to_text(namespace),
+ "data": attrs}
+ if hasChildren:
+ yield self.error("Void element has children")
+
+ def startTag(self, namespace, name, attrs):
+ assert namespace is None or isinstance(namespace, string_types), type(namespace)
+ assert isinstance(name, string_types), type(name)
+ assert all((namespace is None or isinstance(namespace, string_types)) and
+ isinstance(name, string_types) and
+ isinstance(value, string_types)
+ for (namespace, name), value in attrs.items())
+
+ return {"type": "StartTag",
+ "name": text_type(name),
+ "namespace": to_text(namespace),
+ "data": dict(((to_text(namespace, False), to_text(name)),
+ to_text(value, False))
+ for (namespace, name), value in attrs.items())}
+
+ def endTag(self, namespace, name):
+ assert namespace is None or isinstance(namespace, string_types), type(namespace)
+ assert isinstance(name, string_types), type(namespace)
+
+ return {"type": "EndTag",
+ "name": to_text(name, False),
+ "namespace": to_text(namespace),
+ "data": {}}
+
+ def text(self, data):
+ assert isinstance(data, string_types), type(data)
+
+ data = to_text(data)
+ middle = data.lstrip(spaceCharacters)
+ left = data[:len(data) - len(middle)]
+ if left:
+ yield {"type": "SpaceCharacters", "data": left}
+ data = middle
+ middle = data.rstrip(spaceCharacters)
+ right = data[len(middle):]
+ if middle:
+ yield {"type": "Characters", "data": middle}
+ if right:
+ yield {"type": "SpaceCharacters", "data": right}
+
+ def comment(self, data):
+ assert isinstance(data, string_types), type(data)
+
+ return {"type": "Comment", "data": text_type(data)}
+
+ def doctype(self, name, publicId=None, systemId=None, correct=True):
+ assert is_text_or_none(name), type(name)
+ assert is_text_or_none(publicId), type(publicId)
+ assert is_text_or_none(systemId), type(systemId)
+
+ return {"type": "Doctype",
+ "name": to_text(name),
+ "publicId": to_text(publicId),
+ "systemId": to_text(systemId),
+ "correct": to_text(correct)}
+
+ def entity(self, name):
+ assert isinstance(name, string_types), type(name)
+
+ return {"type": "Entity", "name": text_type(name)}
+
+ def unknown(self, nodeType):
+ return self.error("Unknown node type: " + nodeType)
+
+
+class NonRecursiveTreeWalker(TreeWalker):
+ def getNodeDetails(self, node):
+ raise NotImplementedError
+
+ def getFirstChild(self, node):
+ raise NotImplementedError
+
+ def getNextSibling(self, node):
+ raise NotImplementedError
+
+ def getParentNode(self, node):
+ raise NotImplementedError
+
+ def __iter__(self):
+ currentNode = self.tree
+ while currentNode is not None:
+ details = self.getNodeDetails(currentNode)
+ type, details = details[0], details[1:]
+ hasChildren = False
+
+ if type == DOCTYPE:
+ yield self.doctype(*details)
+
+ elif type == TEXT:
+ for token in self.text(*details):
+ yield token
+
+ elif type == ELEMENT:
+ namespace, name, attributes, hasChildren = details
+ if name in voidElements:
+ for token in self.emptyTag(namespace, name, attributes,
+ hasChildren):
+ yield token
+ hasChildren = False
+ else:
+ yield self.startTag(namespace, name, attributes)
+
+ elif type == COMMENT:
+ yield self.comment(details[0])
+
+ elif type == ENTITY:
+ yield self.entity(details[0])
+
+ elif type == DOCUMENT:
+ hasChildren = True
+
+ else:
+ yield self.unknown(details[0])
+
+ if hasChildren:
+ firstChild = self.getFirstChild(currentNode)
+ else:
+ firstChild = None
+
+ if firstChild is not None:
+ currentNode = firstChild
+ else:
+ while currentNode is not None:
+ details = self.getNodeDetails(currentNode)
+ type, details = details[0], details[1:]
+ if type == ELEMENT:
+ namespace, name, attributes, hasChildren = details
+ if name not in voidElements:
+ yield self.endTag(namespace, name)
+ if self.tree is currentNode:
+ currentNode = None
+ break
+ nextSibling = self.getNextSibling(currentNode)
+ if nextSibling is not None:
+ currentNode = nextSibling
+ break
+ else:
+ currentNode = self.getParentNode(currentNode)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py
new file mode 100644
index 00000000000..ac4dcf31bf6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py
@@ -0,0 +1,43 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from xml.dom import Node
+
+from . import _base
+
+
+class TreeWalker(_base.NonRecursiveTreeWalker):
+ def getNodeDetails(self, node):
+ if node.nodeType == Node.DOCUMENT_TYPE_NODE:
+ return _base.DOCTYPE, node.name, node.publicId, node.systemId
+
+ elif node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
+ return _base.TEXT, node.nodeValue
+
+ elif node.nodeType == Node.ELEMENT_NODE:
+ attrs = {}
+ for attr in list(node.attributes.keys()):
+ attr = node.getAttributeNode(attr)
+ if attr.namespaceURI:
+ attrs[(attr.namespaceURI, attr.localName)] = attr.value
+ else:
+ attrs[(None, attr.name)] = attr.value
+ return (_base.ELEMENT, node.namespaceURI, node.nodeName,
+ attrs, node.hasChildNodes())
+
+ elif node.nodeType == Node.COMMENT_NODE:
+ return _base.COMMENT, node.nodeValue
+
+ elif node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE):
+ return (_base.DOCUMENT,)
+
+ else:
+ return _base.UNKNOWN, node.nodeType
+
+ def getFirstChild(self, node):
+ return node.firstChild
+
+ def getNextSibling(self, node):
+ return node.nextSibling
+
+ def getParentNode(self, node):
+ return node.parentNode
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py
new file mode 100644
index 00000000000..69840c21e48
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py
@@ -0,0 +1,136 @@
+from __future__ import absolute_import, division, unicode_literals
+
+try:
+ from collections import OrderedDict
+except ImportError:
+ try:
+ from ordereddict import OrderedDict
+ except ImportError:
+ OrderedDict = dict
+
+import re
+
+from six import string_types
+
+from . import _base
+from ..utils import moduleFactoryFactory
+
+tag_regexp = re.compile("{([^}]*)}(.*)")
+
+
+def getETreeBuilder(ElementTreeImplementation):
+ ElementTree = ElementTreeImplementation
+ ElementTreeCommentType = ElementTree.Comment("asd").tag
+
+ class TreeWalker(_base.NonRecursiveTreeWalker):
+ """Given the particular ElementTree representation, this implementation,
+ to avoid using recursion, returns "nodes" as tuples with the following
+ content:
+
+ 1. The current element
+
+ 2. The index of the element relative to its parent
+
+ 3. A stack of ancestor elements
+
+ 4. A flag "text", "tail" or None to indicate if the current node is a
+ text node; either the text or tail of the current element (1)
+ """
+ def getNodeDetails(self, node):
+ if isinstance(node, tuple): # It might be the root Element
+ elt, key, parents, flag = node
+ if flag in ("text", "tail"):
+ return _base.TEXT, getattr(elt, flag)
+ else:
+ node = elt
+
+ if not(hasattr(node, "tag")):
+ node = node.getroot()
+
+ if node.tag in ("DOCUMENT_ROOT", "DOCUMENT_FRAGMENT"):
+ return (_base.DOCUMENT,)
+
+ elif node.tag == "<!DOCTYPE>":
+ return (_base.DOCTYPE, node.text,
+ node.get("publicId"), node.get("systemId"))
+
+ elif node.tag == ElementTreeCommentType:
+ return _base.COMMENT, node.text
+
+ else:
+ assert isinstance(node.tag, string_types), type(node.tag)
+ # This is assumed to be an ordinary element
+ match = tag_regexp.match(node.tag)
+ if match:
+ namespace, tag = match.groups()
+ else:
+ namespace = None
+ tag = node.tag
+ attrs = OrderedDict()
+ for name, value in list(node.attrib.items()):
+ match = tag_regexp.match(name)
+ if match:
+ attrs[(match.group(1), match.group(2))] = value
+ else:
+ attrs[(None, name)] = value
+ return (_base.ELEMENT, namespace, tag,
+ attrs, len(node) or node.text)
+
+ def getFirstChild(self, node):
+ if isinstance(node, tuple):
+ element, key, parents, flag = node
+ else:
+ element, key, parents, flag = node, None, [], None
+
+ if flag in ("text", "tail"):
+ return None
+ else:
+ if element.text:
+ return element, key, parents, "text"
+ elif len(element):
+ parents.append(element)
+ return element[0], 0, parents, None
+ else:
+ return None
+
+ def getNextSibling(self, node):
+ if isinstance(node, tuple):
+ element, key, parents, flag = node
+ else:
+ return None
+
+ if flag == "text":
+ if len(element):
+ parents.append(element)
+ return element[0], 0, parents, None
+ else:
+ return None
+ else:
+ if element.tail and flag != "tail":
+ return element, key, parents, "tail"
+ elif key < len(parents[-1]) - 1:
+ return parents[-1][key + 1], key + 1, parents, None
+ else:
+ return None
+
+ def getParentNode(self, node):
+ if isinstance(node, tuple):
+ element, key, parents, flag = node
+ else:
+ return None
+
+ if flag == "text":
+ if not parents:
+ return element
+ else:
+ return element, key, parents, None
+ else:
+ parent = parents.pop()
+ if not parents:
+ return parent
+ else:
+ return parent, list(parents[-1]).index(parent), parents, None
+
+ return locals()
+
+getETreeModule = moduleFactoryFactory(getETreeBuilder)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py
new file mode 100644
index 00000000000..f559c45d044
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py
@@ -0,0 +1,69 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from genshi.core import QName
+from genshi.core import START, END, XML_NAMESPACE, DOCTYPE, TEXT
+from genshi.core import START_NS, END_NS, START_CDATA, END_CDATA, PI, COMMENT
+
+from . import _base
+
+from ..constants import voidElements, namespaces
+
+
+class TreeWalker(_base.TreeWalker):
+ def __iter__(self):
+ # Buffer the events so we can pass in the following one
+ previous = None
+ for event in self.tree:
+ if previous is not None:
+ for token in self.tokens(previous, event):
+ yield token
+ previous = event
+
+ # Don't forget the final event!
+ if previous is not None:
+ for token in self.tokens(previous, None):
+ yield token
+
+ def tokens(self, event, next):
+ kind, data, pos = event
+ if kind == START:
+ tag, attribs = data
+ name = tag.localname
+ namespace = tag.namespace
+ converted_attribs = {}
+ for k, v in attribs:
+ if isinstance(k, QName):
+ converted_attribs[(k.namespace, k.localname)] = v
+ else:
+ converted_attribs[(None, k)] = v
+
+ if namespace == namespaces["html"] and name in voidElements:
+ for token in self.emptyTag(namespace, name, converted_attribs,
+ not next or next[0] != END
+ or next[1] != tag):
+ yield token
+ else:
+ yield self.startTag(namespace, name, converted_attribs)
+
+ elif kind == END:
+ name = data.localname
+ namespace = data.namespace
+ if name not in voidElements:
+ yield self.endTag(namespace, name)
+
+ elif kind == COMMENT:
+ yield self.comment(data)
+
+ elif kind == TEXT:
+ for token in self.text(data):
+ yield token
+
+ elif kind == DOCTYPE:
+ yield self.doctype(*data)
+
+ elif kind in (XML_NAMESPACE, DOCTYPE, START_NS, END_NS,
+ START_CDATA, END_CDATA, PI):
+ pass
+
+ else:
+ yield self.unknown(kind)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py
new file mode 100644
index 00000000000..90e116d3866
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py
@@ -0,0 +1,201 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+
+from lxml import etree
+from ..treebuilders.etree import tag_regexp
+
+from . import _base
+
+from .. import ihatexml
+
+
+def ensure_str(s):
+ if s is None:
+ return None
+ elif isinstance(s, text_type):
+ return s
+ else:
+ return s.decode("utf-8", "strict")
+
+
+class Root(object):
+ def __init__(self, et):
+ self.elementtree = et
+ self.children = []
+ if et.docinfo.internalDTD:
+ self.children.append(Doctype(self,
+ ensure_str(et.docinfo.root_name),
+ ensure_str(et.docinfo.public_id),
+ ensure_str(et.docinfo.system_url)))
+ root = et.getroot()
+ node = root
+
+ while node.getprevious() is not None:
+ node = node.getprevious()
+ while node is not None:
+ self.children.append(node)
+ node = node.getnext()
+
+ self.text = None
+ self.tail = None
+
+ def __getitem__(self, key):
+ return self.children[key]
+
+ def getnext(self):
+ return None
+
+ def __len__(self):
+ return 1
+
+
+class Doctype(object):
+ def __init__(self, root_node, name, public_id, system_id):
+ self.root_node = root_node
+ self.name = name
+ self.public_id = public_id
+ self.system_id = system_id
+
+ self.text = None
+ self.tail = None
+
+ def getnext(self):
+ return self.root_node.children[1]
+
+
+class FragmentRoot(Root):
+ def __init__(self, children):
+ self.children = [FragmentWrapper(self, child) for child in children]
+ self.text = self.tail = None
+
+ def getnext(self):
+ return None
+
+
+class FragmentWrapper(object):
+ def __init__(self, fragment_root, obj):
+ self.root_node = fragment_root
+ self.obj = obj
+ if hasattr(self.obj, 'text'):
+ self.text = ensure_str(self.obj.text)
+ else:
+ self.text = None
+ if hasattr(self.obj, 'tail'):
+ self.tail = ensure_str(self.obj.tail)
+ else:
+ self.tail = None
+
+ def __getattr__(self, name):
+ return getattr(self.obj, name)
+
+ def getnext(self):
+ siblings = self.root_node.children
+ idx = siblings.index(self)
+ if idx < len(siblings) - 1:
+ return siblings[idx + 1]
+ else:
+ return None
+
+ def __getitem__(self, key):
+ return self.obj[key]
+
+ def __bool__(self):
+ return bool(self.obj)
+
+ def getparent(self):
+ return None
+
+ def __str__(self):
+ return str(self.obj)
+
+ def __unicode__(self):
+ return str(self.obj)
+
+ def __len__(self):
+ return len(self.obj)
+
+
+class TreeWalker(_base.NonRecursiveTreeWalker):
+ def __init__(self, tree):
+ if hasattr(tree, "getroot"):
+ tree = Root(tree)
+ elif isinstance(tree, list):
+ tree = FragmentRoot(tree)
+ _base.NonRecursiveTreeWalker.__init__(self, tree)
+ self.filter = ihatexml.InfosetFilter()
+
+ def getNodeDetails(self, node):
+ if isinstance(node, tuple): # Text node
+ node, key = node
+ assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key
+ return _base.TEXT, ensure_str(getattr(node, key))
+
+ elif isinstance(node, Root):
+ return (_base.DOCUMENT,)
+
+ elif isinstance(node, Doctype):
+ return _base.DOCTYPE, node.name, node.public_id, node.system_id
+
+ elif isinstance(node, FragmentWrapper) and not hasattr(node, "tag"):
+ return _base.TEXT, node.obj
+
+ elif node.tag == etree.Comment:
+ return _base.COMMENT, ensure_str(node.text)
+
+ elif node.tag == etree.Entity:
+ return _base.ENTITY, ensure_str(node.text)[1:-1] # strip &;
+
+ else:
+ # This is assumed to be an ordinary element
+ match = tag_regexp.match(ensure_str(node.tag))
+ if match:
+ namespace, tag = match.groups()
+ else:
+ namespace = None
+ tag = ensure_str(node.tag)
+ attrs = {}
+ for name, value in list(node.attrib.items()):
+ name = ensure_str(name)
+ value = ensure_str(value)
+ match = tag_regexp.match(name)
+ if match:
+ attrs[(match.group(1), match.group(2))] = value
+ else:
+ attrs[(None, name)] = value
+ return (_base.ELEMENT, namespace, self.filter.fromXmlName(tag),
+ attrs, len(node) > 0 or node.text)
+
+ def getFirstChild(self, node):
+ assert not isinstance(node, tuple), "Text nodes have no children"
+
+ assert len(node) or node.text, "Node has no children"
+ if node.text:
+ return (node, "text")
+ else:
+ return node[0]
+
+ def getNextSibling(self, node):
+ if isinstance(node, tuple): # Text node
+ node, key = node
+ assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key
+ if key == "text":
+ # XXX: we cannot use a "bool(node) and node[0] or None" construct here
+ # because node[0] might evaluate to False if it has no child element
+ if len(node):
+ return node[0]
+ else:
+ return None
+ else: # tail
+ return node.getnext()
+
+ return (node, "tail") if node.tail else node.getnext()
+
+ def getParentNode(self, node):
+ if isinstance(node, tuple): # Text node
+ node, key = node
+ assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key
+ if key == "text":
+ return node
+ # else: fallback to "normal" processing
+
+ return node.getparent()
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py
new file mode 100644
index 00000000000..0b0f515fec7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py
@@ -0,0 +1,63 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from xml.dom.pulldom import START_ELEMENT, END_ELEMENT, \
+ COMMENT, IGNORABLE_WHITESPACE, CHARACTERS
+
+from . import _base
+
+from ..constants import voidElements
+
+
+class TreeWalker(_base.TreeWalker):
+ def __iter__(self):
+ ignore_until = None
+ previous = None
+ for event in self.tree:
+ if previous is not None and \
+ (ignore_until is None or previous[1] is ignore_until):
+ if previous[1] is ignore_until:
+ ignore_until = None
+ for token in self.tokens(previous, event):
+ yield token
+ if token["type"] == "EmptyTag":
+ ignore_until = previous[1]
+ previous = event
+ if ignore_until is None or previous[1] is ignore_until:
+ for token in self.tokens(previous, None):
+ yield token
+ elif ignore_until is not None:
+ raise ValueError("Illformed DOM event stream: void element without END_ELEMENT")
+
+ def tokens(self, event, next):
+ type, node = event
+ if type == START_ELEMENT:
+ name = node.nodeName
+ namespace = node.namespaceURI
+ attrs = {}
+ for attr in list(node.attributes.keys()):
+ attr = node.getAttributeNode(attr)
+ attrs[(attr.namespaceURI, attr.localName)] = attr.value
+ if name in voidElements:
+ for token in self.emptyTag(namespace,
+ name,
+ attrs,
+ not next or next[1] is not node):
+ yield token
+ else:
+ yield self.startTag(namespace, name, attrs)
+
+ elif type == END_ELEMENT:
+ name = node.nodeName
+ namespace = node.namespaceURI
+ if name not in voidElements:
+ yield self.endTag(namespace, name)
+
+ elif type == COMMENT:
+ yield self.comment(node.nodeValue)
+
+ elif type in (IGNORABLE_WHITESPACE, CHARACTERS):
+ for token in self.text(node.nodeValue):
+ yield token
+
+ else:
+ yield self.unknown(type)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/__init__.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/__init__.py
new file mode 100644
index 00000000000..a8cca8a9acf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/__init__.py
@@ -0,0 +1,12 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from .py import Trie as PyTrie
+
+Trie = PyTrie
+
+try:
+ from .datrie import Trie as DATrie
+except ImportError:
+ pass
+else:
+ Trie = DATrie
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/_base.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/_base.py
new file mode 100644
index 00000000000..724486b16eb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/_base.py
@@ -0,0 +1,37 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from collections import Mapping
+
+
+class Trie(Mapping):
+ """Abstract base class for tries"""
+
+ def keys(self, prefix=None):
+ keys = super().keys()
+
+ if prefix is None:
+ return set(keys)
+
+ # Python 2.6: no set comprehensions
+ return set([x for x in keys if x.startswith(prefix)])
+
+ def has_keys_with_prefix(self, prefix):
+ for key in self.keys():
+ if key.startswith(prefix):
+ return True
+
+ return False
+
+ def longest_prefix(self, prefix):
+ if prefix in self:
+ return prefix
+
+ for i in range(1, len(prefix) + 1):
+ if prefix[:-i] in self:
+ return prefix[:-i]
+
+ raise KeyError(prefix)
+
+ def longest_prefix_item(self, prefix):
+ lprefix = self.longest_prefix(prefix)
+ return (lprefix, self[lprefix])
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/datrie.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/datrie.py
new file mode 100644
index 00000000000..51f3d046a74
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/datrie.py
@@ -0,0 +1,44 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from datrie import Trie as DATrie
+from six import text_type
+
+from ._base import Trie as ABCTrie
+
+
+class Trie(ABCTrie):
+ def __init__(self, data):
+ chars = set()
+ for key in data.keys():
+ if not isinstance(key, text_type):
+ raise TypeError("All keys must be strings")
+ for char in key:
+ chars.add(char)
+
+ self._data = DATrie("".join(chars))
+ for key, value in data.items():
+ self._data[key] = value
+
+ def __contains__(self, key):
+ return key in self._data
+
+ def __len__(self):
+ return len(self._data)
+
+ def __iter__(self):
+ raise NotImplementedError()
+
+ def __getitem__(self, key):
+ return self._data[key]
+
+ def keys(self, prefix=None):
+ return self._data.keys(prefix)
+
+ def has_keys_with_prefix(self, prefix):
+ return self._data.has_keys_with_prefix(prefix)
+
+ def longest_prefix(self, prefix):
+ return self._data.longest_prefix(prefix)
+
+ def longest_prefix_item(self, prefix):
+ return self._data.longest_prefix_item(prefix)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/py.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/py.py
new file mode 100644
index 00000000000..c2ba3da7576
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/trie/py.py
@@ -0,0 +1,67 @@
+from __future__ import absolute_import, division, unicode_literals
+from six import text_type
+
+from bisect import bisect_left
+
+from ._base import Trie as ABCTrie
+
+
+class Trie(ABCTrie):
+ def __init__(self, data):
+ if not all(isinstance(x, text_type) for x in data.keys()):
+ raise TypeError("All keys must be strings")
+
+ self._data = data
+ self._keys = sorted(data.keys())
+ self._cachestr = ""
+ self._cachepoints = (0, len(data))
+
+ def __contains__(self, key):
+ return key in self._data
+
+ def __len__(self):
+ return len(self._data)
+
+ def __iter__(self):
+ return iter(self._data)
+
+ def __getitem__(self, key):
+ return self._data[key]
+
+ def keys(self, prefix=None):
+ if prefix is None or prefix == "" or not self._keys:
+ return set(self._keys)
+
+ if prefix.startswith(self._cachestr):
+ lo, hi = self._cachepoints
+ start = i = bisect_left(self._keys, prefix, lo, hi)
+ else:
+ start = i = bisect_left(self._keys, prefix)
+
+ keys = set()
+ if start == len(self._keys):
+ return keys
+
+ while self._keys[i].startswith(prefix):
+ keys.add(self._keys[i])
+ i += 1
+
+ self._cachestr = prefix
+ self._cachepoints = (start, i)
+
+ return keys
+
+ def has_keys_with_prefix(self, prefix):
+ if prefix in self._data:
+ return True
+
+ if prefix.startswith(self._cachestr):
+ lo, hi = self._cachepoints
+ i = bisect_left(self._keys, prefix, lo, hi)
+ else:
+ i = bisect_left(self._keys, prefix)
+
+ if i == len(self._keys):
+ return False
+
+ return self._keys[i].startswith(prefix)
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/html5lib/utils.py b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/utils.py
new file mode 100644
index 00000000000..fdc18febb53
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/html5lib/utils.py
@@ -0,0 +1,103 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from types import ModuleType
+
+from six import text_type
+
+try:
+ import xml.etree.cElementTree as default_etree
+except ImportError:
+ import xml.etree.ElementTree as default_etree
+
+
+__all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair",
+ "surrogatePairToCodepoint", "moduleFactoryFactory",
+ "supports_lone_surrogates"]
+
+
+# Platforms not supporting lone surrogates (\uD800-\uDFFF) should be
+# caught by the below test. In general this would be any platform
+# using UTF-16 as its encoding of unicode strings, such as
+# Jython. This is because UTF-16 itself is based on the use of such
+# surrogates, and there is no mechanism to further escape such
+# escapes.
+try:
+ _x = eval('"\\uD800"')
+ if not isinstance(_x, text_type):
+ # We need this with u"" because of http://bugs.jython.org/issue2039
+ _x = eval('u"\\uD800"')
+ assert isinstance(_x, text_type)
+except:
+ supports_lone_surrogates = False
+else:
+ supports_lone_surrogates = True
+
+
+class MethodDispatcher(dict):
+ """Dict with 2 special properties:
+
+ On initiation, keys that are lists, sets or tuples are converted to
+ multiple keys so accessing any one of the items in the original
+ list-like object returns the matching value
+
+ md = MethodDispatcher({("foo", "bar"):"baz"})
+ md["foo"] == "baz"
+
+ A default value which can be set through the default attribute.
+ """
+
+ def __init__(self, items=()):
+ # Using _dictEntries instead of directly assigning to self is about
+ # twice as fast. Please do careful performance testing before changing
+ # anything here.
+ _dictEntries = []
+ for name, value in items:
+ if type(name) in (list, tuple, frozenset, set):
+ for item in name:
+ _dictEntries.append((item, value))
+ else:
+ _dictEntries.append((name, value))
+ dict.__init__(self, _dictEntries)
+ self.default = None
+
+ def __getitem__(self, key):
+ return dict.get(self, key, self.default)
+
+
+# Some utility functions to dal with weirdness around UCS2 vs UCS4
+# python builds
+
+def isSurrogatePair(data):
+ return (len(data) == 2 and
+ ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and
+ ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF)
+
+
+def surrogatePairToCodepoint(data):
+ char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 +
+ (ord(data[1]) - 0xDC00))
+ return char_val
+
+# Module Factory Factory (no, this isn't Java, I know)
+# Here to stop this being duplicated all over the place.
+
+
+def moduleFactoryFactory(factory):
+ moduleCache = {}
+
+ def moduleFactory(baseModule, *args, **kwargs):
+ if isinstance(ModuleType.__name__, type("")):
+ name = "_%s_factory" % baseModule.__name__
+ else:
+ name = b"_%s_factory" % baseModule.__name__
+
+ if name in moduleCache:
+ return moduleCache[name]
+ else:
+ mod = ModuleType(name)
+ objs = factory(baseModule, *args, **kwargs)
+ mod.__dict__.update(objs)
+ moduleCache[name] = mod
+ return mod
+
+ return moduleFactory
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/parse.py b/chromium/third_party/catapult/third_party/html5lib-python/parse.py
new file mode 100755
index 00000000000..b9bea288ea9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/parse.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+"""usage: %prog [options] filename
+
+Parse a document to a tree, with optional profiling
+"""
+
+import sys
+import os
+import traceback
+from optparse import OptionParser
+
+from html5lib import html5parser, sanitizer
+from html5lib.tokenizer import HTMLTokenizer
+from html5lib import treebuilders, serializer, treewalkers
+from html5lib import constants
+from html5lib import utils
+
+def parse():
+ optParser = getOptParser()
+ opts,args = optParser.parse_args()
+ encoding = "utf8"
+
+ try:
+ f = args[-1]
+ # Try opening from the internet
+ if f.startswith('http://'):
+ try:
+ import urllib.request, urllib.parse, urllib.error, cgi
+ f = urllib.request.urlopen(f)
+ contentType = f.headers.get('content-type')
+ if contentType:
+ (mediaType, params) = cgi.parse_header(contentType)
+ encoding = params.get('charset')
+ except:
+ pass
+ elif f == '-':
+ f = sys.stdin
+ if sys.version_info[0] >= 3:
+ encoding = None
+ else:
+ try:
+ # Try opening from file system
+ f = open(f, "rb")
+ except IOError as e:
+ sys.stderr.write("Unable to open file: %s\n" % e)
+ sys.exit(1)
+ except IndexError:
+ sys.stderr.write("No filename provided. Use -h for help\n")
+ sys.exit(1)
+
+ treebuilder = treebuilders.getTreeBuilder(opts.treebuilder)
+
+ if opts.sanitize:
+ tokenizer = sanitizer.HTMLSanitizer
+ else:
+ tokenizer = HTMLTokenizer
+
+ p = html5parser.HTMLParser(tree=treebuilder, tokenizer=tokenizer, debug=opts.log)
+
+ if opts.fragment:
+ parseMethod = p.parseFragment
+ else:
+ parseMethod = p.parse
+
+ if opts.profile:
+ import cProfile
+ import pstats
+ cProfile.runctx("run(parseMethod, f, encoding)", None,
+ {"run": run,
+ "parseMethod": parseMethod,
+ "f": f,
+ "encoding": encoding},
+ "stats.prof")
+ # XXX - We should use a temp file here
+ stats = pstats.Stats('stats.prof')
+ stats.strip_dirs()
+ stats.sort_stats('time')
+ stats.print_stats()
+ elif opts.time:
+ import time
+ t0 = time.time()
+ document = run(parseMethod, f, encoding)
+ t1 = time.time()
+ if document:
+ printOutput(p, document, opts)
+ t2 = time.time()
+ sys.stderr.write("\n\nRun took: %fs (plus %fs to print the output)"%(t1-t0, t2-t1))
+ else:
+ sys.stderr.write("\n\nRun took: %fs"%(t1-t0))
+ else:
+ document = run(parseMethod, f, encoding)
+ if document:
+ printOutput(p, document, opts)
+
+def run(parseMethod, f, encoding):
+ try:
+ document = parseMethod(f, encoding=encoding)
+ except:
+ document = None
+ traceback.print_exc()
+ return document
+
+def printOutput(parser, document, opts):
+ if opts.encoding:
+ print("Encoding:", parser.tokenizer.stream.charEncoding)
+
+ for item in parser.log:
+ print(item)
+
+ if document is not None:
+ if opts.xml:
+ tb = opts.treebuilder.lower()
+ if tb == "dom":
+ document.writexml(sys.stdout, encoding="utf-8")
+ elif tb == "lxml":
+ import lxml.etree
+ sys.stdout.write(lxml.etree.tostring(document))
+ elif tb == "etree":
+ sys.stdout.write(utils.default_etree.tostring(document))
+ elif opts.tree:
+ if not hasattr(document,'__getitem__'):
+ document = [document]
+ for fragment in document:
+ print(parser.tree.testSerializer(fragment))
+ elif opts.hilite:
+ sys.stdout.write(document.hilite("utf-8"))
+ elif opts.html:
+ kwargs = {}
+ for opt in serializer.HTMLSerializer.options:
+ try:
+ kwargs[opt] = getattr(opts,opt)
+ except:
+ pass
+ if not kwargs['quote_char']:
+ del kwargs['quote_char']
+
+ tokens = treewalkers.getTreeWalker(opts.treebuilder)(document)
+ if sys.version_info[0] >= 3:
+ encoding = None
+ else:
+ encoding = "utf-8"
+ for text in serializer.HTMLSerializer(**kwargs).serialize(tokens, encoding=encoding):
+ sys.stdout.write(text)
+ if not text.endswith('\n'): sys.stdout.write('\n')
+ if opts.error:
+ errList=[]
+ for pos, errorcode, datavars in parser.errors:
+ errList.append("Line %i Col %i"%pos + " " + constants.E.get(errorcode, 'Unknown error "%s"' % errorcode) % datavars)
+ sys.stdout.write("\nParse errors:\n" + "\n".join(errList)+"\n")
+
+def getOptParser():
+ parser = OptionParser(usage=__doc__)
+
+ parser.add_option("-p", "--profile", action="store_true", default=False,
+ dest="profile", help="Use the hotshot profiler to "
+ "produce a detailed log of the run")
+
+ parser.add_option("-t", "--time",
+ action="store_true", default=False, dest="time",
+ help="Time the run using time.time (may not be accurate on all platforms, especially for short runs)")
+
+ parser.add_option("-b", "--treebuilder", action="store", type="string",
+ dest="treebuilder", default="etree")
+
+ parser.add_option("-e", "--error", action="store_true", default=False,
+ dest="error", help="Print a list of parse errors")
+
+ parser.add_option("-f", "--fragment", action="store_true", default=False,
+ dest="fragment", help="Parse as a fragment")
+
+ parser.add_option("", "--tree", action="store_true", default=False,
+ dest="tree", help="Output as debug tree")
+
+ parser.add_option("-x", "--xml", action="store_true", default=False,
+ dest="xml", help="Output as xml")
+
+ parser.add_option("", "--no-html", action="store_false", default=True,
+ dest="html", help="Don't output html")
+
+ parser.add_option("", "--hilite", action="store_true", default=False,
+ dest="hilite", help="Output as formatted highlighted code.")
+
+ parser.add_option("-c", "--encoding", action="store_true", default=False,
+ dest="encoding", help="Print character encoding used")
+
+ parser.add_option("", "--inject-meta-charset", action="store_true",
+ default=False, dest="inject_meta_charset",
+ help="inject <meta charset>")
+
+ parser.add_option("", "--strip-whitespace", action="store_true",
+ default=False, dest="strip_whitespace",
+ help="strip whitespace")
+
+ parser.add_option("", "--omit-optional-tags", action="store_true",
+ default=False, dest="omit_optional_tags",
+ help="omit optional tags")
+
+ parser.add_option("", "--quote-attr-values", action="store_true",
+ default=False, dest="quote_attr_values",
+ help="quote attribute values")
+
+ parser.add_option("", "--use-best-quote-char", action="store_true",
+ default=False, dest="use_best_quote_char",
+ help="use best quote character")
+
+ parser.add_option("", "--quote-char", action="store",
+ default=None, dest="quote_char",
+ help="quote character")
+
+ parser.add_option("", "--no-minimize-boolean-attributes",
+ action="store_false", default=True,
+ dest="minimize_boolean_attributes",
+ help="minimize boolean attributes")
+
+ parser.add_option("", "--use-trailing-solidus", action="store_true",
+ default=False, dest="use_trailing_solidus",
+ help="use trailing solidus")
+
+ parser.add_option("", "--space-before-trailing-solidus",
+ action="store_true", default=False,
+ dest="space_before_trailing_solidus",
+ help="add space before trailing solidus")
+
+ parser.add_option("", "--escape-lt-in-attrs", action="store_true",
+ default=False, dest="escape_lt_in_attrs",
+ help="escape less than signs in attribute values")
+
+ parser.add_option("", "--escape-rcdata", action="store_true",
+ default=False, dest="escape_rcdata",
+ help="escape rcdata element values")
+
+ parser.add_option("", "--sanitize", action="store_true", default=False,
+ dest="sanitize", help="sanitize")
+
+ parser.add_option("-l", "--log", action="store_true", default=False,
+ dest="log", help="log state transitions")
+
+ return parser
+
+if __name__ == "__main__":
+ parse()
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements-install.sh b/chromium/third_party/catapult/third_party/html5lib-python/requirements-install.sh
new file mode 100755
index 00000000000..5f8ba50645f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements-install.sh
@@ -0,0 +1,16 @@
+#!/bin/bash -e
+
+if [[ $USE_OPTIONAL != "true" && $USE_OPTIONAL != "false" ]]; then
+ echo "fatal: \$USE_OPTIONAL not set to true or false. Exiting."
+ exit 1
+fi
+
+pip install -r requirements-test.txt
+
+if [[ $USE_OPTIONAL == "true" && $TRAVIS_PYTHON_VERSION != "pypy" ]]; then
+ if [[ $TRAVIS_PYTHON_VERSION == "2.6" ]]; then
+ pip install --allow-external Genshi --allow-insecure Genshi -r requirements-optional-2.6.txt
+ else
+ pip install --allow-external Genshi --allow-insecure Genshi -r requirements-optional-cpython.txt
+ fi
+fi
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-2.6.txt b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-2.6.txt
new file mode 100644
index 00000000000..37557ac403d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-2.6.txt
@@ -0,0 +1,5 @@
+-r requirements-optional-cpython.txt
+
+# Can be used to force attributes to be serialized in alphabetical
+# order.
+ordereddict
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-cpython.txt b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-cpython.txt
new file mode 100644
index 00000000000..35ed3529c2c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional-cpython.txt
@@ -0,0 +1,5 @@
+-r requirements-optional.txt
+
+# lxml is supported with its own treebuilder ("lxml") and otherwise
+# uses the standard ElementTree support
+lxml
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional.txt b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional.txt
new file mode 100644
index 00000000000..c6355270127
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements-optional.txt
@@ -0,0 +1,13 @@
+-r requirements.txt
+
+# We support a Genshi treewalker that can be used to serialize Genshi
+# streams.
+genshi
+
+# DATrie can be used in place of our Python trie implementation for
+# slightly better parsing performance.
+datrie
+
+# charade can be used as a fallback in case we are unable to determine
+# the encoding of a document.
+charade
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements-test.txt b/chromium/third_party/catapult/third_party/html5lib-python/requirements-test.txt
new file mode 100644
index 00000000000..d5f8088c1c1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements-test.txt
@@ -0,0 +1,5 @@
+-r requirements.txt
+
+flake8
+nose
+ordereddict # Python 2.6
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/requirements.txt b/chromium/third_party/catapult/third_party/html5lib-python/requirements.txt
new file mode 100644
index 00000000000..ffe2fce4989
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/requirements.txt
@@ -0,0 +1 @@
+six
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/setup.py b/chromium/third_party/catapult/third_party/html5lib-python/setup.py
new file mode 100644
index 00000000000..34474724ff9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/setup.py
@@ -0,0 +1,58 @@
+from distutils.core import setup
+import ast
+import os
+import codecs
+
+classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: Text Processing :: Markup :: HTML'
+ ]
+
+packages = ['html5lib'] + ['html5lib.'+name
+ for name in os.listdir(os.path.join('html5lib'))
+ if os.path.isdir(os.path.join('html5lib', name)) and
+ not name.startswith('.') and name != 'tests']
+
+current_dir = os.path.dirname(__file__)
+with codecs.open(os.path.join(current_dir, 'README.rst'), 'r', 'utf8') as readme_file:
+ with codecs.open(os.path.join(current_dir, 'CHANGES.rst'), 'r', 'utf8') as changes_file:
+ long_description = readme_file.read() + '\n' + changes_file.read()
+
+version = None
+with open(os.path.join("html5lib", "__init__.py"), "rb") as init_file:
+ t = ast.parse(init_file.read(), filename="__init__.py", mode="exec")
+ assert isinstance(t, ast.Module)
+ assignments = filter(lambda x: isinstance(x, ast.Assign), t.body)
+ for a in assignments:
+ if (len(a.targets) == 1 and
+ isinstance(a.targets[0], ast.Name) and
+ a.targets[0].id == "__version__" and
+ isinstance(a.value, ast.Str)):
+ version = a.value.s
+
+setup(name='html5lib',
+ version=version,
+ url='https://github.com/html5lib/html5lib-python',
+ license="MIT License",
+ description='HTML parser based on the WHATWG HTML specification',
+ long_description=long_description,
+ classifiers=classifiers,
+ maintainer='James Graham',
+ maintainer_email='james@hoppipolla.co.uk',
+ packages=packages,
+ install_requires=[
+ 'six',
+ ],
+ )
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/tox.ini b/chromium/third_party/catapult/third_party/html5lib-python/tox.ini
new file mode 100644
index 00000000000..479f9e1f732
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/tox.ini
@@ -0,0 +1,30 @@
+[tox]
+envlist = py26,py27,py32,py33,py34,pypy
+
+[testenv]
+deps =
+ -r{toxinidir}/requirements-optional-cpython.txt
+ flake8
+ nose
+commands =
+ {envbindir}/nosetests -q
+ {toxinidir}/flake8-run.sh
+install_command =
+ pip install {opts} {packages}
+
+[testenv:pypy]
+# lxml doesn't work and datrie doesn't make sense
+# (it's slower than the pure-python version)
+deps =
+ charade
+ flake8
+ Genshi
+ nose
+ six
+
+[testenv:py26]
+basepython = python2.6
+deps =
+ -r{toxinidir}/requirements-optional-2.6.txt
+ flake8
+ nose
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/utils/entities.py b/chromium/third_party/catapult/third_party/html5lib-python/utils/entities.py
new file mode 100644
index 00000000000..116a27cbc9b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/utils/entities.py
@@ -0,0 +1,88 @@
+import json
+
+import html5lib
+
+def parse(path="html5ents.xml"):
+ return html5lib.parse(open(path), treebuilder="lxml")
+
+def entity_table(tree):
+ return dict((entity_name("".join(tr[0].xpath(".//text()"))),
+ entity_characters(tr[1].text))
+ for tr in tree.xpath("//h:tbody/h:tr",
+ namespaces={"h":"http://www.w3.org/1999/xhtml"}))
+
+def entity_name(inp):
+ return inp.strip()
+
+def entity_characters(inp):
+ return "".join(codepoint_to_character(item)
+ for item in inp.split()
+ if item)
+
+def codepoint_to_character(inp):
+ return ("\U000"+inp[2:]).decode("unicode-escape")
+
+def make_tests_json(entities):
+ test_list = make_test_list(entities)
+ tests_json = {"tests":
+ [make_test(*item) for item in test_list]
+ }
+ return tests_json
+
+def make_test(name, characters, good):
+ return {
+ "description":test_description(name, good),
+ "input":"&%s"%name,
+ "output":test_expected(name, characters, good)
+ }
+
+def test_description(name, good):
+ with_semicolon = name.endswith(";")
+ semicolon_text = {True:"with a semi-colon",
+ False:"without a semi-colon"}[with_semicolon]
+ if good:
+ text = "Named entity: %s %s"%(name, semicolon_text)
+ else:
+ text = "Bad named entity: %s %s"%(name, semicolon_text)
+ return text
+
+def test_expected(name, characters, good):
+ rv = []
+ if not good or not name.endswith(";"):
+ rv.append("ParseError")
+ rv.append(["Character", characters])
+ return rv
+
+def make_test_list(entities):
+ tests = []
+ for entity_name, characters in entities.items():
+ if entity_name.endswith(";") and not subentity_exists(entity_name, entities):
+ tests.append((entity_name[:-1], "&" + entity_name[:-1], False))
+ tests.append((entity_name, characters, True))
+ return sorted(tests)
+
+def subentity_exists(entity_name, entities):
+ for i in range(1, len(entity_name)):
+ if entity_name[:-i] in entities:
+ return True
+ return False
+
+def make_entities_code(entities):
+ entities_text = "\n".join(" \"%s\": u\"%s\","%(
+ name, entities[name].encode(
+ "unicode-escape").replace("\"", "\\\""))
+ for name in sorted(entities.keys()))
+ return """entities = {
+%s
+}"""%entities_text
+
+def main():
+ entities = entity_table(parse())
+ tests_json = make_tests_json(entities)
+ json.dump(tests_json, open("namedEntities.test", "w"), indent=4)
+ code = make_entities_code(entities)
+ open("entities_constants.py", "w").write(code)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/utils/iana_parse.py b/chromium/third_party/catapult/third_party/html5lib-python/utils/iana_parse.py
new file mode 100644
index 00000000000..6dde94c2829
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/utils/iana_parse.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+import sys
+import urllib.request, urllib.error, urllib.parse
+import codecs
+
+def main():
+ encodings = []
+ f = urllib.request.urlopen(sys.argv[1])
+ for line in f:
+ if line.startswith("Name: ") or line.startswith("Alias: "):
+ enc = line.split()[1]
+ try:
+ codecs.lookup(enc)
+ if enc.lower not in encodings:
+ encodings.append(enc.lower())
+ except LookupError:
+ pass
+ sys.stdout.write("encodings = frozenset((\n")
+ for enc in encodings:
+ sys.stdout.write(' "%s",\n'%enc)
+ sys.stdout.write(' ))')
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/html5lib-python/utils/spider.py b/chromium/third_party/catapult/third_party/html5lib-python/utils/spider.py
new file mode 100644
index 00000000000..a7b8031974b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/html5lib-python/utils/spider.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+"""Spider to try and find bugs in the parser. Requires httplib2 and elementtree
+
+usage:
+import spider
+s = spider.Spider()
+s.spider("http://www.google.com", maxURLs=100)
+"""
+
+import urllib.request, urllib.error, urllib.parse
+import urllib.robotparser
+import md5
+
+import httplib2
+
+import html5lib
+from html5lib.treebuilders import etree
+
+class Spider(object):
+ def __init__(self):
+ self.unvisitedURLs = set()
+ self.visitedURLs = set()
+ self.buggyURLs=set()
+ self.robotParser = urllib.robotparser.RobotFileParser()
+ self.contentDigest = {}
+ self.http = httplib2.Http(".cache")
+
+ def run(self, initialURL, maxURLs=1000):
+ urlNumber = 0
+ self.visitedURLs.add(initialURL)
+ content = self.loadURL(initialURL)
+ while maxURLs is None or urlNumber < maxURLs:
+ if content is not None:
+ self.parse(content)
+ urlNumber += 1
+ if not self.unvisitedURLs:
+ break
+ content = self.loadURL(self.unvisitedURLs.pop())
+
+ def parse(self, content):
+ failed = False
+ p = html5lib.HTMLParser(tree=etree.TreeBuilder)
+ try:
+ tree = p.parse(content)
+ except:
+ self.buggyURLs.add(self.currentURL)
+ failed = True
+ print("BUGGY:", self.currentURL)
+ self.visitedURLs.add(self.currentURL)
+ if not failed:
+ self.updateURLs(tree)
+
+ def loadURL(self, url):
+ resp, content = self.http.request(url, "GET")
+ self.currentURL = url
+ digest = md5.md5(content).hexdigest()
+ if digest in self.contentDigest:
+ content = None
+ self.visitedURLs.add(url)
+ else:
+ self.contentDigest[digest] = url
+
+ if resp['status'] != "200":
+ content = None
+
+ return content
+
+ def updateURLs(self, tree):
+ """Take all the links in the current document, extract the URLs and
+ update the list of visited and unvisited URLs according to whether we
+ have seen them before or not"""
+ urls = set()
+ #Remove all links we have already visited
+ for link in tree.findall(".//a"):
+ try:
+ url = urllib.parse.urldefrag(link.attrib['href'])[0]
+ if (url and url not in self.unvisitedURLs and url
+ not in self.visitedURLs):
+ urls.add(url)
+ except KeyError:
+ pass
+
+ #Remove all non-http URLs and a dd a sutiable base URL where that is
+ #missing
+ newUrls = set()
+ for url in urls:
+ splitURL = list(urllib.parse.urlsplit(url))
+ if splitURL[0] != "http":
+ continue
+ if splitURL[1] == "":
+ splitURL[1] = urllib.parse.urlsplit(self.currentURL)[1]
+ newUrls.add(urllib.parse.urlunsplit(splitURL))
+ urls = newUrls
+
+ responseHeaders = {}
+ #Now we want to find the content types of the links we haven't visited
+ for url in urls:
+ try:
+ resp, content = self.http.request(url, "HEAD")
+ responseHeaders[url] = resp
+ except AttributeError as KeyError:
+ #Don't know why this happens
+ pass
+
+
+ #Remove links not of content-type html or pages not found
+ #XXX - need to deal with other status codes?
+ toVisit = set([url for url in urls if url in responseHeaders and
+ "html" in responseHeaders[url]['content-type'] and
+ responseHeaders[url]['status'] == "200"])
+
+ #Now check we are allowed to spider the page
+ for url in toVisit:
+ robotURL = list(urllib.parse.urlsplit(url)[:2])
+ robotURL.extend(["robots.txt", "", ""])
+ robotURL = urllib.parse.urlunsplit(robotURL)
+ self.robotParser.set_url(robotURL)
+ if not self.robotParser.can_fetch("*", url):
+ toVisit.remove(url)
+
+ self.visitedURLs.update(urls)
+ self.unvisitedURLs.update(toVisit)
diff --git a/chromium/third_party/catapult/third_party/polymer/.bowerrc b/chromium/third_party/catapult/third_party/polymer/.bowerrc
new file mode 100644
index 00000000000..1d83b677782
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory:" : "components"
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/LICENSE.polymer b/chromium/third_party/catapult/third_party/polymer/LICENSE.polymer
new file mode 100644
index 00000000000..92d60b019fd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/LICENSE.polymer
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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
+// OWNER 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.
diff --git a/chromium/third_party/catapult/third_party/polymer/README.chromium b/chromium/third_party/catapult/third_party/polymer/README.chromium
new file mode 100644
index 00000000000..af8e9ad5214
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/README.chromium
@@ -0,0 +1,26 @@
+Name: Polymer
+Short Name: polymer
+URL: http://www.polymer-project.org
+Version: 0.5.2-4
+Revision: (See components/<component>/.bower.json)
+License: BSD
+License File: LICENSE.polymer
+Security Critical: no
+
+Description:
+This directory contains a subset of the components provided by the
+Polymer project. See bower.json for a full list of components.
+
+The version can be found in header of polymer/polymer.js. The license can
+be found in polymer/LICENSE.
+
+The source git repositories can be found at:
+https://github.com/Polymer/<component>
+
+Note on Bower:
+New components can be added by editing bower.json and running `bower update`,
+which requires first installing bower (see http://bower.io/).
+
+Local Modifications:
+Removed unused file with no license header:
+components/web-animations-js/.travis-setup.sh
diff --git a/chromium/third_party/catapult/third_party/polymer/bower.json b/chromium/third_party/catapult/third_party/polymer/bower.json
new file mode 100644
index 00000000000..8b69028b045
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/bower.json
@@ -0,0 +1,24 @@
+{
+ "name": "catapult",
+ "private": true,
+ "dependencies": {
+ "iron-collapse": "PolymerElements/iron-collapse#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-menu": "PolymerElements/paper-menu#^1.0.0",
+ "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.0",
+ "iron-selector": "PolymerElements/iron-selector#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-dialog": "PolymerElements/paper-dialog#^1.0.0",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
+ "paper-input": "PolymerElements/paper-input#^1.0.0",
+ "paper-progress": "PolymerElements/paper-progress#^1.0.0",
+ "paper-spinner": "PolymerElements/paper-spinner#^1.0.0",
+ "paper-toast": "PolymerElements/paper-toast#^1.0.0",
+ "paper-tooltip": "PolymerElements/paper-tooltip#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0",
+ "paper-listbox": "polymerelements/paper-listbox#^1.1.2"
+ }
+}
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/.bower.json
index 0a244bdc190..25da64479c2 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/.bower.json
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/.bower.json
@@ -2,16 +2,16 @@
"name": "core-component-page",
"private": true,
"dependencies": {
- "webcomponentsjs": "Polymer/webcomponentsjs#^0.5",
+ "webcomponentsjs": "Polymer/webcomponentsjs",
"polymer": "Polymer/polymer#^0.5"
},
- "version": "0.5.5",
+ "version": "0.5.6",
"homepage": "https://github.com/Polymer/core-component-page",
- "_release": "0.5.5",
+ "_release": "0.5.6",
"_resolution": {
"type": "version",
- "tag": "0.5.5",
- "commit": "f91588e0297bb3e8e723d4558ab015cf82885571"
+ "tag": "0.5.6",
+ "commit": "01a1d3968d7ece144783bcd03bc87b18344265e3"
},
"_source": "git://github.com/Polymer/core-component-page.git",
"_target": "^0.5",
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-component-page/README.md b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/README.md
new file mode 100644
index 00000000000..9e2384294a3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/README.md
@@ -0,0 +1,9 @@
+core-component-page
+===================
+
+**This element is compatible with Polymer 0.5 and lower only, and will be deprecated.**
+You can check out a similar 0.8-compatible version of this element at [https://github.com/polymerelements/iron-components-page](https://github.com/polymerelements/iron-component-page)
+
+See the [component page](https://www.polymer-project.org/0.5/docs/elements/core-component-page.html) for more information.
+
+Note: this is the vulcanized version of [`core-component-page-dev`](https://github.com/Polymer/core-component-page-dev) (the source).
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/bowager-logo.png b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/bowager-logo.png
index 76be9fb04c1..76be9fb04c1 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/bowager-logo.png
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/bowager-logo.png
Binary files differ
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/bower.json b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/bower.json
index 361124c2dfc..df2d599bd82 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/bower.json
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/bower.json
@@ -2,8 +2,8 @@
"name": "core-component-page",
"private": true,
"dependencies": {
- "webcomponentsjs": "Polymer/webcomponentsjs#^0.5",
+ "webcomponentsjs": "Polymer/webcomponentsjs",
"polymer": "Polymer/polymer#^0.5"
},
- "version": "0.5.5"
+ "version": "0.5.6"
} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-component-page/core-component-page.html b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/core-component-page.html
new file mode 100644
index 00000000000..82a87e7ea8e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/core-component-page.html
@@ -0,0 +1 @@
+<html><head><style> body { margin: 0; }</style><link rel="import" href="../polymer/polymer.html"><style shim-shadowdom="">html /deep/ core-icon { display: inline-block; vertical-align: middle; background-repeat: no-repeat; fill: currentcolor; position: relative; height: 24px; width: 24px;}</style><script>(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(){var out,err;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());</script><script>var IN_GLOBAL_SCOPE=true;window["PR_SHOULD_USE_CONTINUATION"]=true;var prettyPrintOne;var prettyPrint;(function(){var win=window;var FLOW_CONTROL_KEYWORDS=["break,continue,do,else,for,if,return,while"];var C_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default,"+"double,enum,extern,float,goto,inline,int,long,register,short,signed,"+"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var COMMON_KEYWORDS=[C_KEYWORDS,"catch,class,delete,false,import,"+"new,operator,private,protected,public,this,throw,true,try,typeof"];var CPP_KEYWORDS=[COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool,"+"concept,concept_map,const_cast,constexpr,decltype,delegate,"+"dynamic_cast,explicit,export,friend,generic,late_check,"+"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,"+"static_cast,template,typeid,typename,using,virtual,where"];var JAVA_KEYWORDS=[COMMON_KEYWORDS,"abstract,assert,boolean,byte,extends,final,finally,implements,import,"+"instanceof,interface,null,native,package,strictfp,super,synchronized,"+"throws,transient"];var CSHARP_KEYWORDS=[JAVA_KEYWORDS,"as,base,by,checked,decimal,delegate,descending,dynamic,event,"+"fixed,foreach,from,group,implicit,in,internal,into,is,let,"+"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,"+"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,"+"var,virtual,where"];var COFFEE_KEYWORDS="all,and,by,catch,class,else,extends,false,finally,"+"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,"+"throw,true,try,unless,until,when,while,yes";var JSCRIPT_KEYWORDS=[COMMON_KEYWORDS,"debugger,eval,export,function,get,null,set,undefined,var,with,"+"Infinity,NaN"];var PERL_KEYWORDS="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,"+"goto,if,import,last,local,my,next,no,our,print,package,redo,require,"+"sub,undef,unless,until,use,wantarray,while,BEGIN,END";var PYTHON_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"and,as,assert,class,def,del,"+"elif,except,exec,finally,from,global,import,in,is,lambda,"+"nonlocal,not,or,pass,print,raise,try,with,yield,"+"False,True,None"];var RUBY_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"alias,and,begin,case,class,"+"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,"+"rescue,retry,self,super,then,true,undef,unless,until,when,yield,"+"BEGIN,END"];var RUST_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"as,assert,const,copy,drop,"+"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,"+"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"];var SH_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"case,done,elif,esac,eval,fi,"+"function,in,local,set,then,until"];var ALL_KEYWORDS=[CPP_KEYWORDS,CSHARP_KEYWORDS,JSCRIPT_KEYWORDS,PERL_KEYWORDS,PYTHON_KEYWORDS,RUBY_KEYWORDS,SH_KEYWORDS];var C_TYPES=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var PR_STRING="str";var PR_KEYWORD="kwd";var PR_COMMENT="com";var PR_TYPE="typ";var PR_LITERAL="lit";var PR_PUNCTUATION="pun";var PR_PLAIN="pln";var PR_TAG="tag";var PR_DECLARATION="dec";var PR_SOURCE="src";var PR_ATTRIB_NAME="atn";var PR_ATTRIB_VALUE="atv";var PR_NOCODE="nocode";var REGEXP_PRECEDER_PATTERN="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function combinePrefixPatterns(regexs){var capturedGroupIndex=0;var needToFoldCase=false;var ignoreCase=false;for(var i=0,n=regexs.length;i<n;++i){var regex=regexs[i];if(regex.ignoreCase){ignoreCase=true}else if(/[a-z]/i.test(regex.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){needToFoldCase=true;ignoreCase=false;break}}var escapeCharToCodeUnit={b:8,t:9,n:10,v:11,f:12,r:13};function decodeEscape(charsetPart){var cc0=charsetPart.charCodeAt(0);if(cc0!==92){return cc0}var c1=charsetPart.charAt(1);cc0=escapeCharToCodeUnit[c1];if(cc0){return cc0}else if("0"<=c1&&c1<="7"){return parseInt(charsetPart.substring(1),8)}else if(c1==="u"||c1==="x"){return parseInt(charsetPart.substring(2),16)}else{return charsetPart.charCodeAt(1)}}function encodeEscape(charCode){if(charCode<32){return(charCode<16?"\\x0":"\\x")+charCode.toString(16)}var ch=String.fromCharCode(charCode);return ch==="\\"||ch==="-"||ch==="]"||ch==="^"?"\\"+ch:ch}function caseFoldCharset(charSet){var charsetParts=charSet.substring(1,charSet.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}"+"|\\\\x[0-9A-Fa-f]{2}"+"|\\\\[0-3][0-7]{0,2}"+"|\\\\[0-7]{1,2}"+"|\\\\[\\s\\S]"+"|-"+"|[^-\\\\]","g"));var ranges=[];var inverse=charsetParts[0]==="^";var out=["["];if(inverse){out.push("^")}for(var i=inverse?1:0,n=charsetParts.length;i<n;++i){var p=charsetParts[i];if(/\\[bdsw]/i.test(p)){out.push(p)}else{var start=decodeEscape(p);var end;if(i+2<n&&"-"===charsetParts[i+1]){end=decodeEscape(charsetParts[i+2]);i+=2}else{end=start}ranges.push([start,end]);if(!(end<65||start>122)){if(!(end<65||start>90)){ranges.push([Math.max(65,start)|32,Math.min(end,90)|32])}if(!(end<97||start>122)){ranges.push([Math.max(97,start)&~32,Math.min(end,122)&~32])}}}}ranges.sort(function(a,b){return a[0]-b[0]||b[1]-a[1]});var consolidatedRanges=[];var lastRange=[];for(var i=0;i<ranges.length;++i){var range=ranges[i];if(range[0]<=lastRange[1]+1){lastRange[1]=Math.max(lastRange[1],range[1])}else{consolidatedRanges.push(lastRange=range)}}for(var i=0;i<consolidatedRanges.length;++i){var range=consolidatedRanges[i];out.push(encodeEscape(range[0]));if(range[1]>range[0]){if(range[1]+1>range[0]){out.push("-")}out.push(encodeEscape(range[1]))}}out.push("]");return out.join("")}function allowAnywhereFoldCaseAndRenumberGroups(regex){var parts=regex.source.match(new RegExp("(?:"+"\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]"+"|\\\\u[A-Fa-f0-9]{4}"+"|\\\\x[A-Fa-f0-9]{2}"+"|\\\\[0-9]+"+"|\\\\[^ux0-9]"+"|\\(\\?[:!=]"+"|[\\(\\)\\^]"+"|[^\\x5B\\x5C\\(\\)\\^]+"+")","g"));var n=parts.length;var capturedGroups=[];for(var i=0,groupIndex=0;i<n;++i){var p=parts[i];if(p==="("){++groupIndex}else if("\\"===p.charAt(0)){var decimalValue=+p.substring(1);if(decimalValue){if(decimalValue<=groupIndex){capturedGroups[decimalValue]=-1}else{parts[i]=encodeEscape(decimalValue)}}}}for(var i=1;i<capturedGroups.length;++i){if(-1===capturedGroups[i]){capturedGroups[i]=++capturedGroupIndex}}for(var i=0,groupIndex=0;i<n;++i){var p=parts[i];if(p==="("){++groupIndex;if(!capturedGroups[groupIndex]){parts[i]="(?:"}}else if("\\"===p.charAt(0)){var decimalValue=+p.substring(1);if(decimalValue&&decimalValue<=groupIndex){parts[i]="\\"+capturedGroups[decimalValue]}}}for(var i=0;i<n;++i){if("^"===parts[i]&&"^"!==parts[i+1]){parts[i]=""}}if(regex.ignoreCase&&needToFoldCase){for(var i=0;i<n;++i){var p=parts[i];var ch0=p.charAt(0);if(p.length>=2&&ch0==="["){parts[i]=caseFoldCharset(p)}else if(ch0!=="\\"){parts[i]=p.replace(/[a-zA-Z]/g,function(ch){var cc=ch.charCodeAt(0);return"["+String.fromCharCode(cc&~32,cc|32)+"]"})}}}return parts.join("")}var rewritten=[];for(var i=0,n=regexs.length;i<n;++i){var regex=regexs[i];if(regex.global||regex.multiline){throw new Error(""+regex)}rewritten.push("(?:"+allowAnywhereFoldCaseAndRenumberGroups(regex)+")")}return new RegExp(rewritten.join("|"),ignoreCase?"gi":"g")}function extractSourceSpans(node,isPreformatted){var nocode=/(?:^|\s)nocode(?:\s|$)/;var chunks=[];var length=0;var spans=[];var k=0;function walk(node){var type=node.nodeType;if(type==1){if(nocode.test(node.className)){return}for(var child=node.firstChild;child;child=child.nextSibling){walk(child)}var nodeName=node.nodeName.toLowerCase();if("br"===nodeName||"li"===nodeName){chunks[k]="\n";spans[k<<1]=length++;spans[k++<<1|1]=node}}else if(type==3||type==4){var text=node.nodeValue;if(text.length){if(!isPreformatted){text=text.replace(/[ \t\r\n]+/g," ")}else{text=text.replace(/\r\n?/g,"\n")}chunks[k]=text;spans[k<<1]=length;length+=text.length;spans[k++<<1|1]=node}}}walk(node);return{sourceCode:chunks.join("").replace(/\n$/,""),spans:spans}}function appendDecorations(basePos,sourceCode,langHandler,out){if(!sourceCode){return}var job={sourceCode:sourceCode,basePos:basePos};langHandler(job);out.push.apply(out,job.decorations)}var notWs=/\S/;function childContentWrapper(element){var wrapper=undefined;for(var c=element.firstChild;c;c=c.nextSibling){var type=c.nodeType;wrapper=type===1?wrapper?element:c:type===3?notWs.test(c.nodeValue)?element:wrapper:wrapper}return wrapper===element?undefined:wrapper}function createSimpleLexer(shortcutStylePatterns,fallthroughStylePatterns){var shortcuts={};var tokenizer;(function(){var allPatterns=shortcutStylePatterns.concat(fallthroughStylePatterns);var allRegexs=[];var regexKeys={};for(var i=0,n=allPatterns.length;i<n;++i){var patternParts=allPatterns[i];var shortcutChars=patternParts[3];if(shortcutChars){for(var c=shortcutChars.length;--c>=0;){shortcuts[shortcutChars.charAt(c)]=patternParts}}var regex=patternParts[1];var k=""+regex;if(!regexKeys.hasOwnProperty(k)){allRegexs.push(regex);regexKeys[k]=null}}allRegexs.push(/[\0-\uffff]/);tokenizer=combinePrefixPatterns(allRegexs)})();var nPatterns=fallthroughStylePatterns.length;var decorate=function(job){var sourceCode=job.sourceCode,basePos=job.basePos;var decorations=[basePos,PR_PLAIN];var pos=0;var tokens=sourceCode.match(tokenizer)||[];var styleCache={};for(var ti=0,nTokens=tokens.length;ti<nTokens;++ti){var token=tokens[ti];var style=styleCache[token];var match=void 0;var isEmbedded;if(typeof style==="string"){isEmbedded=false}else{var patternParts=shortcuts[token.charAt(0)];if(patternParts){match=token.match(patternParts[1]);style=patternParts[0]}else{for(var i=0;i<nPatterns;++i){patternParts=fallthroughStylePatterns[i];match=token.match(patternParts[1]);if(match){style=patternParts[0];break}}if(!match){style=PR_PLAIN}}isEmbedded=style.length>=5&&"lang-"===style.substring(0,5);if(isEmbedded&&!(match&&typeof match[1]==="string")){isEmbedded=false;style=PR_SOURCE}if(!isEmbedded){styleCache[token]=style}}var tokenStart=pos;pos+=token.length;if(!isEmbedded){decorations.push(basePos+tokenStart,style)}else{var embeddedSource=match[1];var embeddedSourceStart=token.indexOf(embeddedSource);var embeddedSourceEnd=embeddedSourceStart+embeddedSource.length;if(match[2]){embeddedSourceEnd=token.length-match[2].length;embeddedSourceStart=embeddedSourceEnd-embeddedSource.length}var lang=style.substring(5);appendDecorations(basePos+tokenStart,token.substring(0,embeddedSourceStart),decorate,decorations);appendDecorations(basePos+tokenStart+embeddedSourceStart,embeddedSource,langHandlerForExtension(lang,embeddedSource),decorations);appendDecorations(basePos+tokenStart+embeddedSourceEnd,token.substring(embeddedSourceEnd),decorate,decorations)}}job.decorations=decorations};return decorate}function sourceDecorator(options){var shortcutStylePatterns=[],fallthroughStylePatterns=[];if(options["tripleQuotedStrings"]){shortcutStylePatterns.push([PR_STRING,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else if(options["multiLineStrings"]){shortcutStylePatterns.push([PR_STRING,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{shortcutStylePatterns.push([PR_STRING,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}if(options["verbatimStrings"]){fallthroughStylePatterns.push([PR_STRING,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var hc=options["hashComments"];if(hc){if(options["cStyleComments"]){if(hc>1){shortcutStylePatterns.push([PR_COMMENT,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{shortcutStylePatterns.push([PR_COMMENT,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}fallthroughStylePatterns.push([PR_STRING,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{shortcutStylePatterns.push([PR_COMMENT,/^#[^\r\n]*/,null,"#"])}}if(options["cStyleComments"]){fallthroughStylePatterns.push([PR_COMMENT,/^\/\/[^\r\n]*/,null]);fallthroughStylePatterns.push([PR_COMMENT,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}var regexLiterals=options["regexLiterals"];if(regexLiterals){var regexExcls=regexLiterals>1?"":"\n\r";var regexAny=regexExcls?".":"[\\S\\s]";var REGEX_LITERAL="/(?=[^/*"+regexExcls+"])"+"(?:[^/\\x5B\\x5C"+regexExcls+"]"+"|\\x5C"+regexAny+"|\\x5B(?:[^\\x5C\\x5D"+regexExcls+"]"+"|\\x5C"+regexAny+")*(?:\\x5D|$))+"+"/";fallthroughStylePatterns.push(["lang-regex",RegExp("^"+REGEXP_PRECEDER_PATTERN+"("+REGEX_LITERAL+")")])}var types=options["types"];if(types){fallthroughStylePatterns.push([PR_TYPE,types])}var keywords=(""+options["keywords"]).replace(/^ | $/g,"");if(keywords.length){fallthroughStylePatterns.push([PR_KEYWORD,new RegExp("^(?:"+keywords.replace(/[\s,]+/g,"|")+")\\b"),null])}shortcutStylePatterns.push([PR_PLAIN,/^\s+/,null," \r\n  "]);var punctuation="^.[^\\s\\w.$@'\"`/\\\\]*";if(options["regexLiterals"]){punctuation+="(?!s*/)"}fallthroughStylePatterns.push([PR_LITERAL,/^@[a-z_$][a-z_$@0-9]*/i,null],[PR_TYPE,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[PR_PLAIN,/^[a-z_$][a-z_$@0-9]*/i,null],[PR_LITERAL,new RegExp("^(?:"+"0x[a-f0-9]+"+"|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)"+"(?:e[+\\-]?\\d+)?"+")"+"[a-z]*","i"),null,"0123456789"],[PR_PLAIN,/^\\[\s\S]?/,null],[PR_PUNCTUATION,new RegExp(punctuation),null]);return createSimpleLexer(shortcutStylePatterns,fallthroughStylePatterns)}var decorateSource=sourceDecorator({keywords:ALL_KEYWORDS,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function numberLines(node,opt_startLineNum,isPreformatted){var nocode=/(?:^|\s)nocode(?:\s|$)/;var lineBreak=/\r\n?|\n/;var document=node.ownerDocument;var li=document.createElement("li");while(node.firstChild){li.appendChild(node.firstChild)}var listItems=[li];function walk(node){var type=node.nodeType;if(type==1&&!nocode.test(node.className)){if("br"===node.nodeName){breakAfter(node);if(node.parentNode){node.parentNode.removeChild(node)}}else{for(var child=node.firstChild;child;child=child.nextSibling){walk(child)}}}else if((type==3||type==4)&&isPreformatted){var text=node.nodeValue;var match=text.match(lineBreak);if(match){var firstLine=text.substring(0,match.index);node.nodeValue=firstLine;var tail=text.substring(match.index+match[0].length);if(tail){var parent=node.parentNode;parent.insertBefore(document.createTextNode(tail),node.nextSibling)}breakAfter(node);if(!firstLine){node.parentNode.removeChild(node)}}}}function breakAfter(lineEndNode){while(!lineEndNode.nextSibling){lineEndNode=lineEndNode.parentNode;if(!lineEndNode){return}}function breakLeftOf(limit,copy){var rightSide=copy?limit.cloneNode(false):limit;var parent=limit.parentNode;if(parent){var parentClone=breakLeftOf(parent,1);var next=limit.nextSibling;parentClone.appendChild(rightSide);for(var sibling=next;sibling;sibling=next){next=sibling.nextSibling;parentClone.appendChild(sibling)}}return rightSide}var copiedListItem=breakLeftOf(lineEndNode.nextSibling,0);for(var parent;(parent=copiedListItem.parentNode)&&parent.nodeType===1;){copiedListItem=parent}listItems.push(copiedListItem)}for(var i=0;i<listItems.length;++i){walk(listItems[i])}if(opt_startLineNum===(opt_startLineNum|0)){listItems[0].setAttribute("value",opt_startLineNum)}var ol=document.createElement("ol");ol.className="linenums";var offset=Math.max(0,opt_startLineNum-1|0)||0;for(var i=0,n=listItems.length;i<n;++i){li=listItems[i];li.className="L"+(i+offset)%10;if(!li.firstChild){li.appendChild(document.createTextNode(" "))}ol.appendChild(li)}node.appendChild(ol)}function recombineTagsAndDecorations(job){var isIE8OrEarlier=/\bMSIE\s(\d+)/.exec(navigator.userAgent);isIE8OrEarlier=isIE8OrEarlier&&+isIE8OrEarlier[1]<=8;var newlineRe=/\n/g;var source=job.sourceCode;var sourceLength=source.length;var sourceIndex=0;var spans=job.spans;var nSpans=spans.length;var spanIndex=0;var decorations=job.decorations;var nDecorations=decorations.length;var decorationIndex=0;decorations[nDecorations]=sourceLength;var decPos,i;for(i=decPos=0;i<nDecorations;){if(decorations[i]!==decorations[i+2]){decorations[decPos++]=decorations[i++];decorations[decPos++]=decorations[i++]}else{i+=2}}nDecorations=decPos;for(i=decPos=0;i<nDecorations;){var startPos=decorations[i];var startDec=decorations[i+1];var end=i+2;while(end+2<=nDecorations&&decorations[end+1]===startDec){end+=2}decorations[decPos++]=startPos;decorations[decPos++]=startDec;i=end}nDecorations=decorations.length=decPos;var sourceNode=job.sourceNode;var oldDisplay;if(sourceNode){oldDisplay=sourceNode.style.display;sourceNode.style.display="none"}try{var decoration=null;while(spanIndex<nSpans){var spanStart=spans[spanIndex];var spanEnd=spans[spanIndex+2]||sourceLength;var decEnd=decorations[decorationIndex+2]||sourceLength;var end=Math.min(spanEnd,decEnd);var textNode=spans[spanIndex+1];var styledText;if(textNode.nodeType!==1&&(styledText=source.substring(sourceIndex,end))){if(isIE8OrEarlier){styledText=styledText.replace(newlineRe,"\r")}textNode.nodeValue=styledText;var document=textNode.ownerDocument;var span=document.createElement("span");span.className=decorations[decorationIndex+1];var parentNode=textNode.parentNode;parentNode.replaceChild(span,textNode);span.appendChild(textNode);if(sourceIndex<spanEnd){spans[spanIndex+1]=textNode=document.createTextNode(source.substring(end,spanEnd));parentNode.insertBefore(textNode,span.nextSibling)}}sourceIndex=end;if(sourceIndex>=spanEnd){spanIndex+=2}if(sourceIndex>=decEnd){decorationIndex+=2}}}finally{if(sourceNode){sourceNode.style.display=oldDisplay}}}var langHandlerRegistry={};function registerLangHandler(handler,fileExtensions){for(var i=fileExtensions.length;--i>=0;){var ext=fileExtensions[i];if(!langHandlerRegistry.hasOwnProperty(ext)){langHandlerRegistry[ext]=handler}else if(win["console"]){console["warn"]("cannot override language handler %s",ext)}}}function langHandlerForExtension(extension,source){if(!(extension&&langHandlerRegistry.hasOwnProperty(extension))){extension=/^\s*</.test(source)?"default-markup":"default-code"}return langHandlerRegistry[extension]}registerLangHandler(decorateSource,["default-code"]);registerLangHandler(createSimpleLexer([],[[PR_PLAIN,/^[^<?]+/],[PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);registerLangHandler(createSimpleLexer([[PR_PLAIN,/^[\s]+/,null," \r\n"],[PR_ATTRIB_VALUE,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[PR_TAG,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[PR_ATTRIB_NAME,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[PR_PUNCTUATION,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);registerLangHandler(createSimpleLexer([],[[PR_ATTRIB_VALUE,/^[\s\S]+/]]),["uq.val"]);registerLangHandler(sourceDecorator({keywords:CPP_KEYWORDS,hashComments:true,cStyleComments:true,types:C_TYPES}),["c","cc","cpp","cxx","cyc","m"]);registerLangHandler(sourceDecorator({keywords:"null,true,false"}),["json"]);registerLangHandler(sourceDecorator({keywords:CSHARP_KEYWORDS,hashComments:true,cStyleComments:true,verbatimStrings:true,types:C_TYPES}),["cs"]);registerLangHandler(sourceDecorator({keywords:JAVA_KEYWORDS,cStyleComments:true}),["java"]);registerLangHandler(sourceDecorator({keywords:SH_KEYWORDS,hashComments:true,multiLineStrings:true}),["bash","bsh","csh","sh"]);registerLangHandler(sourceDecorator({keywords:PYTHON_KEYWORDS,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py","python"]);registerLangHandler(sourceDecorator({keywords:PERL_KEYWORDS,hashComments:true,multiLineStrings:true,regexLiterals:2}),["perl","pl","pm"]);registerLangHandler(sourceDecorator({keywords:RUBY_KEYWORDS,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb","ruby"]);registerLangHandler(sourceDecorator({keywords:JSCRIPT_KEYWORDS,cStyleComments:true,regexLiterals:true}),["javascript","js"]);registerLangHandler(sourceDecorator({keywords:COFFEE_KEYWORDS,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);registerLangHandler(sourceDecorator({keywords:RUST_KEYWORDS,cStyleComments:true,multilineStrings:true}),["rc","rs","rust"]);registerLangHandler(createSimpleLexer([],[[PR_STRING,/^[\s\S]+/]]),["regex"]);function applyDecorator(job){var opt_langExtension=job.langExtension;try{var sourceAndSpans=extractSourceSpans(job.sourceNode,job.pre);var source=sourceAndSpans.sourceCode;job.sourceCode=source;job.spans=sourceAndSpans.spans;job.basePos=0;langHandlerForExtension(opt_langExtension,source)(job);recombineTagsAndDecorations(job)}catch(e){if(win["console"]){console["log"](e&&e["stack"]||e)}}}function $prettyPrintOne(sourceCodeHtml,opt_langExtension,opt_numberLines){var container=document.createElement("div");container.innerHTML="<pre>"+sourceCodeHtml+"</pre>";container=container.firstChild;if(opt_numberLines){numberLines(container,opt_numberLines,true)}var job={langExtension:opt_langExtension,numberLines:opt_numberLines,sourceNode:container,pre:1};applyDecorator(job);return container.innerHTML}function $prettyPrint(opt_whenDone,opt_root){var root=opt_root||document.body;var doc=root.ownerDocument||document;function byTagName(tn){return root.getElementsByTagName(tn)}var codeSegments=[byTagName("pre"),byTagName("code"),byTagName("xmp")];var elements=[];for(var i=0;i<codeSegments.length;++i){for(var j=0,n=codeSegments[i].length;j<n;++j){elements.push(codeSegments[i][j])}}codeSegments=null;var clock=Date;if(!clock["now"]){clock={now:function(){return+new Date}}}var k=0;var prettyPrintingJob;var langExtensionRe=/\blang(?:uage)?-([\w.]+)(?!\S)/;var prettyPrintRe=/\bprettyprint\b/;var prettyPrintedRe=/\bprettyprinted\b/;var preformattedTagNameRe=/pre|xmp/i;var codeRe=/^code$/i;var preCodeXmpRe=/^(?:pre|code|xmp)$/i;var EMPTY={};function doWork(){var endTime=win["PR_SHOULD_USE_CONTINUATION"]?clock["now"]()+250:Infinity;for(;k<elements.length&&clock["now"]()<endTime;k++){var cs=elements[k];var attrs=EMPTY;{for(var preceder=cs;preceder=preceder.previousSibling;){var nt=preceder.nodeType;var value=(nt===7||nt===8)&&preceder.nodeValue;if(value?!/^\??prettify\b/.test(value):nt!==3||/\S/.test(preceder.nodeValue)){break}if(value){attrs={};value.replace(/\b(\w+)=([\w:.%+-]+)/g,function(_,name,value){attrs[name]=value});break}}}var className=cs.className;if((attrs!==EMPTY||prettyPrintRe.test(className))&&!prettyPrintedRe.test(className)){var nested=false;for(var p=cs.parentNode;p;p=p.parentNode){var tn=p.tagName;if(preCodeXmpRe.test(tn)&&p.className&&prettyPrintRe.test(p.className)){nested=true;break}}if(!nested){cs.className+=" prettyprinted";var langExtension=attrs["lang"];if(!langExtension){langExtension=className.match(langExtensionRe);var wrapper;if(!langExtension&&(wrapper=childContentWrapper(cs))&&codeRe.test(wrapper.tagName)){langExtension=wrapper.className.match(langExtensionRe)}if(langExtension){langExtension=langExtension[1]}}var preformatted;if(preformattedTagNameRe.test(cs.tagName)){preformatted=1}else{var currentStyle=cs["currentStyle"];var defaultView=doc.defaultView;var whitespace=currentStyle?currentStyle["whiteSpace"]:defaultView&&defaultView.getComputedStyle?defaultView.getComputedStyle(cs,null).getPropertyValue("white-space"):0;preformatted=whitespace&&"pre"===whitespace.substring(0,3)}var lineNums=attrs["linenums"];if(!(lineNums=lineNums==="true"||+lineNums)){lineNums=className.match(/\blinenums\b(?::(\d+))?/);lineNums=lineNums?lineNums[1]&&lineNums[1].length?+lineNums[1]:true:false}if(lineNums){numberLines(cs,lineNums,preformatted)}prettyPrintingJob={langExtension:langExtension,sourceNode:cs,numberLines:lineNums,pre:preformatted};applyDecorator(prettyPrintingJob)}}}if(k<elements.length){setTimeout(doWork,250)}else if("function"===typeof opt_whenDone){opt_whenDone()}}doWork()}var PR=win["PR"]={createSimpleLexer:createSimpleLexer,registerLangHandler:registerLangHandler,sourceDecorator:sourceDecorator,PR_ATTRIB_NAME:PR_ATTRIB_NAME,PR_ATTRIB_VALUE:PR_ATTRIB_VALUE,PR_COMMENT:PR_COMMENT,PR_DECLARATION:PR_DECLARATION,PR_KEYWORD:PR_KEYWORD,PR_LITERAL:PR_LITERAL,PR_NOCODE:PR_NOCODE,PR_PLAIN:PR_PLAIN,PR_PUNCTUATION:PR_PUNCTUATION,PR_SOURCE:PR_SOURCE,PR_STRING:PR_STRING,PR_TAG:PR_TAG,PR_TYPE:PR_TYPE,prettyPrintOne:IN_GLOBAL_SCOPE?win["prettyPrintOne"]=$prettyPrintOne:prettyPrintOne=$prettyPrintOne,prettyPrint:prettyPrint=IN_GLOBAL_SCOPE?win["prettyPrint"]=$prettyPrint:prettyPrint=$prettyPrint};if(typeof define==="function"&&define["amd"]){define("google-code-prettify",[],function(){return PR})}})();</script><script>(function(scope){var ContextFreeParser={parse:function(text){var top={};var entities=[];var current=top;var subCurrent={};var scriptDocCommentClause="\\/\\*\\*([\\s\\S]*?)\\*\\/";var htmlDocCommentClause="<!--([\\s\\S]*?)-->";var docCommentRegex=new RegExp(scriptDocCommentClause+"|"+htmlDocCommentClause,"g");var docComments=text.match(docCommentRegex)||[];docComments.forEach(function(m){var lines=m.replace(/\r\n/g,"\n").replace(/^\s*\/\*\*|^\s*\*\/|^\s*\* ?|^\s*\<\!-\-|^s*\-\-\>/gm,"").split("\n");var pragmas=[];lines=lines.filter(function(l){var m=l.match(/\s*@([\w-]*) (.*)/);if(!m){return true}pragmas.push(m)});var code=lines.join("\n");pragmas.forEach(function(m){var pragma=m[1],content=m[2];switch(pragma){case"class":case"element":current={name:content,description:code};entities.push(current);break;case"attribute":case"property":case"method":case"event":subCurrent={name:content,description:code};var label=pragma=="property"?"properties":pragma+"s";makePragma(current,label,subCurrent);break;case"default":case"type":subCurrent[pragma]=content;break;case"param":var eventParmsRe=/\{(.+)\}\s+(\w+[.\w+]+)\s+(.*)$/;var params=content.match(eventParmsRe);if(params){var subEventObj={type:params[1],name:params[2],description:params[3]};makePragma(subCurrent,pragma+"s",subEventObj)}break;case"extends":case"mixins":var parts=content.split(" ");var subObj={name:parts[0],url:parts[1]||null};makePragma(current,pragma,subObj);break;case"return":var returnRe=/\{(.+)\}\s+(.*)$/;var returnReResult=content.match(returnRe);if(returnReResult){var subReturnObj={type:returnReResult[1],description:returnReResult[2]};subCurrent[pragma]=subReturnObj}break;default:current[pragma]=content;break}});function makePragma(object,pragma,content){var p$=object;var p=p$[pragma];if(!p){p$[pragma]=p=[]}p.push(content)}});if(entities.length===0){entities.push({name:"Entity",description:"**Undocumented**"})}return entities}};if(typeof module!=="undefined"&&module.exports){module.exports=ContextFreeParser}else{scope.ContextFreeParser=ContextFreeParser}})(this);</script><link href="http://fonts.googleapis.com/css?family=Roboto:400,300,500,700|Source+Code+Pro" rel="stylesheet" type="text/css"><style shim-shadowdom=""> html /deep/ core-a11y-keys { display: none; }</style></head><body><div hidden=""><polymer-element name="core-meta" attributes="label type" hidden="" assetpath="../core-meta/"><script>(function(){var SKIP_ID="meta";var metaData={},metaArray={};Polymer("core-meta",{type:"default",alwaysPrepare:true,ready:function(){this.register(this.id)},get metaArray(){var t=this.type;if(!metaArray[t]){metaArray[t]=[]}return metaArray[t]},get metaData(){var t=this.type;if(!metaData[t]){metaData[t]={}}return metaData[t]},register:function(id,old){if(id&&id!==SKIP_ID){this.unregister(this,old);this.metaData[id]=this;this.metaArray.push(this)}},unregister:function(meta,id){delete this.metaData[id||meta.id];var i=this.metaArray.indexOf(meta);if(i>=0){this.metaArray.splice(i,1)}},get list(){return this.metaArray},byId:function(id){return this.metaData[id]}})})();</script></polymer-element><polymer-element name="core-iconset" extends="core-meta" attributes="src width icons iconSize" assetpath="../core-iconset/"><script>Polymer("core-iconset",{src:"",width:0,icons:"",iconSize:24,offsetX:0,offsetY:0,type:"iconset",created:function(){this.iconMap={};this.iconNames=[];this.themes={}},ready:function(){if(this.src&&this.ownerDocument!==document){this.src=this.resolvePath(this.src,this.ownerDocument.baseURI)}this.super();this.updateThemes()},iconsChanged:function(){var ox=this.offsetX;var oy=this.offsetY;this.icons&&this.icons.split(/\s+/g).forEach(function(name,i){this.iconNames.push(name);this.iconMap[name]={offsetX:ox,offsetY:oy};if(ox+this.iconSize<this.width){ox+=this.iconSize}else{ox=this.offsetX;oy+=this.iconSize}},this)},updateThemes:function(){var ts=this.querySelectorAll("property[theme]");ts&&ts.array().forEach(function(t){this.themes[t.getAttribute("theme")]={offsetX:parseInt(t.getAttribute("offsetX"))||0,offsetY:parseInt(t.getAttribute("offsetY"))||0}},this)},getOffset:function(icon,theme){var i=this.iconMap[icon];if(!i){var n=this.iconNames[Number(icon)];i=this.iconMap[n]}var t=this.themes[theme];if(i&&t){return{offsetX:i.offsetX+t.offsetX,offsetY:i.offsetY+t.offsetY}}return i},applyIcon:function(element,icon,scale){var offset=this.getOffset(icon);scale=scale||1;if(element&&offset){var icon=element._icon||document.createElement("div");var style=icon.style;style.backgroundImage="url("+this.src+")";style.backgroundPosition=-offset.offsetX*scale+"px"+" "+(-offset.offsetY*scale+"px");style.backgroundSize=scale===1?"auto":this.width*scale+"px";if(icon.parentNode!==element){element.appendChild(icon)}return icon}}});</script></polymer-element><polymer-element name="core-icon" attributes="src icon alt" assetpath="../core-icon/"><script>(function(){var meta;Polymer("core-icon",{src:"",icon:"",alt:null,observe:{icon:"updateIcon",alt:"updateAlt"},defaultIconset:"icons",ready:function(){if(!meta){meta=document.createElement("core-iconset")}if(this.hasAttribute("aria-label")){if(!this.hasAttribute("role")){this.setAttribute("role","img")}return}this.updateAlt()},srcChanged:function(){var icon=this._icon||document.createElement("div");icon.textContent="";icon.setAttribute("fit","");icon.style.backgroundImage="url("+this.src+")";icon.style.backgroundPosition="center";icon.style.backgroundSize="100%";if(!icon.parentNode){this.appendChild(icon)}this._icon=icon},getIconset:function(name){return meta.byId(name||this.defaultIconset)},updateIcon:function(oldVal,newVal){if(!this.icon){this.updateAlt();return}var parts=String(this.icon).split(":");var icon=parts.pop();if(icon){var set=this.getIconset(parts.pop());if(set){this._icon=set.applyIcon(this,icon);if(this._icon){this._icon.setAttribute("fit","")}}}if(oldVal){if(oldVal.split(":").pop()==this.getAttribute("aria-label")){this.updateAlt()}}},updateAlt:function(){if(this.getAttribute("aria-hidden")){return}if(this.alt===""){this.setAttribute("aria-hidden","true");if(this.hasAttribute("role")){this.removeAttribute("role")}if(this.hasAttribute("aria-label")){this.removeAttribute("aria-label")}}else{this.setAttribute("aria-label",this.alt||this.icon.split(":").pop());if(!this.hasAttribute("role")){this.setAttribute("role","img")}if(this.hasAttribute("aria-hidden")){this.removeAttribute("aria-hidden")}}}})})();</script></polymer-element><polymer-element name="core-iconset-svg" extends="core-meta" attributes="iconSize" assetpath="../core-iconset-svg/"><script>Polymer("core-iconset-svg",{iconSize:24,type:"iconset",created:function(){this._icons={}},ready:function(){this.super();this.updateIcons()},iconById:function(id){return this._icons[id]||(this._icons[id]=this.querySelector('[id="'+id+'"]'))},cloneIcon:function(id){var icon=this.iconById(id);if(icon){var content=icon.cloneNode(true);content.removeAttribute("id");var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 "+this.iconSize+" "+this.iconSize);svg.style.pointerEvents="none";svg.appendChild(content);return svg}},get iconNames(){if(!this._iconNames){this._iconNames=this.findIconNames()}return this._iconNames},findIconNames:function(){var icons=this.querySelectorAll("[id]").array();if(icons.length){return icons.map(function(n){return n.id})}},applyIcon:function(element,icon){var root=element;var old=root.querySelector("svg");if(old){old.remove()}var svg=this.cloneIcon(icon);if(!svg){return}svg.setAttribute("height","100%");svg.setAttribute("width","100%");svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.display="block";root.insertBefore(svg,root.firstElementChild);return svg},updateIcons:function(selector,method){selector=selector||"[icon]";method=method||"updateIcon";var deep=window.ShadowDOMPolyfill?"":"html /deep/ ";var i$=document.querySelectorAll(deep+selector);for(var i=0,e;e=i$[i];i++){if(e[method]){e[method].call(e)}}}});</script></polymer-element><core-iconset-svg id="icons" iconsize="24"><svg><defs><g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"></path></g><g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"></path></g><g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"></path></g><g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g><g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"></path></g><g id="account-child"><circle cx="12" cy="13.49" r="1.5"></circle><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 2.5c1.24 0 2.25 1.01 2.25 2.25S13.24 9 12 9 9.75 7.99 9.75 6.75 10.76 4.5 12 4.5zm5 10.56v2.5c-.45.41-.96.77-1.5 1.05v-.68c0-.34-.17-.65-.46-.92-.65-.62-1.89-1.02-3.04-1.02-.96 0-1.96.28-2.65.73l-.17.12-.21.17c.78.47 1.63.72 2.54.82l1.33.15c.37.04.66.36.66.75 0 .29-.16.53-.4.66-.28.15-.64.09-.95.09-.35 0-.69-.01-1.03-.05-.5-.06-.99-.17-1.46-.33-.49-.16-.97-.38-1.42-.64-.22-.13-.44-.27-.65-.43l-.31-.24c-.04-.02-.28-.18-.28-.23v-4.28c0-1.58 2.63-2.78 5-2.78s5 1.2 5 2.78v1.78z"></path></g><g id="account-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"></path></g><g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"></path></g><g id="add-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"></path></g><g id="add-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"></path></g><g id="add-circle-outline"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"></path></g><g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"></path></g><g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"></path></g><g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"></path></g><g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C10.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1.65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"></path></g><g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"></path></g><g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"></path></g><g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"></path></g><g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"></path></g><g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"></path></g><g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path></g><g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"></path></g><g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"></path></g><g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"></path></g><g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></path></g><g id="aspect-ratio"><path d="M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"></path></g><g id="assessment"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"></path></g><g id="assignment"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"></path></g><g id="assignment-ind"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 4c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1.4c0-2 4-3.1 6-3.1s6 1.1 6 3.1V19z"></path></g><g id="assignment-late"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-6 15h-2v-2h2v2zm0-4h-2V8h2v6zm-1-9c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></g><g id="assignment-return"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm4 12h-4v3l-5-5 5-5v3h4v4z"></path></g><g id="assignment-returned"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 15l-5-5h3V9h4v4h3l-5 5z"></path></g><g id="assignment-turned-in"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 14l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g><g id="attachment"><path d="M7.5 18C4.46 18 2 15.54 2 12.5S4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v1.5H9.5c-.55 0-1 .45-1 1s.45 1 1 1H18c1.38 0 2.5-1.12 2.5-2.5S19.38 8.5 18 8.5H7.5c-2.21 0-4 1.79-4 4s1.79 4 4 4H17V18H7.5z"></path></g><g id="autorenew"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"></path></g><g id="backspace"><path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z"></path></g><g id="backup"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g><g id="block"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z"></path></g><g id="book"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></g><g id="bookmark"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"></path></g><g id="bookmark-outline"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g><g id="bug-report"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"></path></g><g id="cached"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z"></path></g><g id="cancel"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"></path></g><g id="check"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></g><g id="check-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path></g><g id="check-box-outline-blank"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g><g id="check-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path></g><g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path></g><g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></g><g id="class"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></g><g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g><g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g><g id="cloud"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"></path></g><g id="cloud-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.5 14H8c-1.66 0-3-1.34-3-3s1.34-3 3-3l.14.01C8.58 8.28 10.13 7 12 7c2.21 0 4 1.79 4 4h.5c1.38 0 2.5 1.12 2.5 2.5S17.88 16 16.5 16z"></path></g><g id="cloud-done"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM10 17l-3.5-3.5 1.41-1.41L10 14.17 15.18 9l1.41 1.41L10 17z"></path></g><g id="cloud-download"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"></path></g><g id="cloud-off"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4c-1.48 0-2.85.43-4.01 1.17l1.46 1.46C10.21 6.23 11.08 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45C23.16 18.16 24 16.68 24 15c0-2.64-2.05-4.78-4.65-4.96zM3 5.27l2.75 2.74C2.56 8.15 0 10.77 0 14c0 3.31 2.69 6 6 6h11.73l2 2L21 20.73 4.27 4 3 5.27zM7.73 10l8 8H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h1.73z"></path></g><g id="cloud-queue"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71C7.37 7.69 9.48 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3s-1.34 3-3 3z"></path></g><g id="cloud-upload"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g><g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"></path></g><g id="content-cut"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z"></path></g><g id="content-paste"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path></g><g id="create"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path></g><g id="credit-card"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g><g id="dashboard"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"></path></g><g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g><g id="description"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"></path></g><g id="dns"><path d="M20 13H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7 19c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g><g id="done"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></g><g id="done-all"><path d="M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z"></path></g><g id="drafts"><path d="M21.99 8c0-.72-.37-1.35-.94-1.7L12 1 2.95 6.3C2.38 6.65 2 7.28 2 8v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zM12 13L3.74 7.84 12 3l8.26 4.84L12 13z"></path></g><g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g><g id="event"><path d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"></path></g><g id="exit-to-app"><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g><g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g><g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path></g><g id="explore"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z"></path></g><g id="extension"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"></path></g><g id="face"><path d="M14.69 17.1c-.74.58-1.7.9-2.69.9s-1.95-.32-2.69-.9c-.22-.17-.53-.13-.7.09-.17.22-.13.53.09.7.91.72 2.09 1.11 3.3 1.11s2.39-.39 3.31-1.1c.22-.17.26-.48.09-.7-.17-.23-.49-.26-.71-.1z"></path><circle cx="8.5" cy="12.5" r="1"></circle><path d="M12 0C5.37 0 0 5.37 0 12s5.37 12 12 12 12-5.37 12-12S18.63 0 12 0zm7.96 14.82c-1.09 3.74-4.27 6.46-8.04 6.46-3.78 0-6.96-2.72-8.04-6.47-1.19-.11-2.13-1.18-2.13-2.52 0-1.27.85-2.31 1.97-2.5 2.09-1.46 3.8-3.49 4.09-5.05v-.01c1.35 2.63 6.3 5.19 11.83 5.06l.3-.03c1.28 0 2.31 1.14 2.31 2.54 0 1.38-1.02 2.51-2.29 2.52z"></path><circle cx="15.5" cy="12.5" r="1"></circle></g><g id="favorite"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"></path></g><g id="favorite-outline"><path d="M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"></path></g><g id="file-download"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path></g><g id="file-upload"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"></path></g><g id="filter-list"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path></g><g id="find-in-page"><path d="M20 19.59V8l-6-6H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c.45 0 .85-.15 1.19-.4l-4.43-4.43c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z"></path></g><g id="find-replace"><path d="M11 6c1.38 0 2.63.56 3.54 1.46L12 10h6V4l-2.05 2.05C14.68 4.78 12.93 4 11 4c-3.53 0-6.43 2.61-6.92 6H6.1c.46-2.28 2.48-4 4.9-4zm5.64 9.14c.66-.9 1.12-1.97 1.28-3.14H15.9c-.46 2.28-2.48 4-4.9 4-1.38 0-2.63-.56-3.54-1.46L10 12H4v6l2.05-2.05C7.32 17.22 9.07 18 11 18c1.55 0 2.98-.51 4.14-1.36L20 21.49 21.49 20l-4.85-4.86z"></path></g><g id="flag"><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"></path></g><g id="flip-to-back"><path d="M9 7H7v2h2V7zm0 4H7v2h2v-2zm0-8c-1.11 0-2 .9-2 2h2V3zm4 12h-2v2h2v-2zm6-12v2h2c0-1.1-.9-2-2-2zm-6 0h-2v2h2V3zM9 17v-2H7c0 1.1.89 2 2 2zm10-4h2v-2h-2v2zm0-4h2V7h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zM5 7H3v12c0 1.1.89 2 2 2h12v-2H5V7zm10-2h2V3h-2v2zm0 12h2v-2h-2v2z"></path></g><g id="flip-to-front"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z"></path></g><g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path></g><g id="folder-open"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"></path></g><g id="folder-shared"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4 8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z"></path></g><g id="forward"><path d="M12 8V4l8 8-8 8v-4H4V8z"></path></g><g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g><g id="fullscreen-exit"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></g><g id="gesture"><path d="M4.59 6.89c.7-.71 1.4-1.35 1.71-1.22.5.2 0 1.03-.3 1.52-.25.42-2.86 3.89-2.86 6.31 0 1.28.48 2.34 1.34 2.98.75.56 1.74.73 2.64.46 1.07-.31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79-3.78.64-5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1H21v-2.5h-2.47c-.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-.58.73-2.06 2.48-2.29 2.72-.25.3-.68.84-1.11.84-.45 0-.72-.83-.36-1.92.35-1.09 1.4-2.86 1.85-3.52.78-1.14 1.3-1.92 1.3-3.28C8.95 3.69 7.31 3 6.44 3 5.12 3 3.97 4 3.72 4.25c-.36.36-.66.66-.88.93l1.75 1.71zm9.29 11.66c-.31 0-.74-.26-.74-.72 0-.6.73-2.2 2.87-2.76-.3 2.69-1.43 3.48-2.13 3.48z"></path></g><g id="get-app"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path></g><g id="grade"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g><g id="group-work"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM8 17.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zM9.5 8c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5S9.5 9.38 9.5 8zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></g><g id="help"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path></g><g id="highlight-remove"><path d="M14.59 8L12 10.59 9.41 8 8 9.41 10.59 12 8 14.59 9.41 16 12 13.41 14.59 16 16 14.59 13.41 12 16 9.41 14.59 8zM12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"></path></g><g id="history"><path opacity=".9" d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g><g id="home"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path></g><g id="https"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g><g id="inbox"><path d="M19 3H4.99c-1.1 0-1.98.9-1.98 2L3 19c0 1.1.89 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.34 3-3 3s-3-1.34-3-3H4.99V5H19v10zm-3-5h-2V7h-4v3H8l4 4 4-4z"></path></g><g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g><g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"></path></g><g id="input"><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1v2h10v3z"></path></g><g id="invert-colors"><path d="M17.66 7.93L12 2.27 6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58c2.05 0 4.1-.78 5.66-2.34 3.12-3.12 3.12-8.19 0-11.31zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"></path></g><g id="label"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"></path></g><g id="label-outline"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"></path></g><g id="language"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"></path></g><g id="launch"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g><g id="link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></g><g id="list"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"></path></g><g id="lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g><g id="lock-open"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"></path></g><g id="lock-outline"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6-5.1c1.71 0 3.1 1.39 3.1 3.1v2H9V6h-.1c0-1.71 1.39-3.1 3.1-3.1zM18 20H6V10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"></path></g><g id="loyalty"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7zm11.77 8.27L13 19.54l-4.27-4.27C8.28 14.81 8 14.19 8 13.5c0-1.38 1.12-2.5 2.5-2.5.69 0 1.32.28 1.77.74l.73.72.73-.73c.45-.45 1.08-.73 1.77-.73 1.38 0 2.5 1.12 2.5 2.5 0 .69-.28 1.32-.73 1.77z"></path></g><g id="mail"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g><g id="markunread"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g><g id="markunread-mailbox"><path d="M20 6H10v6H8V4h6V0H6v6H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2z"></path></g><g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></g><g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g><g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g><g id="note-add"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 14h-3v3h-2v-3H8v-2h3v-3h2v3h3v2zm-3-7V3.5L18.5 9H13z"></path></g><g id="open-in-browser"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"></path></g><g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g><g id="open-with"><path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"></path></g><g id="pageview"><path d="M11 8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3zm8-5H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1.41 16l-3.83-3.83c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L19 17.59 17.59 19z"></path></g><g id="payment"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g><g id="perm-camera-mic"><path d="M20 5h-3.17L15 3H9L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7v-2.09c-2.83-.48-5-2.94-5-5.91h2c0 2.21 1.79 4 4 4s4-1.79 4-4h2c0 2.97-2.17 5.43-5 5.91V21h7c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-6 8c0 1.1-.9 2-2 2s-2-.9-2-2V9c0-1.1.9-2 2-2s2 .9 2 2v4z"></path></g><g id="perm-contact-cal"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1z"></path></g><g id="perm-data-setting"><path d="M18.99 11.5c.34 0 .67.03 1 .07L20 0 0 20h11.56c-.04-.33-.07-.66-.07-1 0-4.14 3.36-7.5 7.5-7.5zm3.71 7.99c.02-.16.04-.32.04-.49 0-.17-.01-.33-.04-.49l1.06-.83c.09-.08.12-.21.06-.32l-1-1.73c-.06-.11-.19-.15-.31-.11l-1.24.5c-.26-.2-.54-.37-.85-.49l-.19-1.32c-.01-.12-.12-.21-.24-.21h-2c-.12 0-.23.09-.25.21l-.19 1.32c-.3.13-.59.29-.85.49l-1.24-.5c-.11-.04-.24 0-.31.11l-1 1.73c-.06.11-.04.24.06.32l1.06.83c-.02.16-.03.32-.03.49 0 .17.01.33.03.49l-1.06.83c-.09.08-.12.21-.06.32l1 1.73c.06.11.19.15.31.11l1.24-.5c.26.2.54.37.85.49l.19 1.32c.02.12.12.21.25.21h2c.12 0 .23-.09.25-.21l.19-1.32c.3-.13.59-.29.84-.49l1.25.5c.11.04.24 0 .31-.11l1-1.73c.06-.11.03-.24-.06-.32l-1.07-.83zm-3.71 1.01c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g><g id="perm-device-info"><path d="M13 7h-2v2h2V7zm0 4h-2v6h2v-6zm4-9.99L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"></path></g><g id="perm-identity"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"></path></g><g id="perm-media"><path d="M2 6H0v5h.01L0 20c0 1.1.9 2 2 2h18v-2H2V6zm20-2h-8l-2-2H6c-1.1 0-1.99.9-1.99 2L4 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7 15l4.5-6 3.5 4.51 2.5-3.01L21 15H7z"></path></g><g id="perm-phone-msg"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM12 3v10l3-3h6V3h-9z"></path></g><g id="perm-scan-wifi"><path d="M12 3C6.95 3 3.15 4.85 0 7.23L12 22 24 7.25C20.85 4.87 17.05 3 12 3zm1 13h-2v-6h2v6zm-2-8V6h2v2h-2z"></path></g><g id="picture-in-picture"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"></path></g><g id="polymer"><path d="M19 4h-4L7.11 16.63 4.5 12 9 4H5L.5 12 5 20h4l7.89-12.63L19.5 12 15 20h4l4.5-8z"></path></g><g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"></path></g><g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zM12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g><g id="question-answer"><path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"></path></g><g id="radio-button-off"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g><g id="radio-button-on"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g><g id="receipt"><path d="M18 17H6v-2h12v2zm0-4H6v-2h12v2zm0-4H6V7h12v2zM3 22l1.5-1.5L6 22l1.5-1.5L9 22l1.5-1.5L12 22l1.5-1.5L15 22l1.5-1.5L18 22l1.5-1.5L21 22V2l-1.5 1.5L18 2l-1.5 1.5L15 2l-1.5 1.5L12 2l-1.5 1.5L9 2 7.5 3.5 6 2 4.5 3.5 3 2v20z"></path></g><g id="redeem"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g><g id="redo"><path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"></path></g><g id="refresh"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></g><g id="remove"><path d="M19 13H5v-2h14v2z"></path></g><g id="remove-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z"></path></g><g id="remove-circle-outline"><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"></path></g><g id="reorder"><path d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z"></path></g><g id="reply"><path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"></path></g><g id="reply-all"><path d="M7 8V5l-7 7 7 7v-3l-4-4 4-4zm6 1V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"></path></g><g id="report"><path d="M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15.73 3zM12 17.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2V7h2v6z"></path></g><g id="report-problem"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g><g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g><g id="room"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></g><g id="save"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"></path></g><g id="schedule"><path fill-opacity=".9" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zM12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g><g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></g><g id="select-all"><path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z"></path></g><g id="send"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path></g><g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></g><g id="settings-applications"><path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm7-7H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-1.75 9c0 .23-.02.46-.05.68l1.48 1.16c.13.11.17.3.08.45l-1.4 2.42c-.09.15-.27.21-.43.15l-1.74-.7c-.36.28-.76.51-1.18.69l-.26 1.85c-.03.17-.18.3-.35.3h-2.8c-.17 0-.32-.13-.35-.29l-.26-1.85c-.43-.18-.82-.41-1.18-.69l-1.74.7c-.16.06-.34 0-.43-.15l-1.4-2.42c-.09-.15-.05-.34.08-.45l1.48-1.16c-.03-.23-.05-.46-.05-.69 0-.23.02-.46.05-.68l-1.48-1.16c-.13-.11-.17-.3-.08-.45l1.4-2.42c.09-.15.27-.21.43-.15l1.74.7c.36-.28.76-.51 1.18-.69l.26-1.85c.03-.17.18-.3.35-.3h2.8c.17 0 .32.13.35.29l.26 1.85c.43.18.82.41 1.18.69l1.74-.7c.16-.06.34 0 .43.15l1.4 2.42c.09.15.05.34-.08.45l-1.48 1.16c.03.23.05.46.05.69z"></path></g><g id="settings-backup-restore"><path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9H0l4 4 4-4H5c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44C8.04 20.3 9.94 21 12 21c4.97 0 9-4.03 9-9s-4.03-9-9-9z"></path></g><g id="settings-bluetooth"><path d="M11 24h2v-2h-2v2zm-4 0h2v-2H7v2zm8 0h2v-2h-2v2zm2.71-18.29L12 0h-1v7.59L6.41 3 5 4.41 10.59 10 5 15.59 6.41 17 11 12.41V20h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 3.83l1.88 1.88L13 7.59V3.83zm1.88 10.46L13 16.17v-3.76l1.88 1.88z"></path></g><g id="settings-cell"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM16 .01L8 0C6.9 0 6 .9 6 2v16c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V2c0-1.1-.9-1.99-2-1.99zM16 16H8V4h8v12z"></path></g><g id="settings-display"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02zM8 16h2.5l1.5 1.5 1.5-1.5H16v-2.5l1.5-1.5-1.5-1.5V8h-2.5L12 6.5 10.5 8H8v2.5L6.5 12 8 13.5V16zm4-7c1.66 0 3 1.34 3 3s-1.34 3-3 3V9z"></path></g><g id="settings-ethernet"><path d="M7.77 6.76L6.23 5.48.82 12l5.41 6.52 1.54-1.28L3.42 12l4.35-5.24zM7 13h2v-2H7v2zm10-2h-2v2h2v-2zm-6 2h2v-2h-2v2zm6.77-7.52l-1.54 1.28L20.58 12l-4.35 5.24 1.54 1.28L23.18 12l-5.41-6.52z"></path></g><g id="settings-input-antenna"><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.12-2.5-2.5-2.5S9.5 10.62 9.5 12c0 1.02.62 1.9 1.5 2.29v3.3L7.59 21 9 22.41l3-3 3 3L16.41 21 13 17.59v-3.3zM12 1C5.93 1 1 5.93 1 12h2c0-4.97 4.03-9 9-9s9 4.03 9 9h2c0-6.07-4.93-11-11-11z"></path></g><g id="settings-input-component"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"></path></g><g id="settings-input-composite"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"></path></g><g id="settings-input-hdmi"><path d="M18 7V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v3H5v6l3 6v3h8v-3l3-6V7h-1zM8 4h8v3h-2V5h-1v2h-2V5h-1v2H8V4z"></path></g><g id="settings-input-svideo"><path d="M8 11.5c0-.83-.67-1.5-1.5-1.5S5 10.67 5 11.5 5.67 13 6.5 13 8 12.33 8 11.5zm7-5c0-.83-.67-1.5-1.5-1.5h-3C9.67 5 9 5.67 9 6.5S9.67 8 10.5 8h3c.83 0 1.5-.67 1.5-1.5zM8.5 15c-.83 0-1.5.67-1.5 1.5S7.67 18 8.5 18s1.5-.67 1.5-1.5S9.33 15 8.5 15zM12 1C5.93 1 1 5.93 1 12s4.93 11 11 11 11-4.93 11-11S18.07 1 12 1zm0 20c-4.96 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9zm5.5-11c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm-2 5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"></path></g><g id="settings-overscan"><path d="M12.01 5.5L10 8h4l-1.99-2.5zM18 10v4l2.5-1.99L18 10zM6 10l-2.5 2.01L6 14v-4zm8 6h-4l2.01 2.5L14 16zm7-13H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"></path></g><g id="settings-phone"><path d="M13 9h-2v2h2V9zm4 0h-2v2h2V9zm3 6.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 9v2h2V9h-2z"></path></g><g id="settings-power"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm2-22h-2v10h2V2zm3.56 2.44l-1.45 1.45C16.84 6.94 18 8.83 18 11c0 3.31-2.69 6-6 6s-6-2.69-6-6c0-2.17 1.16-4.06 2.88-5.12L7.44 4.44C5.36 5.88 4 8.28 4 11c0 4.42 3.58 8 8 8s8-3.58 8-8c0-2.72-1.36-5.12-3.44-6.56zM15 24h2v-2h-2v2z"></path></g><g id="settings-remote"><path d="M15 9H9c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V10c0-.55-.45-1-1-1zm-3 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM7.05 6.05l1.41 1.41C9.37 6.56 10.62 6 12 6s2.63.56 3.54 1.46l1.41-1.41C15.68 4.78 13.93 4 12 4s-3.68.78-4.95 2.05zM12 0C8.96 0 6.21 1.23 4.22 3.22l1.41 1.41C7.26 3.01 9.51 2 12 2s4.74 1.01 6.36 2.64l1.41-1.41C17.79 1.23 15.04 0 12 0z"></path></g><g id="settings-voice"><path d="M7 24h2v-2H7v2zm5-11c1.66 0 2.99-1.34 2.99-3L15 4c0-1.66-1.34-3-3-3S9 2.34 9 4v6c0 1.66 1.34 3 3 3zm-1 11h2v-2h-2v2zm4 0h2v-2h-2v2zm4-14h-1.7c0 3-2.54 5.1-5.3 5.1S6.7 13 6.7 10H5c0 3.41 2.72 6.23 6 6.72V20h2v-3.28c3.28-.49 6-3.31 6-6.72z"></path></g><g id="shop"><path d="M16 6V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H2v13c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6h-6zm-6-2h4v2h-4V4zM9 18V9l7.5 4L9 18z"></path></g><g id="shop-two"><path d="M3 9H1v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2H3V9zm15-4V3c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H5v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2V5h-5zm-6-2h4v2h-4V3zm0 12V8l5.5 3-5.5 4z"></path></g><g id="shopping-basket"><path d="M17.21 9l-4.38-6.56c-.19-.28-.51-.42-.83-.42-.32 0-.64.14-.83.43L6.79 9H2c-.55 0-1 .45-1 1 0 .09.01.18.04.27l2.54 9.27c.23.84 1 1.46 1.92 1.46h13c.92 0 1.69-.62 1.93-1.46l2.54-9.27L23 10c0-.55-.45-1-1-1h-4.79zM9 9l3-4.4L15 9H9zm3 8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g><g id="shopping-cart"><path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"></path></g><g id="sort"><path d="M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z"></path></g><g id="speaker-notes"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM8 14H6v-2h2v2zm0-3H6V9h2v2zm0-3H6V6h2v2zm7 6h-5v-2h5v2zm3-3h-8V9h8v2zm0-3h-8V6h8v2z"></path></g><g id="spellcheck"><path d="M12.45 16h2.09L9.43 3H7.57L2.46 16h2.09l1.12-3h5.64l1.14 3zm-6.02-5L8.5 5.48 10.57 11H6.43zm15.16.59l-8.09 8.09L9.83 16l-1.41 1.41 5.09 5.09L23 13l-1.41-1.41z"></path></g><g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g><g id="star-half"><path d="M22 9.74l-7.19-.62L12 2.5 9.19 9.13 2 9.74l5.46 4.73-1.64 7.03L12 17.77l6.18 3.73-1.63-7.03L22 9.74zM12 15.9V6.6l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.9z"></path></g><g id="star-outline"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"></path></g><g id="star-rate"><path d="M12 14.3l3.71 2.7-1.42-4.36L18 10h-4.55L12 5.5 10.55 10H6l3.71 2.64L8.29 17z"></path></g><g id="stars"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm4.24 16L12 15.45 7.77 18l1.12-4.81-3.73-3.23 4.92-.42L12 5l1.92 4.53 4.92.42-3.73 3.23L16.23 18z"></path></g><g id="store"><path d="M20 4H4v2h16V4zm1 10v-2l-1-5H4l-1 5v2h1v6h10v-6h4v6h2v-6h1zm-9 4H6v-4h6v4z"></path></g><g id="subject"><path d="M14 17H4v2h10v-2zm6-8H4v2h16V9zM4 15h16v-2H4v2zM4 5v2h16V5H4z"></path></g><g id="supervisor-account"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5S17.88 7 16.5 7C15.12 7 14 8.12 14 9.5s1.12 2.5 2.5 2.5zM9 11c1.66 0 2.99-1.34 2.99-3S10.66 5 9 5C7.34 5 6 6.34 6 8s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75V19h11v-2.25c0-1.83-3.67-2.75-5.5-2.75zM9 13c-2.33 0-7 1.17-7 3.5V19h7v-2.25c0-.85.33-2.34 2.37-3.47C10.5 13.1 9.66 13 9 13z"></path></g><g id="swap-horiz"><path d="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z"></path></g><g id="swap-vert"><path d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z"></path></g><g id="swap-vert-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM6.5 9L10 5.5 13.5 9H11v4H9V9H6.5zm11 6L14 18.5 10.5 15H13v-4h2v4h2.5z"></path></g><g id="system-update-tv"><path d="M12 16.5l4-4h-3v-9h-2v9H8l4 4zm9-13h-6v1.99h6v14.03H3V5.49h6V3.5H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2z"></path></g><g id="tab"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h10v4h8v10z"></path></g><g id="tab-unselected"><path d="M1 9h2V7H1v2zm0 4h2v-2H1v2zm0-8h2V3c-1.1 0-2 .9-2 2zm8 16h2v-2H9v2zm-8-4h2v-2H1v2zm2 4v-2H1c0 1.1.9 2 2 2zM21 3h-8v6h10V5c0-1.1-.9-2-2-2zm0 14h2v-2h-2v2zM9 5h2V3H9v2zM5 21h2v-2H5v2zM5 5h2V3H5v2zm16 16c1.1 0 2-.9 2-2h-2v2zm0-8h2v-2h-2v2zm-8 8h2v-2h-2v2zm4 0h2v-2h-2v2z"></path></g><g id="text-format"><path d="M5 17v2h14v-2H5zm4.5-4.2h5l.9 2.2h2.1L12.75 4h-1.5L6.5 15h2.1l.9-2.2zM12 5.98L13.87 11h-3.74L12 5.98z"></path></g><g id="theaters"><path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z"></path></g><g id="thumb-down"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"></path></g><g id="thumb-up"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"></path></g><g id="thumbs-up-down"><path d="M12 6c0-.55-.45-1-1-1H5.82l.66-3.18.02-.23c0-.31-.13-.59-.33-.8L5.38 0 .44 4.94C.17 5.21 0 5.59 0 6v6.5c0 .83.67 1.5 1.5 1.5h6.75c.62 0 1.15-.38 1.38-.91l2.26-5.29c.07-.17.11-.36.11-.55V6zm10.5 4h-6.75c-.62 0-1.15.38-1.38.91l-2.26 5.29c-.07.17-.11.36-.11.55V18c0 .55.45 1 1 1h5.18l-.66 3.18-.02.24c0 .31.13.59.33.8l.79.78 4.94-4.94c.27-.27.44-.65.44-1.06v-6.5c0-.83-.67-1.5-1.5-1.5z"></path></g><g id="toc"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"></path></g><g id="today"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"></path></g><g id="track-changes"><path fill="#231F20" d="M19.07 4.93l-1.41 1.41C19.1 7.79 20 9.79 20 12c0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02C8.16 6.57 6 9.03 6 12c0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41C15.55 9.9 16 10.9 16 12c0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V2h-1C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"></path></g><g id="translate"><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"></path></g><g id="trending-down"><path d="M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z"></path></g><g id="trending-neutral"><path d="M22 12l-4-4v3H3v2h15v3z"></path></g><g id="trending-up"><path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z"></path></g><g id="turned-in"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"></path></g><g id="turned-in-not"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g><g id="undo"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"></path></g><g id="unfold-less"><path d="M7.41 18.59L8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"></path></g><g id="unfold-more"><path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"></path></g><g id="verified-user"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g><g id="view-agenda"><path d="M20 13H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm0-10H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1z"></path></g><g id="view-array"><path d="M4 18h3V5H4v13zM18 5v13h3V5h-3zM8 18h9V5H8v13z"></path></g><g id="view-carousel"><path d="M7 19h10V4H7v15zm-5-2h4V6H2v11zM18 6v11h4V6h-4z"></path></g><g id="view-column"><path d="M10 18h5V5h-5v13zm-6 0h5V5H4v13zM16 5v13h5V5h-5z"></path></g><g id="view-day"><path d="M2 21h19v-3H2v3zM20 8H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zM2 3v3h19V3H2z"></path></g><g id="view-headline"><path d="M4 15h17v-2H4v2zm0 4h17v-2H4v2zm0-8h17V9H4v2zm0-6v2h17V5H4z"></path></g><g id="view-list"><path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z"></path></g><g id="view-module"><path d="M4 11h5V5H4v6zm0 7h5v-6H4v6zm6 0h5v-6h-5v6zm6 0h5v-6h-5v6zm-6-7h5V5h-5v6zm6-6v6h5V5h-5z"></path></g><g id="view-quilt"><path d="M10 18h5v-6h-5v6zm-6 0h5V5H4v13zm12 0h5v-6h-5v6zM10 5v6h11V5H10z"></path></g><g id="view-stream"><path d="M4 18h17v-6H4v6zM4 5v6h17V5H4z"></path></g><g id="view-week"><path d="M6 5H3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zm14 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zm-7 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1z"></path></g><g id="visibility"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path></g><g id="visibility-off"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"></path></g><g id="wallet-giftcard"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g><g id="wallet-membership"><path d="M20 2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h4v5l4-2 4 2v-5h4c1.11 0 2-.89 2-2V4c0-1.11-.89-2-2-2zm0 13H4v-2h16v2zm0-5H4V4h16v6z"></path></g><g id="wallet-travel"><path d="M20 6h-3V4c0-1.11-.89-2-2-2H9c-1.11 0-2 .89-2 2v2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zM9 4h6v2H9V4zm11 15H4v-2h16v2zm0-5H4V8h3v2h2V8h6v2h2V8h3v6z"></path></g><g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g><g id="work"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"></path></g></defs></svg></core-iconset-svg><polymer-element name="core-icon-button" attributes="src icon active" assetpath="../core-icon-button/"><template><style>:host { display: inline-block; box-sizing: border-box; -moz-box-sizing: border-box; user-select: none; -moz-user-select: none; -webkit-user-select: none; border-radius: 2px; padding: 7px; margin: 2px; vertical-align: middle; font-size: 1rem; cursor: pointer;}:host([disabled]) { opacity: 0.6; pointer-events: none;}:host(.outline) { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);}:host(:hover:not([disabled])) { box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.1);}:host(.selected:not([disabled])) { background-color: rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(0, 0, 0, 0.12);}:host(:active:not([disabled]), .selected:active:not([disabled])) { background-color: rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.12);}:host(.core-dark-theme.outline) { background-color: rgba(200, 200, 200, 0.05); box-shadow: 0 0 0 1px rgba(200, 200, 200, 0.1);}:host(.core-dark-theme:hover) { background-color: rgba(200, 200, 200, 0.05); box-shadow: 0 1px 0 0 rgba(200, 200, 200, 0.12), 0 0 0 1px rgba(200, 200, 200, 0.1);}:host(.core-dark-theme.selected) { background-color: rgba(220, 220, 220, 0.05); box-shadow: inset 0 1px 0 0 rgba(200, 200, 200, 0.05), 0 0 0 1px rgba(200, 200, 200, 0.12);}:host(.core-dark-theme:active, .core-dark-theme.selected:active) { background-color: rgba(200, 200, 200, 0.05); box-shadow: inset 0 1px 0 0 rgba(200, 200, 200, 0.1), 0 0 0 1px rgba(200, 200, 200, 0.12);}core-icon { pointer-events: none;}:host ::content > :not(core-icon) { margin-left: 4px;}</style><core-icon src="{{src}}" icon="{{icon}}"></core-icon><content></content></template><script>Polymer("core-icon-button",{src:"",active:false,icon:"",activeChanged:function(){this.classList.toggle("selected",this.active)}});</script></polymer-element><polymer-element name="core-toolbar" attributes="justify middleJustify bottomJustify" assetpath="../core-toolbar/"><template><style>:host { display: block; position: relative; box-sizing: border-box; -moz-box-sizing: border-box; height: 64px; font-size: 1.3em; background-color: #CFD8DC;}:host(.animate) { transition: height 0.18s ease-in;}:host(.medium-tall) { height: 128px;}:host(.tall) { height: 192px;}.toolbar-tools { position: relative; height: 64px; padding: 0 8px; pointer-events: none;}:host(.core-narrow),:host-context(.core-narrow) { height: 56px;}polyfill-next-selector { content: ':host.core-narrow.medium-tall, .core-narrow :host.medium-tall'; }:host(.core-narrow.medium-tall),:host-context(.core-narrow):host(.medium-tall) { height: 112px;}polyfill-next-selector { content: ':host.core-narrow.tall, .core-narrow :host.tall'; }:host(.core-narrow.tall),:host-context(.core-narrow):host(.tall) { height: 168px;}polyfill-next-selector { content: ':host.core-narrow .toolbar-tools, .core-narrow :host .toolbar-tools'; }:host(.core-narrow) .toolbar-tools,:host-context(.core-narrow) .toolbar-tools { height: 56px; padding: 0;}#middleBar { position: absolute; top: 0; right: 0; left: 0;}:host(.tall, .medium-tall) #middleBar { -webkit-transform: translateY(100%); transform: translateY(100%);}#bottomBar { position: absolute; right: 0; bottom: 0; left: 0;}polyfill-next-selector { content: '.toolbar-tools > *:not([disabled])'; }::content > *:not([disabled]) { pointer-events: auto;}polyfill-next-selector { content: '.toolbar-tools > *'; }::content > * { margin: 0 8px;}polyfill-next-selector { content: '.toolbar-tools > .fit'; }::content > .fit { position: absolute; top: auto; right: 0; bottom: 0; left: 0; width: auto; margin: 0;}polyfill-next-selector { content: ':host .indent'; }::content > .indent { margin-left: 60px;}</style><div id="bottomBar" class="toolbar-tools" center="" horizontal="" layout=""><content select=".bottom"></content></div><div id="middleBar" class="toolbar-tools" center="" horizontal="" layout=""><content select=".middle"></content></div><div id="topBar" class="toolbar-tools" center="" horizontal="" layout=""><content></content></div></template><script>(function(){Polymer("core-toolbar",{justify:"",middleJustify:"",bottomJustify:"",justifyChanged:function(old){this.updateBarJustify(this.$.topBar,this.justify,old)},middleJustifyChanged:function(old){this.updateBarJustify(this.$.middleBar,this.middleJustify,old)},bottomJustifyChanged:function(old){this.updateBarJustify(this.$.bottomBar,this.bottomJustify,old)},updateBarJustify:function(bar,justify,old){if(old){bar.removeAttribute(this.toLayoutAttrName(old))}if(justify){bar.setAttribute(this.toLayoutAttrName(justify),"")}},toLayoutAttrName:function(value){return value==="between"?"justified":value+"-justified"}})})();</script></polymer-element><polymer-element name="core-header-panel" assetpath="../core-header-panel/"><template><style>:host { display: block; position: relative;}#outerContainer { position: absolute; top: 0; right: 0; bottom: 0; left: 0;}#mainPanel { position: relative;}#mainContainer { position: relative; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch;}#dropShadow { position: absolute; top: 0; left: 0; right: 0; height: 6px; box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);}#dropShadow.hidden { display: none;}:host([mode=scroll]) #mainContainer { overflow: visible;}:host([mode=scroll]) #outerContainer { overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch;}:host([mode=cover]) #mainPanel { position: static;}:host([mode=cover]) #mainContainer { position: absolute; top: 0; right: 0; bottom: 0; left: 0;}:host([mode=cover]) #dropShadow { position: static; width: 100%;}</style><div id="outerContainer" vertical="" layout=""><content id="headerContent" select="core-toolbar, .core-header"></content><div id="mainPanel" flex="" vertical="" layout=""><div id="mainContainer" flex?="{{mode !== 'cover'}}"><content id="mainContent" select="*"></content></div><div id="dropShadow"></div></div></div></template><script>Polymer("core-header-panel",{publish:{mode:{value:"",reflect:true},tallClass:"tall",shadow:false},animateDuration:200,modeConfigs:{shadowMode:{waterfall:1,"waterfall-tall":1},noShadow:{seamed:1,cover:1,scroll:1},tallMode:{"waterfall-tall":1},outerScroll:{scroll:1}},ready:function(){this.scrollHandler=this.scroll.bind(this);this.addListener()},detached:function(){this.removeListener(this.mode)},addListener:function(){this.scroller.addEventListener("scroll",this.scrollHandler)},removeListener:function(mode){var s=this.getScrollerForMode(mode);s.removeEventListener("scroll",this.scrollHandler)},domReady:function(){this.async("scroll")},modeChanged:function(old){var configs=this.modeConfigs;var header=this.header;if(header){if(configs.tallMode[old]&&!configs.tallMode[this.mode]){header.classList.remove(this.tallClass);this.async(function(){header.classList.remove("animate")},null,this.animateDuration)}else{header.classList.toggle("animate",configs.tallMode[this.mode])}}if(configs&&(configs.outerScroll[this.mode]||configs.outerScroll[old])){this.removeListener(old);this.addListener()}this.scroll()},get header(){return this.$.headerContent.getDistributedNodes()[0]},getScrollerForMode:function(mode){return this.modeConfigs.outerScroll[mode]?this.$.outerContainer:this.$.mainContainer},get scroller(){return this.getScrollerForMode(this.mode)},scroll:function(){var configs=this.modeConfigs;var main=this.$.mainContainer;var header=this.header;var sTop=main.scrollTop;var atTop=sTop===0;this.$.dropShadow.classList.toggle("hidden",!this.shadow&&(atTop&&configs.shadowMode[this.mode]||configs.noShadow[this.mode]));if(header&&configs.tallMode[this.mode]){header.classList.toggle(this.tallClass,atTop||header.classList.contains(this.tallClass)&&main.scrollHeight<this.$.outerContainer.offsetHeight)}this.fire("scroll",{target:this.scroller},this,false)}});</script></polymer-element><polymer-element name="marked-element" attributes="text" assetpath="../marked-element/"><script>Polymer("marked-element",{text:"",attached:function(){marked.setOptions({highlight:this.highlight.bind(this)});if(!this.text){this.text=this.innerHTML}},textChanged:function(oldVal,newVal){if(newVal){this.innerHTML=marked(this.text)}},highlight:function(code,lang){var event=this.fire("marked-js-highlight",{code:code,lang:lang});return event.detail.code||code}});</script></polymer-element><polymer-element name="core-xhr" hidden="" assetpath="../core-ajax/"><script>Polymer("core-xhr",{request:function(options){var xhr=new XMLHttpRequest;var url=options.url;var method=options.method||"GET";var async=!options.sync;var params=this.toQueryString(options.params);if(params&&method.toUpperCase()=="GET"){url+=(url.indexOf("?")>0?"&":"?")+params}var xhrParams=this.isBodyMethod(method)?options.body||params:null;xhr.open(method,url,async);if(options.responseType){xhr.responseType=options.responseType}if(options.withCredentials){xhr.withCredentials=true}this.makeReadyStateHandler(xhr,options.callback);this.setRequestHeaders(xhr,options.headers);xhr.send(xhrParams);if(!async){xhr.onreadystatechange(xhr)}return xhr},toQueryString:function(params){var r=[];for(var n in params){var v=params[n];n=encodeURIComponent(n);r.push(v==null?n:n+"="+encodeURIComponent(v))}return r.join("&")},isBodyMethod:function(method){return this.bodyMethods[(method||"").toUpperCase()]},bodyMethods:{POST:1,PUT:1,PATCH:1,DELETE:1},makeReadyStateHandler:function(xhr,callback){xhr.onreadystatechange=function(){if(xhr.readyState==4){callback&&callback.call(null,xhr.response,xhr)}}},setRequestHeaders:function(xhr,headers){if(headers){for(var name in headers){xhr.setRequestHeader(name,headers[name])}}}});</script></polymer-element><polymer-element name="core-ajax" hidden="" attributes="url handleAs auto params response error method headers body contentType withCredentials progress loading" assetpath="../core-ajax/"><script>Polymer("core-ajax",{url:"",handleAs:"",auto:false,params:"",response:null,error:null,loading:false,progress:null,method:"",headers:null,body:null,contentType:"application/x-www-form-urlencoded",withCredentials:false,xhrArgs:null,created:function(){this.progress={}},ready:function(){this.xhr=document.createElement("core-xhr")},receive:function(response,xhr){if(this.isSuccess(xhr)){this.processResponse(xhr)}else{this.processError(xhr)}this.complete(xhr)},isSuccess:function(xhr){var status=xhr.status||0;return status>=200&&status<300},processResponse:function(xhr){var response=this.evalResponse(xhr);if(xhr===this.activeRequest){this.response=response}this.fire("core-response",{response:response,xhr:xhr})},processError:function(xhr){var response=this.evalResponse(xhr);var error={statusCode:xhr.status,response:response};if(xhr===this.activeRequest){this.error=error}this.fire("core-error",{response:error,xhr:xhr})},processProgress:function(progress,xhr){if(xhr!==this.activeRequest){return}var progressProxy={lengthComputable:progress.lengthComputable,loaded:progress.loaded,total:progress.total};this.progress=progressProxy},complete:function(xhr){if(xhr===this.activeRequest){this.loading=false}this.fire("core-complete",{response:xhr.status,xhr:xhr})},evalResponse:function(xhr){return this[(this.handleAs||"text")+"Handler"](xhr)},xmlHandler:function(xhr){return xhr.responseXML},textHandler:function(xhr){return xhr.responseText},jsonHandler:function(xhr){var r=xhr.responseText;try{return JSON.parse(r)}catch(x){console.warn("core-ajax caught an exception trying to parse response as JSON:");console.warn("url:",this.url);console.warn(x);return r}},documentHandler:function(xhr){return xhr.response},blobHandler:function(xhr){return xhr.response},arraybufferHandler:function(xhr){return xhr.response},urlChanged:function(){if(!this.handleAs){var ext=String(this.url).split(".").pop();switch(ext){case"json":this.handleAs="json";break}}this.autoGo()},paramsChanged:function(){this.autoGo()},bodyChanged:function(){this.autoGo()},autoChanged:function(){this.autoGo()},autoGo:function(){if(this.auto){this.goJob=this.job(this.goJob,this.go,0)}},getParams:function(params){params=this.params||params;if(params&&typeof params=="string"){params=JSON.parse(params)}return params},go:function(){var args=this.xhrArgs||{};args.body=this.body||args.body;args.params=this.getParams(args.params);args.headers=this.headers||args.headers||{};if(args.headers&&typeof args.headers=="string"){args.headers=JSON.parse(args.headers)}var hasContentType=Object.keys(args.headers).some(function(header){return header.toLowerCase()==="content-type"});if(args.body instanceof FormData){delete args.headers["Content-Type"]}else if(!hasContentType&&this.contentType){args.headers["Content-Type"]=this.contentType}if(this.handleAs==="arraybuffer"||this.handleAs==="blob"||this.handleAs==="document"){args.responseType=this.handleAs}args.withCredentials=this.withCredentials;args.callback=this.receive.bind(this);args.url=this.url;args.method=this.method;this.response=this.error=this.progress=null;this.activeRequest=args.url&&this.xhr.request(args);if(this.activeRequest){this.loading=true;var activeRequest=this.activeRequest;if("onprogress"in activeRequest){this.activeRequest.addEventListener("progress",function(progress){this.processProgress(progress,activeRequest)}.bind(this),false)}else{this.progress={lengthComputable:false}}}return this.activeRequest},abort:function(){if(!this.activeRequest)return;this.activeRequest.abort();this.activeRequest=null;this.progress={};this.loading=false}});</script></polymer-element><polymer-element name="context-free-parser" attributes="url text data" assetpath="../context-free-parser/"><template><core-ajax url="{{url}}" response="{{text}}" auto=""></core-ajax></template><script>Polymer("context-free-parser",{text:null,textChanged:function(){if(this.text){var entities=ContextFreeParser.parse(this.text);if(!entities||entities.length===0){entities=[{name:this.url.split("/").pop(),description:"**Undocumented**"}]}this.data={classes:entities}}},dataChanged:function(){this.fire("data-ready")}});</script></polymer-element><polymer-element name="core-doc-page" attributes="data" relative="" assetpath="../core-doc-viewer/elements/"><template><style>:host { display: block; font-family: Roboto;}#info > * { margin-right: 20px;}core-icon { margin-right: 5px;}.main { padding: 0 72px; max-width: 832px; margin: 0 auto;}marked-element { display: block;}h1 { color: #E91E63; font-size: 52px; line-height: 60px; font-weight: 300;}h3 { font-weight: 500;}.box { margin-bottom: 40px;}.box:not(.top) .details { padding: 16px;}.box:not(.top) .details .params { margin-top: 40px;}.params > p:first-child { text-decoration: underline;}.box:not(.top) h3 { padding: 16px; color: white; font-weight: inherit; font-size: 20px; line-height: 48px; margin: 0;}.box:not(.top) pre { padding: initial; background-color: transparent; margin: initial; font-size: 12px;}.box code { color: currentcolor; font-weight: 500;}.inheritance { border-bottom: 1px solid #eee; border-top: 1px solid #eee; padding: 16px 0;}.inheritance h3 { margin: 0 10px 0 0;}.inheritance .top > * { margin-right: 7px;}.top b,.top strong { text-transform: uppercase; font-size: 14px;}.top pre { background-color: rgb(250, 250, 250); padding: 16px;}pre { max-width: 832px; white-space: pre-wrap; overflow: hidden; border: none;}.attribute-box .details { background-color: #ffcbbb; border-bottom: 1px solid rgba(255, 86, 33, 0.5);}.attribute-box h3 { background-color: #ff5621;}.property-box .details { background-color: #fbe7b1; border-bottom: 1px solid rgba(243, 179, 0, 0.5);}.property-box h3 { background-color: #f3b300;}.method-box .details { background-color: #a6ffea; border-bottom: 1px solid rgba(0, 190, 164, 0.5);}.method-box h3 { background-color: #00bea4;}.event-box .details { background-color: #c5d9fb; border-bottom: 1px solid rgba(65, 132, 243, 0.5);}.event-box h3 { background-color: #4184f3;}.badge { color: currentcolor;}code, pre { color: #9f499b; font-family: "Source Code Pro",Monaco,Menlo,Consolas,"Courier New",monospace;}pre .typ,pre .inline,.prettyprint .typ,.prettyprint .inline { color: #6b499f}pre .pun,.prettyprint .pun { color: #5c6bc0}pre .str,pre .string,.prettyprint .str,.prettyprint .string { color: #ff4081}pre .pln,.prettyprint .pln { color: #7986cb}pre .kwd,.prettyprint .kwd { color: #d61a7f}pre .atn,pre .attribute-name,.prettyprint .atn,.prettyprint .attribute-name { color: #6b499f}pre .atv,pre .attribute-value,.prettyprint .atv,.prettyprint .attribute-value { color: #7986cb}pre .com,pre .comment,.prettyprint .com,.prettyprint .comment { color: #8a8a8a}</style><core-header-panel id="panel" mode="waterfall" fit=""><div class="main" on-marked-js-highlight="{{hilight}}"><h1>{{data.name}}</h1><p id="info" layout="" horizontal="" center=""><span layout="" horizontal="" center=""><core-icon icon="home"></core-icon><a href="{{data | homepageFilter}}">Home Page</a></span><span layout="" horizontal="" center="" hidden?="{{!data.version}}"><core-icon icon="info-outline"></core-icon>Version: {{data.version}}</span></p><template bind="{{data as data}}" if="{{data.extends || data.mixins}}"><div class="inheritance"><template if="{{data.extends}}"><section class="top extends" layout="" horizontal="" center=""><h3 id="{{data.name}}.extends">Extends:</h3><template repeat="{{e, i in data.extends}}"><div><template if="{{e.url}}"><a href="{{e.url}}">{{e.name}}</a></template><template if="{{!e.url}}"><a href="#{{e.name}}">{{e.name}}</a></template><span hidden?="{{i == data.extends.length - 1}}">,</span></div></template></section></template><template if="{{data.mixins}}"><section class="top mixins" layout="" horizontal="" center=""><h3 id="{{data.name}}.mixins">Mixins:</h3><template repeat="{{e, i in data.mixins}}"><div><template if="{{e.url}}"><a href="{{e.url ? e.url : e.name}}">{{e.name}}</a></template><template if="{{!e.url}}"><span>{{e.name}}</span></template><span hidden?="{{i == data.mixins.length - 1}}">,</span></div></template></section></template></div></template><template if="{{data.description}}"><section class="box top"><h3 id="{{data.name}}.summary">Summary</h3><marked-element text="{{data.description}}"></marked-element></section></template><template if="{{data.attributes.length}}"><section class="box attribute-box"><h3 id="{{data.name}}.attributes">Attributes</h3><template repeat="{{attribute in data.attributes}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.attributes.{{attribute.name}}"><p><code>{{attribute.name}}</code></p></div><div class="details-info" flex="" three=""><p layout="" horizontal="" center="" justified=""><code>&lt;<em>{{attribute.type}}</em>&gt;</code><span class="default" hidden?="{{!attribute.default}}">default: <code>{{attribute.default}}</code></span></p><marked-element text="{{attribute.description}}"></marked-element></div></div></template></section></template><template if="{{data.properties.length}}"><section class="box property-box"><h3 id="{{data.name}}.properties">Properties</h3><template repeat="{{property in data.properties}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.properties.{{property.name}}"><p><code>{{property.name}}</code></p></div><div class="details-info" flex="" three=""><p layout="" horizontal="" center="" justified=""><code>&lt;<em>{{property.type}}</em>&gt;</code><span class="default" hidden?="{{!property.default}}">default: <code>{{property.default}}</code></span></p><marked-element text="{{property.description}}"></marked-element></div></div></template></section></template><template if="{{data.events.length}}"><section class="box event-box"><h3 id="{{data.name}}.events">Events</h3><template repeat="{{event in data.events}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.events.{{event.name}}"><p><code>{{event.name}}</code></p></div><div class="details-info" flex="" three=""><marked-element text="{{event.description}}"></marked-element><template if="{{event.params.length}}"><div class="params"><p>Event details:</p><template repeat="{{param in event.params}}"><p><code>&lt;<em>{{param.type}}</em>&gt; {{param.name}}</code></p><p><span>{{param.description}}</span></p></template></div></template></div></div></template></section></template><template if="{{data.methods.length}}"><section class="box method-box"><h3 id="{{data.name}}.methods">Methods</h3><template repeat="{{method in data.methods}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.methods.{{method.name}}"><p><code>{{method.name}}</code></p></div><div class="details-info" flex="" three=""><marked-element text="{{method.description}}"></marked-element><template if="{{method.params.length}}"><div class="params"><p>Method parameters:</p><template repeat="{{param in method.params}}"><p><code>&lt;<em>{{param.type}}</em>&gt; {{param.name}}</code></p><p><span>{{param.description}}</span></p></template></div></template><template if="{{method.return}}"><div class="params"><p>Returns:</p><p><code>&lt;<em>{{method.return.type}}</em>&gt;</code></p><p><span>{{method.return.description}}</span></p></div></template></div></div></template></section></template></div></core-header-panel></template><script>Polymer("core-doc-page",{hilight:function(event,detail,sender){detail.code=prettyPrintOne((detail.code||"").replace(/</g,"&lt;").replace(/>/g,"&gt;"))},homepageFilter:function(data){if(!data){return""}if(!data.homepage||data.homepage==="github.io"){return"//polymer.github.io/"+data.name}else{return data.homepage}},dataChanged:function(){this.async(function(){var elementToFocus=this.shadowRoot.getElementById(window.location.hash.slice(1));if(elementToFocus){elementToFocus.scrollIntoView()}else{var viewer=this.$.panel.scroller;viewer.scrollTop=0;viewer.scrollLeft=0}})}});</script></polymer-element><polymer-element name="core-selection" attributes="multi" hidden="" assetpath="../core-selection/"><script>Polymer("core-selection",{multi:false,ready:function(){this.clear()},clear:function(){this.selection=[]},getSelection:function(){return this.multi?this.selection:this.selection[0]},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!==undefined&&item!==null){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}this.fire("core-select",{isSelected:isSelected,item:item})}},select:function(item){if(this.multi){this.toggle(item)}else if(this.getSelection()!==item){this.setItemSelected(this.getSelection(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}});</script></polymer-element><polymer-element name="core-selector" attributes="selected multi valueattr selectedClass selectedProperty selectedAttribute selectedItem selectedModel selectedIndex notap excludedLocalNames target itemsSelector activateEvent" assetpath="../core-selector/"><template><core-selection id="selection" multi="{{multi}}" on-core-select="{{selectionSelect}}"></core-selection><content id="items" select="*"></content></template><script>Polymer("core-selector",{selected:null,multi:false,valueattr:"name",selectedClass:"core-selected",selectedProperty:"",selectedAttribute:"active",selectedItem:null,selectedModel:null,selectedIndex:-1,excludedLocalNames:"",target:null,itemsSelector:"",activateEvent:"tap",notap:false,defaultExcludedLocalNames:"template",observe:{"selected multi":"selectedChanged"},ready:function(){this.activateListener=this.activateHandler.bind(this);this.itemFilter=this.filterItem.bind(this);this.excludedLocalNamesChanged();this.observer=new MutationObserver(this.updateSelected.bind(this));if(!this.target){this.target=this}},get items(){if(!this.target){return[]}var nodes=this.target!==this?this.itemsSelector?this.target.querySelectorAll(this.itemsSelector):this.target.children:this.$.items.getDistributedNodes();return Array.prototype.filter.call(nodes,this.itemFilter)},filterItem:function(node){return!this._excludedNames[node.localName]},excludedLocalNamesChanged:function(){this._excludedNames={};var s=this.defaultExcludedLocalNames;if(this.excludedLocalNames){s+=" "+this.excludedLocalNames}s.split(/\s+/g).forEach(function(n){this._excludedNames[n]=1},this)},targetChanged:function(old){if(old){this.removeListener(old);this.observer.disconnect();this.clearSelection()}if(this.target){this.addListener(this.target);this.observer.observe(this.target,{childList:true});this.updateSelected()}},addListener:function(node){Polymer.addEventListener(node,this.activateEvent,this.activateListener)},removeListener:function(node){Polymer.removeEventListener(node,this.activateEvent,this.activateListener)},get selection(){return this.$.selection.getSelection()},selectedChanged:function(){if(arguments.length===1){this.processSplices(arguments[0])}else{this.updateSelected()}},updateSelected:function(){this.validateSelected();if(this.multi){this.clearSelection(this.selected);this.selected&&this.selected.forEach(function(s){this.setValueSelected(s,true)},this)}else{this.valueToSelection(this.selected)}},validateSelected:function(){if(this.multi&&!Array.isArray(this.selected)&&this.selected!=null){this.selected=[this.selected]}else if(!this.multi&&Array.isArray(this.selected)){var s=this.selected[0];this.clearSelection([s]);this.selected=s}},processSplices:function(splices){for(var i=0,splice;splice=splices[i];i++){for(var j=0;j<splice.removed.length;j++){this.setValueSelected(splice.removed[j],false)}for(var j=0;j<splice.addedCount;j++){this.setValueSelected(this.selected[splice.index+j],true)}}},clearSelection:function(excludes){this.$.selection.selection.slice().forEach(function(item){var v=this.valueForNode(item)||this.items.indexOf(item);if(!excludes||excludes.indexOf(v)<0){this.$.selection.setItemSelected(item,false)}},this)},valueToSelection:function(value){var item=this.valueToItem(value);this.$.selection.select(item)},setValueSelected:function(value,isSelected){var item=this.valueToItem(value);if(isSelected^this.$.selection.isSelected(item)){this.$.selection.setItemSelected(item,isSelected)}},updateSelectedItem:function(){this.selectedItem=this.selection},selectedItemChanged:function(){if(this.selectedItem){var t=this.selectedItem.templateInstance;this.selectedModel=t?t.model:undefined}else{this.selectedModel=null}this.selectedIndex=this.selectedItem?parseInt(this.valueToIndex(this.selected)):-1},valueToItem:function(value){return value===null||value===undefined?null:this.items[this.valueToIndex(value)]},valueToIndex:function(value){for(var i=0,items=this.items,c;c=items[i];i++){if(this.valueForNode(c)==value){return i}}return value},valueForNode:function(node){return node[this.valueattr]||node.getAttribute(this.valueattr)},selectionSelect:function(e,detail){this.updateSelectedItem();if(detail.item){this.applySelection(detail.item,detail.isSelected)}},applySelection:function(item,isSelected){if(this.selectedClass){item.classList.toggle(this.selectedClass,isSelected)}if(this.selectedProperty){item[this.selectedProperty]=isSelected}if(this.selectedAttribute&&item.setAttribute){if(isSelected){item.setAttribute(this.selectedAttribute,"")}else{item.removeAttribute(this.selectedAttribute)}}},activateHandler:function(e){if(!this.notap){var i=this.findDistributedTarget(e.target,this.items);if(i>=0){var item=this.items[i];var s=this.valueForNode(item)||i;if(this.multi){if(this.selected){this.addRemoveSelected(s)}else{this.selected=[s]}}else{this.selected=s}this.asyncFire("core-activate",{item:item})}}},addRemoveSelected:function(value){var i=this.selected.indexOf(value);if(i>=0){this.selected.splice(i,1)}else{this.selected.push(value)}},findDistributedTarget:function(target,nodes){while(target&&target!=this){var i=Array.prototype.indexOf.call(nodes,target);if(i>=0){return i}target=target.parentNode}},selectIndex:function(index){var item=this.items[index];if(item){this.selected=this.valueForNode(item)||index;return item}},selectPrevious:function(wrapped){var i=wrapped&&!this.selectedIndex?this.items.length-1:this.selectedIndex-1;return this.selectIndex(i)},selectNext:function(wrapped){var i=wrapped&&this.selectedIndex>=this.items.length-1?0:this.selectedIndex+1;return this.selectIndex(i)}});</script></polymer-element><polymer-element name="core-a11y-keys" assetpath="../core-a11y-keys/"><script>(function(){var KEY_IDENTIFIER={"U+0009":"tab","U+001B":"esc","U+0020":"space","U+002A":"*","U+0030":"0","U+0031":"1","U+0032":"2","U+0033":"3","U+0034":"4","U+0035":"5","U+0036":"6","U+0037":"7","U+0038":"8","U+0039":"9","U+0041":"a","U+0042":"b","U+0043":"c","U+0044":"d","U+0045":"e","U+0046":"f","U+0047":"g","U+0048":"h","U+0049":"i","U+004A":"j","U+004B":"k","U+004C":"l","U+004D":"m","U+004E":"n","U+004F":"o","U+0050":"p","U+0051":"q","U+0052":"r","U+0053":"s","U+0054":"t","U+0055":"u","U+0056":"v","U+0057":"w","U+0058":"x","U+0059":"y","U+005A":"z","U+007F":"del"};var KEY_CODE={9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var KEY_CHAR=/[a-z0-9*]/;function transformKey(key){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey.length==1){if(KEY_CHAR.test(lKey)){validKey=lKey}}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}var IDENT_CHAR=/U\+/;function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(IDENT_CHAR.test(keyIdent)){validKey=KEY_IDENTIFIER[keyIdent]}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(48-keyCode)}else if(keyCode>=96&&keyCode<=105){validKey=String(96-keyCode)}else{validKey=KEY_CODE[keyCode]}}return validKey}function keyboardEventToKey(ev){var normalizedKey=transformKey(ev.key)||transformKeyIdentifier(ev.keyIdentifier)||transformKeyCode(ev.keyCode)||transformKey(ev.detail.key)||"";return{shift:ev.shiftKey,ctrl:ev.ctrlKey,meta:ev.metaKey,alt:ev.altKey,key:normalizedKey}}function stringToKey(keyCombo){var keys=keyCombo.split("+");var keyObj=Object.create(null);keys.forEach(function(key){if(key=="shift"){keyObj.shift=true}else if(key=="ctrl"){keyObj.ctrl=true}else if(key=="alt"){keyObj.alt=true}else{keyObj.key=key}});return keyObj}function keyMatches(a,b){return Boolean(a.alt)==Boolean(b.alt)&&Boolean(a.ctrl)==Boolean(b.ctrl)&&Boolean(a.shift)==Boolean(b.shift)&&a.key===b.key}function processKeys(ev){var current=keyboardEventToKey(ev);for(var i=0,dk;i<this._desiredKeys.length;i++){dk=this._desiredKeys[i];if(keyMatches(dk,current)){ev.preventDefault();ev.stopPropagation();this.fire("keys-pressed",current,this,false);break}}}function listen(node,handler){if(node&&node.addEventListener){node.addEventListener("keydown",handler)}}function unlisten(node,handler){if(node&&node.removeEventListener){node.removeEventListener("keydown",handler)}}Polymer("core-a11y-keys",{created:function(){this._keyHandler=processKeys.bind(this)},attached:function(){if(!this.target){this.target=this.parentNode}listen(this.target,this._keyHandler)},detached:function(){unlisten(this.target,this._keyHandler)},publish:{keys:"",target:null},keysChanged:function(){var normalized=this.keys.replace("*","* shift+*");this._desiredKeys=normalized.toLowerCase().split(" ").map(stringToKey)},targetChanged:function(oldTarget){unlisten(oldTarget,this._keyHandler);listen(this.target,this._keyHandler)}})})();</script></polymer-element><polymer-element name="core-menu" extends="core-selector" assetpath="../core-menu/"><template><style>:host { display: block; margin: 12px;}polyfill-next-selector { content: ':host > core-item'; }::content > core-item { cursor: default;}</style><core-a11y-keys target="{{}}" keys="up" on-keys-pressed="{{ selectPrevious }}"></core-a11y-keys><core-a11y-keys target="{{}}" keys="down" on-keys-pressed="{{ selectNext }}"></core-a11y-keys><core-a11y-keys target="{{}}" keys="enter" on-keys-pressed="{{ validateSelected }}"></core-a11y-keys><shadow></shadow></template><script>Polymer("core-menu");</script></polymer-element><polymer-element name="core-item" attributes="label icon src" horizontal="" center="" layout="" assetpath="../core-item/"><template><style>:host { display: block; position: relative; min-height: 40px; white-space: nowrap;}:host(.font-scalable) { min-height: 2.5em;}:host(.core-selected) { font-weight: bold;}#icon { margin: 0 16px 0 4px;}:host(.font-scalable) #icon { margin: 0 1em 0 0.25em; height: 1.5em; width: 1.5em;}polyfill-next-selector { content: ':host > a'; }::content > a { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, 0.000001);}</style><template if="{{icon || src}}"><core-icon src="{{src}}" id="icon" icon="{{icon}}" hidden?="{{!src &amp;&amp; !icon}}"></core-icon></template><div id="label">{{label}}</div><content></content></template><script>Polymer("core-item",{});</script></polymer-element><polymer-element name="core-doc-toc" attributes="data selected" assetpath="../core-doc-viewer/elements/"><template><style>:host { display: block; position: relative; border-right: 1px solid silver;}core-header-panel { position: absolute; top: 0; left: 0; height: 100%; width: 100%;}core-toolbar { background-color: #eeeeee;}</style><core-header-panel mode="waterfall"><core-menu selected="{{selected}}"><template repeat="{{data}}"><core-item><a href="#{{name}}">{{name}}</a></core-item></template></core-menu></core-header-panel></template><script>Polymer("core-doc-toc",{searchAction:function(){this.$.searchBar.style.opacity=1;this.$.searchBar.style.display=""},closeSearchAction:function(){this.$.searchBar.style.opacity=0;this.$.searchBar.style.display="none"}});</script></polymer-element><polymer-element name="core-doc-viewer" attributes="sources route url" horizontal="" layout="" assetpath="../core-doc-viewer/"><template><style> core-doc-toc { display: none; width: 332px; overflow-x: hidden; } </style><context-free-parser url="{{url}}" on-data-ready="{{parserDataReady}}"></context-free-parser><template repeat="{{sources}}"><context-free-parser url="{{}}" on-data-ready="{{parserDataReady}}"></context-free-parser></template><core-doc-toc id="toc" data="{{classes}}" selected="{{selected}}"></core-doc-toc><core-doc-page flex="" data="{{data}}"></core-doc-page></template><script>Polymer("core-doc-viewer",{classes:[],sources:[],ready:function(){window.addEventListener("hashchange",this.parseLocationHash.bind(this));this.parseLocationHash()},parseLocationHash:function(){this.route=window.location.hash.slice(1)},routeChanged:function(){this.validateRoute()},validateRoute:function(){if(this.route){this.classes.some(function(c){if(c.name===this.route.split(".")[0]){this.data=c;this.route="";return}},this)}},selectedChanged:function(){this.data=this.classes[this.selected]},parserDataReady:function(event,detail,sender){var path="";if(this.sources.length){var path=event.target.templateInstance.model;var idx=path.lastIndexOf("/");path=idx!=-1?path.substr(0,idx):"."}else{var parts=location.pathname.split("/");parts.pop();path=parts.join("/")}var data=event.target.data;var xhr=new XMLHttpRequest;xhr.open("GET",path+"/bower.json");xhr.onerror=function(e){this.assimilateData(data)}.bind(this);xhr.onloadend=function(e){if(e.target.status==200){var version=JSON.parse(e.target.response).version;for(var i=0,c;c=data.classes[i];++i){c.version=version}}this.assimilateData(data)}.bind(this);xhr.send()},assimilateData:function(data){this.classes=this.classes.concat(data.classes);this.classes.sort(function(a,b){var na=a&&a.name.toLowerCase(),nb=b&&b.name.toLowerCase();return na<nb?-1:na==nb?0:1});if(!this.data&&!this.route&&this.classes.length){this.data=this.classes[0]}if(this.classes.length>1){this.$.toc.style.display="block"}this.validateRoute()}});</script></polymer-element></div><polymer-element name="core-component-page" attributes="moduleName sources" layout="" vertical="" assetpath="../core-component-page-dev/"><template><style>:host { font-family: Arial, sans-serif; height: 100vh;}h2 { display: inline-block; margin: 8px 6px; vertical-align: middle;}.choiceB, .choiceC, .choiceD { color: white; font-size: 12px; font-weight: bold; text-decoration: none; background-color: #4285F4; box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.1); box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.1); border-radius: 2px; cursor: pointer; display: inline-block; padding: 4px 12px 5px 12px; margin: 4px 0;}.appbar { background-color: #E91E63; color: white;}</style><core-toolbar class="appbar"><span>{{moduleName}}</span><a class="choiceC" target="_blank" href="../{{moduleName}}/demo.html">demo</a></core-toolbar><core-doc-viewer flex="" url="{{url}}" sources="{{sources}}"></core-doc-viewer></template><script>Polymer("core-component-page",{moduleName:"",sources:[],ready:function(){this.moduleName=this.moduleName||this.findModuleName()},moduleNameChanged:function(){document.title=this.moduleName;this.url=!this.sources.length&&this.moduleName?this.moduleName+".html":""},findModuleName:function(){var path=location.pathname.split("/");var name=path.pop()||path.pop();if(name.indexOf(".html")>=0){name=path.pop()}return name||""}});</script></polymer-element></body></html> \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/demo.html b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/demo.html
index 92313c48211..92313c48211 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/demo.html
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/demo.html
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/index.html b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/index.html
index 294215a738b..294215a738b 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/index.html
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-component-page/index.html
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/.bower.json
new file mode 100644
index 00000000000..5ce64b34c5b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/.bower.json
@@ -0,0 +1,18 @@
+{
+ "name": "core-media-query",
+ "private": true,
+ "dependencies": {
+ "polymer": "Polymer/polymer#^0.5"
+ },
+ "version": "0.5.6",
+ "homepage": "https://github.com/Polymer/core-media-query",
+ "_release": "0.5.6",
+ "_resolution": {
+ "type": "version",
+ "tag": "0.5.6",
+ "commit": "5d2a477d8f28ebd195b8a781a7bb053ac6b44299"
+ },
+ "_source": "git://github.com/Polymer/core-media-query.git",
+ "_target": "^0.5",
+ "_originalSource": "Polymer/core-media-query"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/README.md b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/README.md
new file mode 100644
index 00000000000..6c5158bfe90
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/README.md
@@ -0,0 +1,7 @@
+core-media-query
+================
+
+**This element is compatible with Polymer 0.5 and lower only, and will be deprecated.**
+You can check out a similar 0.8-compatible version of this element at [https://github.com/polymerelements/iron-media-query](https://github.com/polymerelements/iron-media-query)
+
+See the [component page](https://www.polymer-project.org/0.5/docs/elements/core-media-query.html) for more information.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/bower.json b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/bower.json
new file mode 100644
index 00000000000..1d182f51989
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/bower.json
@@ -0,0 +1,8 @@
+{
+ "name": "core-media-query",
+ "private": true,
+ "dependencies": {
+ "polymer": "Polymer/polymer#^0.5"
+ },
+ "version": "0.5.6"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/core-media-query.html b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/core-media-query.html
new file mode 100644
index 00000000000..20cfd09ef30
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/core-media-query.html
@@ -0,0 +1,87 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!--
+/**
+ * @group Polymer Core Elements
+ * @element core-media-query
+ * @status beta
+ * @homepage github.io
+ *
+ * core-media-query can be used to data bind to a CSS media query.
+ * The "query" property is a bare CSS media query.
+ * The "queryMatches" property will be a boolean representing if the page matches that media query.
+ *
+ * core-media-query uses media query listeners to dynamically update the "queryMatches" property.
+ * A "core-media-change" event also fires when queryMatches changes.
+ *
+ * Example:
+ *
+ * <core-media-query query="max-width: 640px" queryMatches="{{phoneScreen}}"></core-media-query>
+ *
+ */
+
+ /**
+ * Fired when the media query state changes
+ *
+ * @event core-media-change
+ */
+-->
+<link rel="import" href="../polymer/polymer.html">
+
+<polymer-element name="core-media-query" attributes="query queryMatches">
+ <template>
+ <style>
+ :host {
+ display: none;
+ }
+ </style>
+ </template>
+ <script>
+ Polymer('core-media-query', {
+
+ /**
+ * The Boolean return value of the media query
+ *
+ * @attribute queryMatches
+ * @type Boolean
+ * @default false
+ */
+ queryMatches: false,
+
+ /**
+ * The CSS media query to evaulate
+ *
+ * @attribute query
+ * @type string
+ * @default ''
+ */
+ query: '',
+ ready: function() {
+ this._mqHandler = this.queryHandler.bind(this);
+ this._mq = null;
+ },
+ queryChanged: function() {
+ if (this._mq) {
+ this._mq.removeListener(this._mqHandler);
+ }
+ var query = this.query;
+ if (query[0] !== '(') {
+ query = '(' + this.query + ')';
+ }
+ this._mq = window.matchMedia(query);
+ this._mq.addListener(this._mqHandler);
+ this.queryHandler(this._mq);
+ },
+ queryHandler: function(mq) {
+ this.queryMatches = mq.matches;
+ this.asyncFire('core-media-change', mq);
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/demo.html b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/demo.html
new file mode 100644
index 00000000000..8c1d6397610
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/demo.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Polymer match media</title>
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+ <link rel="import" href="core-media-query.html" />
+</head>
+<body>
+
+ <polymer-element name="match-example">
+ <template>
+ <core-media-query query="{{query}}" queryMatches="{{qMatches}}"></core-media-query>
+ My query of "{{query}}" {{qMatches ? "matches" : "doesn't match"}}
+ </template>
+ <script>
+ Polymer('match-example', {
+ query: 'min-width: 600px'
+ });
+ </script>
+ </polymer-element>
+
+ <match-example id="me"></match-example>
+ <pre id="output">
+ Log of 'mediachange' events on document, from polymer-match-media:
+ </pre>
+
+ <script>
+ var output = document.querySelector('#output');
+ // on-mediachange would give true or false as second param to the handler
+ document.addEventListener('core-media-change', function(e) {
+ output.textContent += '\nevent: ' + e.type + ' query: ' + e.detail.media + ' matches: ' + e.detail.matches;
+ });
+ </script>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-media-query/index.html b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/index.html
new file mode 100644
index 00000000000..294215a738b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-media-query/index.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+ <link rel="import" href="../core-component-page/core-component-page.html">
+
+</head>
+<body unresolved>
+
+ <core-component-page></core-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/README.md b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/README.md
new file mode 100644
index 00000000000..22d55c10825
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/README.md
@@ -0,0 +1,4 @@
+core-tooltip
+============
+
+See the [component page](http://polymer-project.org/docs/elements/core-elements.html#core-tooltip) for more information.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/bower.json b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/bower.json
new file mode 100644
index 00000000000..9f116444c47
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/bower.json
@@ -0,0 +1,13 @@
+{
+ "name": "core-tooltip",
+ "private": true,
+ "description": "Tooltip popup for content",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^0.5",
+ "core-focusable": "Polymer/core-focusable#^0.5",
+ "core-icon-button": "Polymer/core-icon-button#^0.5",
+ "paper-fab": "Polymer/paper-fab#^0.5",
+ "core-resizable": "Polymer/core-resizable#^0.5"
+ },
+ "version": "0.5.5"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.css b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.css
new file mode 100644
index 00000000000..aa24c39fcaa
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.css
@@ -0,0 +1,104 @@
+/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
+
+:host {
+ box-sizing: border-box;
+ position: relative;
+ display: inline-block;
+ outline: none;
+}
+
+:host(:hover:not([disabled])) .core-tooltip {
+ visibility: visible !important;
+}
+
+:host([focused]) .core-tooltip {
+ visibility: visible !important;
+}
+
+.core-tooltip:not(.show) {
+ visibility: hidden;
+}
+
+.core-tooltip {
+ position: absolute;
+ font-size: 10px;
+ font-weight: 500;
+ padding: 8px;
+ color: white;
+ background-color: rgba(0, 0, 0, 0.9);
+ box-sizing: border-box;
+ border-radius: 3px; /* TODO: not in spec. */
+ white-space: nowrap;
+ line-height: 6px;
+ z-index: 1002; /* TODO: this is brittle. */
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+:host([large]) .core-tooltip {
+ line-height: 14px;
+ font-size: 14px;
+ padding: 16px;
+}
+
+.core-tooltip.noarrow::after {
+ display: none;
+}
+
+.core-tooltip::after {
+ position: absolute;
+ border: solid transparent;
+ content: '';
+ height: 0;
+ width: 0;
+ border-width: 4px;
+}
+
+.top {
+ margin-bottom: 10px; /* TODO: not specified in spec */
+ bottom: 100%;
+}
+
+.right {
+ margin-left: 10px; /* TODO: not specified in spec */
+ left: 100%;
+}
+
+.bottom {
+ top: 100%;
+ margin-top: 10px; /* TODO: not specified in spec */
+}
+
+.left {
+ margin-right: 10px; /* TODO: not specified in spec */
+ right: 100%;
+}
+
+.core-tooltip.bottom::after {
+ bottom: 100%;
+ left: calc(50% - 4px);
+ border-bottom-color: rgba(0,0,0,0.8);
+}
+
+.core-tooltip.left::after {
+ left: 100%;
+ top: calc(50% - 4px);
+ border-left-color: rgba(0,0,0,0.8);
+}
+
+.core-tooltip.top::after {
+ top: 100%;
+ left: calc(50% - 4px);
+ border-top-color: rgba(0,0,0,0.8);
+}
+
+.core-tooltip.right::after {
+ right: 100%;
+ top: calc(50% - 4px);
+ border-right-color: rgba(0,0,0,0.8);
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.html b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.html
new file mode 100644
index 00000000000..634be4696a8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/core-tooltip.html
@@ -0,0 +1,217 @@
+<!--
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<!--
+The `core-tooltip` element creates a hover tooltip centered for the content
+it contains. It can be positioned on the top|bottom|left|right of content using
+the `position` attribute.
+
+To include HTML in the tooltip, include the `tip` attribute on the relevant
+content.
+
+<b>Example</b>:
+
+ <core-tooltip label="I'm a tooltip">
+ <span>Hover over me.</span>
+ </core-tooltip>
+
+<b>Example</b> - positioning the tooltip to the right:
+
+ <core-tooltip label="I'm a tooltip to the right" position="right">
+ <core-icon-button icon="drawer"></core-icon-button>
+ </core-tooltip>
+
+<b>Example</b> - no arrow and showing by default:
+
+ <core-tooltip label="Tooltip with no arrow and always on" noarrow show>
+ <img src="image.jpg">
+ </core-tooltip>
+
+<b>Example</b> - disable the tooltip.
+
+ <core-tooltip label="Disabled label never shows" disabled>
+ ...
+ </core-tooltip>
+
+<b>Example</b> - rich tooltip using the `tip` attribute:
+
+ <core-tooltip>
+ <div>Example of a rich information tooltip</div>
+ <div tip>
+ <img src="profile.jpg">Foo <b>Bar</b> - <a href="#">@baz</a>
+ </div>
+ </core-tooltip>
+
+By default, the `tip` attribute specifies the HTML content for a rich tooltip.
+You can customize this attribute with the `tipAttribute` attribute:
+
+ <core-tooltip tipAttribute="htmltooltip">
+ <div>Example of a rich information tooltip</div>
+ <div htmltooltip>
+ ...
+ </div>
+ </core-tooltip>
+
+@group Polymer Core Elements
+@element core-tooltip
+@mixins Polymer.CoreFocusable https://github.com/polymer/core-focusable
+@mixins Polymer.CoreResizable https://github.com/polymer/core-resizable
+@homepage http://www.polymer-project.org/components/core-tooltip/index.html
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../core-focusable/core-focusable.html">
+<link rel="import" href="../core-resizable/core-resizable.html">
+
+<!-- TODO: would be nice to inherit from label to get .htmlFor, and .control,
+ but the latter is readonly. -->
+<!-- TODO: support off center arrows. -->
+<!-- TODO: detect mobile and apply the .large class, instead of manual
+ control. -->
+<!-- TODO: possibly reuse core-overlay. -->
+<polymer-element name="core-tooltip" attributes="noarrow position label show tipAttribute" role="tooltip" tabindex="0">
+<template>
+ <link rel="stylesheet" href="core-tooltip.css">
+
+ <div id="tooltip" hidden?="{{!hasTooltipContent}}"
+ class="core-tooltip {{position}} {{ {noarrow: noarrow, show: show && !disabled} | tokenList}}">
+ <content id="c" select="[{{tipAttribute}}]">{{label}}</content>
+ </div>
+
+ <content></content>
+
+</template>
+<script>
+(function() {
+
+ var proto = {
+
+ /**
+ * A simple string label for the tooltip to display. To display a rich
+ * HTML tooltip instead, omit `label` and include the `tip` attribute
+ * on a child node of `core-tooltip`.
+ *
+ * @attribute label
+ * @type string
+ * @default null
+ */
+ label: null,
+
+ eventDelegates: {
+ 'core-resize': 'positionChanged'
+ },
+
+ computed: {
+ // Indicates whether the tooltip has a set label propety or
+ // an element with the `tip` attribute.
+ hasTooltipContent: 'label || !!tipElement'
+ },
+
+ publish: {
+ /**
+ * Forces the tooltip to display. If `disabled` is set, this property is ignored.
+ *
+ * @attribute show
+ * @type boolean
+ * @default false
+ */
+ show: {value: false, reflect: true},
+
+ /**
+ * Positions the tooltip to the top, right, bottom, left of its content.
+ *
+ * @attribute position
+ * @type string
+ * @default 'bottom'
+ */
+ position: {value: 'bottom', reflect: true},
+
+ /**
+ * If true, the tooltip an arrow pointing towards the content.
+ *
+ * @attribute noarrow
+ * @type boolean
+ * @default false
+ */
+ noarrow: {value: false, reflect: true}
+ },
+
+ /**
+ * Customizes the attribute used to specify which content
+ * is the rich HTML tooltip.
+ *
+ * @attribute tipAttribute
+ * @type string
+ * @default 'tip'
+ */
+ tipAttribute: 'tip',
+
+ attached: function() {
+ this.updatedChildren();
+ this.resizableAttachedHandler();
+ },
+
+ detached: function() {
+ this.resizableDetachedHandler();
+ },
+
+ updatedChildren: function () {
+ this.tipElement = null;
+
+ for (var i = 0, el; el = this.$.c.getDistributedNodes()[i]; ++i) {
+ if (el.hasAttribute && el.hasAttribute(this.tipAttribute)) {
+ this.tipElement = el;
+ break;
+ }
+ }
+
+ // Job ensures we're not double calling setPosition() on DOM attach.
+ this.job('positionJob', this.setPosition);
+
+ // Monitor children to re-position tooltip when light dom changes.
+ this.onMutation(this, this.updatedChildren);
+ },
+
+ labelChanged: function(oldVal, newVal) {
+ this.job('positionJob', this.setPosition);
+ },
+
+ positionChanged: function(oldVal, newVal) {
+ this.job('positionJob', this.setPosition);
+ },
+
+ setPosition: function() {
+ var controlWidth = this.clientWidth;
+ var controlHeight = this.clientHeight;
+ var toolTipWidth = this.$.tooltip.clientWidth;
+ var toolTipHeight = this.$.tooltip.clientHeight;
+
+ switch (this.position) {
+ case 'top':
+ case 'bottom':
+ this.$.tooltip.style.left = (controlWidth - toolTipWidth) / 2 + 'px';
+ this.$.tooltip.style.top = null;
+ break;
+ case 'left':
+ case 'right':
+ this.$.tooltip.style.left = null;
+ this.$.tooltip.style.top = (controlHeight - toolTipHeight) / 2 + 'px';
+ break;
+ }
+ }
+
+ };
+
+ Polymer.mixin2(proto, Polymer.CoreFocusable);
+ Polymer.mixin(proto, Polymer.CoreResizable);
+ Polymer(proto);
+ })();
+
+</script>
+</polymer-element>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/demo.html b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/demo.html
new file mode 100644
index 00000000000..7ea6aea9d57
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/demo.html
@@ -0,0 +1,211 @@
+<!--
+ @license
+ Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html lang="en">
+<head>
+
+ <meta charset="utf-8">
+ <title>Core Tooltip</title>
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+
+ <link rel="import" href="../core-icon-button/core-icon-button.html">
+ <link rel="import" href="../paper-fab/paper-fab.html">
+ <link rel="import" href="core-tooltip.html">
+
+ <style>
+ body {
+ font-family: "Open Sans", sans-serif;
+ font-weight: 300;
+ padding: 24px;
+ }
+
+ .example {
+ margin: 35px 15px;
+ }
+
+ .example > * {
+ margin: 0 15px;
+ }
+
+ .fakebutton {
+ box-shadow: 0 0 3px #aaa inset;
+ border-radius: 3px;
+ padding: 7px 5px;
+ }
+ .fakebutton:hover {
+ background-color: white;
+ }
+
+ img {
+ width: 400px;
+ height: 150px;
+ object-fit: cover;
+ }
+
+ img.large {
+ border: 15px solid white;
+ box-sizing: border-box;
+ }
+
+ .profile {
+ width: 60px;
+ height: auto;
+ border-radius: 50%;
+ vertical-align: middle;
+ }
+
+ a {
+ color: currentcolor;
+ text-decoration: none;
+ }
+
+ .rich {
+ background: hotpink;
+ color: white;
+ padding:20px;
+ border-radius: 5px;
+ }
+
+ </style>
+
+ <style shim-shadowdom>
+ core-tooltip.fancy::shadow .core-tooltip {
+ opacity: 0;
+ -webkit-transition: all 300ms cubic-bezier(0,1.92,.99,1.07);
+ transition: all 300ms cubic-bezier(0,1.92,.99,1.07);
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ core-tooltip.fancy:hover::shadow .core-tooltip,
+ core-tooltip.fancy:focus::shadow .core-tooltip {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+ </style>
+
+</head>
+<body unresolved>
+
+ <article>
+
+ <button>Toggle all</button>
+
+ <section class="small" layout horizontal center-center>
+
+ <div class="example">
+
+ <core-tooltip label='position="left"' position="left">
+ <core-icon-button icon="drawer"></core-icon-button>
+ </core-tooltip>
+
+ <core-tooltip label='position="top"' position="top">
+ <core-icon-button icon="drawer"></core-icon-button>
+ </core-tooltip>
+
+ <core-tooltip label='position="bottom"' position="bottom">
+ <core-icon-button icon="drawer"></core-icon-button>
+ </core-tooltip>
+
+ <core-tooltip label='position="right"' position="right">
+ <core-icon-button icon="drawer"></core-icon-button>
+ </core-tooltip>
+
+ </div>
+
+ <div class="example">
+
+ <core-tooltip label="Fancy effect" class="fancy">
+ <paper-fab icon="add"></paper-fab>
+ </core-tooltip>
+
+ </div>
+
+ </section>
+
+ <section layout horizontal center-center>
+
+ <div class="example">
+
+ <core-tooltip>
+ <div class="rich">Rich tooltip with HTML</div>
+ <div tip>
+ <img src="https://pbs.twimg.com/profile_images/378800000548263523/c110b0a4c3e3e4d3dcce1d2020f3eded.jpeg
+ " class="profile" style="width: 40px;margin-right: 8px;">Eric <b>Bidelman</b> - <a href="#">@ebidel</a></div>
+ </core-tooltip>
+
+ </div>
+
+ <div class="example">
+
+ <core-tooltip label="<core-tooltip large>" large>
+ Larger tooltips for mobile
+ </core-tooltip>
+
+ </div>
+
+ <div class="example">
+
+ <core-tooltip label="disabled" disabled>
+ Disabled Tooltip
+ </core-tooltip>
+
+ </div>
+
+ </section>
+
+ <section layout horizontal center-center>
+
+ <div class="example">
+
+ <core-tooltip label="Tooltip with no arrow and always on: <core-tooltip noarrow show>" position="bottom" noarrow show>
+ <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/building.jpg" class="large">
+ </core-tooltip>
+
+ </div>
+
+ </section>
+
+ <section layout horizontal center-center>
+
+ <div class="example">
+
+ <core-tooltip id="dynamic" show>
+ Tooltips are only shown (on hover) when a label is set<br> or a html rich snippet is given. &rarr;
+ </core-tooltip>
+ <button id="fillbutton">Fill tooltip</button>
+
+ </div>
+
+ </section>
+
+ </article>
+
+<script>
+ document.querySelector('button').addEventListener('click', function(e) {
+ var tooltips = document.querySelectorAll('core-tooltip');
+ Array.prototype.forEach.call(tooltips, function(tooltip) {
+ tooltip.show = !tooltip.show;
+ });
+ });
+
+ document.querySelector('#fillbutton').addEventListener('click', function(e) {
+ e.stopPropagation();
+
+ var el = document.querySelector('#dynamic');
+ el.insertAdjacentHTML('beforeend', '<div tip><b>See</b>. Told ya so!</div>');
+
+ });
+</script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/index.html b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/index.html
new file mode 100644
index 00000000000..cdf58085266
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/index.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<!--
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+ <link rel="import" href="../core-component-page/core-component-page.html">
+
+</head>
+<body unresolved>
+
+ <core-component-page></core-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/metadata.html b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/metadata.html
new file mode 100644
index 00000000000..ffcf73ac715
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/core-tooltip/metadata.html
@@ -0,0 +1,20 @@
+<!--
+ @license
+ Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<x-meta id="core-tooltip" label="Tooltip" group="Core">
+ <template>
+ <core-tooltip label="I'm a tooltip">
+ <span>Hover over me.</span>
+ </core-tooltip>
+ </template>
+ <template id="imports">
+ <link rel="import" href="core-tooltip.html">
+ </template>
+</x-meta>
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/font-roboto/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/.bower.json
new file mode 100644
index 00000000000..eafbb18866b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/.bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "font-roboto",
+ "version": "1.0.1",
+ "description": "An HTML import for Roboto",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "font",
+ "roboto"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/font-roboto.git"
+ },
+ "main": "roboto.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/font-roboto/",
+ "ignore": [
+ "/.*"
+ ],
+ "_release": "1.0.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.1",
+ "commit": "21ce9b51a417fa9995cf6606e886aba0728f70a1"
+ },
+ "_source": "git://github.com/PolymerElements/font-roboto.git",
+ "_target": "^1.0.1",
+ "_originalSource": "PolymerElements/font-roboto"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/font-roboto/README.md b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/README.md
new file mode 100644
index 00000000000..61c6394ce36
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/README.md
@@ -0,0 +1 @@
+# font-roboto
diff --git a/chromium/third_party/catapult/third_party/polymer/components/font-roboto/bower.json b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/bower.json
new file mode 100644
index 00000000000..977cf2d4ed8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/bower.json
@@ -0,0 +1,22 @@
+{
+ "name": "font-roboto",
+ "version": "1.0.1",
+ "description": "An HTML import for Roboto",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "font",
+ "roboto"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/font-roboto.git"
+ },
+ "main": "roboto.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/font-roboto/",
+ "ignore": [
+ "/.*"
+ ]
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/font-roboto/roboto.html b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/roboto.html
new file mode 100644
index 00000000000..7a24999fffd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/font-roboto/roboto.html
@@ -0,0 +1,11 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,500,500italic,700,700italic">
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/README.md
new file mode 100644
index 00000000000..ffadd3db606
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/README.md
@@ -0,0 +1,49 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-a11y-announcer.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-a11y-announcer.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-a11y-announcer)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-a11y-announcer)_
+
+
+##&lt;iron-a11y-announcer&gt;
+
+
+`iron-a11y-announcer` is a singleton element that is intended to add a11y
+to features that require on-demand announcement from screen readers. In
+order to make use of the announcer, it is best to request its availability
+in the announcing element.
+
+Example:
+
+ Polymer({
+
+ is: 'x-chatty',
+
+ attached: function() {
+ // This will create the singleton element if it has not
+ // been created yet:
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ }
+ });
+
+After the `iron-a11y-announcer` has been made available, elements can
+make announces by firing bubbling `iron-announce` events.
+
+Example:
+
+ this.fire('iron-announce', {
+ text: 'This is an announcement!'
+ }, { bubbles: true });
+
+Note: announcements are only audible if you have a screen reader enabled.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/bower.json
new file mode 100644
index 00000000000..ed8d8d00816
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-a11y-announcer",
+ "version": "1.0.4",
+ "description": "A singleton element that simplifies announcing text to screen readers.",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "a11y",
+ "live"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-a11y-announcer.git"
+ },
+ "main": "iron-a11y-announcer.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "dependencies": {
+ "polymer": "polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-button": "polymerelements/paper-button#^1.0.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "polymer/web-component-tester#^3.4.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/index.html
new file mode 100644
index 00000000000..0dd286acf5e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/index.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-a11y-announcer demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="x-announces.html">
+
+</head>
+<body>
+ <div class="horizontal-section-container">
+ <div>
+ <div class="vertical-section">
+ <span>Note: in order to hear the announcements, be sure to turn on your favorite screen reader!</span>
+ <x-announces>Hello, my name is Ava.</x-announces>
+ <x-announces>This true sentence is false.</x-announces>
+ <x-announces>Are you paying attention?</x-announces>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/x-announces.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/x-announces.html
new file mode 100644
index 00000000000..404f7c09b55
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/demo/x-announces.html
@@ -0,0 +1,50 @@
+<!--
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../paper-button/paper-button.html">
+<link rel="import" href="../iron-a11y-announcer.html">
+
+<dom-module id="x-announces">
+ <style>
+ :host {
+ display: block;
+ position: relative;
+ padding: 1em 0;
+ }
+
+ paper-button {
+ background: #4285f4;
+ color: #fff;
+ }
+ </style>
+ <template>
+ <paper-button on-tap="_onTapAnnounce" raised>Announce</paper-button>
+ <span id="content" aria-hidden="true">
+ <content></content>
+ </span>
+ </template>
+ <script>
+ Polymer({
+ is: 'x-announces',
+
+ attached: function() {
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ },
+
+ _onTapAnnounce: function() {
+ this.fire('iron-announce', {
+ text: this.$.content.textContent.trim()
+ }, {
+ bubbles: true
+ });
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/index.html
new file mode 100644
index 00000000000..1f8889a8da9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-a11y-announcer</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/iron-a11y-announcer.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/iron-a11y-announcer.html
new file mode 100644
index 00000000000..da42ba964ef
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-announcer/iron-a11y-announcer.html
@@ -0,0 +1,125 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!--
+`iron-a11y-announcer` is a singleton element that is intended to add a11y
+to features that require on-demand announcement from screen readers. In
+order to make use of the announcer, it is best to request its availability
+in the announcing element.
+
+Example:
+
+ Polymer({
+
+ is: 'x-chatty',
+
+ attached: function() {
+ // This will create the singleton element if it has not
+ // been created yet:
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ }
+ });
+
+After the `iron-a11y-announcer` has been made available, elements can
+make announces by firing bubbling `iron-announce` events.
+
+Example:
+
+ this.fire('iron-announce', {
+ text: 'This is an announcement!'
+ }, { bubbles: true });
+
+Note: announcements are only audible if you have a screen reader enabled.
+
+@group Iron Elements
+@demo demo/index.html
+-->
+
+<dom-module id="iron-a11y-announcer">
+ <style>
+ :host {
+ display: inline-block;
+ position: fixed;
+ clip: rect(0px,0px,0px,0px);
+ }
+ </style>
+
+ <template>
+ <div aria-live$="[[mode]]">[[_text]]</div>
+ </template>
+
+ <script>
+
+ (function() {
+ 'use strict';
+
+ Polymer.IronA11yAnnouncer = Polymer({
+ is: 'iron-a11y-announcer',
+
+ properties: {
+
+ /**
+ * The value of mode is used to set the `aria-live` attribute
+ * for the element that will be announced. Valid values are: `off`,
+ * `polite` and `assertive`.
+ */
+ mode: {
+ type: String,
+ value: 'polite'
+ },
+
+ _text: {
+ type: String,
+ value: ''
+ }
+ },
+
+ created: function() {
+ if (!Polymer.IronA11yAnnouncer.instance) {
+ Polymer.IronA11yAnnouncer.instance = this;
+ }
+
+ document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
+ },
+
+ /**
+ * Cause a text string to be announced by screen readers.
+ *
+ * @param {string} text The text that should be announced.
+ */
+ announce: function(text) {
+ this._text = '';
+ this.async(function() {
+ this._text = text;
+ }, 100);
+ },
+
+ _onIronAnnounce: function(event) {
+ if (event.detail && event.detail.text) {
+ this.announce(event.detail.text);
+ }
+ }
+ });
+
+ Polymer.IronA11yAnnouncer.instance = null;
+
+ Polymer.IronA11yAnnouncer.requestAvailability = function() {
+ if (!Polymer.IronA11yAnnouncer.instance) {
+ Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-announcer');
+ }
+
+ document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
+ };
+ })();
+
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.bower.json
new file mode 100644
index 00000000000..22dfa4486ba
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.bower.json
@@ -0,0 +1,43 @@
+{
+ "name": "iron-a11y-keys-behavior",
+ "version": "1.1.6",
+ "description": "A behavior that enables keybindings for greater a11y.",
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "a11y",
+ "input"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-a11y-keys-behavior.git"
+ },
+ "main": "iron-a11y-keys-behavior.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-a11y-keys-behavior",
+ "_release": "1.1.6",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.6",
+ "commit": "28435b2e02d0e5e5268e984d925b03643cea5e34"
+ },
+ "_source": "git://github.com/PolymerElements/iron-a11y-keys-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-a11y-keys-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.travis.yml
new file mode 100644
index 00000000000..bb7b10a3e24
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: OZhLlPsjjnWU4FyZ+RKq5i/Nv/tElvcjr9+OT04ENGKfh9+fkuij/XdHJQe6EpOCjrNkwt23c+I6V5YWRrSatRX/AxEkViW8EXnF32rX3HV8fWnjD6Vfn+4Qz82y4huc9II8OV5I7jFDln6yzEGZn08zAtbmhj5dSpYtT1spSf/ZuUkqn4mMRJW2wCOnzbjueP56Ry40IwQm0enLXVQLPYB3LC4fBWfT+VFrsE9qH1ZgGKcSD/n2dOD3d6xjts4FSilNp2IZ8Km5RNAFUxYmkcwrY4O2ltNtKUngWwIpeplpz0bNj5k8kOpT5xA/FT630M5sFd1ODVp846kTr/EyYTq/VCiwTaA/vDfZL85DC3O+Zt0vTHAvkxKAaXkg9sMp8gJOJ6gt6cK8rV8z7npeAUVsK1gmuHYXne1Z76SRgWwbE0/z82vyFLNgitmZDLLM1fP3TpzsK1QQg1ikn6iYXdWpHcrzBi6lk8mCafnP7D7B/yFB/Z6Y9AFI6NQI/jWP2FMMJjMWbaJVG9DAU4PWlVTiFnhfVjPI7FUEmW46/QjH1ztSZWpDA9SBozJluIpKRA1qk1EgGX1RBFBHrbFtHG//x0AGyAV6gWOfdKjl/nqcM02xFUSrDb0tkNUnEAS6K7l+X1eDaBbiaAQiakPt9Je2WvvHyc+OiZviSc72Gmc=
+ - secure: vIs86+z7s1QwihkHtLBRQzlmJRSIWIadq3SlDdZHS4HOivH7fNV0d4hm8QnZYZ9X8yvSvxFCzEFdLuX1TpU0H3oy5wgYky7DnfJtsEhuOfW8dobHHZeCNi/t2FQAXpobqpRwojC3A+1b1lNrY1XNpYRz7aEialO4Yr8e1SQSLex5zw/pqm7g9Vz6PnQwobDQcGXKc6ZWc84+DqOo9qfkSlnEJC/1vQxHYpUa172UnnAnmHJ7gZKdhf9aLWJSZcSpPcoKEnvslRFmeDyRMNRDWVzcg2vHnV+tc1aYzp1wsrRW3P+oqwYlvGlxo+5U92QLXKIcKZhGblVWxe8BtXgiVzgS1sz5D11vKs61Xe46onbguG/XK3UxX9bPRK5uklkC5fwAY2hhvOTGXqimTb2YrlyEWO3BCKGBk6Is3KGyCe7c2nNEmXPUSun9X1JLGRPivJb9iBR4/WSEFvibYHl6/gIke9LdXPOCHuJ3+Iu14lCz+pwi8ADIWVuGpDIxFcorG8a3BCoxQo5VouUbSe0mcNttAvSzBNxhljaaBuFs56DLDpLRr0sGhqvfA1JzdCyzVyrk4WECfZw26pAnYCyTczVXmu5msVdKnjPJKtDqWazvIhHk2G1mk8CKb14lrN58u/Kh6PQ3miJ+61c1stBWhRDlp2QffOkBJiOATKHF+AA=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/README.md
new file mode 100644
index 00000000000..b0949871d18
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/README.md
@@ -0,0 +1,58 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-a11y-keys-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-a11y-keys-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-a11y-keys-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-a11y-keys-behavior)_
+
+
+##Polymer.IronA11yKeysBehavior
+
+`Polymer.IronA11yKeysBehavior` provides a normalized interface for processing
+keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
+The element takes care of browser differences with respect to Keyboard events
+and uses an expressive syntax to filter key presses.
+
+Use the `keyBindings` prototype property to express what combination of keys
+will trigger the callback. A key binding has the format
+`"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or
+`"KEY:EVENT": "callback"` are valid as well). Some examples:
+
+```javascript
+ keyBindings: {
+ 'space': '_onKeydown', // same as 'space:keydown'
+ 'shift+tab': '_onKeydown',
+ 'enter:keypress': '_onKeypress',
+ 'esc:keyup': '_onKeyup'
+ }
+```
+
+The callback will receive with an event containing the following information in `event.detail`:
+
+```javascript
+ _onKeydown: function(event) {
+ console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab"
+ console.log(event.detail.key); // KEY only, e.g. "tab"
+ console.log(event.detail.event); // EVENT, e.g. "keydown"
+ console.log(event.detail.keyboardEvent); // the original KeyboardEvent
+ }
+```
+
+Use the `keyEventTarget` attribute to set up event handlers on a specific
+node.
+
+See the [demo source code](https://github.com/PolymerElements/iron-a11y-keys-behavior/blob/master/demo/x-key-aware.html)
+for an example.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/bower.json
new file mode 100644
index 00000000000..ae6cb655989
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-a11y-keys-behavior",
+ "version": "1.1.6",
+ "description": "A behavior that enables keybindings for greater a11y.",
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "a11y",
+ "input"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-a11y-keys-behavior.git"
+ },
+ "main": "iron-a11y-keys-behavior.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/index.html
new file mode 100644
index 00000000000..2c3fec7c598
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Iron A11y Keys Behavior demo</title>
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="x-key-aware.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+</head>
+<body>
+ <div class="vertical-section vertical-section-container centered">
+ <x-key-aware></x-key-aware>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/x-key-aware.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/x-key-aware.html
new file mode 100644
index 00000000000..16b9b2a518d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/demo/x-key-aware.html
@@ -0,0 +1,104 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../paper-styles/color.html">
+<link rel="import" href="../iron-a11y-keys-behavior.html">
+
+<dom-module id="x-key-aware">
+ <style>
+ :host {
+ display: block;
+ position: relative;
+ }
+
+ pre {
+ color: var(--google-blue-700);
+ }
+
+ .keys {
+ line-height: 25px;
+ }
+
+ .keys span {
+ cursor: default;
+ background-color: var(--google-grey-100);
+ border: 1px solid var(--google-grey-300);
+ padding: 1px 5px;
+ border-radius: 5px;
+ }
+ </style>
+ <template>
+ <h4>Press any of these keys</h4>
+ <input type="checkbox" checked="{{preventDefault::change}}"> prevent default = {{preventDefault}}
+ <p class="keys">
+ <template is="dom-repeat" items="[[boundKeys]]">
+ <span>{{item}}</span>
+ </template>
+ </p>
+ <pre>[[pressed]]</pre>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'x-key-aware',
+
+ behaviors: [
+ Polymer.IronA11yKeysBehavior
+ ],
+
+ properties: {
+ pressed: {
+ type: String,
+ readOnly: true,
+ value: ''
+ },
+
+ boundKeys: {
+ type: Array,
+ value: function() {
+ return Object.keys(this.keyBindings).join(' ').split(' ');
+ }
+ },
+
+ preventDefault: {
+ type: Boolean,
+ value: true,
+ notify: true
+ },
+
+ keyEventTarget: {
+ type: Object,
+ value: function() {
+ return document.body;
+ }
+ }
+ },
+
+ keyBindings: {
+ '* pageup pagedown left right down up home end space enter @ ~ " $ ? ! \\ + : # backspace': '_updatePressed',
+ 'a': '_updatePressed',
+ 'shift+a alt+a': '_updatePressed',
+ 'shift+tab shift+space': '_updatePressed'
+ },
+
+ _updatePressed: function(event) {
+ console.log(event.detail);
+
+ if (this.preventDefault) {
+ event.preventDefault();
+ }
+ this._setPressed(
+ this.pressed + event.detail.combo + ' pressed!\n'
+ );
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/index.html
new file mode 100644
index 00000000000..c53ba6cf31e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>iron-a11y-keys-behavior</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html
new file mode 100644
index 00000000000..35756c61e61
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html
@@ -0,0 +1,492 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+ (function() {
+ 'use strict';
+
+ /**
+ * Chrome uses an older version of DOM Level 3 Keyboard Events
+ *
+ * Most keys are labeled as text, but some are Unicode codepoints.
+ * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
+ */
+ var KEY_IDENTIFIER = {
+ 'U+0008': 'backspace',
+ 'U+0009': 'tab',
+ 'U+001B': 'esc',
+ 'U+0020': 'space',
+ 'U+007F': 'del'
+ };
+
+ /**
+ * Special table for KeyboardEvent.keyCode.
+ * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better
+ * than that.
+ *
+ * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
+ */
+ var KEY_CODE = {
+ 8: 'backspace',
+ 9: 'tab',
+ 13: 'enter',
+ 27: 'esc',
+ 33: 'pageup',
+ 34: 'pagedown',
+ 35: 'end',
+ 36: 'home',
+ 32: 'space',
+ 37: 'left',
+ 38: 'up',
+ 39: 'right',
+ 40: 'down',
+ 46: 'del',
+ 106: '*'
+ };
+
+ /**
+ * MODIFIER_KEYS maps the short name for modifier keys used in a key
+ * combo string to the property name that references those same keys
+ * in a KeyboardEvent instance.
+ */
+ var MODIFIER_KEYS = {
+ 'shift': 'shiftKey',
+ 'ctrl': 'ctrlKey',
+ 'alt': 'altKey',
+ 'meta': 'metaKey'
+ };
+
+ /**
+ * KeyboardEvent.key is mostly represented by printable character made by
+ * the keyboard, with unprintable keys labeled nicely.
+ *
+ * However, on OS X, Alt+char can make a Unicode character that follows an
+ * Apple-specific mapping. In this case, we fall back to .keyCode.
+ */
+ var KEY_CHAR = /[a-z0-9*]/;
+
+ /**
+ * Matches a keyIdentifier string.
+ */
+ var IDENT_CHAR = /U\+/;
+
+ /**
+ * Matches arrow keys in Gecko 27.0+
+ */
+ var ARROW_KEY = /^arrow/;
+
+ /**
+ * Matches space keys everywhere (notably including IE10's exceptional name
+ * `spacebar`).
+ */
+ var SPACE_KEY = /^space(bar)?/;
+
+ /**
+ * Matches ESC key.
+ *
+ * Value from: http://w3c.github.io/uievents-key/#key-Escape
+ */
+ var ESC_KEY = /^escape$/;
+
+ /**
+ * Transforms the key.
+ * @param {string} key The KeyBoardEvent.key
+ * @param {Boolean} [noSpecialChars] Limits the transformation to
+ * alpha-numeric characters.
+ */
+ function transformKey(key, noSpecialChars) {
+ var validKey = '';
+ if (key) {
+ var lKey = key.toLowerCase();
+ if (lKey === ' ' || SPACE_KEY.test(lKey)) {
+ validKey = 'space';
+ } else if (ESC_KEY.test(lKey)) {
+ validKey = 'esc';
+ } else if (lKey.length == 1) {
+ if (!noSpecialChars || KEY_CHAR.test(lKey)) {
+ validKey = lKey;
+ }
+ } else if (ARROW_KEY.test(lKey)) {
+ validKey = lKey.replace('arrow', '');
+ } else if (lKey == 'multiply') {
+ // numpad '*' can map to Multiply on IE/Windows
+ validKey = '*';
+ } else {
+ validKey = lKey;
+ }
+ }
+ return validKey;
+ }
+
+ function transformKeyIdentifier(keyIdent) {
+ var validKey = '';
+ if (keyIdent) {
+ if (keyIdent in KEY_IDENTIFIER) {
+ validKey = KEY_IDENTIFIER[keyIdent];
+ } else if (IDENT_CHAR.test(keyIdent)) {
+ keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
+ validKey = String.fromCharCode(keyIdent).toLowerCase();
+ } else {
+ validKey = keyIdent.toLowerCase();
+ }
+ }
+ return validKey;
+ }
+
+ function transformKeyCode(keyCode) {
+ var validKey = '';
+ if (Number(keyCode)) {
+ if (keyCode >= 65 && keyCode <= 90) {
+ // ascii a-z
+ // lowercase is 32 offset from uppercase
+ validKey = String.fromCharCode(32 + keyCode);
+ } else if (keyCode >= 112 && keyCode <= 123) {
+ // function keys f1-f12
+ validKey = 'f' + (keyCode - 112);
+ } else if (keyCode >= 48 && keyCode <= 57) {
+ // top 0-9 keys
+ validKey = String(keyCode - 48);
+ } else if (keyCode >= 96 && keyCode <= 105) {
+ // num pad 0-9
+ validKey = String(keyCode - 96);
+ } else {
+ validKey = KEY_CODE[keyCode];
+ }
+ }
+ return validKey;
+ }
+
+ /**
+ * Calculates the normalized key for a KeyboardEvent.
+ * @param {KeyboardEvent} keyEvent
+ * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key
+ * transformation to alpha-numeric chars. This is useful with key
+ * combinations like shift + 2, which on FF for MacOS produces
+ * keyEvent.key = @
+ * To get 2 returned, set noSpecialChars = true
+ * To get @ returned, set noSpecialChars = false
+ */
+ function normalizedKeyForEvent(keyEvent, noSpecialChars) {
+ // Fall back from .key, to .keyIdentifier, to .keyCode, and then to
+ // .detail.key to support artificial keyboard events.
+ return transformKey(keyEvent.key, noSpecialChars) ||
+ transformKeyIdentifier(keyEvent.keyIdentifier) ||
+ transformKeyCode(keyEvent.keyCode) ||
+ transformKey(keyEvent.detail ? keyEvent.detail.key : keyEvent.detail, noSpecialChars) || '';
+ }
+
+ function keyComboMatchesEvent(keyCombo, event) {
+ // For combos with modifiers we support only alpha-numeric keys
+ var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
+ return keyEvent === keyCombo.key &&
+ (!keyCombo.hasModifiers || (
+ !!event.shiftKey === !!keyCombo.shiftKey &&
+ !!event.ctrlKey === !!keyCombo.ctrlKey &&
+ !!event.altKey === !!keyCombo.altKey &&
+ !!event.metaKey === !!keyCombo.metaKey)
+ );
+ }
+
+ function parseKeyComboString(keyComboString) {
+ if (keyComboString.length === 1) {
+ return {
+ combo: keyComboString,
+ key: keyComboString,
+ event: 'keydown'
+ };
+ }
+ return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
+ var eventParts = keyComboPart.split(':');
+ var keyName = eventParts[0];
+ var event = eventParts[1];
+
+ if (keyName in MODIFIER_KEYS) {
+ parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
+ parsedKeyCombo.hasModifiers = true;
+ } else {
+ parsedKeyCombo.key = keyName;
+ parsedKeyCombo.event = event || 'keydown';
+ }
+
+ return parsedKeyCombo;
+ }, {
+ combo: keyComboString.split(':').shift()
+ });
+ }
+
+ function parseEventString(eventString) {
+ return eventString.trim().split(' ').map(function(keyComboString) {
+ return parseKeyComboString(keyComboString);
+ });
+ }
+
+ /**
+ * `Polymer.IronA11yKeysBehavior` provides a normalized interface for processing
+ * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
+ * The element takes care of browser differences with respect to Keyboard events
+ * and uses an expressive syntax to filter key presses.
+ *
+ * Use the `keyBindings` prototype property to express what combination of keys
+ * will trigger the callback. A key binding has the format
+ * `"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or
+ * `"KEY:EVENT": "callback"` are valid as well). Some examples:
+ *
+ * keyBindings: {
+ * 'space': '_onKeydown', // same as 'space:keydown'
+ * 'shift+tab': '_onKeydown',
+ * 'enter:keypress': '_onKeypress',
+ * 'esc:keyup': '_onKeyup'
+ * }
+ *
+ * The callback will receive with an event containing the following information in `event.detail`:
+ *
+ * _onKeydown: function(event) {
+ * console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab"
+ * console.log(event.detail.key); // KEY only, e.g. "tab"
+ * console.log(event.detail.event); // EVENT, e.g. "keydown"
+ * console.log(event.detail.keyboardEvent); // the original KeyboardEvent
+ * }
+ *
+ * Use the `keyEventTarget` attribute to set up event handlers on a specific
+ * node.
+ *
+ * See the [demo source code](https://github.com/PolymerElements/iron-a11y-keys-behavior/blob/master/demo/x-key-aware.html)
+ * for an example.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior
+ */
+ Polymer.IronA11yKeysBehavior = {
+ properties: {
+ /**
+ * The EventTarget that will be firing relevant KeyboardEvents. Set it to
+ * `null` to disable the listeners.
+ * @type {?EventTarget}
+ */
+ keyEventTarget: {
+ type: Object,
+ value: function() {
+ return this;
+ }
+ },
+
+ /**
+ * If true, this property will cause the implementing element to
+ * automatically stop propagation on any handled KeyboardEvents.
+ */
+ stopKeyboardEventPropagation: {
+ type: Boolean,
+ value: false
+ },
+
+ _boundKeyHandlers: {
+ type: Array,
+ value: function() {
+ return [];
+ }
+ },
+
+ // We use this due to a limitation in IE10 where instances will have
+ // own properties of everything on the "prototype".
+ _imperativeKeyBindings: {
+ type: Object,
+ value: function() {
+ return {};
+ }
+ }
+ },
+
+ observers: [
+ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)'
+ ],
+
+
+ /**
+ * To be used to express what combination of keys will trigger the relative
+ * callback. e.g. `keyBindings: { 'esc': '_onEscPressed'}`
+ * @type {Object}
+ */
+ keyBindings: {},
+
+ registered: function() {
+ this._prepKeyBindings();
+ },
+
+ attached: function() {
+ this._listenKeyEventListeners();
+ },
+
+ detached: function() {
+ this._unlistenKeyEventListeners();
+ },
+
+ /**
+ * Can be used to imperatively add a key binding to the implementing
+ * element. This is the imperative equivalent of declaring a keybinding
+ * in the `keyBindings` prototype property.
+ */
+ addOwnKeyBinding: function(eventString, handlerName) {
+ this._imperativeKeyBindings[eventString] = handlerName;
+ this._prepKeyBindings();
+ this._resetKeyEventListeners();
+ },
+
+ /**
+ * When called, will remove all imperatively-added key bindings.
+ */
+ removeOwnKeyBindings: function() {
+ this._imperativeKeyBindings = {};
+ this._prepKeyBindings();
+ this._resetKeyEventListeners();
+ },
+
+ /**
+ * Returns true if a keyboard event matches `eventString`.
+ *
+ * @param {KeyboardEvent} event
+ * @param {string} eventString
+ * @return {boolean}
+ */
+ keyboardEventMatchesKeys: function(event, eventString) {
+ var keyCombos = parseEventString(eventString);
+ for (var i = 0; i < keyCombos.length; ++i) {
+ if (keyComboMatchesEvent(keyCombos[i], event)) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _collectKeyBindings: function() {
+ var keyBindings = this.behaviors.map(function(behavior) {
+ return behavior.keyBindings;
+ });
+
+ if (keyBindings.indexOf(this.keyBindings) === -1) {
+ keyBindings.push(this.keyBindings);
+ }
+
+ return keyBindings;
+ },
+
+ _prepKeyBindings: function() {
+ this._keyBindings = {};
+
+ this._collectKeyBindings().forEach(function(keyBindings) {
+ for (var eventString in keyBindings) {
+ this._addKeyBinding(eventString, keyBindings[eventString]);
+ }
+ }, this);
+
+ for (var eventString in this._imperativeKeyBindings) {
+ this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
+ }
+
+ // Give precedence to combos with modifiers to be checked first.
+ for (var eventName in this._keyBindings) {
+ this._keyBindings[eventName].sort(function (kb1, kb2) {
+ var b1 = kb1[0].hasModifiers;
+ var b2 = kb2[0].hasModifiers;
+ return (b1 === b2) ? 0 : b1 ? -1 : 1;
+ })
+ }
+ },
+
+ _addKeyBinding: function(eventString, handlerName) {
+ parseEventString(eventString).forEach(function(keyCombo) {
+ this._keyBindings[keyCombo.event] =
+ this._keyBindings[keyCombo.event] || [];
+
+ this._keyBindings[keyCombo.event].push([
+ keyCombo,
+ handlerName
+ ]);
+ }, this);
+ },
+
+ _resetKeyEventListeners: function() {
+ this._unlistenKeyEventListeners();
+
+ if (this.isAttached) {
+ this._listenKeyEventListeners();
+ }
+ },
+
+ _listenKeyEventListeners: function() {
+ if (!this.keyEventTarget) {
+ return;
+ }
+ Object.keys(this._keyBindings).forEach(function(eventName) {
+ var keyBindings = this._keyBindings[eventName];
+ var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
+
+ this._boundKeyHandlers.push([this.keyEventTarget, eventName, boundKeyHandler]);
+
+ this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
+ }, this);
+ },
+
+ _unlistenKeyEventListeners: function() {
+ var keyHandlerTuple;
+ var keyEventTarget;
+ var eventName;
+ var boundKeyHandler;
+
+ while (this._boundKeyHandlers.length) {
+ // My kingdom for block-scope binding and destructuring assignment..
+ keyHandlerTuple = this._boundKeyHandlers.pop();
+ keyEventTarget = keyHandlerTuple[0];
+ eventName = keyHandlerTuple[1];
+ boundKeyHandler = keyHandlerTuple[2];
+
+ keyEventTarget.removeEventListener(eventName, boundKeyHandler);
+ }
+ },
+
+ _onKeyBindingEvent: function(keyBindings, event) {
+ if (this.stopKeyboardEventPropagation) {
+ event.stopPropagation();
+ }
+
+ // if event has been already prevented, don't do anything
+ if (event.defaultPrevented) {
+ return;
+ }
+
+ for (var i = 0; i < keyBindings.length; i++) {
+ var keyCombo = keyBindings[i][0];
+ var handlerName = keyBindings[i][1];
+ if (keyComboMatchesEvent(keyCombo, event)) {
+ this._triggerKeyHandler(keyCombo, handlerName, event);
+ // exit the loop if eventDefault was prevented
+ if (event.defaultPrevented) {
+ return;
+ }
+ }
+ }
+ },
+
+ _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
+ var detail = Object.create(keyCombo);
+ detail.keyboardEvent = keyboardEvent;
+ var event = new CustomEvent(keyCombo.event, {
+ detail: detail,
+ cancelable: true
+ });
+ this[handlerName].call(this, event);
+ if (event.defaultPrevented) {
+ keyboardEvent.preventDefault();
+ }
+ }
+ };
+ })();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.bower.json
new file mode 100644
index 00000000000..e6d37e625c7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.bower.json
@@ -0,0 +1,48 @@
+{
+ "name": "iron-autogrow-textarea",
+ "version": "1.0.12",
+ "description": "A textarea element that automatically grows with input",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input",
+ "textarea"
+ ],
+ "main": "iron-autogrow-textarea.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-autogrow-textarea.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-autogrow-textarea",
+ "ignore": [],
+ "dependencies": {
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.0.12",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.12",
+ "commit": "86f8fd61b412bcea6bc7b8feaee9b24bc2ad48ea"
+ },
+ "_source": "git://github.com/PolymerElements/iron-autogrow-textarea.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-autogrow-textarea"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.travis.yml
new file mode 100644
index 00000000000..771bf35d1e6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: lIogwlz5kFUKYy1OWASXxQgZE4YTyjUY0QcEgnqbv6wQ0GX8wRMgbI3zhbAv+xXU5ieYXg6Bd47ZFZZ1kVEWzQynAdd2od14Eu1vfN60/yc/llz62VTYuFsPt8r+Tgw41Iz8plwejK4a+V26Da5tXW+soJQOJKvE/MOiPzKi2m0=
+ - secure: cj3uSCQwLY6pyP3oTdGFjJoTRjv3G1lSe73fMd6i15XnMMxM4DVarfDtK+a0dPPxDY8BBhfr4sFClZuWX71bAHQuqUA84oigbeWt2xfl8d3HUuvr9aEnQxAGe2eQE7atpYJPC9M447sw48QKiUVgQo33DeJ1BGj6SBqkw0BJXO8=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/README.md
new file mode 100644
index 00000000000..b207d330fd1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/README.md
@@ -0,0 +1,44 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-autogrow-textarea.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-autogrow-textarea.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-autogrow-textarea)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-autogrow-textarea)_
+
+
+##&lt;iron-autogrow-textarea&gt;
+
+`iron-autogrow-textarea` is an element containing a textarea that grows in height as more
+lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
+never scroll.
+
+Example:
+
+```html
+<iron-autogrow-textarea></iron-autogrow-textarea>
+```
+
+Because the `textarea`'s `value` property is not observable, you should use
+this element's `bind-value` instead for imperative updates.
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-autogrow-textarea` | Mixin applied to the textarea | `{}` |
+| `--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/bower.json
new file mode 100644
index 00000000000..67be4a66860
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/bower.json
@@ -0,0 +1,39 @@
+{
+ "name": "iron-autogrow-textarea",
+ "version": "1.0.12",
+ "description": "A textarea element that automatically grows with input",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input",
+ "textarea"
+ ],
+ "main": "iron-autogrow-textarea.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-autogrow-textarea.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-autogrow-textarea",
+ "ignore": [],
+ "dependencies": {
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/demo/index.html
new file mode 100644
index 00000000000..525d90a43e8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/demo/index.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-autogrow-textarea demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../iron-autogrow-textarea.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ iron-autogrow-textarea {
+ display: block;
+ width: 200px;
+ margin: 5px 0;
+ }
+
+ textarea {
+ width: 200px;
+ }
+
+ .vertical-section {
+ box-sizing: border-box;
+ width: 400px;
+ margin: 0;
+ }
+ </style>
+ </head>
+ <body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>An iron-autogrow-textarea grows automatically as more text is entered</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <iron-autogrow-textarea></iron-autogrow-textarea>
+ </template>
+ </demo-snippet>
+
+ <h3>The maximum height can be controlled either through the <i>max-rows</i>
+ property, or through a fixed max height</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <iron-autogrow-textarea max-rows="4" placeholder="scrolls after 4 rows"></iron-autogrow-textarea>
+ <iron-autogrow-textarea style="max-height: 50px;" placeholder="scrolls after 50px"></iron-autogrow-textarea>
+ </template>
+ </demo-snippet>
+
+ <h3>The initial height can also be controlled using the <i>rows</i> property,
+ or through a fixed height</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <iron-autogrow-textarea rows="4" placeholder="start with 4 rows"></iron-autogrow-textarea>
+ <iron-autogrow-textarea style="height: 50px;"></iron-autogrow-textarea>
+ </template>
+ </demo-snippet>
+
+ <h3>Example of updating the value imperatively</h3>
+ <!-- TODO: replace this with a demo-snippet when https://github.com/webcomponents/webcomponentsjs/issues/362
+ is fixed -->
+ <div class="example">
+ <template is="dom-bind">
+ <div class="vertical-section">
+ <iron-autogrow-textarea bind-value="{{bindValue}}" id="a1"></iron-autogrow-textarea>
+ <br>
+ <code>bind-value</code>: <span>[[bindValue]]</span>
+ <p on-click="setValue">
+ Imperatively changing <code>bind-value</code> will also update
+ <code>textarea.value</code>:<br>
+ <textarea></textarea>
+ <button value="bindValue">set</button>
+ <br><br>
+
+ Imperatively updating <code>textarea.value</code> will update
+ the display, but not update <code>bind-value</code>:<br>
+ <textarea></textarea>
+ <button value="value">set</button>
+ </p>
+ </div>
+ </template>
+ </div>
+ </div>
+ <script>
+ var scope = document.querySelector('template[is=dom-bind]');
+
+ scope.setValue = function(event) {
+ if (!(event.target instanceof HTMLButtonElement)) {
+ return;
+ }
+ var inputValue = event.target.previousElementSibling.value;
+ if (event.target.value == "bindValue") {
+ document.querySelector('#a1').bindValue = inputValue;
+ } else {
+ document.querySelector('#a1').textarea.value = inputValue;
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/hero.svg
new file mode 100755
index 00000000000..19ec70a0545
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/hero.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <path d="M140,47c-3,0-4.7-2.4-6.2-4.4c-1.3-1.9-2.4-3.6-4.7-3.6c-2.3,0-3.4,1.7-4.7,3.6c-1.5,2.1-3.1,4.4-6.4,4.4
+ c-3.3,0-4.9-2.4-6.4-4.4c-1.3-1.9-2.5-3.6-4.8-3.6c-2.3,0-3.4,1.7-4.8,3.6c-1.5,2.1-3.1,4.4-6.4,4.4s-5.2-2.4-6.7-4.4
+ c-1.3-1.9-2-3.6-5-3.6v-2c4,0,5.2,2.4,6.7,4.4c1.3,1.9,2.6,3.6,4.9,3.6c2.3,0,3.5-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.5-4.4
+ s5,2.4,6.4,4.4c1.3,1.9,2.5,3.6,4.8,3.6c2.3,0,3.4-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.4-4.4c3.3,0,4.7,2.4,6.2,4.4
+ c1.3,1.9,2.5,3.6,4.5,3.6V47z"/>
+ <path d="M140,65c-3,0-4.7-2.4-6.2-4.4c-1.3-1.9-2.4-3.6-4.7-3.6c-2.3,0-3.4,1.7-4.7,3.6c-1.5,2.1-3.1,4.4-6.4,4.4
+ c-3.3,0-4.9-2.4-6.4-4.4c-1.3-1.9-2.5-3.6-4.8-3.6c-2.3,0-3.4,1.7-4.8,3.6c-1.5,2.1-3.1,4.4-6.4,4.4s-5.2-2.4-6.7-4.4
+ c-1.3-1.9-2-3.6-5-3.6v-2c4,0,5.2,2.4,6.7,4.4c1.3,1.9,2.6,3.6,4.9,3.6c2.3,0,3.5-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.5-4.4
+ s5,2.4,6.4,4.4c1.3,1.9,2.5,3.6,4.8,3.6c2.3,0,3.4-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.4-4.4c3.3,0,4.7,2.4,6.2,4.4
+ c1.3,1.9,2.5,3.6,4.5,3.6V65z"/>
+ <path d="M140,83c-3,0-4.7-2.4-6.2-4.4c-1.3-1.9-2.4-3.6-4.7-3.6c-2.3,0-3.4,1.7-4.7,3.6c-1.5,2.1-3.1,4.4-6.4,4.4
+ c-3.3,0-4.9-2.4-6.4-4.4c-1.3-1.9-2.5-3.6-4.8-3.6c-2.3,0-3.4,1.7-4.8,3.6c-1.5,2.1-3.1,4.4-6.4,4.4s-5.2-2.4-6.7-4.4
+ c-1.3-1.9-2-3.6-5-3.6v-2c4,0,5.2,2.4,6.7,4.4c1.3,1.9,2.6,3.6,4.9,3.6c2.3,0,3.5-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.5-4.4
+ s5,2.4,6.4,4.4c1.3,1.9,2.5,3.6,4.8,3.6c2.3,0,3.4-1.7,4.8-3.6c1.5-2.1,3.1-4.4,6.4-4.4c3.3,0,4.7,2.4,6.2,4.4
+ c1.3,1.9,2.5,3.6,4.5,3.6V83z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+ <path d="M151,102H73V24h78V102z M75,100h74V26H75V100z"/>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/index.html
new file mode 100644
index 00000000000..3be2964faf2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-autogrow-textarea</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+ </head>
+ <body>
+
+ <iron-component-page></iron-component-page>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/iron-autogrow-textarea.html b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/iron-autogrow-textarea.html
new file mode 100644
index 00000000000..b04f89b3bd7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-autogrow-textarea/iron-autogrow-textarea.html
@@ -0,0 +1,353 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+
+<!--
+`iron-autogrow-textarea` is an element containing a textarea that grows in height as more
+lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
+never scroll.
+
+Example:
+
+ <iron-autogrow-textarea></iron-autogrow-textarea>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--iron-autogrow-textarea` | Mixin applied to the textarea | `{}`
+`--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}`
+
+@group Iron Elements
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="iron-autogrow-textarea">
+
+ <style>
+ :host {
+ display: inline-block;
+ position: relative;
+ width: 400px;
+ border: 1px solid;
+ padding: 2px;
+ -moz-appearance: textarea;
+ -webkit-appearance: textarea;
+ overflow: hidden;
+ }
+
+ .mirror-text {
+ visibility: hidden;
+ word-wrap: break-word;
+ }
+
+ .fit {
+ @apply(--layout-fit);
+ }
+
+ textarea {
+ position: relative;
+ outline: none;
+ border: none;
+ resize: none;
+ background: inherit;
+ color: inherit;
+ /* see comments in template */
+ width: 100%;
+ height: 100%;
+ font-size: inherit;
+ font-family: inherit;
+ line-height: inherit;
+ text-align: inherit;
+ @apply(--iron-autogrow-textarea);
+ }
+
+ ::content textarea:invalid {
+ box-shadow: none;
+ }
+
+ textarea::-webkit-input-placeholder {
+ @apply(--iron-autogrow-textarea-placeholder);
+ }
+
+ textarea:-moz-placeholder {
+ @apply(--iron-autogrow-textarea-placeholder);
+ }
+
+ textarea::-moz-placeholder {
+ @apply(--iron-autogrow-textarea-placeholder);
+ }
+
+ textarea:-ms-input-placeholder {
+ @apply(--iron-autogrow-textarea-placeholder);
+ }
+ </style>
+ <template>
+ <!-- the mirror sizes the input/textarea so it grows with typing -->
+ <!-- use &#160; instead &nbsp; of to allow this element to be used in XHTML -->
+ <div id="mirror" class="mirror-text" aria-hidden="true">&#160;</div>
+
+ <!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
+ <div class="textarea-container fit">
+ <textarea id="textarea"
+ name$="[[name]]"
+ autocomplete$="[[autocomplete]]"
+ autofocus$="[[autofocus]]"
+ inputmode$="[[inputmode]]"
+ placeholder$="[[placeholder]]"
+ readonly$="[[readonly]]"
+ required$="[[required]]"
+ disabled$="[[disabled]]"
+ rows$="[[rows]]"
+ maxlength$="[[maxlength]]"></textarea>
+ </div>
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'iron-autogrow-textarea',
+
+ behaviors: [
+ Polymer.IronFormElementBehavior,
+ Polymer.IronValidatableBehavior,
+ Polymer.IronControlState
+ ],
+
+ properties: {
+
+ /**
+ * Use this property instead of `value` for two-way data binding.
+ * This property will be deprecated in the future. Use `value` instead.
+ * @type {string|number}
+ */
+ bindValue: {
+ observer: '_bindValueChanged',
+ type: String
+ },
+
+ /**
+ * The initial number of rows.
+ *
+ * @attribute rows
+ * @type number
+ * @default 1
+ */
+ rows: {
+ type: Number,
+ value: 1,
+ observer: '_updateCached'
+ },
+
+ /**
+ * The maximum number of rows this element can grow to until it
+ * scrolls. 0 means no maximum.
+ *
+ * @attribute maxRows
+ * @type number
+ * @default 0
+ */
+ maxRows: {
+ type: Number,
+ value: 0,
+ observer: '_updateCached'
+ },
+
+ /**
+ * Bound to the textarea's `autocomplete` attribute.
+ */
+ autocomplete: {
+ type: String,
+ value: 'off'
+ },
+
+ /**
+ * Bound to the textarea's `autofocus` attribute.
+ */
+ autofocus: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Bound to the textarea's `inputmode` attribute.
+ */
+ inputmode: {
+ type: String
+ },
+
+ /**
+ * Bound to the textarea's `placeholder` attribute.
+ */
+ placeholder: {
+ type: String
+ },
+
+ /**
+ * Bound to the textarea's `readonly` attribute.
+ */
+ readonly: {
+ type: String
+ },
+
+ /**
+ * Set to true to mark the textarea as required.
+ */
+ required: {
+ type: Boolean
+ },
+
+ /**
+ * The maximum length of the input value.
+ */
+ maxlength: {
+ type: Number
+ }
+
+ },
+
+ listeners: {
+ 'input': '_onInput'
+ },
+
+ observers: [
+ '_onValueChanged(value)'
+ ],
+
+ /**
+ * Returns the underlying textarea.
+ * @type HTMLTextAreaElement
+ */
+ get textarea() {
+ return this.$.textarea;
+ },
+
+ /**
+ * Returns textarea's selection start.
+ * @type Number
+ */
+ get selectionStart() {
+ return this.$.textarea.selectionStart;
+ },
+
+ /**
+ * Returns textarea's selection end.
+ * @type Number
+ */
+ get selectionEnd() {
+ return this.$.textarea.selectionEnd;
+ },
+
+ /**
+ * Sets the textarea's selection start.
+ */
+ set selectionStart(value) {
+ this.$.textarea.selectionStart = value;
+ },
+
+ /**
+ * Sets the textarea's selection end.
+ */
+ set selectionEnd(value) {
+ this.$.textarea.selectionEnd = value;
+ },
+
+ /**
+ * Returns true if `value` is valid. The validator provided in `validator`
+ * will be used first, if it exists; otherwise, the `textarea`'s validity
+ * is used.
+ * @return {boolean} True if the value is valid.
+ */
+ validate: function() {
+ // Empty, non-required input is valid.
+ if (!this.required && this.value == '') {
+ this.invalid = false;
+ return true;
+ }
+
+ var valid;
+ if (this.hasValidator()) {
+ valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
+ } else {
+ valid = this.$.textarea.validity.valid;
+ this.invalid = !valid;
+ }
+ this.fire('iron-input-validate');
+ return valid;
+ },
+
+ _bindValueChanged: function() {
+ var textarea = this.textarea;
+ if (!textarea) {
+ return;
+ }
+
+ // If the bindValue changed manually, then we need to also update
+ // the underlying textarea's value. Otherwise this change was probably
+ // generated from the _onInput handler, and the two values are already
+ // the same.
+ if (textarea.value !== this.bindValue) {
+ textarea.value = !(this.bindValue || this.bindValue === 0) ? '' : this.bindValue;
+ }
+
+ this.value = this.bindValue;
+ this.$.mirror.innerHTML = this._valueForMirror();
+ // manually notify because we don't want to notify until after setting value
+ this.fire('bind-value-changed', {value: this.bindValue});
+ },
+
+ _onInput: function(event) {
+ this.bindValue = event.path ? event.path[0].value : event.target.value;
+ },
+
+ _constrain: function(tokens) {
+ var _tokens;
+ tokens = tokens || [''];
+ // Enforce the min and max heights for a multiline input to avoid measurement
+ if (this.maxRows > 0 && tokens.length > this.maxRows) {
+ _tokens = tokens.slice(0, this.maxRows);
+ } else {
+ _tokens = tokens.slice(0);
+ }
+ while (this.rows > 0 && _tokens.length < this.rows) {
+ _tokens.push('');
+ }
+ // Use &#160; instead &nbsp; of to allow this element to be used in XHTML.
+ return _tokens.join('<br/>') + '&#160;';
+ },
+
+ _valueForMirror: function() {
+ var input = this.textarea;
+ if (!input) {
+ return;
+ }
+ this.tokens = (input && input.value) ? input.value.replace(/&/gm, '&amp;').replace(/"/gm, '&quot;').replace(/'/gm, '&#39;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;').split('\n') : [''];
+ return this._constrain(this.tokens);
+ },
+
+ _updateCached: function() {
+ this.$.mirror.innerHTML = this._constrain(this.tokens);
+ },
+
+ _onValueChanged: function() {
+ this.bindValue = this.value;
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.bower.json
new file mode 100644
index 00000000000..a8b8863cc88
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "iron-behaviors",
+ "version": "1.0.16",
+ "description": "Provides a set of behaviors for the iron elements",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-behaviors.git"
+ },
+ "main": [
+ "iron-button-state.html",
+ "iron-control-state.html"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "paper-input": "polymerelements/paper-input#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/polymerelements/iron-behaviors",
+ "_release": "1.0.16",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.16",
+ "commit": "161e67233c4776e32a275a719a000865ed309393"
+ },
+ "_source": "git://github.com/polymerelements/iron-behaviors.git",
+ "_target": "^1.0.0",
+ "_originalSource": "polymerelements/iron-behaviors"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.github/ISSUE_TEMPLATE.md b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000000..1cc85c0c790
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+<!-- Instructions: https://github.com/PolymerElements/iron-behaviors/CONTRIBUTING.md#filing-issues -->
+### Description
+<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
+
+### Expected outcome
+
+<!-- Example: The page stays the same color. -->
+
+### Actual outcome
+
+<!-- Example: The page turns pink. -->
+
+### Live Demo
+<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
+
+### Steps to reproduce
+
+<!-- Example
+1. Put a `paper-foo` element in the page.
+2. Open the page in a web browser.
+3. Click the `paper-foo` element.
+-->
+
+### Browsers Affected
+<!-- Check all that apply -->
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari 9
+- [ ] Safari 8
+- [ ] Safari 7
+- [ ] Edge
+- [ ] IE 11
+- [ ] IE 10
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.travis.yml
new file mode 100644
index 00000000000..9379f90f5b0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: ZOqj2XVNVwfT74rHxg/ljcAsS6FnmDpRSsXbsy1Icv9DcLHrMlmyQ10gWBjE/YXYF0Uv4akQ1qqn0TJaKOtp9HZeH+P6OPAYk2vJbWD7qp52pPtIqEFomcsUyflt4IjfaXKuN4FMod7PSWVSGJ+DxSguJvZKILkrs5d/rJdFv3c=
+ - secure: clkqemGQG16TXyAPkv9LBv6x3SbT3ZM0eo8LETx4uNKi3WzlwgXxZA9b5Sr5wYzxyxFFpnhDXW7CL4+UjYu1atGNeTW2TuSaYUPHtgu67OFDr8Jbw047p1XQb5enPSt9+YxrHKfjHBiJvWulJ8rCSQshU9Rhe0DC6NrFRPFgk0A=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/README.md
new file mode 100644
index 00000000000..0a0629ec7e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/README.md
@@ -0,0 +1,22 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-button-state.html iron-control-state.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-behaviors.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-behaviors)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-behaviors)_
+
+
+<!-- No docs for Polymer.IronButtonState found. -->
+
+<!-- No docs for Polymer.IronControlState found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/bower.json
new file mode 100644
index 00000000000..89d24c05148
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/bower.json
@@ -0,0 +1,32 @@
+{
+ "name": "iron-behaviors",
+ "version": "1.0.16",
+ "description": "Provides a set of behaviors for the iron elements",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-behaviors.git"
+ },
+ "main": [
+ "iron-button-state.html",
+ "iron-control-state.html"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "paper-input": "polymerelements/paper-input#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/index.html
new file mode 100644
index 00000000000..51fe2d648a4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>simple-button</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link href="../../paper-styles/demo-pages.html" rel="import">
+ <link href="simple-button.html" rel="import">
+
+ <style>
+
+ .vertical-section {
+ text-align: center;
+ }
+
+ </style>
+
+</head>
+<body>
+ <div class="vertical-section vertical-section-container centered">
+ <h3>Normal</h3>
+
+ <simple-button tabindex="0">Hello World</simple-button>
+
+ <h3>Toggles</h3>
+
+ <simple-button toggles tabindex="0">Hello World</simple-button>
+
+ <h3>Disabled</h3>
+
+ <simple-button disabled tabindex="0">Hello World</simple-button>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/simple-button.html b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/simple-button.html
new file mode 100644
index 00000000000..8df8635de34
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/demo/simple-button.html
@@ -0,0 +1,71 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-button-state.html">
+<link rel="import" href="../iron-control-state.html">
+
+<dom-module id="simple-button">
+
+ <style>
+
+ :host {
+ display: inline-block;
+ background-color: #4285F4;
+ color: #fff;
+ min-height: 8px;
+ min-width: 8px;
+ padding: 16px;
+ text-transform: uppercase;
+ border-radius: 3px;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ }
+
+ :host([disabled]) {
+ opacity: 0.3;
+ pointer-events: none;
+ }
+
+ :host([active]),
+ :host([pressed]) {
+ background-color: #3367D6;
+ box-shadow: inset 0 3px 5px rgba(0,0,0,.2);
+ }
+
+ </style>
+
+ <template>
+
+ <content></content>
+
+ </template>
+
+ <script>
+
+ Polymer({
+
+ behaviors: [
+ Polymer.IronControlState,
+ Polymer.IronButtonState
+ ],
+
+ hostAttributes: {
+ role: 'button'
+ }
+ });
+
+ </script>
+
+</dom-module>
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/index.html
new file mode 100644
index 00000000000..220deb00349
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/index.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>Iron Behaviors</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page src="iron-button-state.html"></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-button-state.html b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-button-state.html
new file mode 100644
index 00000000000..8114e2ddea8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-button-state.html
@@ -0,0 +1,228 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="iron-control-state.html">
+
+<script>
+
+ /**
+ * @demo demo/index.html
+ * @polymerBehavior Polymer.IronButtonState
+ */
+ Polymer.IronButtonStateImpl = {
+
+ properties: {
+
+ /**
+ * If true, the user is currently holding down the button.
+ */
+ pressed: {
+ type: Boolean,
+ readOnly: true,
+ value: false,
+ reflectToAttribute: true,
+ observer: '_pressedChanged'
+ },
+
+ /**
+ * If true, the button toggles the active state with each tap or press
+ * of the spacebar.
+ */
+ toggles: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ /**
+ * If true, the button is a toggle and is currently in the active state.
+ */
+ active: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ reflectToAttribute: true
+ },
+
+ /**
+ * True if the element is currently being pressed by a "pointer," which
+ * is loosely defined as mouse or touch input (but specifically excluding
+ * keyboard input).
+ */
+ pointerDown: {
+ type: Boolean,
+ readOnly: true,
+ value: false
+ },
+
+ /**
+ * True if the input device that caused the element to receive focus
+ * was a keyboard.
+ */
+ receivedFocusFromKeyboard: {
+ type: Boolean,
+ readOnly: true
+ },
+
+ /**
+ * The aria attribute to be set if the button is a toggle and in the
+ * active state.
+ */
+ ariaActiveAttribute: {
+ type: String,
+ value: 'aria-pressed',
+ observer: '_ariaActiveAttributeChanged'
+ }
+ },
+
+ listeners: {
+ down: '_downHandler',
+ up: '_upHandler',
+ tap: '_tapHandler'
+ },
+
+ observers: [
+ '_detectKeyboardFocus(focused)',
+ '_activeChanged(active, ariaActiveAttribute)'
+ ],
+
+ keyBindings: {
+ 'enter:keydown': '_asyncClick',
+ 'space:keydown': '_spaceKeyDownHandler',
+ 'space:keyup': '_spaceKeyUpHandler',
+ },
+
+ _mouseEventRe: /^mouse/,
+
+ _tapHandler: function() {
+ if (this.toggles) {
+ // a tap is needed to toggle the active state
+ this._userActivate(!this.active);
+ } else {
+ this.active = false;
+ }
+ },
+
+ _detectKeyboardFocus: function(focused) {
+ this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
+ },
+
+ // to emulate native checkbox, (de-)activations from a user interaction fire
+ // 'change' events
+ _userActivate: function(active) {
+ if (this.active !== active) {
+ this.active = active;
+ this.fire('change');
+ }
+ },
+
+ _downHandler: function(event) {
+ this._setPointerDown(true);
+ this._setPressed(true);
+ this._setReceivedFocusFromKeyboard(false);
+ },
+
+ _upHandler: function() {
+ this._setPointerDown(false);
+ this._setPressed(false);
+ },
+
+ /**
+ * @param {!KeyboardEvent} event .
+ */
+ _spaceKeyDownHandler: function(event) {
+ var keyboardEvent = event.detail.keyboardEvent;
+ var target = Polymer.dom(keyboardEvent).localTarget;
+
+ // Ignore the event if this is coming from a focused light child, since that
+ // element will deal with it.
+ if (this.isLightDescendant(/** @type {Node} */(target)))
+ return;
+
+ keyboardEvent.preventDefault();
+ keyboardEvent.stopImmediatePropagation();
+ this._setPressed(true);
+ },
+
+ /**
+ * @param {!KeyboardEvent} event .
+ */
+ _spaceKeyUpHandler: function(event) {
+ var keyboardEvent = event.detail.keyboardEvent;
+ var target = Polymer.dom(keyboardEvent).localTarget;
+
+ // Ignore the event if this is coming from a focused light child, since that
+ // element will deal with it.
+ if (this.isLightDescendant(/** @type {Node} */(target)))
+ return;
+
+ if (this.pressed) {
+ this._asyncClick();
+ }
+ this._setPressed(false);
+ },
+
+ // trigger click asynchronously, the asynchrony is useful to allow one
+ // event handler to unwind before triggering another event
+ _asyncClick: function() {
+ this.async(function() {
+ this.click();
+ }, 1);
+ },
+
+ // any of these changes are considered a change to button state
+
+ _pressedChanged: function(pressed) {
+ this._changedButtonState();
+ },
+
+ _ariaActiveAttributeChanged: function(value, oldValue) {
+ if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
+ this.removeAttribute(oldValue);
+ }
+ },
+
+ _activeChanged: function(active, ariaActiveAttribute) {
+ if (this.toggles) {
+ this.setAttribute(this.ariaActiveAttribute,
+ active ? 'true' : 'false');
+ } else {
+ this.removeAttribute(this.ariaActiveAttribute);
+ }
+ this._changedButtonState();
+ },
+
+ _controlStateChanged: function() {
+ if (this.disabled) {
+ this._setPressed(false);
+ } else {
+ this._changedButtonState();
+ }
+ },
+
+ // provide hook for follow-on behaviors to react to button-state
+
+ _changedButtonState: function() {
+ if (this._buttonStateChanged) {
+ this._buttonStateChanged(); // abstract
+ }
+ }
+
+ };
+
+ /** @polymerBehavior */
+ Polymer.IronButtonState = [
+ Polymer.IronA11yKeysBehavior,
+ Polymer.IronButtonStateImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-control-state.html b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-control-state.html
new file mode 100644
index 00000000000..f34d057994a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-behaviors/iron-control-state.html
@@ -0,0 +1,110 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /**
+ * @demo demo/index.html
+ * @polymerBehavior
+ */
+ Polymer.IronControlState = {
+
+ properties: {
+
+ /**
+ * If true, the element currently has focus.
+ */
+ focused: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ readOnly: true,
+ reflectToAttribute: true
+ },
+
+ /**
+ * If true, the user cannot interact with this element.
+ */
+ disabled: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ observer: '_disabledChanged',
+ reflectToAttribute: true
+ },
+
+ _oldTabIndex: {
+ type: Number
+ },
+
+ _boundFocusBlurHandler: {
+ type: Function,
+ value: function() {
+ return this._focusBlurHandler.bind(this);
+ }
+ }
+
+ },
+
+ observers: [
+ '_changedControlState(focused, disabled)'
+ ],
+
+ ready: function() {
+ this.addEventListener('focus', this._boundFocusBlurHandler, true);
+ this.addEventListener('blur', this._boundFocusBlurHandler, true);
+ },
+
+ _focusBlurHandler: function(event) {
+ // NOTE(cdata): if we are in ShadowDOM land, `event.target` will
+ // eventually become `this` due to retargeting; if we are not in
+ // ShadowDOM land, `event.target` will eventually become `this` due
+ // to the second conditional which fires a synthetic event (that is also
+ // handled). In either case, we can disregard `event.path`.
+
+ if (event.target === this) {
+ this._setFocused(event.type === 'focus');
+ } else if (!this.shadowRoot) {
+ var target = /** @type {Node} */(Polymer.dom(event).localTarget);
+ if (!this.isLightDescendant(target)) {
+ this.fire(event.type, {sourceEvent: event}, {
+ node: this,
+ bubbles: event.bubbles,
+ cancelable: event.cancelable
+ });
+ }
+ }
+ },
+
+ _disabledChanged: function(disabled, old) {
+ this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
+ this.style.pointerEvents = disabled ? 'none' : '';
+ if (disabled) {
+ this._oldTabIndex = this.tabIndex;
+ this._setFocused(false);
+ this.tabIndex = -1;
+ this.blur();
+ } else if (this._oldTabIndex !== undefined) {
+ this.tabIndex = this._oldTabIndex;
+ }
+ },
+
+ _changedControlState: function() {
+ // _controlStateChanged is abstract, follow-on behaviors may implement it
+ if (this._controlStateChanged) {
+ this._controlStateChanged();
+ }
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.bower.json
new file mode 100644
index 00000000000..31b32b0aef1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.bower.json
@@ -0,0 +1,43 @@
+{
+ "name": "iron-checked-element-behavior",
+ "version": "1.0.4",
+ "description": "Implements an element that has a checked attribute and can be added to a form",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "main": "iron-checked-element-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-checked-element-behavior.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-checked-element-behavior",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "*",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.0.4",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.4",
+ "commit": "cc30263ec2871ae8f8f944948f44299d3f3cdf0d"
+ },
+ "_source": "git://github.com/PolymerElements/iron-checked-element-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-checked-element-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.travis.yml
new file mode 100644
index 00000000000..0b7456d71e8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/.travis.yml
@@ -0,0 +1,22 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install web-component-tester
+ - npm install bower
+ - 'export PATH=$PWD/node_modules/.bin:$PATH'
+ - bower install
+env:
+ global:
+ - secure: EJSBYkW/C3ppDTbxHYRzyFPAko5R1ET1LSbdM484/j0OHGLkSIwtKrrZLNz5+QEmKSw79MpLpBoD+SfXuSCn0yKkf6tvK4mt+kRs32vKVfoWrYReVcfth+EWV7QDpTDJw1QEijT1bKUxULhP0OrT2/5vVpKpXX2zczg+VFL7IZuY3y1dsA4qWmWTfMiAk3762dZx47D5qzJ4POHlpG0i/cHH2EgqV8sFXFBctf6EY68GqzStPUuMuea6xX2wMrebg6vqQDfDb1gs8N34gxGE+u8QaqOSniW1Vzdoe1vwOUo4dbJYw3JMYK5Qn2pj3p2E4m9J609JNnBfqjS7mB5KVC7Hf5r9ul3UMsAIlOnlmSqOq1oO22/3regjWHGjlrzCNHzma2SgDhTxGaLDJl1LnsUevbVb6TGloiQPXwum8oa7dvZ1PqspqyqZEb31t/FyUnG+VXnC0YYpdRj3eRGqeoqqaNtad97DrPHP7er9LdvJIKjsXux7gUW4hKWsr+jsU/krdHpTUC8GYWdTF54EcLhxfzNYKL7voTq+xoQ2yxCOSiBmcQCviuQyVvNQyhde/+edAmOt24CLiuSQjHCbEWzBQs9QinUPRekg6+LJ1WaifTIKkhsm04AdaZrs7LR34hF+Mpqp4HHl/AfcbtVeB/W7jUnhJyMFaQDfGkpzSZs=
+ - secure: izhN5Z3WdajR3ois2T55qepsvLwVg/wv8u4kVQ4TqWhUL08tka83m/W+EMzS/tcvfz7J3VkuTFrJ5scYD9kaTVhRo4dv2u+DdbPmTNcf/hmADXLVLxddyueK3bWEcBurg8+rSdqq/RdI+5CPwWeGtQl+lmjRCyBzodIpQ90zJQF4Al7nmmLuEUhiNVjuqQ3VB1pFLYgky4SVM0bfJnoKSDsZ2z9DOOJE34ZUUmcNqVcQoZ5/oM+PWdVDkUqW3vMK1lTMtE/dk6WcSztQwFyoMrW+uzEstPwUsJCyuBEx4KdioXZH3vrlxRApySfHmEf5eVWwE6jyPSHuWj/2D5O4R9LY1dq1Wcoiu3BJj19B4V3s4L2uJF+xL077d4Mna6z9dE4RSRzs8Z8MvSMTgzDkga/A25JI3XxJMJ78WTbkNQ4hVFN2xwcU5cm+fbs3Sr1ZEdFW/MWAPtUQOzscqS5Op7sSLLaiqO+R0zj56H2NA2bl/zCmbZhyLcOPl0oAfJ85bqNxyF8CoO+GZ98UG15ROigC90/HCP7TUHZnQSrGtiFGTiPTBm+VCITYmC5IEyJBTwgqh/ljbDzz4UuSZ3KsldL3MwWnqO3tGr6VvPfqKF6xq0vuyn9P7f9WNAYwZGcRi3AtxtY+znO+IGv2sGmrfo7ZY+U4nceXTEDrG8OY0Jo=
+node_js: 4
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/README.md
new file mode 100644
index 00000000000..fc570916df1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/README.md
@@ -0,0 +1,25 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-checked-element-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-checked-element-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-checked-element-behavior)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-checked-element-behavior)_
+
+
+##Polymer.IronCheckedElementBehavior
+
+
+Use `Polymer.IronCheckedElementBehavior` to implement a custom element
+that has a `checked` property, which can be used for validation if the
+element is also `required`. Element instances implementing this behavior
+will also be registered for use in an `iron-form` element.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/bower.json
new file mode 100644
index 00000000000..65154c82faf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/bower.json
@@ -0,0 +1,34 @@
+{
+ "name": "iron-checked-element-behavior",
+ "version": "1.0.4",
+ "description": "Implements an element that has a checked attribute and can be added to a form",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "main": "iron-checked-element-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-checked-element-behavior.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-checked-element-behavior",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "*",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/index.html
new file mode 100644
index 00000000000..788a64f0016
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/index.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-checked-element-behavior demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="simple-checkbox.html">
+</head>
+<body unresolved>
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Not required</h4>
+ <div class="horizontal-section">
+ <simple-checkbox></simple-checkbox>
+ </div>
+ </div>
+ <div>
+ <h4>Required</h4>
+ <div class="horizontal-section">
+ <simple-checkbox required></simple-checkbox>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/simple-checkbox.html b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/simple-checkbox.html
new file mode 100644
index 00000000000..fd99c98a486
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/demo/simple-checkbox.html
@@ -0,0 +1,64 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../paper-button/paper-button.html">
+<link rel="import" href="../iron-checked-element-behavior.html">
+
+<dom-module id="simple-checkbox">
+ <style>
+ :host {
+ display: block;
+ }
+
+ :host([invalid]) span {
+ color: red;
+ }
+
+ #labelText {
+ display: inline-block;
+ width: 100px;
+ }
+ </style>
+ <template>
+ <input type="checkbox" id="checkbox" on-tap="_onCheckTap">
+ <span id="labelText">{{label}}</span>
+ <paper-button raised on-click="_onClick">validate</paper-button>
+
+ </template>
+ <script>
+ Polymer({
+
+ is: 'simple-checkbox',
+
+ behaviors: [
+ Polymer.IronCheckedElementBehavior
+ ],
+
+ properties: {
+ label: {
+ type: String,
+ value: 'not validated'
+ }
+ },
+
+ _onCheckTap: function() {
+ this.checked = this.$.checkbox.checked;
+ },
+
+ _onClick: function() {
+ this.validate();
+ this.label = this.invalid ? 'is invalid' : 'is valid';
+ }
+ });
+
+ </script>
+
+ </dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/index.html
new file mode 100644
index 00000000000..1975dc5a75c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-checked-element-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/iron-checked-element-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/iron-checked-element-behavior.html
new file mode 100644
index 00000000000..5809c03761a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-checked-element-behavior/iron-checked-element-behavior.html
@@ -0,0 +1,120 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+
+<script>
+
+ /**
+ * Use `Polymer.IronCheckedElementBehavior` to implement a custom element
+ * that has a `checked` property, which can be used for validation if the
+ * element is also `required`. Element instances implementing this behavior
+ * will also be registered for use in an `iron-form` element.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior Polymer.IronCheckedElementBehavior
+ */
+ Polymer.IronCheckedElementBehaviorImpl = {
+
+ properties: {
+ /**
+ * Fired when the checked state changes.
+ *
+ * @event iron-change
+ */
+
+ /**
+ * Gets or sets the state, `true` is checked and `false` is unchecked.
+ */
+ checked: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ notify: true,
+ observer: '_checkedChanged'
+ },
+
+ /**
+ * If true, the button toggles the active state with each tap or press
+ * of the spacebar.
+ */
+ toggles: {
+ type: Boolean,
+ value: true,
+ reflectToAttribute: true
+ },
+
+ /* Overriden from Polymer.IronFormElementBehavior */
+ value: {
+ type: String,
+ value: 'on',
+ observer: '_valueChanged'
+ }
+ },
+
+ observers: [
+ '_requiredChanged(required)'
+ ],
+
+ created: function() {
+ // Used by `iron-form` to handle the case that an element with this behavior
+ // doesn't have a role of 'checkbox' or 'radio', but should still only be
+ // included when the form is serialized if `this.checked === true`.
+ this._hasIronCheckedElementBehavior = true;
+ },
+
+ /**
+ * Returns false if the element is required and not checked, and true otherwise.
+ * @param {*=} _value Ignored.
+ * @return {boolean} true if `required` is false, or if `required` and `checked` are both true.
+ */
+ _getValidity: function(_value) {
+ return this.disabled || !this.required || (this.required && this.checked);
+ },
+
+ /**
+ * Update the aria-required label when `required` is changed.
+ */
+ _requiredChanged: function() {
+ if (this.required) {
+ this.setAttribute('aria-required', 'true');
+ } else {
+ this.removeAttribute('aria-required');
+ }
+ },
+
+ /**
+ * Fire `iron-changed` when the checked state changes.
+ */
+ _checkedChanged: function() {
+ this.active = this.checked;
+ this.fire('iron-change');
+ },
+
+ /**
+ * Reset value to 'on' if it is set to `undefined`.
+ */
+ _valueChanged: function() {
+ if (this.value === undefined || this.value === null) {
+ this.value = 'on';
+ }
+ }
+ };
+
+ /** @polymerBehavior Polymer.IronCheckedElementBehavior */
+ Polymer.IronCheckedElementBehavior = [
+ Polymer.IronFormElementBehavior,
+ Polymer.IronValidatableBehavior,
+ Polymer.IronCheckedElementBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.bower.json
new file mode 100644
index 00000000000..5156c032c2a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.bower.json
@@ -0,0 +1,43 @@
+{
+ "name": "iron-collapse",
+ "version": "1.1.0",
+ "description": "Provides a collapsable container",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "container"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/PolymerElements/iron-collapse"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-collapse",
+ "ignore": [],
+ "dependencies": {
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.5.0"
+ },
+ "devDependencies": {
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": "iron-collapse.html",
+ "_release": "1.1.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.0",
+ "commit": "f9e64ea7731c43430f48d64dddb80166334122c7"
+ },
+ "_source": "git://github.com/PolymerElements/iron-collapse.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-collapse"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.travis.yml
new file mode 100644
index 00000000000..e865fbcba66
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: W+IhreK2iEWsI8CtHVmTx6PVuXrQ6wULdox7o18XIcd3V2HMRKb0Wqz3OF8CqJ+OfkU6R5pKZI3pGhmba+2ecyTAzvF24f4bX6xP1XLKQn61fNFmwihhMkcCsjrv48mMsKIFTzmlIel2Wbvajks5ahf6Q3MfWa9/1rIATXgbEFE=
+ - secure: UIS5DqFiRpXOxaalEiBcEqWSqn0SgXq7s0crXxa1391dojKCHY5Q/j8nQ0rfrVw5gT19wFnvci20Fn9i2USa1BbBCmzBSXAckDXt40G5ajHt0BwVdYB8eA4N5WBOlIjti8LfNRkrRy0yCvRq2OwpLmiFciCaQXGL1aZ6dig8x+k=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/README.md
new file mode 100644
index 00000000000..d1bf46b8655
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/README.md
@@ -0,0 +1,58 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-collapse.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-collapse.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-collapse)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-collapse)_
+
+
+##&lt;iron-collapse&gt;
+
+`iron-collapse` creates a collapsible block of content. By default, the content
+will be collapsed. Use `opened` or `toggle()` to show/hide the content.
+
+```html
+<button on-click="toggle">toggle collapse</button>
+
+<iron-collapse id="collapse">
+ <div>Content goes here...</div>
+</iron-collapse>
+
+...
+
+toggle: function() {
+ this.$.collapse.toggle();
+}
+```
+
+`iron-collapse` adjusts the max-height/max-width of the collapsible element to show/hide
+the content. So avoid putting padding/margin/border on the collapsible directly,
+and instead put a div inside and style that.
+
+```html
+<style>
+ .collapse-content {
+ padding: 15px;
+ border: 1px solid #dedede;
+ }
+</style>
+
+<iron-collapse>
+ <div class="collapse-content">
+ <div>Content goes here...</div>
+ </div>
+</iron-collapse>
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/bower.json
new file mode 100644
index 00000000000..c11034a9422
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/bower.json
@@ -0,0 +1,34 @@
+{
+ "name": "iron-collapse",
+ "version": "1.1.0",
+ "description": "Provides a collapsable container",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "container"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/PolymerElements/iron-collapse"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-collapse",
+ "ignore": [],
+ "dependencies": {
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.5.0"
+ },
+ "devDependencies": {
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": "iron-collapse.html"
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/demo/index.html
new file mode 100644
index 00000000000..79a873c3c57
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/demo/index.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+ <head>
+
+ <title>iron-collapse demo</title>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-collapse.html">
+ <link rel="import" href="../../paper-styles/shadow.html">
+ <link rel="stylesheet" href="../../paper-styles/demo.css">
+
+ <style is="custom-style">
+ .heading {
+ padding: 10px 15px;
+ margin-top: 20px;
+ background-color: #f3f3f3;
+ border: 1px solid #dedede;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ font-size: 18px;
+ cursor: pointer;
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ width: 100%;
+ text-align: left;
+ }
+
+ .content {
+ padding: 15px;
+ border: 1px solid #dedede;
+ border-top: none;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ @apply(--shadow-elevation-2dp);
+ }
+
+ #collapse3 {
+ max-height: 250px;
+ }
+
+ </style>
+
+ </head>
+ <body unresolved>
+ <template is="dom-bind">
+
+ <button class="heading" aria-expanded$="[[isExpanded(opened1)]]" aria-controls="collapse1" onclick="toggle('#collapse1')">Collapse #1</button>
+
+ <iron-collapse id="collapse1" tabindex="0" opened="{{opened1}}">
+ <div class="content">
+ <div>Lorem ipsum dolor sit amet, per in nusquam nominavi periculis, sit elit oportere ea, id minim maiestatis incorrupte duo. Dolorum verterem ad ius, his et nullam verterem. Eu alia debet usu, an doming tritani est. Vix ad ponderum petentium suavitate, eum eu tempor populo, graece sententiae constituam vim ex. Cu torquatos reprimique neglegentur nec, voluptua periculis has ut, at eos discere deleniti sensibus. Lorem ipsum dolor sit amet, per in nusquam nominavi periculis, sit elit oportere ea, id minim maiestatis incorrupte duo. Dolorum verterem ad ius, his et nullam verterem. Eu alia debet usu, an doming tritani est. Vix ad ponderum petentium suavitate, eum eu tempor populo, graece sententiae constituam vim ex. Cu torquatos reprimique neglegentur nec, voluptua periculis has ut, at eos discere deleniti sensibus.</div>
+ </div>
+ </iron-collapse>
+
+ <button class="heading" aria-expanded$="[[isExpanded(opened2)]]" aria-controls="collapse2" onclick="toggle('#collapse2')">Collapse #2</button>
+
+ <iron-collapse id="collapse2" tabindex="0" opened="{{opened2}}">
+ <div class="content">
+ <div>Pro saepe pertinax ei, ad pri animal labores suscipiantur. Modus commodo minimum eum te, vero utinam assueverit per eu, zril oportere suscipiantur pri te. Partem percipitur deterruisset ad sea, at eam suas luptatum dissentiunt. No error alienum pro, erant senserit ex mei, pri semper alterum no. Ut habemus menandri vulputate mea. Feugiat verterem ut sed. Dolores maiestatis id per. Pro saepe pertinax ei, ad pri animal labores suscipiantur. Modus commodo minimum eum te, vero utinam assueverit per eu, zril oportere suscipiantur pri te. Partem percipitur deterruisset ad sea, at eam suas luptatum dissentiunt. No error alienum pro, erant senserit ex mei, pri semper alterum no. Ut habemus menandri vulputate mea. Feugiat verterem ut sed. Dolores maiestatis id per.</div>
+
+ <button class="heading" aria-expanded$="[[isExpanded(opened3)]]" aria-controls="collapse3" onclick="toggle('#collapse3')">Collapse #3 (horizontal)</button>
+
+ <iron-collapse id="collapse3" tabindex="0" opened="{{opened3}}" horizontal>
+ <div class="content">
+ <div>Iisque perfecto dissentiet cum et, sit ut quot mandamus, ut vim tibique splendide instructior. Id nam odio natum malorum, tibique copiosae expetenda mel ea. Mea melius malorum ut. Ut nec tollit vocent timeam. Facer nonumy numquam id his, munere salutatus consequuntur eum et, eum cotidieque definitionem signiferumque id. Ei oblique graecis patrioque vis, et probatus dignissim inciderint vel. Sed id paulo erroribus, autem semper accusamus in mel. Iisque perfecto dissentiet cum et, sit ut quot mandamus, ut vim tibique splendide instructior. Id nam odio natum malorum, tibique copiosae expetenda mel ea. Mea melius malorum ut. Ut nec tollit vocent timeam. Facer nonumy numquam id his, munere salutatus consequuntur eum et, eum cotidieque definitionem signiferumque id. Ei oblique graecis patrioque vis, et probatus dignissim inciderint vel. Sed id paulo erroribus, autem semper accusamus in mel.</div>
+ </div>
+ </iron-collapse>
+
+ <button class="heading" aria-expanded$="[[isExpanded(opened4)]]" aria-controls="collapse4" onclick="toggle('#collapse4')">Collapse #4 (no animation)</button>
+
+ <iron-collapse id="collapse4" tabindex="0" opened="{{opened4}}" no-animation>
+ <div class="content">
+ <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
+ </div>
+ </iron-collapse>
+ </div>
+ </iron-collapse>
+</template>
+
+<script>
+
+ function toggle(selector) {
+ document.querySelector(selector).toggle();
+ }
+
+ document.querySelector('template[is=dom-bind]').isExpanded = function(opened) {
+ return String(opened);
+ };
+
+</script>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/hero.svg
new file mode 100755
index 00000000000..ae1a49efab0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/hero.svg
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+ <path display="inline" fill="none" d="M167.5,51.7c3.7-0.8,6.9,2.4,6.1,6.1c-0.4,1.9-1.9,3.4-3.8,3.8c-3.7,0.8-6.9-2.4-6.1-6.1
+ C164.2,53.6,165.7,52.1,167.5,51.7z"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <path d="M151,102H73V52h78V102z M75,100h74V54H75V100z"/>
+ <path d="M151,38H73V24h78V38z M75,36h74V26H75V36z"/>
+ <circle cx="171" cy="51" r="4"/>
+ <path d="M151,72v-2c10.5,0,19-8.5,19-19s-8.5-19-19-19v-2c11.6,0,21,9.4,21,21S162.6,72,151,72z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/index.html
new file mode 100644
index 00000000000..b5d20077c41
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+ <head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-collapse</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+ </head>
+ <body>
+
+ <iron-component-page></iron-component-page>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/iron-collapse.html b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/iron-collapse.html
new file mode 100644
index 00000000000..03e32f46659
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-collapse/iron-collapse.html
@@ -0,0 +1,285 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
+
+<!--
+`iron-collapse` creates a collapsible block of content. By default, the content
+will be collapsed. Use `opened` or `toggle()` to show/hide the content.
+
+ <button on-click="toggle">toggle collapse</button>
+
+ <iron-collapse id="collapse">
+ <div>Content goes here...</div>
+ </iron-collapse>
+
+ ...
+
+ toggle: function() {
+ this.$.collapse.toggle();
+ }
+
+`iron-collapse` adjusts the max-height/max-width of the collapsible element to show/hide
+the content. So avoid putting padding/margin/border on the collapsible directly,
+and instead put a div inside and style that.
+
+ <style>
+ .collapse-content {
+ padding: 15px;
+ border: 1px solid #dedede;
+ }
+ </style>
+
+ <iron-collapse>
+ <div class="collapse-content">
+ <div>Content goes here...</div>
+ </div>
+ </iron-collapse>
+
+@group Iron Elements
+@hero hero.svg
+@demo demo/index.html
+@element iron-collapse
+-->
+
+<dom-module id="iron-collapse">
+
+ <template>
+
+ <style>
+ :host {
+ display: block;
+ transition-duration: 300ms;
+ overflow: visible;
+ }
+
+ :host(.iron-collapse-closed) {
+ display: none;
+ }
+
+ :host(:not(.iron-collapse-opened)) {
+ overflow: hidden;
+ }
+ </style>
+
+ <content></content>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'iron-collapse',
+
+ behaviors: [
+ Polymer.IronResizableBehavior
+ ],
+
+ properties: {
+
+ /**
+ * If true, the orientation is horizontal; otherwise is vertical.
+ *
+ * @attribute horizontal
+ */
+ horizontal: {
+ type: Boolean,
+ value: false,
+ observer: '_horizontalChanged'
+ },
+
+ /**
+ * Set opened to true to show the collapse element and to false to hide it.
+ *
+ * @attribute opened
+ */
+ opened: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ observer: '_openedChanged'
+ },
+
+ /**
+ * Set noAnimation to true to disable animations
+ *
+ * @attribute noAnimation
+ */
+ noAnimation: {
+ type: Boolean
+ },
+
+ },
+
+ get dimension() {
+ return this.horizontal ? 'width' : 'height';
+ },
+
+ /**
+ * `maxWidth` or `maxHeight`.
+ * @private
+ */
+ get _dimensionMax() {
+ return this.horizontal ? 'maxWidth' : 'maxHeight';
+ },
+
+ /**
+ * `max-width` or `max-height`.
+ * @private
+ */
+ get _dimensionMaxCss() {
+ return this.horizontal ? 'max-width' : 'max-height';
+ },
+
+ hostAttributes: {
+ role: 'group',
+ 'aria-hidden': 'true',
+ 'aria-expanded': 'false'
+ },
+
+ listeners: {
+ transitionend: '_transitionEnd'
+ },
+
+ attached: function() {
+ // It will take care of setting correct classes and styles.
+ this._transitionEnd();
+ },
+
+ /**
+ * Toggle the opened state.
+ *
+ * @method toggle
+ */
+ toggle: function() {
+ this.opened = !this.opened;
+ },
+
+ show: function() {
+ this.opened = true;
+ },
+
+ hide: function() {
+ this.opened = false;
+ },
+
+ /**
+ * Updates the size of the element.
+ * @param {!String} size The new value for `maxWidth`/`maxHeight` as css property value, usually `auto` or `0px`.
+ * @param {boolean=} animated if `true` updates the size with an animation, otherwise without.
+ */
+ updateSize: function(size, animated) {
+ // No change!
+ var curSize = this.style[this._dimensionMax];
+ if (curSize === size || (size === 'auto' && !curSize)) {
+ return;
+ }
+
+ this._updateTransition(false);
+ // If we can animate, must do some prep work.
+ if (animated && !this.noAnimation && this._isDisplayed) {
+ // Animation will start at the current size.
+ var startSize = this._calcSize();
+ // For `auto` we must calculate what is the final size for the animation.
+ // After the transition is done, _transitionEnd will set the size back to `auto`.
+ if (size === 'auto') {
+ this.style[this._dimensionMax] = '';
+ size = this._calcSize();
+ }
+ // Go to startSize without animation.
+ this.style[this._dimensionMax] = startSize;
+ // Force layout to ensure transition will go. Set offsetHeight to itself
+ // so that compilers won't remove it.
+ this.offsetHeight = this.offsetHeight;
+ // Enable animation.
+ this._updateTransition(true);
+ }
+ // Set the final size.
+ if (size === 'auto') {
+ this.style[this._dimensionMax] = '';
+ } else {
+ this.style[this._dimensionMax] = size;
+ }
+ },
+
+ /**
+ * enableTransition() is deprecated, but left over so it doesn't break existing code.
+ * Please use `noAnimation` property instead.
+ *
+ * @method enableTransition
+ * @deprecated since version 1.0.4
+ */
+ enableTransition: function(enabled) {
+ Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` instead.');
+ this.noAnimation = !enabled;
+ },
+
+ _updateTransition: function(enabled) {
+ this.style.transitionDuration = (enabled && !this.noAnimation) ? '' : '0s';
+ },
+
+ _horizontalChanged: function() {
+ this.style.transitionProperty = this._dimensionMaxCss;
+ var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth';
+ this.style[otherDimension] = '';
+ this.updateSize(this.opened ? 'auto' : '0px', false);
+ },
+
+ _openedChanged: function() {
+ this.setAttribute('aria-expanded', this.opened);
+ this.setAttribute('aria-hidden', !this.opened);
+
+ this.toggleClass('iron-collapse-closed', false);
+ this.toggleClass('iron-collapse-opened', false);
+ this.updateSize(this.opened ? 'auto' : '0px', true);
+
+ // Focus the current collapse.
+ if (this.opened) {
+ this.focus();
+ }
+ if (this.noAnimation) {
+ this._transitionEnd();
+ }
+ },
+
+ _transitionEnd: function() {
+ if (this.opened) {
+ this.style[this._dimensionMax] = '';
+ }
+ this.toggleClass('iron-collapse-closed', !this.opened);
+ this.toggleClass('iron-collapse-opened', this.opened);
+ this._updateTransition(false);
+ this.notifyResize();
+ },
+
+ /**
+ * Simplistic heuristic to detect if element has a parent with display: none
+ *
+ * @private
+ */
+ get _isDisplayed() {
+ var rect = this.getBoundingClientRect();
+ for (var prop in rect) {
+ if (rect[prop] !== 0) return true;
+ }
+ return false;
+ },
+
+ _calcSize: function() {
+ return this.getBoundingClientRect()[this.dimension] + 'px';
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.bower.json
new file mode 100644
index 00000000000..f5990d896ba
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.bower.json
@@ -0,0 +1,48 @@
+{
+ "name": "iron-dropdown",
+ "version": "1.4.1",
+ "description": "An unstyled element that works similarly to a native browser select",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer"
+ ],
+ "main": "iron-dropdown.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-dropdown"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-dropdown",
+ "dependencies": {
+ "polymer": "polymer/polymer#^1.0.0",
+ "iron-behaviors": "polymerelements/iron-behaviors#^1.0.0",
+ "iron-overlay-behavior": "polymerelements/iron-overlay-behavior#^1.0.0",
+ "iron-resizable-behavior": "polymerelements/iron-resizable-behavior#^1.0.0",
+ "neon-animation": "polymerelements/neon-animation#^1.0.0",
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0",
+ "iron-image": "polymerelements/iron-image#^1.0.0"
+ },
+ "ignore": [],
+ "_release": "1.4.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.4.1",
+ "commit": "fc5ce3d2ee6be97beef00b9456e6e06498408401"
+ },
+ "_source": "git://github.com/PolymerElements/iron-dropdown.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-dropdown"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.travis.yml
new file mode 100644
index 00000000000..52bdee54eb8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: Nd7sbgkYVekuQRB4K3svNCL3veA6t6aGopNP2FUxlJvQuzRV1vKV67angPvMUAFelEA7/rTzrFPBMfNbsz9C2wInLLLPux4wEk1MQX+2KYZVeXKMHjgl8iQKMXnodaL7XXwBPg0L7053TWtYkIt8wZ/vN0JGPQFKhlQkSrduztkPCJQfkFsMPJ7SudPG3Ld0UPBVxo8TwH/d44p8VhLGiI0oEWw3GnGZZ1T7RJLDAVBwj1BiVHAOaS0SSeOR3ngpZyXbk8OItgzw4o/bbAt2yrHMfwymBy0Xv9v3G0QLFJnMi/gE2lWnN4+IttUPI8gVyr1TuiTgtFxdwteLO3R5iFe+qlQjq0VGssmAHcPwtLhvrT4wEkGMc8ZeyW11z+GdkIw4XHGACWj+9Jz9f19mJd9xU3fkJ+f5mFiB8vEkzjsUI9pswgd3RoHt2WewcVdHnCED2wRdQCw9H34dX7d2ieWKPl/pv+EKZOgEJJ8UNZMyKnj57Y25WRrTpIQBt6p9uVv5MsiZQm7Sd1pYQnJKPQ+BxvvL5fsoT1YkFSjyz9gwijtftXhfL8KLB6i04V3mra3f9d5hc20wAOt+ad+mTOkaM/aGxE/I3Ko13BceMvRSNzuz+N2WE6FEJj1NuOCW/AeSh5/6n9nnlDeu7Nu7VeM9kjk4dyBGNRDWLNcSCEk=
+ - secure: aFsYKL6Sw8/r57wzj3pnzEwBE1mnTajJasHAbXgQMd336S2Sq/f39DCNTXgKBA4AKZGvWKe8w9nzaocQoMa4l9bLWEBJMCMPQFawOhTkuEjsLjpU3g74b46/EhjBP5zixR32xoyF5o9FTzC6UyrDjt2XpKwIQJYxaEfoyIW1vTPdoasWdaG5rXvWFTsmXtaMDpCKFH9aQ1DHn9Sbi9NZlR4izdULsbv9GZwg53xvuH4xYEkGtB29KKy04uK1nJ+9SmRWTAnu4Q/ivYWlbwBArjiYTTi0wclvDNvT1iaFNAaeK2pJea8CnoyJJ0pg9NcuzZtStGUvP00kGUpJQ4lqkr+gBCHDPYtoZ17XCz59cg6LrhG1q//vPi7Yz0xW51GHuwmcVs+PsjmWaRuO/1UFreDCQYf+GU4I1pQZf2q1R4m8noe4i5CcFXLKTrC4udBzPmzVB4As2LsxRc3HCIXmhaMxI8MJwdkQBA22u4vCwU2xpqBawJocj0Gvbeme6wG99PW7+XSkijQDk2cTJ5/CJtY22nAECvn4tve3OVvybSTjQ1yipLxJm/dtjgEXFWtknFZr++tId88wPd3EBtrwEhliD3zD/TyLPO2RPZGuI0i6oD3O89P5d8qp66T/eByDr1IEm0+FIQjgiCEMbhmaIuUKGG2GCfwPglI3uR0kbg0=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/README.md
new file mode 100644
index 00000000000..6440ec68a7c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/README.md
@@ -0,0 +1,46 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-dropdown.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-dropdown.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-dropdown)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-dropdown)_
+
+
+##&lt;iron-dropdown&gt;
+
+`<iron-dropdown>` is a generalized element that is useful when you have
+hidden content (`.dropdown-content`) that is revealed due to some change in
+state that should cause it to do so.
+
+Note that this is a low-level element intended to be used as part of other
+composite elements that cause dropdowns to be revealed.
+
+Examples of elements that might be implemented using an `iron-dropdown`
+include comboboxes, menubuttons, selects. The list goes on.
+
+The `<iron-dropdown>` element exposes attributes that allow the position
+of the `.dropdown-content` relative to the `.dropdown-trigger` to be
+configured.
+
+```html
+<iron-dropdown horizontal-align="right" vertical-align="top">
+ <div class="dropdown-content">Hello!</div>
+</iron-dropdown>
+```
+
+In the above example, the `<div>` with class `.dropdown-content` will be
+hidden until the dropdown element has `opened` set to true, or when the `open`
+method is called on the element.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/bower.json
new file mode 100644
index 00000000000..0cc2bc59764
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/bower.json
@@ -0,0 +1,39 @@
+{
+ "name": "iron-dropdown",
+ "version": "1.4.1",
+ "description": "An unstyled element that works similarly to a native browser select",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer"
+ ],
+ "main": "iron-dropdown.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-dropdown"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-dropdown",
+ "dependencies": {
+ "polymer": "polymer/polymer#^1.0.0",
+ "iron-behaviors": "polymerelements/iron-behaviors#^1.0.0",
+ "iron-overlay-behavior": "polymerelements/iron-overlay-behavior#^1.0.0",
+ "iron-resizable-behavior": "polymerelements/iron-resizable-behavior#^1.0.0",
+ "neon-animation": "polymerelements/neon-animation#^1.0.0",
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0",
+ "iron-image": "polymerelements/iron-image#^1.0.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/grow-height-animation.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/grow-height-animation.html
new file mode 100644
index 00000000000..e2fdc448a07
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/grow-height-animation.html
@@ -0,0 +1,36 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../neon-animation/neon-animation-behavior.html">
+
+<script>
+ Polymer({
+ is: 'expand-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ var height = node.getBoundingClientRect().height;
+
+ this._effect = new KeyframeEffect(node, [{
+ height: (height / 2) + 'px'
+ }, {
+ height: height + 'px'
+ }], this.timingFromConfig(config));
+
+ return this._effect;
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/index.html
new file mode 100644
index 00000000000..3ddbaf209bc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/index.html
@@ -0,0 +1,160 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>iron-dropdown</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../iron-image/iron-image.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="x-select.html">
+ <style>
+
+ .dropdown-content {
+ background-color: white;
+ line-height: 20px;
+ border-radius: 3px;
+ box-shadow: 0px 2px 6px #ccc;
+ }
+
+ .random-content {
+ padding: 1.5em 2em;
+ max-width: 250px;
+ }
+
+ button {
+ border: 1px solid #ccc;
+ background-color: #eee;
+ padding: 1em;
+ border-radius: 3px;
+ cursor: pointer;
+ }
+
+ button:focus {
+ outline: none;
+ border-color: blue;
+ }
+
+ ul {
+ margin: 0;
+ padding: 0;
+ }
+
+ li {
+ display: block;
+ position: relative;
+ margin: 0;
+ padding: 0;
+ }
+
+ a {
+ display: block;
+ position: relative;
+ padding: 1em;
+ text-decoration: none;
+ }
+
+ li:not(:last-of-type) {
+ border-bottom: 1px solid #eee;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ iron-image {
+ padding: 1em;
+ background-color: #fff;
+ box-shadow: 0px 2px 6px #ccc;
+ border-radius: 3px;
+ }
+ </style>
+</head>
+<body>
+ <template is="dom-bind" id="Demo">
+ <div class="vertical-section vertical-section-container ">
+ <h1>iron-dropdown</h1>
+ <p>Examples of vanilla elements.</p>
+ <div>
+ <x-select>
+ <button class="dropdown-trigger">Basic</button>
+ <div class="dropdown-content random-content">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </div>
+ </x-select>
+ <x-select>
+ <button class="dropdown-trigger">Overflowing</button>
+ <div class="dropdown-content random-content">
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
+ </div>
+ </x-select>
+ <x-select vertical-align="bottom">
+ <button class="dropdown-trigger">Bottom-left Aligned</button>
+ <div class="dropdown-content random-content">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </div>
+ </x-select>
+ <x-select horizontal-align="right" vertical-align="top">
+ <button class="dropdown-trigger">Top-right Aligned</button>
+ <div class="dropdown-content random-content">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </div>
+ </x-select>
+ <x-select horizontal-align="left" vertical-align="top">
+ <button class="dropdown-trigger"> Content</button>
+ <iron-image class="dropdown-content" src="../../iron-image/demo/polymer.svg"></iron-image>
+ </x-select>
+ <x-select horizontal-align="right" vertical-align="top">
+ <button class="dropdown-trigger">Unordered list</button>
+ <ul class="dropdown-content" tabindex="0">
+ <template is="dom-repeat" items="[[dinosaurs]]">
+ <li><a href="javascript:void(0)">[[item]]</a></li>
+ </template>
+ </ul>
+ </x-select>
+ </div>
+ </div>
+ </template>
+
+ <script>
+ Demo.dinosaurs = [
+ 'allosaurus',
+ 'brontosaurus',
+ 'carcharodontosaurus',
+ 'diplodocus',
+ 'ekrixinatosaurus',
+ 'fukuiraptor',
+ 'gallimimus',
+ 'hadrosaurus',
+ 'iguanodon',
+ 'jainosaurus',
+ 'kritosaurus',
+ 'liaoceratops',
+ 'megalosaurus',
+ 'nemegtosaurus',
+ 'ornithomimus',
+ 'protoceratops',
+ 'quetecsaurus',
+ 'rajasaurus',
+ 'stegosaurus',
+ 'triceratops',
+ 'utahraptor',
+ 'vulcanodon',
+ 'wannanosaurus',
+ 'xenoceratops',
+ 'yandusaurus',
+ 'zephyrosaurus'
+ ];
+ </script>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/x-select.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/x-select.html
new file mode 100644
index 00000000000..2216c659461
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/demo/x-select.html
@@ -0,0 +1,80 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-dropdown.html">
+<link rel="import" href="../../neon-animation/neon-animations.html">
+<link rel="import" href="grow-height-animation.html">
+
+<dom-module id="x-select">
+ <style>
+ :host {
+ display: inline-block;
+ margin: 1em;
+ }
+ </style>
+ <template>
+ <div on-tap="open">
+ <content select=".dropdown-trigger"></content>
+ </div>
+ <iron-dropdown id="dropdown"
+ vertical-align="[[verticalAlign]]"
+ horizontal-align="[[horizontalAlign]]"
+ disabled="[[disabled]]"
+ open-animation-config="[[openAnimationConfig]]"
+ close-animation-config="[[closeAnimationConfig]]">
+ <content select=".dropdown-content"></content>
+ </iron-dropdown>
+ </template>
+ <script>
+ Polymer({
+ is: 'x-select',
+
+ properties: {
+ verticalAlign: String,
+ horizontalAlign: String,
+ disabled: Boolean,
+ openAnimationConfig: {
+ type: Array,
+ value: function() {
+ return [{
+ name: 'fade-in-animation',
+ timing: {
+ delay: 150,
+ duration: 50
+ }
+ }, {
+ name: 'expand-animation',
+ timing: {
+ delay: 150,
+ duration: 200
+ }
+ }];
+ }
+ },
+
+ closeAnimationConfig: {
+ type: Array,
+ value: function() {
+ return [{
+ name: 'fade-out-animation',
+ timing: {
+ duration: 200
+ }
+ }];
+ }
+ }
+ },
+
+ open: function() {
+ this.$.dropdown.open();
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/index.html
new file mode 100644
index 00000000000..1d3d6cada97
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <title>iron-dropdown</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown-scroll-manager.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown-scroll-manager.html
new file mode 100644
index 00000000000..5e9176efafe
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown-scroll-manager.html
@@ -0,0 +1,233 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+
+<script>
+ (function() {
+ 'use strict';
+
+ /**
+ * The IronDropdownScrollManager is intended to provide a central source
+ * of authority and control over which elements in a document are currently
+ * allowed to scroll.
+ */
+
+ Polymer.IronDropdownScrollManager = {
+
+ /**
+ * The current element that defines the DOM boundaries of the
+ * scroll lock. This is always the most recently locking element.
+ */
+ get currentLockingElement() {
+ return this._lockingElements[this._lockingElements.length - 1];
+ },
+
+
+ /**
+ * Returns true if the provided element is "scroll locked," which is to
+ * say that it cannot be scrolled via pointer or keyboard interactions.
+ *
+ * @param {HTMLElement} element An HTML element instance which may or may
+ * not be scroll locked.
+ */
+ elementIsScrollLocked: function(element) {
+ var currentLockingElement = this.currentLockingElement;
+
+ if (currentLockingElement === undefined)
+ return false;
+
+ var scrollLocked;
+
+ if (this._hasCachedLockedElement(element)) {
+ return true;
+ }
+
+ if (this._hasCachedUnlockedElement(element)) {
+ return false;
+ }
+
+ scrollLocked = !!currentLockingElement &&
+ currentLockingElement !== element &&
+ !this._composedTreeContains(currentLockingElement, element);
+
+ if (scrollLocked) {
+ this._lockedElementCache.push(element);
+ } else {
+ this._unlockedElementCache.push(element);
+ }
+
+ return scrollLocked;
+ },
+
+ /**
+ * Push an element onto the current scroll lock stack. The most recently
+ * pushed element and its children will be considered scrollable. All
+ * other elements will not be scrollable.
+ *
+ * Scroll locking is implemented as a stack so that cases such as
+ * dropdowns within dropdowns are handled well.
+ *
+ * @param {HTMLElement} element The element that should lock scroll.
+ */
+ pushScrollLock: function(element) {
+ // Prevent pushing the same element twice
+ if (this._lockingElements.indexOf(element) >= 0) {
+ return;
+ }
+
+ if (this._lockingElements.length === 0) {
+ this._lockScrollInteractions();
+ }
+
+ this._lockingElements.push(element);
+
+ this._lockedElementCache = [];
+ this._unlockedElementCache = [];
+ },
+
+ /**
+ * Remove an element from the scroll lock stack. The element being
+ * removed does not need to be the most recently pushed element. However,
+ * the scroll lock constraints only change when the most recently pushed
+ * element is removed.
+ *
+ * @param {HTMLElement} element The element to remove from the scroll
+ * lock stack.
+ */
+ removeScrollLock: function(element) {
+ var index = this._lockingElements.indexOf(element);
+
+ if (index === -1) {
+ return;
+ }
+
+ this._lockingElements.splice(index, 1);
+
+ this._lockedElementCache = [];
+ this._unlockedElementCache = [];
+
+ if (this._lockingElements.length === 0) {
+ this._unlockScrollInteractions();
+ }
+ },
+
+ _lockingElements: [],
+
+ _lockedElementCache: null,
+
+ _unlockedElementCache: null,
+
+ _originalBodyStyles: {},
+
+ _isScrollingKeypress: function(event) {
+ return Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(
+ event, 'pageup pagedown home end up left down right');
+ },
+
+ _hasCachedLockedElement: function(element) {
+ return this._lockedElementCache.indexOf(element) > -1;
+ },
+
+ _hasCachedUnlockedElement: function(element) {
+ return this._unlockedElementCache.indexOf(element) > -1;
+ },
+
+ _composedTreeContains: function(element, child) {
+ // NOTE(cdata): This method iterates over content elements and their
+ // corresponding distributed nodes to implement a contains-like method
+ // that pierces through the composed tree of the ShadowDOM. Results of
+ // this operation are cached (elsewhere) on a per-scroll-lock basis, to
+ // guard against potentially expensive lookups happening repeatedly as
+ // a user scrolls / touchmoves.
+ var contentElements;
+ var distributedNodes;
+ var contentIndex;
+ var nodeIndex;
+
+ if (element.contains(child)) {
+ return true;
+ }
+
+ contentElements = Polymer.dom(element).querySelectorAll('content');
+
+ for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
+
+ distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
+
+ for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
+
+ if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ _scrollInteractionHandler: function(event) {
+ var scrolledElement =
+ /** @type {HTMLElement} */(Polymer.dom(event).rootTarget);
+ if (Polymer
+ .IronDropdownScrollManager
+ .elementIsScrollLocked(scrolledElement)) {
+ if (event.type === 'keydown' &&
+ !Polymer.IronDropdownScrollManager._isScrollingKeypress(event)) {
+ return;
+ }
+
+ event.preventDefault();
+ }
+ },
+
+ _lockScrollInteractions: function() {
+ // Memoize body inline styles:
+ this._originalBodyStyles.overflow = document.body.style.overflow;
+ this._originalBodyStyles.overflowX = document.body.style.overflowX;
+ this._originalBodyStyles.overflowY = document.body.style.overflowY;
+
+ // Disable overflow scrolling on body:
+ // TODO(cdata): It is technically not sufficient to hide overflow on
+ // body alone. A better solution might be to traverse all ancestors of
+ // the current scroll locking element and hide overflow on them. This
+ // becomes expensive, though, as it would have to be redone every time
+ // a new scroll locking element is added.
+ document.body.style.overflow = 'hidden';
+ document.body.style.overflowX = 'hidden';
+ document.body.style.overflowY = 'hidden';
+
+ // Modern `wheel` event for mouse wheel scrolling:
+ document.addEventListener('wheel', this._scrollInteractionHandler, true);
+ // Older, non-standard `mousewheel` event for some FF:
+ document.addEventListener('mousewheel', this._scrollInteractionHandler, true);
+ // IE:
+ document.addEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
+ // Mobile devices can scroll on touch move:
+ document.addEventListener('touchmove', this._scrollInteractionHandler, true);
+ // Capture keydown to prevent scrolling keys (pageup, pagedown etc.)
+ document.addEventListener('keydown', this._scrollInteractionHandler, true);
+ },
+
+ _unlockScrollInteractions: function() {
+ document.body.style.overflow = this._originalBodyStyles.overflow;
+ document.body.style.overflowX = this._originalBodyStyles.overflowX;
+ document.body.style.overflowY = this._originalBodyStyles.overflowY;
+
+ document.removeEventListener('wheel', this._scrollInteractionHandler, true);
+ document.removeEventListener('mousewheel', this._scrollInteractionHandler, true);
+ document.removeEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
+ document.removeEventListener('touchmove', this._scrollInteractionHandler, true);
+ document.removeEventListener('keydown', this._scrollInteractionHandler, true);
+ }
+ };
+ })();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown.html b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown.html
new file mode 100644
index 00000000000..21b074a5b13
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-dropdown/iron-dropdown.html
@@ -0,0 +1,275 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html">
+<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
+<link rel="import" href="../neon-animation/animations/opaque-animation.html">
+<link rel="import" href="iron-dropdown-scroll-manager.html">
+
+<!--
+`<iron-dropdown>` is a generalized element that is useful when you have
+hidden content (`.dropdown-content`) that is revealed due to some change in
+state that should cause it to do so.
+
+Note that this is a low-level element intended to be used as part of other
+composite elements that cause dropdowns to be revealed.
+
+Examples of elements that might be implemented using an `iron-dropdown`
+include comboboxes, menubuttons, selects. The list goes on.
+
+The `<iron-dropdown>` element exposes attributes that allow the position
+of the `.dropdown-content` relative to the `.dropdown-trigger` to be
+configured.
+
+ <iron-dropdown horizontal-align="right" vertical-align="top">
+ <div class="dropdown-content">Hello!</div>
+ </iron-dropdown>
+
+In the above example, the `<div>` with class `.dropdown-content` will be
+hidden until the dropdown element has `opened` set to true, or when the `open`
+method is called on the element.
+
+@demo demo/index.html
+-->
+
+<dom-module id="iron-dropdown">
+ <style>
+ :host {
+ position: fixed;
+ }
+
+ #contentWrapper ::content > * {
+ overflow: auto;
+ }
+
+ #contentWrapper.animating ::content > * {
+ overflow: hidden;
+ }
+ </style>
+ <template>
+ <div id="contentWrapper">
+ <content id="content" select=".dropdown-content"></content>
+ </div>
+ </template>
+
+ <script>
+ (function() {
+ 'use strict';
+
+ Polymer({
+ is: 'iron-dropdown',
+
+ behaviors: [
+ Polymer.IronControlState,
+ Polymer.IronA11yKeysBehavior,
+ Polymer.IronOverlayBehavior,
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+ /**
+ * The orientation against which to align the dropdown content
+ * horizontally relative to the dropdown trigger.
+ * Overridden from `Polymer.IronFitBehavior`.
+ */
+ horizontalAlign: {
+ type: String,
+ value: 'left',
+ reflectToAttribute: true
+ },
+
+ /**
+ * The orientation against which to align the dropdown content
+ * vertically relative to the dropdown trigger.
+ * Overridden from `Polymer.IronFitBehavior`.
+ */
+ verticalAlign: {
+ type: String,
+ value: 'top',
+ reflectToAttribute: true
+ },
+
+ /**
+ * An animation config. If provided, this will be used to animate the
+ * opening of the dropdown.
+ */
+ openAnimationConfig: {
+ type: Object
+ },
+
+ /**
+ * An animation config. If provided, this will be used to animate the
+ * closing of the dropdown.
+ */
+ closeAnimationConfig: {
+ type: Object
+ },
+
+ /**
+ * If provided, this will be the element that will be focused when
+ * the dropdown opens.
+ */
+ focusTarget: {
+ type: Object
+ },
+
+ /**
+ * Set to true to disable animations when opening and closing the
+ * dropdown.
+ */
+ noAnimations: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * By default, the dropdown will constrain scrolling on the page
+ * to itself when opened.
+ * Set to true in order to prevent scroll from being constrained
+ * to the dropdown when it opens.
+ */
+ allowOutsideScroll: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+
+ observers: [
+ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)'
+ ],
+
+ /**
+ * The element that is contained by the dropdown, if any.
+ */
+ get containedElement() {
+ return Polymer.dom(this.$.content).getDistributedNodes()[0];
+ },
+
+ /**
+ * The element that should be focused when the dropdown opens.
+ * @deprecated
+ */
+ get _focusTarget() {
+ return this.focusTarget || this.containedElement;
+ },
+
+ detached: function() {
+ this.cancelAnimation();
+ Polymer.IronDropdownScrollManager.removeScrollLock(this);
+ },
+
+ /**
+ * Called when the value of `opened` changes.
+ * Overridden from `IronOverlayBehavior`
+ */
+ _openedChanged: function() {
+ if (this.opened && this.disabled) {
+ this.cancel();
+ } else {
+ this.cancelAnimation();
+ this.sizingTarget = this.containedElement || this.sizingTarget;
+ this._updateAnimationConfig();
+ if (this.opened && !this.allowOutsideScroll) {
+ Polymer.IronDropdownScrollManager.pushScrollLock(this);
+ } else {
+ Polymer.IronDropdownScrollManager.removeScrollLock(this);
+ }
+ Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
+ }
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ */
+ _renderOpened: function() {
+ if (!this.noAnimations && this.animationConfig.open) {
+ this.$.contentWrapper.classList.add('animating');
+ this.playAnimation('open');
+ } else {
+ Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
+ }
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ */
+ _renderClosed: function() {
+ if (!this.noAnimations && this.animationConfig.close) {
+ this.$.contentWrapper.classList.add('animating');
+ this.playAnimation('close');
+ } else {
+ Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
+ }
+ },
+
+ /**
+ * Called when animation finishes on the dropdown (when opening or
+ * closing). Responsible for "completing" the process of opening or
+ * closing the dropdown by positioning it or setting its display to
+ * none.
+ */
+ _onNeonAnimationFinish: function() {
+ this.$.contentWrapper.classList.remove('animating');
+ if (this.opened) {
+ this._finishRenderOpened();
+ } else {
+ this._finishRenderClosed();
+ }
+ },
+
+ /**
+ * Constructs the final animation config from different properties used
+ * to configure specific parts of the opening and closing animations.
+ */
+ _updateAnimationConfig: function() {
+ var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
+ for (var i = 0; i < animations.length; i++) {
+ animations[i].node = this.containedElement;
+ }
+ this.animationConfig = {
+ open: this.openAnimationConfig,
+ close: this.closeAnimationConfig
+ };
+ },
+
+ /**
+ * Updates the overlay position based on configured horizontal
+ * and vertical alignment.
+ */
+ _updateOverlayPosition: function() {
+ if (this.isAttached) {
+ // This triggers iron-resize, and iron-overlay-behavior will call refit if needed.
+ this.notifyResize();
+ }
+ },
+
+ /**
+ * Apply focus to focusTarget or containedElement
+ */
+ _applyFocus: function () {
+ var focusTarget = this.focusTarget || this.containedElement;
+ if (focusTarget && this.opened && !this.noAutoFocus) {
+ focusTarget.focus();
+ } else {
+ Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
+ }
+ }
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json
new file mode 100644
index 00000000000..f1de37bd86d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "iron-fit-behavior",
+ "version": "1.2.3",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Fits an element inside another element",
+ "private": true,
+ "main": "iron-fit-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-fit-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-fit-behavior",
+ "_release": "1.2.3",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.3",
+ "commit": "ad54693c57aeb893407a4b5d843e36ee8178f72b"
+ },
+ "_source": "git://github.com/PolymerElements/iron-fit-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-fit-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml
new file mode 100644
index 00000000000..f7ceec787f7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: QL2j7nfSA/40iIPMKLMosv9hj8q7eGBbPQXVQmCL3uXD5qoMPTqo1qronKKX+bi3Rh7W104ufV4CzzbWvBwQh8gipx+4REGijzc77Fro2y3v3/wUp9H/UEWnbhAWPDsqEoAD8xQXFHkVv7874/VwOlubQyXDGlvqh0fzYbUNUQo=
+ - secure: ajBo8YcSzi4kNuCHcmajCirWQKf5Mj4OZ3tQjNAcJJAy0UtyrAgTenayWN2ijKqD5V8wfTK66jUXGYMZkoJV4EpknrUliqRgRqKHHfULXYWRSC7lDGxf835ReFxstkPun4HmNtxraAWJgmgFz7mylntTVKm46Ce4INj3n8reWaY=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/README.md
new file mode 100644
index 00000000000..8dbc78e363d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/README.md
@@ -0,0 +1,57 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-fit-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-fit-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-fit-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-fit-behavior)_
+
+
+##Polymer.IronFitBehavior
+
+`Polymer.IronFitBehavior` fits an element in another element using `max-height` and `max-width`, and
+optionally centers it in the window or another element.
+
+The element will only be sized and/or positioned if it has not already been sized and/or positioned
+by CSS.
+
+| CSS properties | Action |
+| --- | --- |
+| `position` set | Element is not centered horizontally or vertically |
+| `top` or `bottom` set | Element is not vertically centered |
+| `left` or `right` set | Element is not horizontally centered |
+| `max-height` set | Element respects `max-height` |
+| `max-width` set | Element respects `max-width` |
+
+`Polymer.IronFitBehavior` can position an element into another element using
+`verticalAlign` and `horizontalAlign`. This will override the element's css position.
+
+```html
+ <div class="container">
+ <iron-fit-impl vertical-align="top" horizontal-align="auto">
+ Positioned into the container
+ </iron-fit-impl>
+ </div>
+```
+
+Use `noOverlap` to position the element around another element without overlapping it.
+
+```html
+ <div class="container">
+ <iron-fit-impl no-overlap vertical-align="auto" horizontal-align="auto">
+ Positioned around the container
+ </iron-fit-impl>
+ </div>
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/bower.json
new file mode 100644
index 00000000000..715b5737ac3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "iron-fit-behavior",
+ "version": "1.2.3",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Fits an element inside another element",
+ "private": true,
+ "main": "iron-fit-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-fit-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html
new file mode 100644
index 00000000000..2c716e06e0a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html
@@ -0,0 +1,166 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+
+<head>
+
+ <title>iron-fit-behavior demo</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="simple-fit.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ .centered {
+ min-width: 500px;
+ }
+ demo-snippet {
+ --demo-snippet-code: {
+ max-height: 250px;
+ }
+ }
+ </style>
+
+</head>
+
+<body unresolved class="centered">
+ <h3>
+ An element with <code>IronFitBehavior</code> can be centered in
+ <code>fitInto</code> or positioned around a <code>positionTarget</code>
+ </h3>
+ <demo-snippet>
+ <template>
+ <style>
+ .target {
+ cursor: pointer;
+ text-align: center;
+ display: inline-block;
+ box-sizing: border-box;
+ border: 1px solid;
+ width: 100px;
+ padding: 20px 0;
+ margin: 5px;
+ }
+
+ #myFit {
+ z-index: 10;
+ padding: 20px;
+ overflow: auto;
+ min-width: 100px;
+ min-height: 100px;
+ }
+
+ button {
+ background-color: white;
+ border-radius: 5px;
+ border-width: 1px;
+ }
+
+ button.selected {
+ background-color: #b3e5fc;
+ }
+ </style>
+ <template is="dom-bind">
+ <template is="dom-repeat" items="[[containers]]">
+ <div class="target" on-tap="updatePositionTarget">Target</div>
+ </template>
+ <simple-fit id="myFit" auto-fit-on-attach>
+ <h2>Align</h2>
+ <p>
+ <button on-tap="updateAlign" vertical-align="top">top</button>
+ <button on-tap="updateAlign" vertical-align="bottom">bottom</button>
+ <button on-tap="updateAlign" vertical-align="auto">auto</button>
+ <button on-tap="updateAlign" vertical-align>null</button>
+ </p>
+ <p>
+ <button on-tap="updateAlign" horizontal-align="left">left</button>
+ <button on-tap="updateAlign" horizontal-align="right">right</button>
+ <button on-tap="updateAlign" horizontal-align="auto">auto</button>
+ <button on-tap="updateAlign" horizontal-align>null</button>
+ </p>
+ <button on-tap="toggleNoOverlap">no overlap</button>
+ <button on-tap="toggleDynamicAlign">dynamic align</button>
+ </simple-fit>
+ <script>
+ var defaultTarget = Polymer.dom(myFit).parentNode;
+ var template = document.querySelector('template[is="dom-bind"]');
+
+ template.containers = new Array(30);
+
+ template.updatePositionTarget = function(e) {
+ var target = Polymer.dom(e).rootTarget;
+ target = myFit.positionTarget === target ? defaultTarget : target;
+ myFit.positionTarget.style.backgroundColor = '';
+ target.style.backgroundColor = 'orange';
+ myFit.positionTarget = target;
+ template.refit();
+ };
+
+ template._raf = null;
+ template.refit = function() {
+ template._raf && window.cancelAnimationFrame(template._raf);
+ template._raf = window.requestAnimationFrame(function() {
+ template._raf = null;
+ myFit.refit();
+ });
+ };
+
+ template.updateAlign = function(e) {
+ var target = Polymer.dom(e).rootTarget;
+ if (target.hasAttribute('horizontal-align')) {
+ myFit.horizontalAlign = target.getAttribute('horizontal-align');
+ var children = target.parentNode.querySelectorAll('[horizontal-align]');
+ for (var i = 0; i < children.length; i++) {
+ toggleClass(children[i], 'selected', children[i] === target);
+ }
+ }
+ if (target.hasAttribute('vertical-align')) {
+ myFit.verticalAlign = target.getAttribute('vertical-align');
+ var children = target.parentNode.querySelectorAll('[vertical-align]');
+ for (var i = 0; i < children.length; i++) {
+ toggleClass(children[i], 'selected', children[i] === target);
+ }
+ }
+ template.refit();
+ };
+
+ template.toggleNoOverlap = function(e) {
+ myFit.noOverlap = !myFit.noOverlap;
+ toggleClass(Polymer.dom(e).rootTarget, 'selected', myFit.noOverlap);
+ template.refit();
+ };
+
+ template.toggleDynamicAlign = function(e) {
+ myFit.dynamicAlign = !myFit.dynamicAlign;
+ toggleClass(Polymer.dom(e).rootTarget, 'selected', myFit.dynamicAlign);
+ template.refit();
+ };
+
+ // Listen for resize and scroll on window.
+ window.addEventListener('resize', template.refit);
+ window.addEventListener('scroll', template.refit);
+
+ function toggleClass(element, cssClass, condition) {
+ element.classList[condition ? 'add' : 'remove'](cssClass);
+ }
+ </script>
+ </template>
+ </template>
+ </demo-snippet>
+
+</body>
+
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html
new file mode 100644
index 00000000000..2283e526aeb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html
@@ -0,0 +1,42 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-fit-behavior.html">
+<link rel="import" href="../../paper-styles/color.html">
+
+<dom-module id="simple-fit">
+
+ <style>
+ :host {
+ background-color: var(--paper-light-blue-500);
+ color: white;
+ text-align: center;
+ }
+ </style>
+
+ <template>
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'simple-fit',
+
+ behaviors: [
+ Polymer.IronFitBehavior
+ ]
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/index.html
new file mode 100644
index 00000000000..5ffa7d61cec
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-fit-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html
new file mode 100644
index 00000000000..d51d87dfe44
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html
@@ -0,0 +1,594 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+/**
+`Polymer.IronFitBehavior` fits an element in another element using `max-height` and `max-width`, and
+optionally centers it in the window or another element.
+
+The element will only be sized and/or positioned if it has not already been sized and/or positioned
+by CSS.
+
+CSS properties | Action
+-----------------------------|-------------------------------------------
+`position` set | Element is not centered horizontally or vertically
+`top` or `bottom` set | Element is not vertically centered
+`left` or `right` set | Element is not horizontally centered
+`max-height` set | Element respects `max-height`
+`max-width` set | Element respects `max-width`
+
+`Polymer.IronFitBehavior` can position an element into another element using
+`verticalAlign` and `horizontalAlign`. This will override the element's css position.
+
+ <div class="container">
+ <iron-fit-impl vertical-align="top" horizontal-align="auto">
+ Positioned into the container
+ </iron-fit-impl>
+ </div>
+
+Use `noOverlap` to position the element around another element without overlapping it.
+
+ <div class="container">
+ <iron-fit-impl no-overlap vertical-align="auto" horizontal-align="auto">
+ Positioned around the container
+ </iron-fit-impl>
+ </div>
+
+@demo demo/index.html
+@polymerBehavior
+*/
+
+ Polymer.IronFitBehavior = {
+
+ properties: {
+
+ /**
+ * The element that will receive a `max-height`/`width`. By default it is the same as `this`,
+ * but it can be set to a child element. This is useful, for example, for implementing a
+ * scrolling region inside the element.
+ * @type {!Element}
+ */
+ sizingTarget: {
+ type: Object,
+ value: function() {
+ return this;
+ }
+ },
+
+ /**
+ * The element to fit `this` into.
+ */
+ fitInto: {
+ type: Object,
+ value: window
+ },
+
+ /**
+ * Will position the element around the positionTarget without overlapping it.
+ */
+ noOverlap: {
+ type: Boolean
+ },
+
+ /**
+ * The element that should be used to position the element. If not set, it will
+ * default to the parent node.
+ * @type {!Element}
+ */
+ positionTarget: {
+ type: Element
+ },
+
+ /**
+ * The orientation against which to align the element horizontally
+ * relative to the `positionTarget`. Possible values are "left", "right", "auto".
+ */
+ horizontalAlign: {
+ type: String
+ },
+
+ /**
+ * The orientation against which to align the element vertically
+ * relative to the `positionTarget`. Possible values are "top", "bottom", "auto".
+ */
+ verticalAlign: {
+ type: String
+ },
+
+ /**
+ * If true, it will use `horizontalAlign` and `verticalAlign` values as preferred alignment
+ * and if there's not enough space, it will pick the values which minimize the cropping.
+ */
+ dynamicAlign: {
+ type: Boolean
+ },
+
+ /**
+ * The same as setting margin-left and margin-right css properties.
+ * @deprecated
+ */
+ horizontalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * The same as setting margin-top and margin-bottom css properties.
+ * @deprecated
+ */
+ verticalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * Set to true to auto-fit on attach.
+ */
+ autoFitOnAttach: {
+ type: Boolean,
+ value: false
+ },
+
+ /** @type {?Object} */
+ _fitInfo: {
+ type: Object
+ }
+ },
+
+ get _fitWidth() {
+ var fitWidth;
+ if (this.fitInto === window) {
+ fitWidth = this.fitInto.innerWidth;
+ } else {
+ fitWidth = this.fitInto.getBoundingClientRect().width;
+ }
+ return fitWidth;
+ },
+
+ get _fitHeight() {
+ var fitHeight;
+ if (this.fitInto === window) {
+ fitHeight = this.fitInto.innerHeight;
+ } else {
+ fitHeight = this.fitInto.getBoundingClientRect().height;
+ }
+ return fitHeight;
+ },
+
+ get _fitLeft() {
+ var fitLeft;
+ if (this.fitInto === window) {
+ fitLeft = 0;
+ } else {
+ fitLeft = this.fitInto.getBoundingClientRect().left;
+ }
+ return fitLeft;
+ },
+
+ get _fitTop() {
+ var fitTop;
+ if (this.fitInto === window) {
+ fitTop = 0;
+ } else {
+ fitTop = this.fitInto.getBoundingClientRect().top;
+ }
+ return fitTop;
+ },
+
+ /**
+ * The element that should be used to position the element,
+ * if no position target is configured.
+ */
+ get _defaultPositionTarget() {
+ var parent = Polymer.dom(this).parentNode;
+
+ if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+ parent = parent.host;
+ }
+
+ return parent;
+ },
+
+ /**
+ * The horizontal align value, accounting for the RTL/LTR text direction.
+ */
+ get _localeHorizontalAlign() {
+ if (this._isRTL) {
+ // In RTL, "left" becomes "right".
+ if (this.horizontalAlign === 'right') {
+ return 'left';
+ }
+ if (this.horizontalAlign === 'left') {
+ return 'right';
+ }
+ }
+ return this.horizontalAlign;
+ },
+
+ attached: function() {
+ // Memoize this to avoid expensive calculations & relayouts.
+ this._isRTL = window.getComputedStyle(this).direction == 'rtl';
+ this.positionTarget = this.positionTarget || this._defaultPositionTarget;
+ if (this.autoFitOnAttach) {
+ if (window.getComputedStyle(this).display === 'none') {
+ setTimeout(function() {
+ this.fit();
+ }.bind(this));
+ } else {
+ this.fit();
+ }
+ }
+ },
+
+ /**
+ * Positions and fits the element into the `fitInto` element.
+ */
+ fit: function() {
+ this._discoverInfo();
+ this.position();
+ this.constrain();
+ this.center();
+ },
+
+ /**
+ * Memoize information needed to position and size the target element.
+ * @suppress {deprecated}
+ */
+ _discoverInfo: function() {
+ if (this._fitInfo) {
+ return;
+ }
+ var target = window.getComputedStyle(this);
+ var sizer = window.getComputedStyle(this.sizingTarget);
+
+ this._fitInfo = {
+ inlineStyle: {
+ top: this.style.top || '',
+ left: this.style.left || '',
+ position: this.style.position || ''
+ },
+ sizerInlineStyle: {
+ maxWidth: this.sizingTarget.style.maxWidth || '',
+ maxHeight: this.sizingTarget.style.maxHeight || '',
+ boxSizing: this.sizingTarget.style.boxSizing || ''
+ },
+ positionedBy: {
+ vertically: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto' ?
+ 'bottom' : null),
+ horizontally: target.left !== 'auto' ? 'left' : (target.right !== 'auto' ?
+ 'right' : null)
+ },
+ sizedBy: {
+ height: sizer.maxHeight !== 'none',
+ width: sizer.maxWidth !== 'none',
+ minWidth: parseInt(sizer.minWidth, 10) || 0,
+ minHeight: parseInt(sizer.minHeight, 10) || 0
+ },
+ margin: {
+ top: parseInt(target.marginTop, 10) || 0,
+ right: parseInt(target.marginRight, 10) || 0,
+ bottom: parseInt(target.marginBottom, 10) || 0,
+ left: parseInt(target.marginLeft, 10) || 0
+ }
+ };
+
+ // Support these properties until they are removed.
+ if (this.verticalOffset) {
+ this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
+ this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
+ this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
+ this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
+ }
+ if (this.horizontalOffset) {
+ this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
+ this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
+ this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
+ this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
+ }
+ },
+
+ /**
+ * Resets the target element's position and size constraints, and clear
+ * the memoized data.
+ */
+ resetFit: function() {
+ var info = this._fitInfo || {};
+ for (var property in info.sizerInlineStyle) {
+ this.sizingTarget.style[property] = info.sizerInlineStyle[property];
+ }
+ for (var property in info.inlineStyle) {
+ this.style[property] = info.inlineStyle[property];
+ }
+
+ this._fitInfo = null;
+ },
+
+ /**
+ * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
+ * the element or the `fitInto` element has been resized, or if any of the
+ * positioning properties (e.g. `horizontalAlign, verticalAlign`) is updated.
+ * It preserves the scroll position of the sizingTarget.
+ */
+ refit: function() {
+ var scrollLeft = this.sizingTarget.scrollLeft;
+ var scrollTop = this.sizingTarget.scrollTop;
+ this.resetFit();
+ this.fit();
+ this.sizingTarget.scrollLeft = scrollLeft;
+ this.sizingTarget.scrollTop = scrollTop;
+ },
+
+ /**
+ * Positions the element according to `horizontalAlign, verticalAlign`.
+ */
+ position: function() {
+ if (!this.horizontalAlign && !this.verticalAlign) {
+ // needs to be centered, and it is done after constrain.
+ return;
+ }
+
+ this.style.position = 'fixed';
+ // Need border-box for margin/padding.
+ this.sizingTarget.style.boxSizing = 'border-box';
+ // Set to 0, 0 in order to discover any offset caused by parent stacking contexts.
+ this.style.left = '0px';
+ this.style.top = '0px';
+
+ var rect = this.getBoundingClientRect();
+ var positionRect = this.__getNormalizedRect(this.positionTarget);
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+
+ var margin = this._fitInfo.margin;
+
+ // Consider the margin as part of the size for position calculations.
+ var size = {
+ width: rect.width + margin.left + margin.right,
+ height: rect.height + margin.top + margin.bottom
+ };
+
+ var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
+
+ var left = position.left + margin.left;
+ var top = position.top + margin.top;
+
+ // Use original size (without margin).
+ var right = Math.min(fitRect.right - margin.right, left + rect.width);
+ var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
+
+ var minWidth = this._fitInfo.sizedBy.minWidth;
+ var minHeight = this._fitInfo.sizedBy.minHeight;
+ if (left < margin.left) {
+ left = margin.left;
+ if (right - left < minWidth) {
+ left = right - minWidth;
+ }
+ }
+ if (top < margin.top) {
+ top = margin.top;
+ if (bottom - top < minHeight) {
+ top = bottom - minHeight;
+ }
+ }
+
+ this.sizingTarget.style.maxWidth = (right - left) + 'px';
+ this.sizingTarget.style.maxHeight = (bottom - top) + 'px';
+
+ // Remove the offset caused by any stacking context.
+ this.style.left = (left - rect.left) + 'px';
+ this.style.top = (top - rect.top) + 'px';
+ },
+
+ /**
+ * Constrains the size of the element to `fitInto` by setting `max-height`
+ * and/or `max-width`.
+ */
+ constrain: function() {
+ if (this.horizontalAlign || this.verticalAlign) {
+ return;
+ }
+ var info = this._fitInfo;
+ // position at (0px, 0px) if not already positioned, so we can measure the natural size.
+ if (!info.positionedBy.vertically) {
+ this.style.position = 'fixed';
+ this.style.top = '0px';
+ }
+ if (!info.positionedBy.horizontally) {
+ this.style.position = 'fixed';
+ this.style.left = '0px';
+ }
+
+ // need border-box for margin/padding
+ this.sizingTarget.style.boxSizing = 'border-box';
+ // constrain the width and height if not already set
+ var rect = this.getBoundingClientRect();
+ if (!info.sizedBy.height) {
+ this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
+ }
+ if (!info.sizedBy.width) {
+ this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
+ }
+ },
+
+ /**
+ * @protected
+ * @deprecated
+ */
+ _sizeDimension: function(rect, positionedBy, start, end, extent) {
+ this.__sizeDimension(rect, positionedBy, start, end, extent);
+ },
+
+ /**
+ * @private
+ */
+ __sizeDimension: function(rect, positionedBy, start, end, extent) {
+ var info = this._fitInfo;
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+ var max = extent === 'Width' ? fitRect.width : fitRect.height;
+ var flip = (positionedBy === end);
+ var offset = flip ? max - rect[end] : rect[start];
+ var margin = info.margin[flip ? start : end];
+ var offsetExtent = 'offset' + extent;
+ var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
+ this.sizingTarget.style['max' + extent] = (max - margin - offset - sizingOffset) + 'px';
+ },
+
+ /**
+ * Centers horizontally and vertically if not already positioned. This also sets
+ * `position:fixed`.
+ */
+ center: function() {
+ if (this.horizontalAlign || this.verticalAlign) {
+ return;
+ }
+ var positionedBy = this._fitInfo.positionedBy;
+ if (positionedBy.vertically && positionedBy.horizontally) {
+ // Already positioned.
+ return;
+ }
+ // Need position:fixed to center
+ this.style.position = 'fixed';
+ // Take into account the offset caused by parents that create stacking
+ // contexts (e.g. with transform: translate3d). Translate to 0,0 and
+ // measure the bounding rect.
+ if (!positionedBy.vertically) {
+ this.style.top = '0px';
+ }
+ if (!positionedBy.horizontally) {
+ this.style.left = '0px';
+ }
+ // It will take in consideration margins and transforms
+ var rect = this.getBoundingClientRect();
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+ if (!positionedBy.vertically) {
+ var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
+ this.style.top = top + 'px';
+ }
+ if (!positionedBy.horizontally) {
+ var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
+ this.style.left = left + 'px';
+ }
+ },
+
+ __getNormalizedRect: function(target) {
+ if (target === document.documentElement || target === window) {
+ return {
+ top: 0,
+ left: 0,
+ width: window.innerWidth,
+ height: window.innerHeight,
+ right: window.innerWidth,
+ bottom: window.innerHeight
+ };
+ }
+ return target.getBoundingClientRect();
+ },
+
+ __getCroppedArea: function(position, size, fitRect) {
+ var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
+ var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
+ return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
+ },
+
+
+ __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
+ // All the possible configurations.
+ // Ordered as top-left, top-right, bottom-left, bottom-right.
+ var positions = [{
+ verticalAlign: 'top',
+ horizontalAlign: 'left',
+ top: positionRect.top,
+ left: positionRect.left
+ }, {
+ verticalAlign: 'top',
+ horizontalAlign: 'right',
+ top: positionRect.top,
+ left: positionRect.right - size.width
+ }, {
+ verticalAlign: 'bottom',
+ horizontalAlign: 'left',
+ top: positionRect.bottom - size.height,
+ left: positionRect.left
+ }, {
+ verticalAlign: 'bottom',
+ horizontalAlign: 'right',
+ top: positionRect.bottom - size.height,
+ left: positionRect.right - size.width
+ }];
+
+ if (this.noOverlap) {
+ // Duplicate.
+ for (var i = 0, l = positions.length; i < l; i++) {
+ var copy = {};
+ for (var key in positions[i]) {
+ copy[key] = positions[i][key];
+ }
+ positions.push(copy);
+ }
+ // Horizontal overlap only.
+ positions[0].top = positions[1].top += positionRect.height;
+ positions[2].top = positions[3].top -= positionRect.height;
+ // Vertical overlap only.
+ positions[4].left = positions[6].left += positionRect.width;
+ positions[5].left = positions[7].left -= positionRect.width;
+ }
+
+ // Consider auto as null for coding convenience.
+ vAlign = vAlign === 'auto' ? null : vAlign;
+ hAlign = hAlign === 'auto' ? null : hAlign;
+
+ var position;
+ for (var i = 0; i < positions.length; i++) {
+ var pos = positions[i];
+
+ // If both vAlign and hAlign are defined, return exact match.
+ // For dynamicAlign and noOverlap we'll have more than one candidate, so
+ // we'll have to check the croppedArea to make the best choice.
+ if (!this.dynamicAlign && !this.noOverlap &&
+ pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
+ position = pos;
+ break;
+ }
+
+ // Align is ok if alignment preferences are respected. If no preferences,
+ // it is considered ok.
+ var alignOk = (!vAlign || pos.verticalAlign === vAlign) &&
+ (!hAlign || pos.horizontalAlign === hAlign);
+
+ // Filter out elements that don't match the alignment (if defined).
+ // With dynamicAlign, we need to consider all the positions to find the
+ // one that minimizes the cropped area.
+ if (!this.dynamicAlign && !alignOk) {
+ continue;
+ }
+
+ position = position || pos;
+ pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
+ var diff = pos.croppedArea - position.croppedArea;
+ // Check which crops less. If it crops equally, check if align is ok.
+ if (diff < 0 || (diff === 0 && alignOk)) {
+ position = pos;
+ }
+ // If not cropped and respects the align requirements, keep it.
+ // This allows to prefer positions overlapping horizontally over the
+ // ones overlapping vertically.
+ if (position.croppedArea === 0 && alignOk) {
+ break;
+ }
+ }
+
+ return position;
+ }
+
+ };
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.bower.json
new file mode 100644
index 00000000000..023b53e0e53
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "iron-flex-layout",
+ "version": "1.3.1",
+ "description": "Provide flexbox-based layouts",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "layout"
+ ],
+ "main": "iron-flex-layout.html",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-flex-layout.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/polymerelements/iron-flex-layout",
+ "_release": "1.3.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.3.1",
+ "commit": "6d88f29f3a7181daa2a5c7f678de44f0a0e6a717"
+ },
+ "_source": "git://github.com/polymerelements/iron-flex-layout.git",
+ "_target": "^1.0.0",
+ "_originalSource": "polymerelements/iron-flex-layout"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.travis.yml
new file mode 100644
index 00000000000..516b453f813
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: jFaXkmco40NlJT4VyFYM34Zv9D1XVfLXgixobnyHQyJDBKSXrNLcwDuvrGUpJx/pwBCxEhKAbvxeJ+PBMUv8QV08MAdw2S6QOsIe3CUxAehoNoOMJw5duhE8faWlz8qzmCWEowHVFUeVsd0ZUsgOu6RTspj2A51D/CztQuW0Ljw=
+ - secure: fKrO5yMx8kZM1WQ3k0bzo6MCREKGW2WkCl2suDjuEtb1SQ/SaZa9Tun0fcqIHVJqg9+jOS1Romt/+MN27Nc6IT1tv/NdLd+uWjtMA+OzLyv48gzcdu8Ls/TISUGm5Wb7XHkcvMAb1tRoBs5BOvQ/85FilZLEq1km8snG9ZsOOWI=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/README.md
new file mode 100644
index 00000000000..219fca7d721
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/README.md
@@ -0,0 +1,55 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-flex-layout.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-flex-layout.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-flex-layout)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-flex-layout)_
+
+
+##&lt;iron-flex-layout&gt;
+
+The `<iron-flex-layout>` component provides simple ways to use
+[CSS flexible box layout](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes),
+also known as flexbox. This component provides two different ways to use flexbox:
+
+1. [Layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+The layout class stylesheet provides a simple set of class-based flexbox rules, that
+let you specify layout properties directly in markup. You must include this file
+in every element that needs to use them.
+
+Sample use:
+
+ <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
+
+ <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
+
+ <div class="layout horizontal layout-start">
+ <div>cross axis start alignment</div>
+ </div>
+
+1. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html).
+The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+
+
+
+Please note that the old [/deep/ layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/classes)
+are deprecated, and should not be used. To continue using layout properties
+directly in markup, please switch to using the new `dom-module`-based
+[layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+Please note that the new version does not use `/deep/`, and therefore requires you
+to import the `dom-modules` in every element that needs to use them.
+
+A complete [guide](https://elements.polymer-project.org/guides/flex-layout) to `<iron-flex-layout>` is available.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/bower.json
new file mode 100644
index 00000000000..e1752973341
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "iron-flex-layout",
+ "version": "1.3.1",
+ "description": "Provide flexbox-based layouts",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "layout"
+ ],
+ "main": "iron-flex-layout.html",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-flex-layout.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-flex-layout.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-flex-layout.html
new file mode 100644
index 00000000000..0c6aad604b6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-flex-layout.html
@@ -0,0 +1,311 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="iron-shadow-flex-layout.html">
+
+<script>
+ console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
+</script>
+
+<style>
+
+ /*******************************
+ Flex Layout
+ *******************************/
+
+ .layout.horizontal,
+ .layout.horizontal-reverse,
+ .layout.vertical,
+ .layout.vertical-reverse {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ .layout.inline {
+ display: -ms-inline-flexbox;
+ display: -webkit-inline-flex;
+ display: inline-flex;
+ }
+
+ .layout.horizontal {
+ -ms-flex-direction: row;
+ -webkit-flex-direction: row;
+ flex-direction: row;
+ }
+
+ .layout.horizontal-reverse {
+ -ms-flex-direction: row-reverse;
+ -webkit-flex-direction: row-reverse;
+ flex-direction: row-reverse;
+ }
+
+ .layout.vertical {
+ -ms-flex-direction: column;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ }
+
+ .layout.vertical-reverse {
+ -ms-flex-direction: column-reverse;
+ -webkit-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ }
+
+ .layout.wrap {
+ -ms-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ flex-wrap: wrap;
+ }
+
+ .layout.wrap-reverse {
+ -ms-flex-wrap: wrap-reverse;
+ -webkit-flex-wrap: wrap-reverse;
+ flex-wrap: wrap-reverse;
+ }
+
+ .flex-auto {
+ -ms-flex: 1 1 auto;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ }
+
+ .flex-none {
+ -ms-flex: none;
+ -webkit-flex: none;
+ flex: none;
+ }
+
+ .flex,
+ .flex-1 {
+ -ms-flex: 1;
+ -webkit-flex: 1;
+ flex: 1;
+ }
+
+ .flex-2 {
+ -ms-flex: 2;
+ -webkit-flex: 2;
+ flex: 2;
+ }
+
+ .flex-3 {
+ -ms-flex: 3;
+ -webkit-flex: 3;
+ flex: 3;
+ }
+
+ .flex-4 {
+ -ms-flex: 4;
+ -webkit-flex: 4;
+ flex: 4;
+ }
+
+ .flex-5 {
+ -ms-flex: 5;
+ -webkit-flex: 5;
+ flex: 5;
+ }
+
+ .flex-6 {
+ -ms-flex: 6;
+ -webkit-flex: 6;
+ flex: 6;
+ }
+
+ .flex-7 {
+ -ms-flex: 7;
+ -webkit-flex: 7;
+ flex: 7;
+ }
+
+ .flex-8 {
+ -ms-flex: 8;
+ -webkit-flex: 8;
+ flex: 8;
+ }
+
+ .flex-9 {
+ -ms-flex: 9;
+ -webkit-flex: 9;
+ flex: 9;
+ }
+
+ .flex-10 {
+ -ms-flex: 10;
+ -webkit-flex: 10;
+ flex: 10;
+ }
+
+ .flex-11 {
+ -ms-flex: 11;
+ -webkit-flex: 11;
+ flex: 11;
+ }
+
+ .flex-12 {
+ -ms-flex: 12;
+ -webkit-flex: 12;
+ flex: 12;
+ }
+
+ /* alignment in cross axis */
+
+ .layout.start {
+ -ms-flex-align: start;
+ -webkit-align-items: flex-start;
+ align-items: flex-start;
+ }
+
+ .layout.center,
+ .layout.center-center {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ }
+
+ .layout.end {
+ -ms-flex-align: end;
+ -webkit-align-items: flex-end;
+ align-items: flex-end;
+ }
+
+ /* alignment in main axis */
+
+ .layout.start-justified {
+ -ms-flex-pack: start;
+ -webkit-justify-content: flex-start;
+ justify-content: flex-start;
+ }
+
+ .layout.center-justified,
+ .layout.center-center {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ }
+
+ .layout.end-justified {
+ -ms-flex-pack: end;
+ -webkit-justify-content: flex-end;
+ justify-content: flex-end;
+ }
+
+ .layout.around-justified {
+ -ms-flex-pack: around;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ }
+
+ .layout.justified {
+ -ms-flex-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ }
+
+ /* self alignment */
+
+ .self-start {
+ -ms-align-self: flex-start;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ }
+
+ .self-center {
+ -ms-align-self: center;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+
+ .self-end {
+ -ms-align-self: flex-end;
+ -webkit-align-self: flex-end;
+ align-self: flex-end;
+ }
+
+ .self-stretch {
+ -ms-align-self: stretch;
+ -webkit-align-self: stretch;
+ align-self: stretch;
+ }
+
+ /*******************************
+ Other Layout
+ *******************************/
+
+ .block {
+ display: block;
+ }
+
+ /* IE 10 support for HTML5 hidden attr */
+ [hidden] {
+ display: none !important;
+ }
+
+ .invisible {
+ visibility: hidden !important;
+ }
+
+ .relative {
+ position: relative;
+ }
+
+ .fit {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ body.fullbleed {
+ margin: 0;
+ height: 100vh;
+ }
+
+ .scroll {
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ }
+
+ /* fixed position */
+
+ .fixed-bottom,
+ .fixed-left,
+ .fixed-right,
+ .fixed-top {
+ position: fixed;
+ }
+
+ .fixed-top {
+ top: 0;
+ left: 0;
+ right: 0;
+ }
+
+ .fixed-right {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ }
+
+ .fixed-bottom {
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ .fixed-left {
+ top: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-shadow-flex-layout.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-shadow-flex-layout.html
new file mode 100644
index 00000000000..196df284c05
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/classes/iron-shadow-flex-layout.html
@@ -0,0 +1,307 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<script>
+ console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
+</script>
+
+<style>
+
+ /*******************************
+ Flex Layout
+ *******************************/
+
+ html /deep/ .layout.horizontal,
+ html /deep/ .layout.horizontal-reverse,
+ html /deep/ .layout.vertical,
+ html /deep/ .layout.vertical-reverse {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ html /deep/ .layout.inline {
+ display: -ms-inline-flexbox;
+ display: -webkit-inline-flex;
+ display: inline-flex;
+ }
+
+ html /deep/ .layout.horizontal {
+ -ms-flex-direction: row;
+ -webkit-flex-direction: row;
+ flex-direction: row;
+ }
+
+ html /deep/ .layout.horizontal-reverse {
+ -ms-flex-direction: row-reverse;
+ -webkit-flex-direction: row-reverse;
+ flex-direction: row-reverse;
+ }
+
+ html /deep/ .layout.vertical {
+ -ms-flex-direction: column;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ }
+
+ html /deep/ .layout.vertical-reverse {
+ -ms-flex-direction: column-reverse;
+ -webkit-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ }
+
+ html /deep/ .layout.wrap {
+ -ms-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ flex-wrap: wrap;
+ }
+
+ html /deep/ .layout.wrap-reverse {
+ -ms-flex-wrap: wrap-reverse;
+ -webkit-flex-wrap: wrap-reverse;
+ flex-wrap: wrap-reverse;
+ }
+
+ html /deep/ .flex-auto {
+ -ms-flex: 1 1 auto;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ }
+
+ html /deep/ .flex-none {
+ -ms-flex: none;
+ -webkit-flex: none;
+ flex: none;
+ }
+
+ html /deep/ .flex,
+ html /deep/ .flex-1 {
+ -ms-flex: 1;
+ -webkit-flex: 1;
+ flex: 1;
+ }
+
+ html /deep/ .flex-2 {
+ -ms-flex: 2;
+ -webkit-flex: 2;
+ flex: 2;
+ }
+
+ html /deep/ .flex-3 {
+ -ms-flex: 3;
+ -webkit-flex: 3;
+ flex: 3;
+ }
+
+ html /deep/ .flex-4 {
+ -ms-flex: 4;
+ -webkit-flex: 4;
+ flex: 4;
+ }
+
+ html /deep/ .flex-5 {
+ -ms-flex: 5;
+ -webkit-flex: 5;
+ flex: 5;
+ }
+
+ html /deep/ .flex-6 {
+ -ms-flex: 6;
+ -webkit-flex: 6;
+ flex: 6;
+ }
+
+ html /deep/ .flex-7 {
+ -ms-flex: 7;
+ -webkit-flex: 7;
+ flex: 7;
+ }
+
+ html /deep/ .flex-8 {
+ -ms-flex: 8;
+ -webkit-flex: 8;
+ flex: 8;
+ }
+
+ html /deep/ .flex-9 {
+ -ms-flex: 9;
+ -webkit-flex: 9;
+ flex: 9;
+ }
+
+ html /deep/ .flex-10 {
+ -ms-flex: 10;
+ -webkit-flex: 10;
+ flex: 10;
+ }
+
+ html /deep/ .flex-11 {
+ -ms-flex: 11;
+ -webkit-flex: 11;
+ flex: 11;
+ }
+
+ html /deep/ .flex-12 {
+ -ms-flex: 12;
+ -webkit-flex: 12;
+ flex: 12;
+ }
+
+ /* alignment in cross axis */
+
+ html /deep/ .layout.start {
+ -ms-flex-align: start;
+ -webkit-align-items: flex-start;
+ align-items: flex-start;
+ }
+
+ html /deep/ .layout.center,
+ html /deep/ .layout.center-center {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ }
+
+ html /deep/ .layout.end {
+ -ms-flex-align: end;
+ -webkit-align-items: flex-end;
+ align-items: flex-end;
+ }
+
+ /* alignment in main axis */
+
+ html /deep/ .layout.start-justified {
+ -ms-flex-pack: start;
+ -webkit-justify-content: flex-start;
+ justify-content: flex-start;
+ }
+
+ html /deep/ .layout.center-justified,
+ html /deep/ .layout.center-center {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ }
+
+ html /deep/ .layout.end-justified {
+ -ms-flex-pack: end;
+ -webkit-justify-content: flex-end;
+ justify-content: flex-end;
+ }
+
+ html /deep/ .layout.around-justified {
+ -ms-flex-pack: around;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ }
+
+ html /deep/ .layout.justified {
+ -ms-flex-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ }
+
+ /* self alignment */
+
+ html /deep/ .self-start {
+ -ms-align-self: flex-start;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ }
+
+ html /deep/ .self-center {
+ -ms-align-self: center;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+
+ html /deep/ .self-end {
+ -ms-align-self: flex-end;
+ -webkit-align-self: flex-end;
+ align-self: flex-end;
+ }
+
+ html /deep/ .self-stretch {
+ -ms-align-self: stretch;
+ -webkit-align-self: stretch;
+ align-self: stretch;
+ }
+
+ /*******************************
+ Other Layout
+ *******************************/
+
+ html /deep/ .block {
+ display: block;
+ }
+
+ /* IE 10 support for HTML5 hidden attr */
+ html /deep/ [hidden] {
+ display: none !important;
+ }
+
+ html /deep/ .invisible {
+ visibility: hidden !important;
+ }
+
+ html /deep/ .relative {
+ position: relative;
+ }
+
+ html /deep/ .fit {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ body.fullbleed {
+ margin: 0;
+ height: 100vh;
+ }
+
+ html /deep/ .scroll {
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ }
+
+ .fixed-bottom,
+ .fixed-left,
+ .fixed-right,
+ .fixed-top {
+ position: fixed;
+ }
+
+ html /deep/ .fixed-top {
+ top: 0;
+ left: 0;
+ right: 0;
+ }
+
+ html /deep/ .fixed-right {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ }
+
+ html /deep/ .fixed-bottom {
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ html /deep/ .fixed-left {
+ top: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/demo/index.html
new file mode 100644
index 00000000000..2c3f5f7d213
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/demo/index.html
@@ -0,0 +1,396 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-flex-layout demo</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../iron-flex-layout.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ demo-snippet {
+ --demo-snippet-demo: {
+ padding: 0;
+ }
+ }
+ .container {
+ background-color: #ccc;
+ padding: 5px;
+ margin: 0;
+ }
+ .container > div {
+ padding: 15px;
+ margin: 5px;
+ background-color: white;
+ min-height: 20px;
+ }
+
+ .vertical-section-container {
+ max-width: 700px
+ }
+ </style>
+
+</head>
+<body unresolved class="fullbleed">
+ <div class="vertical-section-container centered">
+ <h4>Horizontal and vertical layout</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex {
+ @apply(--layout-horizontal);
+ }
+ </style>
+ <div class="container flex">
+ <div>one</div>
+ <div>two</div>
+ <div>three</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Flexible children</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-horizontal {
+ @apply(--layout-horizontal);
+ }
+ .flexchild {
+ @apply(--layout-flex);
+ }
+ </style>
+
+ <div class="container flex-horizontal">
+ <div>one</div>
+ <div class="flexchild">two (flex)</div>
+ <div>three</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Flexible children in vertical layouts</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-vertical {
+ @apply(--layout-vertical);
+ height: 220px;
+ }
+ .flexchild-vertical {
+ @apply(--layout-flex);
+ }
+ </style>
+
+ <div class="container flex-vertical">
+ <div>one</div>
+ <div class="flexchild-vertical">two (flex)</div>
+ <div>three</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Flex ratios</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-horizontal-with-ratios {
+ @apply(--layout-horizontal);
+ }
+ .flexchild {
+ @apply(--layout-flex);
+ }
+ .flex2child {
+ @apply(--layout-flex-2);
+ }
+ .flex3child {
+ @apply(--layout-flex-3);
+ }
+ </style>
+
+ <div class="container flex-horizontal-with-ratios">
+ <div class="flex3child">one</div>
+ <div class="flexchild">two</div>
+ <div class="flex2child">three</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Cross-axis stretch alignment (default)</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-stretch-align {
+ @apply(--layout-horizontal);
+ height: 120px;
+ }
+ </style>
+
+ <div class="container flex-stretch-align">
+ <div>stretch</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Cross-axis center alignment</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-center-align {
+ @apply(--layout-horizontal);
+ @apply(--layout-center);
+ height: 120px;
+ }
+ </style>
+
+ <div class="container flex-center-align">
+ <div>center</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Cross-axis start alignment</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-start-align {
+ @apply(--layout-horizontal);
+ @apply(--layout-start);
+ height: 120px;
+ }
+ </style>
+
+ <div class="container flex-start-align">
+ <div>start</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Cross-axis end alignment</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-end-align {
+ @apply(--layout-horizontal);
+ @apply(--layout-end);
+ height: 120px;
+ }
+ </style>
+
+ <div class="container flex-end-align">
+ <div>end</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Justification, start justified</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-start-justified {
+ @apply(--layout-horizontal);
+ @apply(--layout-start-justified);
+ }
+ </style>
+
+ <div class="container flex-start-justified">
+ <div>start-justified</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Justification, start justified</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-center-justified {
+ @apply(--layout-horizontal);
+ @apply(--layout-center-justified);
+ }
+ </style>
+
+ <div class="container flex-center-justified">
+ <div>center-justified</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Justification, end justified</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-end-justified {
+ @apply(--layout-horizontal);
+ @apply(--layout-end-justified);
+ }
+ </style>
+
+ <div class="container flex-end-justified">
+ <div>end-justified</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Justification, equal space between elements</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-equal-justified {
+ @apply(--layout-horizontal);
+ @apply(--layout-justified);
+ }
+ </style>
+
+ <div class="container flex-equal-justified">
+ <div>justified</div>
+ <div>justified</div>
+ <div>justified</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Justification, equal space around each element</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-equal-around-justified {
+ @apply(--layout-horizontal);
+ @apply(--layout-around-justified);
+ }
+ </style>
+
+ <div class="container flex-equal-around-justified">
+ <div>around-justified</div>
+ <div>around-justified</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Self alignment</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-self-align {
+ @apply(--layout-horizontal);
+ @apply(--layout-justified);
+ height: 120px;
+ }
+ .flex-self-align div {
+ @apply(--layout-flex);
+ }
+ .child1 {
+ @apply(--layout-self-start);
+ }
+ .child2 {
+ @apply(--layout-self-center);
+ }
+ .child3 {
+ @apply(--layout-self-end);
+ }
+ .child4 {
+ @apply(--layout-self-stretch);
+ }
+ </style>
+
+ <div class="container flex-self-align">
+ <div class="child1">one</div>
+ <div class="child2">two</div>
+ <div class="child3">three</div>
+ <div class="child4">four</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Wrapping</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-wrap {
+ @apply(--layout-horizontal);
+ @apply(--layout-wrap);
+ width: 200px;
+ }
+ </style>
+
+ <div class="container flex-wrap">
+ <div>one</div>
+ <div>two</div>
+ <div>three</div>
+ <div>four</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>Reversed layouts</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .flex-reversed {
+ @apply(--layout-horizontal-reverse);
+ }
+ </style>
+
+ <div class="container flex-reversed">
+ <div>one</div>
+ <div>two</div>
+ <div>three</div>
+ <div>four</div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h4>General purpose rules</h4>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .general {
+ width: 100%;
+ }
+ .general > div {
+ background-color: #ccc;
+ padding: 4px;
+ margin: 12px;
+ }
+ .block {
+ @apply(--layout-block);
+ }
+ .invisible {
+ @apply(--layout-invisible);
+ }
+ .relative {
+ @apply(--layout-relative);
+ }
+ .fit {
+ @apply(--layout-fit);
+ }
+ </style>
+
+ <div class="general">
+ <div>Before <span>[A Span]</span> After</div>
+ <div>Before <span class="block">[A Block Span]</span> After</div>
+ <div>Before invisible span <span class="invisible">Not displayed</span> After invisible span</div>
+ <div class="relative" style="height: 100px;">
+ <div class="fit" style="background-color: #000;color: white">Fit</div>
+ </div>
+ </div>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/index.html
new file mode 100644
index 00000000000..7d3b0881f8c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>iron-flex-layout</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout-classes.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout-classes.html
new file mode 100644
index 00000000000..d382652b717
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout-classes.html
@@ -0,0 +1,431 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<!--
+A set of layout classes that let you specify layout properties directly in markup.
+You must include this file in every element that needs to use them.
+
+Sample use:
+
+ <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
+ <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
+
+ <div class="layout horizontal layout-start">
+ <div>cross axis start alignment</div>
+ </div>
+
+The following imports are available:
+ - iron-flex
+ - iron-flex-reverse
+ - iron-flex-alignment
+ - iron-flex-factors
+ - iron-positioning
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!-- Most common used flex styles-->
+<dom-module id="iron-flex">
+ <template>
+ <style>
+ .layout.horizontal,
+ .layout.vertical {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ .layout.inline {
+ display: -ms-inline-flexbox;
+ display: -webkit-inline-flex;
+ display: inline-flex;
+ }
+
+ .layout.horizontal {
+ -ms-flex-direction: row;
+ -webkit-flex-direction: row;
+ flex-direction: row;
+ }
+
+ .layout.vertical {
+ -ms-flex-direction: column;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ }
+
+ .layout.wrap {
+ -ms-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ flex-wrap: wrap;
+ }
+
+ .layout.center,
+ .layout.center-center {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ }
+
+ .layout.center-justified,
+ .layout.center-center {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ }
+
+ .flex {
+ -ms-flex: 1 1 0.000000001px;
+ -webkit-flex: 1;
+ flex: 1;
+ -webkit-flex-basis: 0.000000001px;
+ flex-basis: 0.000000001px;
+ }
+
+ .flex-auto {
+ -ms-flex: 1 1 auto;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ }
+
+ .flex-none {
+ -ms-flex: none;
+ -webkit-flex: none;
+ flex: none;
+ }
+ </style>
+ </template>
+</dom-module>
+
+<!-- Basic flexbox reverse styles -->
+<dom-module id="iron-flex-reverse">
+ <template>
+ <style>
+ .layout.horizontal-reverse,
+ .layout.vertical-reverse {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ .layout.horizontal-reverse {
+ -ms-flex-direction: row-reverse;
+ -webkit-flex-direction: row-reverse;
+ flex-direction: row-reverse;
+ }
+
+ .layout.vertical-reverse {
+ -ms-flex-direction: column-reverse;
+ -webkit-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ }
+
+ .layout.wrap-reverse {
+ -ms-flex-wrap: wrap-reverse;
+ -webkit-flex-wrap: wrap-reverse;
+ flex-wrap: wrap-reverse;
+ }
+ </style>
+ </template>
+</dom-module>
+
+<!-- Flexbox alignment -->
+<dom-module id="iron-flex-alignment">
+ <template>
+ <style>
+ /**
+ * Alignment in cross axis.
+ */
+ .layout.start {
+ -ms-flex-align: start;
+ -webkit-align-items: flex-start;
+ align-items: flex-start;
+ }
+
+ .layout.center,
+ .layout.center-center {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ }
+
+ .layout.end {
+ -ms-flex-align: end;
+ -webkit-align-items: flex-end;
+ align-items: flex-end;
+ }
+
+ .layout.baseline {
+ -ms-flex-align: baseline;
+ -webkit-align-items: baseline;
+ align-items: baseline;
+ }
+
+ /**
+ * Alignment in main axis.
+ */
+ .layout.start-justified {
+ -ms-flex-pack: start;
+ -webkit-justify-content: flex-start;
+ justify-content: flex-start;
+ }
+
+ .layout.center-justified,
+ .layout.center-center {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ }
+
+ .layout.end-justified {
+ -ms-flex-pack: end;
+ -webkit-justify-content: flex-end;
+ justify-content: flex-end;
+ }
+
+ .layout.around-justified {
+ -ms-flex-pack: distribute;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ }
+
+ .layout.justified {
+ -ms-flex-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ }
+
+ /**
+ * Self alignment.
+ */
+ .self-start {
+ -ms-align-self: flex-start;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ }
+
+ .self-center {
+ -ms-align-self: center;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+
+ .self-end {
+ -ms-align-self: flex-end;
+ -webkit-align-self: flex-end;
+ align-self: flex-end;
+ }
+
+ .self-stretch {
+ -ms-align-self: stretch;
+ -webkit-align-self: stretch;
+ align-self: stretch;
+ }
+
+ .self-baseline {
+ -ms-align-self: baseline;
+ -webkit-align-self: baseline;
+ align-self: baseline;
+ };
+
+ /**
+ * multi-line alignment in main axis.
+ */
+ .layout.start-aligned {
+ -ms-flex-line-pack: start; /* IE10 */
+ -ms-align-content: flex-start;
+ -webkit-align-content: flex-start;
+ align-content: flex-start;
+ }
+
+ .layout.end-aligned {
+ -ms-flex-line-pack: end; /* IE10 */
+ -ms-align-content: flex-end;
+ -webkit-align-content: flex-end;
+ align-content: flex-end;
+ }
+
+ .layout.center-aligned {
+ -ms-flex-line-pack: center; /* IE10 */
+ -ms-align-content: center;
+ -webkit-align-content: center;
+ align-content: center;
+ }
+
+ .layout.between-aligned {
+ -ms-flex-line-pack: justify; /* IE10 */
+ -ms-align-content: space-between;
+ -webkit-align-content: space-between;
+ align-content: space-between;
+ }
+
+ .layout.around-aligned {
+ -ms-flex-line-pack: distribute; /* IE10 */
+ -ms-align-content: space-around;
+ -webkit-align-content: space-around;
+ align-content: space-around;
+ }
+ </style>
+ </template>
+</dom-module>
+
+<dom-module id="iron-flex-factors">
+ <template>
+ <style>
+ .flex,
+ .flex-1 {
+ -ms-flex: 1 1 0.000000001px;
+ -webkit-flex: 1;
+ flex: 1;
+ -webkit-flex-basis: 0.000000001px;
+ flex-basis: 0.000000001px;
+ }
+
+ .flex-2 {
+ -ms-flex: 2;
+ -webkit-flex: 2;
+ flex: 2;
+ }
+
+ .flex-3 {
+ -ms-flex: 3;
+ -webkit-flex: 3;
+ flex: 3;
+ }
+
+ .flex-4 {
+ -ms-flex: 4;
+ -webkit-flex: 4;
+ flex: 4;
+ }
+
+ .flex-5 {
+ -ms-flex: 5;
+ -webkit-flex: 5;
+ flex: 5;
+ }
+
+ .flex-6 {
+ -ms-flex: 6;
+ -webkit-flex: 6;
+ flex: 6;
+ }
+
+ .flex-7 {
+ -ms-flex: 7;
+ -webkit-flex: 7;
+ flex: 7;
+ }
+
+ .flex-8 {
+ -ms-flex: 8;
+ -webkit-flex: 8;
+ flex: 8;
+ }
+
+ .flex-9 {
+ -ms-flex: 9;
+ -webkit-flex: 9;
+ flex: 9;
+ }
+
+ .flex-10 {
+ -ms-flex: 10;
+ -webkit-flex: 10;
+ flex: 10;
+ }
+
+ .flex-11 {
+ -ms-flex: 11;
+ -webkit-flex: 11;
+ flex: 11;
+ }
+
+ .flex-12 {
+ -ms-flex: 12;
+ -webkit-flex: 12;
+ flex: 12;
+ }
+ </style>
+ </template>
+</dom-module>
+
+<!-- Non-flexbox positioning helper styles -->
+<dom-module id="iron-positioning">
+ <template>
+ <style>
+ .block {
+ display: block;
+ }
+
+ /* IE 10 support for HTML5 hidden attr */
+ [hidden] {
+ display: none !important;
+ }
+
+ .invisible {
+ visibility: hidden !important;
+ }
+
+ .relative {
+ position: relative;
+ }
+
+ .fit {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ body.fullbleed {
+ margin: 0;
+ height: 100vh;
+ }
+
+ .scroll {
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ }
+
+ /* fixed position */
+ .fixed-bottom,
+ .fixed-left,
+ .fixed-right,
+ .fixed-top {
+ position: fixed;
+ }
+
+ .fixed-top {
+ top: 0;
+ left: 0;
+ right: 0;
+ }
+
+ .fixed-right {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ }
+
+ .fixed-bottom {
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ .fixed-left {
+ top: 0;
+ bottom: 0;
+ left: 0;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout.html b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout.html
new file mode 100644
index 00000000000..d98e9d0fddf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-flex-layout/iron-flex-layout.html
@@ -0,0 +1,399 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!--
+The `<iron-flex-layout>` component provides simple ways to use
+[CSS flexible box layout](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes),
+also known as flexbox. This component provides two different ways to use flexbox:
+
+1. [Layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+The layout class stylesheet provides a simple set of class-based flexbox rules, that
+let you specify layout properties directly in markup. You must include this file
+in every element that needs to use them.
+
+ Sample use:
+
+ <link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
+ <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
+
+ <div class="layout horizontal layout-start">
+ <div>cross axis start alignment</div>
+ </div>
+
+2. [Custom CSS mixins](https://github.com/PolymerElements/iron-flex-layout/blob/master/iron-flex-layout.html).
+The mixin stylesheet includes custom CSS mixins that can be applied inside a CSS rule using the `@apply` function.
+
+Please note that the old [/deep/ layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/classes)
+are deprecated, and should not be used. To continue using layout properties
+directly in markup, please switch to using the new `dom-module`-based
+[layout classes](https://github.com/PolymerElements/iron-flex-layout/tree/master/iron-flex-layout-classes.html).
+Please note that the new version does not use `/deep/`, and therefore requires you
+to import the `dom-modules` in every element that needs to use them.
+
+A complete [guide](https://elements.polymer-project.org/guides/flex-layout) to `<iron-flex-layout>` is available.
+
+@group Iron Elements
+@pseudoElement iron-flex-layout
+@demo demo/index.html
+-->
+
+<style>
+ /* IE 10 support for HTML5 hidden attr */
+ [hidden] {
+ display: none !important;
+ }
+</style>
+
+<style is="custom-style">
+ :root {
+
+ --layout: {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ };
+
+ --layout-inline: {
+ display: -ms-inline-flexbox;
+ display: -webkit-inline-flex;
+ display: inline-flex;
+ };
+
+ --layout-horizontal: {
+ @apply(--layout);
+
+ -ms-flex-direction: row;
+ -webkit-flex-direction: row;
+ flex-direction: row;
+ };
+
+ --layout-horizontal-reverse: {
+ @apply(--layout);
+
+ -ms-flex-direction: row-reverse;
+ -webkit-flex-direction: row-reverse;
+ flex-direction: row-reverse;
+ };
+
+ --layout-vertical: {
+ @apply(--layout);
+
+ -ms-flex-direction: column;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ };
+
+ --layout-vertical-reverse: {
+ @apply(--layout);
+
+ -ms-flex-direction: column-reverse;
+ -webkit-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ };
+
+ --layout-wrap: {
+ -ms-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ flex-wrap: wrap;
+ };
+
+ --layout-wrap-reverse: {
+ -ms-flex-wrap: wrap-reverse;
+ -webkit-flex-wrap: wrap-reverse;
+ flex-wrap: wrap-reverse;
+ };
+
+ --layout-flex-auto: {
+ -ms-flex: 1 1 auto;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ };
+
+ --layout-flex-none: {
+ -ms-flex: none;
+ -webkit-flex: none;
+ flex: none;
+ };
+
+ --layout-flex: {
+ -ms-flex: 1 1 0.000000001px;
+ -webkit-flex: 1;
+ flex: 1;
+ -webkit-flex-basis: 0.000000001px;
+ flex-basis: 0.000000001px;
+ };
+
+ --layout-flex-2: {
+ -ms-flex: 2;
+ -webkit-flex: 2;
+ flex: 2;
+ };
+
+ --layout-flex-3: {
+ -ms-flex: 3;
+ -webkit-flex: 3;
+ flex: 3;
+ };
+
+ --layout-flex-4: {
+ -ms-flex: 4;
+ -webkit-flex: 4;
+ flex: 4;
+ };
+
+ --layout-flex-5: {
+ -ms-flex: 5;
+ -webkit-flex: 5;
+ flex: 5;
+ };
+
+ --layout-flex-6: {
+ -ms-flex: 6;
+ -webkit-flex: 6;
+ flex: 6;
+ };
+
+ --layout-flex-7: {
+ -ms-flex: 7;
+ -webkit-flex: 7;
+ flex: 7;
+ };
+
+ --layout-flex-8: {
+ -ms-flex: 8;
+ -webkit-flex: 8;
+ flex: 8;
+ };
+
+ --layout-flex-9: {
+ -ms-flex: 9;
+ -webkit-flex: 9;
+ flex: 9;
+ };
+
+ --layout-flex-10: {
+ -ms-flex: 10;
+ -webkit-flex: 10;
+ flex: 10;
+ };
+
+ --layout-flex-11: {
+ -ms-flex: 11;
+ -webkit-flex: 11;
+ flex: 11;
+ };
+
+ --layout-flex-12: {
+ -ms-flex: 12;
+ -webkit-flex: 12;
+ flex: 12;
+ };
+
+ /* alignment in cross axis */
+
+ --layout-start: {
+ -ms-flex-align: start;
+ -webkit-align-items: flex-start;
+ align-items: flex-start;
+ };
+
+ --layout-center: {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ };
+
+ --layout-end: {
+ -ms-flex-align: end;
+ -webkit-align-items: flex-end;
+ align-items: flex-end;
+ };
+
+ --layout-baseline: {
+ -ms-flex-align: baseline;
+ -webkit-align-items: baseline;
+ align-items: baseline;
+ };
+
+ /* alignment in main axis */
+
+ --layout-start-justified: {
+ -ms-flex-pack: start;
+ -webkit-justify-content: flex-start;
+ justify-content: flex-start;
+ };
+
+ --layout-center-justified: {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ };
+
+ --layout-end-justified: {
+ -ms-flex-pack: end;
+ -webkit-justify-content: flex-end;
+ justify-content: flex-end;
+ };
+
+ --layout-around-justified: {
+ -ms-flex-pack: distribute;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ };
+
+ --layout-justified: {
+ -ms-flex-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ };
+
+ --layout-center-center: {
+ @apply(--layout-center);
+ @apply(--layout-center-justified);
+ };
+
+ /* self alignment */
+
+ --layout-self-start: {
+ -ms-align-self: flex-start;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ };
+
+ --layout-self-center: {
+ -ms-align-self: center;
+ -webkit-align-self: center;
+ align-self: center;
+ };
+
+ --layout-self-end: {
+ -ms-align-self: flex-end;
+ -webkit-align-self: flex-end;
+ align-self: flex-end;
+ };
+
+ --layout-self-stretch: {
+ -ms-align-self: stretch;
+ -webkit-align-self: stretch;
+ align-self: stretch;
+ };
+
+ --layout-self-baseline: {
+ -ms-align-self: baseline;
+ -webkit-align-self: baseline;
+ align-self: baseline;
+ };
+
+ /* multi-line alignment in main axis */
+
+ --layout-start-aligned: {
+ -ms-flex-line-pack: start; /* IE10 */
+ -ms-align-content: flex-start;
+ -webkit-align-content: flex-start;
+ align-content: flex-start;
+ };
+
+ --layout-end-aligned: {
+ -ms-flex-line-pack: end; /* IE10 */
+ -ms-align-content: flex-end;
+ -webkit-align-content: flex-end;
+ align-content: flex-end;
+ };
+
+ --layout-center-aligned: {
+ -ms-flex-line-pack: center; /* IE10 */
+ -ms-align-content: center;
+ -webkit-align-content: center;
+ align-content: center;
+ };
+
+ --layout-between-aligned: {
+ -ms-flex-line-pack: justify; /* IE10 */
+ -ms-align-content: space-between;
+ -webkit-align-content: space-between;
+ align-content: space-between;
+ };
+
+ --layout-around-aligned: {
+ -ms-flex-line-pack: distribute; /* IE10 */
+ -ms-align-content: space-around;
+ -webkit-align-content: space-around;
+ align-content: space-around;
+ };
+
+ /*******************************
+ Other Layout
+ *******************************/
+
+ --layout-block: {
+ display: block;
+ };
+
+ --layout-invisible: {
+ visibility: hidden !important;
+ };
+
+ --layout-relative: {
+ position: relative;
+ };
+
+ --layout-fit: {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ };
+
+ --layout-scroll: {
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ };
+
+ --layout-fullbleed: {
+ margin: 0;
+ height: 100vh;
+ };
+
+ /* fixed position */
+
+ --layout-fixed-top: {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ };
+
+ --layout-fixed-right: {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ };
+
+ --layout-fixed-bottom: {
+ position: fixed;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ };
+
+ --layout-fixed-left: {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ };
+
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.bower.json
new file mode 100644
index 00000000000..e09f62a1606
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "iron-form-element-behavior",
+ "version": "1.0.6",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "private": true,
+ "main": "iron-form-element-behavior.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "description": "Enables a custom element to be included in an iron-form",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "form"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-form-element-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "polymer/web-component-tester#^3.4.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-form-element-behavior",
+ "_release": "1.0.6",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.6",
+ "commit": "cf9e09ded62daf3363852ce98260aaad1ed0fae1"
+ },
+ "_source": "git://github.com/PolymerElements/iron-form-element-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-form-element-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.travis.yml
new file mode 100644
index 00000000000..6d4a6216ae0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/.travis.yml
@@ -0,0 +1,22 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install web-component-tester
+ - npm install bower
+ - 'export PATH=$PWD/node_modules/.bin:$PATH'
+ - bower install
+env:
+ global:
+ - secure: EN5HtbAeaCE1IzGk5JlSq7GWcANh/zYgbpZn1y0VocfkZfzOv8cIh8Zmr4Q6shII6K07Fyx1LQuAjsURqX9mc3AmfMHgPIbpZGpOKrjvt1Vf0bPN+uIC9vIFj3sLQj12gcfJg48EXk6HWsHscCZ3+am1xvRflhNEY3TjHPrUTgkF+KLbBEfb4mCZwVc4dln76ffvTQ/cPI9eYczNp1q9wWpYvn794qRLtAkKuQ5Z1b6hunOAx/hzCjGNbJDO3gkxO68dzzSp9YDIhKEFAUlMDalwLRr7sNgB4sNeDCg4mmie5fe6xk831HvBYFxZxmXD1uS6/Hvd8MiBDiols3lwz8uEUnPyrwDlxUkjn2sl5S+gO8CcHU2mShUCl73JfBtyWDKPSfQLR5QHEk4eqNzNn2HinAE/aezi4/TVCY7P3ujeK8sFlTsb9vlywnlJO3fqyZ+lBwZ4CbNjOTs1L2W+guT1Oq30PJ5TVxU2mvmIMtdpPveZB0iM/PM9FECsb303KeV5Zomk4dp2MxirK1O/4mPAHIz9UUpGopGOtpuODnRV4Lq7V9HaDxYOZzAHZDK4mJ1y6tSRH/yMUTEidhG2j5F6MXmhbKXj3I0oR95xx1RH+b8myErvUBlto4jR21Pd+mOVlkU78CBSN9XGhtBQjklF5+aC8YeH1DEv6mTn2o8=
+ - secure: q3AjjaoaTZcdAdjIvzSf8Q1SdEg1mY6lBkeoDTMKJcftJ8zz1qIfjGzEuycSVVnOJhZ6WmvMMBxdThQCymF1wzT++SV+u34DYSFoZ5EhjM0TFhP63PRuhbE3DquPaISpM5aCH7epV4nMFD7PFE1BP4u/qiETAgPeAoY9LMT/JPclOfcQ3euwks3TSM6O8g7Ro1h1ElywCQ1souzkcjvJ3FxsqysJb7Mg/n9bmtwnkol/mrBaP6JzQMURUyswx7ZPj3qiFoA9ZLiNirzf+O781A4msKursjYrKr6TZtB6xcMlEg89YhFBXrLE9IEEM/fNp+vPNhaIA5VjYRy8iIK402RXpbh7/AlPD7yMFITeMSfT+Bqldur+pi0oN1N9SeWrmk6P+bdfdkdyGl1CVKP4S35z8cyFRgmvxO4/UG65cb66AdMeNVBEQsi2flCWgPyaTmOQ53YryCs7cFRu3zSMnU3F/gWqlmletgxGhFOBHTtEmr2A9QBLgg+EvB/83wj2dEEfMlIpoeq83/2PaE8hKAWyqPga7t532vU5AIFNOUk9vGzRCxsqGKF2j0/zFBdgHSLYCsWVrbjxmxdu6Fzi8ZATeqjDoc0eaIPhBkekOvDrUtUSHA9sSSG8j69GGUL4+WkoCMB74dz+GXz85fMJlMZWBXPtazDlNXYfU60T/1E=
+node_js: 4
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/README.md
new file mode 100644
index 00000000000..b68d08fb068
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/README.md
@@ -0,0 +1,23 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-form-element-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-form-element-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-form-element-behavior)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-form-element-behavior)_
+
+
+##Polymer.IronFormElementBehavior
+
+
+ Polymer.IronFormElementBehavior enables a custom element to be included
+ in an `iron-form`.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/bower.json
new file mode 100644
index 00000000000..865f9b549c0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "iron-form-element-behavior",
+ "version": "1.0.6",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "private": true,
+ "main": "iron-form-element-behavior.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "description": "Enables a custom element to be included in an iron-form",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "form"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-form-element-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "polymer/web-component-tester#^3.4.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/index.html
new file mode 100644
index 00000000000..e919d0bcca5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/index.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <title>iron-form-element-behavior demo</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="simple-form.html">
+ <link rel="import" href="simple-element.html">
+ </head>
+ <style>
+ input {
+ margin-bottom: 24px;
+ width: 200px;
+ }
+ </style>
+ <body>
+
+ <div class="vertical-section-container centered">
+ <div class="vertical-section">
+ <form is="simple-form" id="form">
+ Element with iron-form-element-behavior <input is="simple-element" type="text" name="one" value="one">
+ <br>
+ Element without iron-form-element-behavior <input type="text" name="two" value="two">
+ <br>
+ Element with iron-form-element-behavior <input is="simple-element" type="text" name="three" value="three">
+ </form>
+
+ <h4>Elements tracked by the form: <button onclick="update()">Update</button> </h4>
+
+ <ul id="output">
+ </ul>
+ </div>
+ </div>
+
+ <script>
+ function update() {
+ var output = document.getElementById('output');
+ var elements = document.getElementById('form').formElements;
+ document.getElementById('output').innerHTML = '';
+ for (var i = 0; i < elements.length; i++) {
+ var li = document.createElement('li');
+ var text = document.createTextNode(elements[i].value);
+ li.appendChild(text);
+ output.appendChild(li);
+ }
+ }
+ </script>
+ </body>
+
+
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-element.html b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-element.html
new file mode 100644
index 00000000000..450276923b3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-element.html
@@ -0,0 +1,27 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-form-element-behavior.html">
+
+<script>
+
+ Polymer({
+
+ is: 'simple-element',
+
+ extends: 'input',
+
+ behaviors: [
+ Polymer.IronFormElementBehavior
+ ]
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-form.html b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-form.html
new file mode 100644
index 00000000000..4dc5dc6bb8f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/demo/simple-form.html
@@ -0,0 +1,53 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+
+<script>
+
+ Polymer({
+
+ is: 'simple-form',
+
+ extends: 'form',
+
+ properties: {
+ formElements: {
+ type: Object,
+ notify: true
+ }
+ },
+
+ listeners: {
+ 'iron-form-element-register': '_elementRegistered',
+ 'iron-form-element-unregister': '_elementUnregistered'
+ },
+
+ ready: function() {
+ this.formElements = [];
+ },
+
+ _elementRegistered: function(e) {
+ this.formElements.push(e.target);
+ e.target._parentForm = this;
+ },
+
+ _elementUnregistered: function(e) {
+ var target = e.detail.target;
+ if (target) {
+ var index = this.formElements.indexOf(target);
+ if (index > -1) {
+ this.formElements.splice(index, 1);
+ }
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/index.html
new file mode 100644
index 00000000000..8d748c0509b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-form-element-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/iron-form-element-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/iron-form-element-behavior.html
new file mode 100644
index 00000000000..cd9c6b4ab66
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-form-element-behavior/iron-form-element-behavior.html
@@ -0,0 +1,86 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+ /**
+ Polymer.IronFormElementBehavior enables a custom element to be included
+ in an `iron-form`.
+
+ @demo demo/index.html
+ @polymerBehavior
+ */
+ Polymer.IronFormElementBehavior = {
+
+ properties: {
+ /**
+ * Fired when the element is added to an `iron-form`.
+ *
+ * @event iron-form-element-register
+ */
+
+ /**
+ * Fired when the element is removed from an `iron-form`.
+ *
+ * @event iron-form-element-unregister
+ */
+
+ /**
+ * The name of this element.
+ */
+ name: {
+ type: String
+ },
+
+ /**
+ * The value for this element.
+ */
+ value: {
+ notify: true,
+ type: String
+ },
+
+ /**
+ * Set to true to mark the input as required. If used in a form, a
+ * custom element that uses this behavior should also use
+ * Polymer.IronValidatableBehavior and define a custom validation method.
+ * Otherwise, a `required` element will always be considered valid.
+ * It's also strongly recommended to provide a visual style for the element
+ * when its value is invalid.
+ */
+ required: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The form that the element is registered to.
+ */
+ _parentForm: {
+ type: Object
+ }
+ },
+
+ attached: function() {
+ // Note: the iron-form that this element belongs to will set this
+ // element's _parentForm property when handling this event.
+ this.fire('iron-form-element-register');
+ },
+
+ detached: function() {
+ if (this._parentForm) {
+ this._parentForm.fire('iron-form-element-unregister', {target: this});
+ }
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.bower.json
new file mode 100644
index 00000000000..9784e3a3b78
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.bower.json
@@ -0,0 +1,45 @@
+{
+ "name": "iron-icon",
+ "private": true,
+ "version": "1.0.8",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "An element that supports displaying an icon",
+ "main": "iron-icon.html",
+ "author": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-icon.git"
+ },
+ "ignore": [],
+ "dependencies": {
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "promise-polyfill": "polymerlabs/promise-polyfill#^1.0.0",
+ "iron-iconset": "polymerelements/iron-iconset#^1.0.0",
+ "iron-icons": "polymerelements/iron-icons#^1.0.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "homepage": "https://github.com/PolymerElements/iron-icon",
+ "_release": "1.0.8",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.8",
+ "commit": "f36b38928849ef3853db727faa8c9ef104d611eb"
+ },
+ "_source": "git://github.com/PolymerElements/iron-icon.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-icon"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.travis.yml
new file mode 100644
index 00000000000..982392253e0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: Cyo7MV8FASyf2EZyrSmDbmoZmopQhuTbV79Ntl6eDq6JxEOAApULHn6W+ht0tvmaA+L2cRNq3Z4uvy3tbZCI5SCgQuEKLDJFoghzNp4Izc54bBlJzsxMjcgxEEMbw1jDIKp+PJ+1+8oyT5H1NogcGoNWcvMCjn+8Vl64/999mhw=
+ - secure: dI3wfjJoooFlq6Kb8V1fkbc9N5jrvw7dExN4tp4KlvJFiXIvgb823jEyLGnK/oeVLwP9yncvOYxiG/enNbjpk6fId3zjwptN2H1am3pIsPQASOZJ0Pwvwa1dX7EYGk2kxOwY1pyX4is/QRVDrlUkLm3YAPOFfYJEiVB7m6TNFIo=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/README.md
new file mode 100644
index 00000000000..a08298f6495
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/README.md
@@ -0,0 +1,92 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-icon.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-icon.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-icon)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-icon)_
+
+
+##&lt;iron-icon&gt;
+
+The `iron-icon` element displays an icon. By default an icon renders as a 24px square.
+
+Example using src:
+
+```html
+<iron-icon src="star.png"></iron-icon>
+```
+
+Example setting size to 32px x 32px:
+
+```html
+<iron-icon class="big" src="big_star.png"></iron-icon>
+
+<style is="custom-style">
+ .big {
+ --iron-icon-height: 32px;
+ --iron-icon-width: 32px;
+ }
+</style>
+```
+
+The iron elements include several sets of icons.
+To use the default set of icons, import `iron-icons.html` and use the `icon` attribute to specify an icon:
+
+```html
+<link rel="import" href="/components/iron-icons/iron-icons.html">
+
+<iron-icon icon="menu"></iron-icon>
+```
+
+To use a different built-in set of icons, import the specific `iron-icons/<iconset>-icons.html`, and
+specify the icon as `<iconset>:<icon>`. For example, to use a communication icon, you would
+use:
+
+```html
+<link rel="import" href="/components/iron-icons/communication-icons.html">
+
+<iron-icon icon="communication:email"></iron-icon>
+```
+
+You can also create custom icon sets of bitmap or SVG icons.
+
+Example of using an icon named `cherry` from a custom iconset with the ID `fruit`:
+
+```html
+<iron-icon icon="fruit:cherry"></iron-icon>
+```
+
+See [iron-iconset](iron-iconset) and [iron-iconset-svg](iron-iconset-svg) for more information about
+how to create a custom iconset.
+
+See the [iron-icons demo](iron-icons?view=demo:demo/index.html) to see the icons available
+in the various iconsets.
+
+To load a subset of icons from one of the default `iron-icons` sets, you can
+use the [poly-icon](https://poly-icon.appspot.com/) tool. It allows you
+to select individual icons, and creates an iconset from them that you can
+use directly in your elements.
+
+### Styling
+
+The following custom properties are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-icon-width` | Width of the icon | `24px` |
+| `--iron-icon-height` | Height of the icon | `24px` |
+| `--iron-icon-fill-color` | Fill color of the svg icon | `currentcolor` |
+| `--iron-icon-stroke-color` | Stroke color of the svg icon | none |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/bower.json
new file mode 100644
index 00000000000..38e4ba45d0a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "iron-icon",
+ "private": true,
+ "version": "1.0.8",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "An element that supports displaying an icon",
+ "main": "iron-icon.html",
+ "author": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-icon.git"
+ },
+ "ignore": [],
+ "dependencies": {
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "promise-polyfill": "polymerlabs/promise-polyfill#^1.0.0",
+ "iron-iconset": "polymerelements/iron-iconset#^1.0.0",
+ "iron-icons": "polymerelements/iron-icons#^1.0.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/async.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/async.html
new file mode 100644
index 00000000000..eaf40d1ba2c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/async.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <title>iron-icon demo</title>
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-icon.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html" >
+
+ <style is="custom-style">
+ #loading_message {
+ color: #444;
+ margin-bottom: 16px;
+ }
+ .vertical-section h4 {
+ border-left: 3px solid var(--paper-grey-300);
+ padding-left: 10px;
+ }
+
+ .vertical-section h4:hover {
+ border-left-color: var(--google-blue-700);
+ }
+ </style>
+</head>
+<body>
+ <div class="vertical-section-container centered">
+ <h4>
+ This demo is for an &lt;iron-icon&gt; with an asynchronously loaded
+ iconset.
+ </h4>
+
+ <div id='loading_message'>Waiting to load iconset...</div>
+
+ <div class="vertical-section">
+ <!-- iron-icon using a iron-iconset as its icon source -->
+ <iron-iconset name="example" icons="location" src="location.png" size="24" width="24"></iron-iconset>
+
+ <h4>&lt;iron-icon icon="example:location"&gt;</h4>
+ <iron-icon icon="example:location"></iron-icon>
+
+ </div>
+ </div>
+ <script>
+ setTimeout(function() {
+ // Import the code that powers the iron-iconset asynchronously
+ var linkElem = document.createElement('link');
+ linkElem.setAttribute('rel', 'import');
+ linkElem.setAttribute('href', '../../iron-iconset/iron-iconset.html');
+ document.head.appendChild(linkElem);
+ document.querySelector('#loading_message').innerText = "Iconset Loaded.";
+ }, 1000);
+ </script>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/index.html
new file mode 100644
index 00000000000..999ed35b484
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <title>iron-icon demo</title>
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-icon.html">
+ <link rel="import" href="../../iron-iconset/iron-iconset.html">
+ <link href="../../paper-styles/demo-pages.html" rel="import">
+
+ <style is="custom-style">
+ .vertical-section h4 {
+ border-left: 3px solid var(--paper-grey-300);
+ padding-left: 10px;
+ }
+
+ .vertical-section h4:hover {
+ border-left-color: var(--google-blue-700);
+ }
+ </style>
+</head>
+<body>
+ <div class="vertical-section-container centered">
+ <h4>This demo is for a single &lt;iron-icon&gt;. If you're looking for the
+ whole set of available icons, check out the <a href="/elements/iron-icons?view=demo:demo/index.html">&lt;iron-icons&gt; demo.</a></h5>
+
+ <div class="vertical-section">
+ <!-- iron-icon using a iron-iconset as its icon source -->
+ <iron-iconset name="example" icons="location" src="location.png" size="24" width="24"></iron-iconset>
+
+ <h4>&lt;iron-icon icon="example:location"&gt;</h4>
+ <iron-icon icon="example:location"></iron-icon>
+
+ <!-- iron-icon using an image url as its icon source -->
+ <h4>&lt;iron-icon src="location.png"&gt;</h4>
+ <iron-icon src="location.png"></iron-icon>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/location.png b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/location.png
new file mode 100644
index 00000000000..9bb74236b85
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/demo/location.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/hero.svg
new file mode 100755
index 00000000000..f0f58536e53
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/hero.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <circle cx="112" cy="61" r="8"/>
+ <path d="M129,78H95V44h34V78z M97,76h30V46H97V76z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/index.html
new file mode 100644
index 00000000000..487bb5c38a5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/index.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icon/iron-icon.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/iron-icon.html
new file mode 100644
index 00000000000..3428062b9db
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icon/iron-icon.html
@@ -0,0 +1,207 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-meta/iron-meta.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+
+<!--
+
+The `iron-icon` element displays an icon. By default an icon renders as a 24px square.
+
+Example using src:
+
+ <iron-icon src="star.png"></iron-icon>
+
+Example setting size to 32px x 32px:
+
+ <iron-icon class="big" src="big_star.png"></iron-icon>
+
+ <style is="custom-style">
+ .big {
+ --iron-icon-height: 32px;
+ --iron-icon-width: 32px;
+ }
+ </style>
+
+The iron elements include several sets of icons.
+To use the default set of icons, import `iron-icons.html` and use the `icon` attribute to specify an icon:
+
+ <link rel="import" href="/components/iron-icons/iron-icons.html">
+
+ <iron-icon icon="menu"></iron-icon>
+
+To use a different built-in set of icons, import the specific `iron-icons/<iconset>-icons.html`, and
+specify the icon as `<iconset>:<icon>`. For example, to use a communication icon, you would
+use:
+
+ <link rel="import" href="/components/iron-icons/communication-icons.html">
+
+ <iron-icon icon="communication:email"></iron-icon>
+
+You can also create custom icon sets of bitmap or SVG icons.
+
+Example of using an icon named `cherry` from a custom iconset with the ID `fruit`:
+
+ <iron-icon icon="fruit:cherry"></iron-icon>
+
+See [iron-iconset](iron-iconset) and [iron-iconset-svg](iron-iconset-svg) for more information about
+how to create a custom iconset.
+
+See the [iron-icons demo](iron-icons?view=demo:demo/index.html) to see the icons available
+in the various iconsets.
+
+To load a subset of icons from one of the default `iron-icons` sets, you can
+use the [poly-icon](https://poly-icon.appspot.com/) tool. It allows you
+to select individual icons, and creates an iconset from them that you can
+use directly in your elements.
+
+### Styling
+
+The following custom properties are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--iron-icon-width` | Width of the icon | `24px`
+`--iron-icon-height` | Height of the icon | `24px`
+`--iron-icon-fill-color` | Fill color of the svg icon | `currentcolor`
+`--iron-icon-stroke-color` | Stroke color of the svg icon | none
+
+@group Iron Elements
+@element iron-icon
+@demo demo/index.html
+@hero hero.svg
+@homepage polymer.github.io
+-->
+
+<dom-module id="iron-icon">
+
+ <style>
+ :host {
+ @apply(--layout-inline);
+ @apply(--layout-center-center);
+ position: relative;
+
+ vertical-align: middle;
+
+ fill: var(--iron-icon-fill-color, currentcolor);
+ stroke: var(--iron-icon-stroke-color, none);
+
+ width: var(--iron-icon-width, 24px);
+ height: var(--iron-icon-height, 24px);
+ }
+ </style>
+
+ <template>
+ </template>
+
+ <script>
+
+ Polymer({
+
+ is: 'iron-icon',
+
+ properties: {
+
+ /**
+ * The name of the icon to use. The name should be of the form:
+ * `iconset_name:icon_name`.
+ */
+ icon: {
+ type: String,
+ observer: '_iconChanged'
+ },
+
+ /**
+ * The name of the theme to used, if one is specified by the
+ * iconset.
+ */
+ theme: {
+ type: String,
+ observer: '_updateIcon'
+ },
+
+ /**
+ * If using iron-icon without an iconset, you can set the src to be
+ * the URL of an individual icon image file. Note that this will take
+ * precedence over a given icon attribute.
+ */
+ src: {
+ type: String,
+ observer: '_srcChanged'
+ },
+
+ /**
+ * @type {!Polymer.IronMeta}
+ */
+ _meta: {
+ value: Polymer.Base.create('iron-meta', {type: 'iconset'}),
+ observer: '_updateIcon'
+ }
+
+ },
+
+ _DEFAULT_ICONSET: 'icons',
+
+ _iconChanged: function(icon) {
+ var parts = (icon || '').split(':');
+ this._iconName = parts.pop();
+ this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
+ this._updateIcon();
+ },
+
+ _srcChanged: function(src) {
+ this._updateIcon();
+ },
+
+ _usesIconset: function() {
+ return this.icon || !this.src;
+ },
+
+ /** @suppress {visibility} */
+ _updateIcon: function() {
+ if (this._usesIconset()) {
+ if (this._img && this._img.parentNode) {
+ Polymer.dom(this.root).removeChild(this._img);
+ }
+ if (this._iconName === "") {
+ if (this._iconset) {
+ this._iconset.removeIcon(this);
+ }
+ } else if (this._iconsetName && this._meta) {
+ this._iconset = /** @type {?Polymer.Iconset} */ (
+ this._meta.byKey(this._iconsetName));
+ if (this._iconset) {
+ this._iconset.applyIcon(this, this._iconName, this.theme);
+ this.unlisten(window, 'iron-iconset-added', '_updateIcon');
+ } else {
+ this.listen(window, 'iron-iconset-added', '_updateIcon');
+ }
+ }
+ } else {
+ if (this._iconset) {
+ this._iconset.removeIcon(this);
+ }
+ if (!this._img) {
+ this._img = document.createElement('img');
+ this._img.style.width = '100%';
+ this._img.style.height = '100%';
+ this._img.draggable = false;
+ }
+ this._img.src = this.src;
+ Polymer.dom(this.root).appendChild(this._img);
+ }
+ }
+
+ });
+
+ </script>
+
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.bower.json
new file mode 100644
index 00000000000..be52e7bfd21
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.bower.json
@@ -0,0 +1,47 @@
+{
+ "name": "iron-icons",
+ "version": "1.1.3",
+ "description": "A set of icons for use with iron-icon",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "main": "iron-icons.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-icons"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-icons",
+ "dependencies": {
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "iron-iconset-svg": "polymerelements/iron-iconset-svg#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "polymerelements/iron-component-page#1.0.0",
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0"
+ },
+ "ignore": [
+ "util",
+ "update-icons.sh"
+ ],
+ "_release": "1.1.3",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.3",
+ "commit": "c13869b57a9464dfc3a1f26e89858f8be37e7441"
+ },
+ "_source": "git://github.com/PolymerElements/iron-icons.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-icons"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.travis.yml
new file mode 100644
index 00000000000..57e6cef9c9e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: itlu3qIX/3ggZQIuzTJc62A5MD2Rdms+zB1EvNEWFiQZQgNGu2+hhp72PcVB/urybOTFmMeq4W12RGr53KMvwj6mwNlXPhQxeP1oyR+icZZVbuLDfj5pF8OvNf4OXEkGv0yH+OTuNTB8CU4msJzgB2W8iuC+pFH/dIas6fQDTfE=
+ - secure: LBT0VumsEPWUYm0OLhqHU1XWmVY18QP64cMeqZAwASnYYyH/R5OGYAcI7aH8To29FWpkZSL85NPto37bN+f8DWRSULq4p+1wl2HviYHsam8x1NzN7hKq6nv+203qaT9SflheaNy6sSDfZJQ+36bRcGQ5khKkVeDpw7h8D/osSQ4=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/README.md
new file mode 100644
index 00000000000..bd11ba7082a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/README.md
@@ -0,0 +1,44 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-icons.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-icons.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-icons)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-icons)_
+
+
+##&lt;iron-icons&gt;
+
+`iron-icons` is a utility import that includes the definition for the `iron-icon` element, `iron-iconset-svg` element, as well as an import for the default icon set.
+
+The `iron-icons` directory also includes imports for additional icon sets that can be loaded into your project.
+
+Example loading icon set:
+
+```html
+<link rel="import" href="../iron-icons/maps-icons.html">
+```
+
+To use an icon from one of these sets, first prefix your `iron-icon` with the icon set name, followed by a colon, ":", and then the icon id.
+
+Example using the directions-bus icon from the maps icon set:
+
+```html
+<iron-icon icon="maps:directions-bus"></iron-icon>
+```
+
+See [iron-icon](#iron-icon) for more information about working with icons.
+
+See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for more information about how to create a custom iconset.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/av-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/av-icons.html
new file mode 100644
index 00000000000..e4a0d245bda
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/av-icons.html
@@ -0,0 +1,88 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="av" size="24">
+<svg><defs>
+<g id="add-to-queue"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-7v2h-3v3h-2v-3H8v-2h3V7h2v3h3z"/></g>
+<g id="airplay"><path d="M6 22h12l-6-6zM21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4v-2H3V5h18v12h-4v2h4c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="album"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></g>
+<g id="art-track"><path d="M22 13h-8v-2h8v2zm0-6h-8v2h8V7zm-8 10h8v-2h-8v2zm-2-8v6c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V9c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2zm-1.5 6l-2.25-3-1.75 2.26-1.25-1.51L3.5 15h7z"/></g>
+<g id="av-timer"><path d="M11 17c0 .55.45 1 1 1s1-.45 1-1-.45-1-1-1-1 .45-1 1zm0-14v4h2V5.08c3.39.49 6 3.39 6 6.92 0 3.87-3.13 7-7 7s-7-3.13-7-7c0-1.68.59-3.22 1.58-4.42L12 13l1.41-1.41-6.8-6.8v.02C4.42 6.45 3 9.05 3 12c0 4.97 4.02 9 9 9 4.97 0 9-4.03 9-9s-4.03-9-9-9h-1zm7 9c0-.55-.45-1-1-1s-1 .45-1 1 .45 1 1 1 1-.45 1-1zM6 12c0 .55.45 1 1 1s1-.45 1-1-.45-1-1-1-1 .45-1 1z"/></g>
+<g id="closed-caption"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1c0 .55-.45 1-1 1H7c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1c0 .55-.45 1-1 1h-3c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1z"/></g>
+<g id="equalizer"><path d="M10 20h4V4h-4v16zm-6 0h4v-8H4v8zM16 9v11h4V9h-4z"/></g>
+<g id="explicit"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 6h-4v2h4v2h-4v2h4v2H9V7h6v2z"/></g>
+<g id="fast-forward"><path d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></g>
+<g id="fast-rewind"><path d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></g>
+<g id="fiber-dvr"><path d="M17.5 10.5h2v1h-2zm-13 0h2v3h-2zM21 3H3c-1.11 0-2 .89-2 2v14c0 1.1.89 2 2 2h18c1.11 0 2-.9 2-2V5c0-1.11-.89-2-2-2zM8 13.5c0 .85-.65 1.5-1.5 1.5H3V9h3.5c.85 0 1.5.65 1.5 1.5v3zm4.62 1.5h-1.5L9.37 9h1.5l1 3.43 1-3.43h1.5l-1.75 6zM21 11.5c0 .6-.4 1.15-.9 1.4L21 15h-1.5l-.85-2H17.5v2H16V9h3.5c.85 0 1.5.65 1.5 1.5v1z"/></g>
+<g id="fiber-manual-record"><circle cx="12" cy="12" r="8"/></g>
+<g id="fiber-new"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zM8.5 15H7.3l-2.55-3.5V15H3.5V9h1.25l2.5 3.5V9H8.5v6zm5-4.74H11v1.12h2.5v1.26H11v1.11h2.5V15h-4V9h4v1.26zm7 3.74c0 .55-.45 1-1 1h-4c-.55 0-1-.45-1-1V9h1.25v4.51h1.13V9.99h1.25v3.51h1.12V9h1.25v5z"/></g>
+<g id="fiber-pin"><path d="M5.5 10.5h2v1h-2zM20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zM9 11.5c0 .85-.65 1.5-1.5 1.5h-2v2H4V9h3.5c.85 0 1.5.65 1.5 1.5v1zm3.5 3.5H11V9h1.5v6zm7.5 0h-1.2l-2.55-3.5V15H15V9h1.25l2.5 3.5V9H20v6z"/></g>
+<g id="fiber-smart-record"><g><circle cx="9" cy="12" r="8"/><path d="M17 4.26v2.09c2.33.82 4 3.04 4 5.65s-1.67 4.83-4 5.65v2.09c3.45-.89 6-4.01 6-7.74s-2.55-6.85-6-7.74z"/></g></g>
+<g id="forward-10"><path d="M4 13c0 4.4 3.6 8 8 8s8-3.6 8-8h-2c0 3.3-2.7 6-6 6s-6-2.7-6-6 2.7-6 6-6v4l5-5-5-5v4c-4.4 0-8 3.6-8 8zm6.8 3H10v-3.3L9 13v-.7l1.8-.6h.1V16zm4.3-1.8c0 .3 0 .6-.1.8l-.3.6s-.3.3-.5.3-.4.1-.6.1-.4 0-.6-.1-.3-.2-.5-.3-.2-.3-.3-.6-.1-.5-.1-.8v-.7c0-.3 0-.6.1-.8l.3-.6s.3-.3.5-.3.4-.1.6-.1.4 0 .6.1.3.2.5.3.2.3.3.6.1.5.1.8v.7zm-.8-.8v-.5s-.1-.2-.1-.3-.1-.1-.2-.2-.2-.1-.3-.1-.2 0-.3.1l-.2.2s-.1.2-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3-.1l.2-.2s.1-.2.1-.3v-1.5z"/></g>
+<g id="forward-30"><path d="M9.6 13.5h.4c.2 0 .4-.1.5-.2s.2-.2.2-.4v-.2s-.1-.1-.1-.2-.1-.1-.2-.1h-.5s-.1.1-.2.1-.1.1-.1.2v.2h-1c0-.2 0-.3.1-.5s.2-.3.3-.4.3-.2.4-.2.4-.1.5-.1c.2 0 .4 0 .6.1s.3.1.5.2.2.2.3.4.1.3.1.5v.3s-.1.2-.1.3-.1.2-.2.2-.2.1-.3.2c.2.1.4.2.5.4s.2.4.2.6c0 .2 0 .4-.1.5s-.2.3-.3.4-.3.2-.5.2-.4.1-.6.1c-.2 0-.4 0-.5-.1s-.3-.1-.5-.2-.2-.2-.3-.4-.1-.4-.1-.6h.8v.2s.1.1.1.2.1.1.2.1h.5s.1-.1.2-.1.1-.1.1-.2v-.5s-.1-.1-.1-.2-.1-.1-.2-.1h-.6v-.7zm5.7.7c0 .3 0 .6-.1.8l-.3.6s-.3.3-.5.3-.4.1-.6.1-.4 0-.6-.1-.3-.2-.5-.3-.2-.3-.3-.6-.1-.5-.1-.8v-.7c0-.3 0-.6.1-.8l.3-.6s.3-.3.5-.3.4-.1.6-.1.4 0 .6.1.3.2.5.3.2.3.3.6.1.5.1.8v.7zm-.9-.8v-.5s-.1-.2-.1-.3-.1-.1-.2-.2-.2-.1-.3-.1-.2 0-.3.1l-.2.2s-.1.2-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3-.1l.2-.2s.1-.2.1-.3v-1.5zM4 13c0 4.4 3.6 8 8 8s8-3.6 8-8h-2c0 3.3-2.7 6-6 6s-6-2.7-6-6 2.7-6 6-6v4l5-5-5-5v4c-4.4 0-8 3.6-8 8z"/></g>
+<g id="forward-5"><path d="M4 13c0 4.4 3.6 8 8 8s8-3.6 8-8h-2c0 3.3-2.7 6-6 6s-6-2.7-6-6 2.7-6 6-6v4l5-5-5-5v4c-4.4 0-8 3.6-8 8zm6.7.9l.2-2.2h2.4v.7h-1.7l-.1.9s.1 0 .1-.1.1 0 .1-.1.1 0 .2 0h.2c.2 0 .4 0 .5.1s.3.2.4.3.2.3.3.5.1.4.1.6c0 .2 0 .4-.1.5s-.1.3-.3.5-.3.2-.5.3-.4.1-.6.1c-.2 0-.4 0-.5-.1s-.3-.1-.5-.2-.2-.2-.3-.4-.1-.3-.1-.5h.8c0 .2.1.3.2.4s.2.1.4.1c.1 0 .2 0 .3-.1l.2-.2s.1-.2.1-.3v-.6l-.1-.2-.2-.2s-.2-.1-.3-.1h-.2s-.1 0-.2.1-.1 0-.1.1-.1.1-.1.1h-.6z"/></g>
+<g id="games"><path d="M15 7.5V2H9v5.5l3 3 3-3zM7.5 9H2v6h5.5l3-3-3-3zM9 16.5V22h6v-5.5l-3-3-3 3zM16.5 9l-3 3 3 3H22V9h-5.5z"/></g>
+<g id="hd"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm2-6h4c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1h-4V9zm1.5 4.5h2v-3h-2v3z"/></g>
+<g id="hearing"><path d="M17 20c-.29 0-.56-.06-.76-.15-.71-.37-1.21-.88-1.71-2.38-.51-1.56-1.47-2.29-2.39-3-.79-.61-1.61-1.24-2.32-2.53C9.29 10.98 9 9.93 9 9c0-2.8 2.2-5 5-5s5 2.2 5 5h2c0-3.93-3.07-7-7-7S7 5.07 7 9c0 1.26.38 2.65 1.07 3.9.91 1.65 1.98 2.48 2.85 3.15.81.62 1.39 1.07 1.71 2.05.6 1.82 1.37 2.84 2.73 3.55.51.23 1.07.35 1.64.35 2.21 0 4-1.79 4-4h-2c0 1.1-.9 2-2 2zM7.64 2.64L6.22 1.22C4.23 3.21 3 5.96 3 9s1.23 5.79 3.22 7.78l1.41-1.41C6.01 13.74 5 11.49 5 9s1.01-4.74 2.64-6.36zM11.5 9c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5-2.5 1.12-2.5 2.5z"/></g>
+<g id="high-quality"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 11H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/></g>
+<g id="library-add"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z"/></g>
+<g id="library-books"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/></g>
+<g id="library-music"><path d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 5h-3v5.5c0 1.38-1.12 2.5-2.5 2.5S10 13.88 10 12.5s1.12-2.5 2.5-2.5c.57 0 1.08.19 1.5.51V5h4v2zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z"/></g>
+<g id="loop"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></g>
+<g id="mic"><path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/></g>
+<g id="mic-none"><path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1.2-9.1c0-.66.54-1.2 1.2-1.2.66 0 1.2.54 1.2 1.2l-.01 6.2c0 .66-.53 1.2-1.19 1.2-.66 0-1.2-.54-1.2-1.2V4.9zm6.5 6.1c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/></g>
+<g id="mic-off"><path d="M19 11h-1.7c0 .74-.16 1.43-.43 2.05l1.23 1.23c.56-.98.9-2.09.9-3.28zm-4.02.17c0-.06.02-.11.02-.17V5c0-1.66-1.34-3-3-3S9 3.34 9 5v.18l5.98 5.99zM4.27 3L3 4.27l6.01 6.01V11c0 1.66 1.33 3 2.99 3 .22 0 .44-.03.65-.08l1.66 1.66c-.71.33-1.5.52-2.31.52-2.76 0-5.3-2.1-5.3-5.1H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c.91-.13 1.77-.45 2.54-.9L19.73 21 21 19.73 4.27 3z"/></g>
+<g id="movie"><path d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4h-4z"/></g>
+<g id="music-video"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14zM8 15c0-1.66 1.34-3 3-3 .35 0 .69.07 1 .18V6h5v2h-3v7.03c-.02 1.64-1.35 2.97-3 2.97-1.66 0-3-1.34-3-3z"/></g>
+<g id="new-releases"><path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12zm-10 5h-2v-2h2v2zm0-4h-2V7h2v6z"/></g>
+<g id="not-interested"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31C15.55 19.37 13.85 20 12 20zm6.31-3.1L7.1 5.69C8.45 4.63 10.15 4 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9z"/></g>
+<g id="pause"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></g>
+<g id="pause-circle-filled"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/></g>
+<g id="pause-circle-outline"><path d="M9 16h2V8H9v8zm3-14C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm1-4h2V8h-2v8z"/></g>
+<g id="play-arrow"><path d="M8 5v14l11-7z"/></g>
+<g id="play-circle-filled"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/></g>
+<g id="play-circle-outline"><path d="M10 16.5l6-4.5-6-4.5v9zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="playlist-add"><path d="M14 10H2v2h12v-2zm0-4H2v2h12V6zm4 8v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2 16h8v-2H2v2z"/></g>
+<g id="playlist-add-check"><path d="M14 10H2v2h12v-2zm0-4H2v2h12V6zM2 16h8v-2H2v2zm19.5-4.5L23 13l-6.99 7-4.51-4.5L13 14l3.01 3 5.49-5.5z"/></g>
+<g id="playlist-play"><path d="M19 9H2v2h17V9zm0-4H2v2h17V5zM2 15h13v-2H2v2zm15-2v6l5-3-5-3z"/></g>
+<g id="queue"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z"/></g>
+<g id="queue-music"><path d="M15 6H3v2h12V6zm0 4H3v2h12v-2zM3 16h8v-2H3v2zM17 6v8.18c-.31-.11-.65-.18-1-.18-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3V8h3V6h-5z"/></g>
+<g id="queue-play-next"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h2v-2H3V5h18v8h2V5c0-1.11-.9-2-2-2zm-8 7V7h-2v3H8v2h3v3h2v-3h3v-2h-3zm11 8l-4.5 4.5L18 21l3-3-3-3 1.5-1.5L24 18z"/></g>
+<g id="radio"><path d="M3.24 6.15C2.51 6.43 2 7.17 2 8v12c0 1.1.89 2 2 2h16c1.11 0 2-.9 2-2V8c0-1.11-.89-2-2-2H8.3l8.26-3.34L15.88 1 3.24 6.15zM7 20c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-8h-2v-2h-2v2H4V8h16v4z"/></g>
+<g id="recent-actors"><path d="M21 5v14h2V5h-2zm-4 14h2V5h-2v14zM14 5H2c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zM8 7.75c1.24 0 2.25 1.01 2.25 2.25S9.24 12.25 8 12.25 5.75 11.24 5.75 10 6.76 7.75 8 7.75zM12.5 17h-9v-.75c0-1.5 3-2.25 4.5-2.25s4.5.75 4.5 2.25V17z"/></g>
+<g id="remove-from-queue"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-7v2H8v-2h8z"/></g>
+<g id="repeat"><path d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z"/></g>
+<g id="repeat-one"><path d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4zm-4-2V9h-1l-2 1v1h1.5v4H13z"/></g>
+<g id="replay"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></g>
+<g id="replay-10"><path d="M12 5V1L7 6l5 5V7c3.3 0 6 2.7 6 6s-2.7 6-6 6-6-2.7-6-6H4c0 4.4 3.6 8 8 8s8-3.6 8-8-3.6-8-8-8zm-1.1 11H10v-3.3L9 13v-.7l1.8-.6h.1V16zm4.3-1.8c0 .3 0 .6-.1.8l-.3.6s-.3.3-.5.3-.4.1-.6.1-.4 0-.6-.1-.3-.2-.5-.3-.2-.3-.3-.6-.1-.5-.1-.8v-.7c0-.3 0-.6.1-.8l.3-.6s.3-.3.5-.3.4-.1.6-.1.4 0 .6.1c.2.1.3.2.5.3s.2.3.3.6.1.5.1.8v.7zm-.9-.8v-.5s-.1-.2-.1-.3-.1-.1-.2-.2-.2-.1-.3-.1-.2 0-.3.1l-.2.2s-.1.2-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3-.1l.2-.2s.1-.2.1-.3v-1.5z"/></g>
+<g id="replay-30"><path d="M12 5V1L7 6l5 5V7c3.3 0 6 2.7 6 6s-2.7 6-6 6-6-2.7-6-6H4c0 4.4 3.6 8 8 8s8-3.6 8-8-3.6-8-8-8zm-2.4 8.5h.4c.2 0 .4-.1.5-.2s.2-.2.2-.4v-.2s-.1-.1-.1-.2-.1-.1-.2-.1h-.5s-.1.1-.2.1-.1.1-.1.2v.2h-1c0-.2 0-.3.1-.5s.2-.3.3-.4.3-.2.4-.2.4-.1.5-.1c.2 0 .4 0 .6.1s.3.1.5.2.2.2.3.4.1.3.1.5v.3s-.1.2-.1.3-.1.2-.2.2-.2.1-.3.2c.2.1.4.2.5.4s.2.4.2.6c0 .2 0 .4-.1.5s-.2.3-.3.4-.3.2-.5.2-.4.1-.6.1c-.2 0-.4 0-.5-.1s-.3-.1-.5-.2-.2-.2-.3-.4-.1-.4-.1-.6h.8v.2s.1.1.1.2.1.1.2.1h.5s.1-.1.2-.1.1-.1.1-.2v-.5s-.1-.1-.1-.2-.1-.1-.2-.1h-.6v-.7zm5.7.7c0 .3 0 .6-.1.8l-.3.6s-.3.3-.5.3-.4.1-.6.1-.4 0-.6-.1-.3-.2-.5-.3-.2-.3-.3-.6-.1-.5-.1-.8v-.7c0-.3 0-.6.1-.8l.3-.6s.3-.3.5-.3.4-.1.6-.1.4 0 .6.1.3.2.5.3.2.3.3.6.1.5.1.8v.7zm-.8-.8v-.5c0-.1-.1-.2-.1-.3s-.1-.1-.2-.2-.2-.1-.3-.1-.2 0-.3.1l-.2.2s-.1.2-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3-.1l.2-.2s.1-.2.1-.3v-1.5z"/></g>
+<g id="replay-5"><path d="M12 5V1L7 6l5 5V7c3.3 0 6 2.7 6 6s-2.7 6-6 6-6-2.7-6-6H4c0 4.4 3.6 8 8 8s8-3.6 8-8-3.6-8-8-8zm-1.3 8.9l.2-2.2h2.4v.7h-1.7l-.1.9s.1 0 .1-.1.1 0 .1-.1.1 0 .2 0h.2c.2 0 .4 0 .5.1s.3.2.4.3.2.3.3.5.1.4.1.6c0 .2 0 .4-.1.5s-.1.3-.3.5-.3.2-.4.3-.4.1-.6.1c-.2 0-.4 0-.5-.1s-.3-.1-.5-.2-.2-.2-.3-.4-.1-.3-.1-.5h.8c0 .2.1.3.2.4s.2.1.4.1c.1 0 .2 0 .3-.1l.2-.2s.1-.2.1-.3v-.6l-.1-.2-.2-.2s-.2-.1-.3-.1h-.2s-.1 0-.2.1-.1 0-.1.1-.1.1-.1.1h-.7z"/></g>
+<g id="shuffle"><path d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"/></g>
+<g id="skip-next"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></g>
+<g id="skip-previous"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/></g>
+<g id="slow-motion-video"><path d="M13.05 9.79L10 7.5v9l3.05-2.29L16 12zm0 0L10 7.5v9l3.05-2.29L16 12zm0 0L10 7.5v9l3.05-2.29L16 12zM11 4.07V2.05c-2.01.2-3.84 1-5.32 2.21L7.1 5.69c1.11-.86 2.44-1.44 3.9-1.62zM5.69 7.1L4.26 5.68C3.05 7.16 2.25 8.99 2.05 11h2.02c.18-1.46.76-2.79 1.62-3.9zM4.07 13H2.05c.2 2.01 1 3.84 2.21 5.32l1.43-1.43c-.86-1.1-1.44-2.43-1.62-3.89zm1.61 6.74C7.16 20.95 9 21.75 11 21.95v-2.02c-1.46-.18-2.79-.76-3.9-1.62l-1.42 1.43zM22 12c0 5.16-3.92 9.42-8.95 9.95v-2.02C16.97 19.41 20 16.05 20 12s-3.03-7.41-6.95-7.93V2.05C18.08 2.58 22 6.84 22 12z"/></g>
+<g id="snooze"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-3-9h3.63L9 15.2V17h6v-2h-3.63L15 10.8V9H9v2z"/></g>
+<g id="sort-by-alpha"><path d="M14.94 4.66h-4.72l2.36-2.36zm-4.69 14.71h4.66l-2.33 2.33zM6.1 6.27L1.6 17.73h1.84l.92-2.45h5.11l.92 2.45h1.84L7.74 6.27H6.1zm-1.13 7.37l1.94-5.18 1.94 5.18H4.97zm10.76 2.5h6.12v1.59h-8.53v-1.29l5.92-8.56h-5.88v-1.6h8.3v1.26l-5.93 8.6z"/></g>
+<g id="stop"><path d="M6 6h12v12H6z"/></g>
+<g id="subscriptions"><path d="M20 8H4V6h16v2zm-2-6H6v2h12V2zm4 10v8c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2v-8c0-1.1.9-2 2-2h16c1.1 0 2 .9 2 2zm-6 4l-6-3.27v6.53L16 16z"/></g>
+<g id="subtitles"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM4 12h4v2H4v-2zm10 6H4v-2h10v2zm6 0h-4v-2h4v2zm0-4H10v-2h10v2z"/></g>
+<g id="surround-sound"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7.76 16.24l-1.41 1.41C4.78 16.1 4 14.05 4 12c0-2.05.78-4.1 2.34-5.66l1.41 1.41C6.59 8.93 6 10.46 6 12s.59 3.07 1.76 4.24zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm5.66 1.66l-1.41-1.41C17.41 15.07 18 13.54 18 12s-.59-3.07-1.76-4.24l1.41-1.41C19.22 7.9 20 9.95 20 12c0 2.05-.78 4.1-2.34 5.66zM12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="video-library"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8 12.5v-9l6 4.5-6 4.5z"/></g>
+<g id="videocam"><path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"/></g>
+<g id="videocam-off"><path d="M21 6.5l-4 4V7c0-.55-.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.21 0 .39-.08.54-.18L19.73 21 21 19.73 3.27 2z"/></g>
+<g id="volume-down"><path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/></g>
+<g id="volume-mute"><path d="M7 9v6h4l5 5V4l-5 5H7z"/></g>
+<g id="volume-off"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></g>
+<g id="volume-up"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></g>
+<g id="web"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-5 14H4v-4h11v4zm0-5H4V9h11v4zm5 5h-4V9h4v9z"/></g>
+<g id="web-asset"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm0 14H5V8h14v10z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/bower.json
new file mode 100644
index 00000000000..c5066e9fbcd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/bower.json
@@ -0,0 +1,38 @@
+{
+ "name": "iron-icons",
+ "version": "1.1.3",
+ "description": "A set of icons for use with iron-icon",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "main": "iron-icons.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-icons"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-icons",
+ "dependencies": {
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "iron-iconset-svg": "polymerelements/iron-iconset-svg#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "polymerelements/iron-component-page#1.0.0",
+ "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0"
+ },
+ "ignore": [
+ "util",
+ "update-icons.sh"
+ ]
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/communication-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/communication-icons.html
new file mode 100644
index 00000000000..b522e6db68f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/communication-icons.html
@@ -0,0 +1,64 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="communication" size="24">
+<svg><defs>
+<g id="business"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></g>
+<g id="call"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></g>
+<g id="call-end"><path d="M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08c-.18-.17-.29-.42-.29-.7 0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z"/></g>
+<g id="call-made"><path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5z"/></g>
+<g id="call-merge"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></g>
+<g id="call-missed"><path d="M19.59 7L12 14.59 6.41 9H11V7H3v8h2v-4.59l7 7 9-9z"/></g>
+<g id="call-missed-outgoing"><path d="M3 8.41l9 9 7-7V15h2V7h-8v2h4.59L12 14.59 4.41 7 3 8.41z"/></g>
+<g id="call-received"><path d="M20 5.41L18.59 4 7 15.59V9H5v10h10v-2H8.41z"/></g>
+<g id="call-split"><path d="M14 4l2.29 2.29-2.88 2.88 1.42 1.42 2.88-2.88L20 10V4zm-4 0H4v6l2.29-2.29 4.71 4.7V20h2v-8.41l-5.29-5.3z"/></g>
+<g id="chat"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 9h12v2H6V9zm8 5H6v-2h8v2zm4-6H6V6h12v2z"/></g>
+<g id="chat-bubble"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></g>
+<g id="chat-bubble-outline"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></g>
+<g id="clear-all"><path d="M5 13h14v-2H5v2zm-2 4h14v-2H3v2zM7 7v2h14V7H7z"/></g>
+<g id="comment"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18zM18 14H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/></g>
+<g id="contact-mail"><path d="M21 8V7l-3 2-3-2v1l3 2 3-2zm1-5H2C.9 3 0 3.9 0 5v14c0 1.1.9 2 2 2h20c1.1 0 1.99-.9 1.99-2L24 5c0-1.1-.9-2-2-2zM8 6c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H2v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1zm8-6h-8V6h8v6z"/></g>
+<g id="contact-phone"><path d="M22 3H2C.9 3 0 3.9 0 5v14c0 1.1.9 2 2 2h20c1.1 0 1.99-.9 1.99-2L24 5c0-1.1-.9-2-2-2zM8 6c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H2v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1zm3.85-4h1.64L21 16l-1.99 1.99c-1.31-.98-2.28-2.38-2.73-3.99-.18-.64-.28-1.31-.28-2s.1-1.36.28-2c.45-1.62 1.42-3.01 2.73-3.99L21 8l-1.51 2h-1.64c-.22.63-.35 1.3-.35 2s.13 1.37.35 2z"/></g>
+<g id="contacts"><path d="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25 2.25S9.75 10.24 9.75 9 10.76 6.75 12 6.75zM17 17H7v-1.5c0-1.67 3.33-2.5 5-2.5s5 .83 5 2.5V17z"/></g>
+<g id="dialer-sip"><path d="M17 3h-1v5h1V3zm-2 2h-2V4h2V3h-3v3h2v1h-2v1h3V5zm3-2v5h1V6h2V3h-3zm2 2h-1V4h1v1zm0 10.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.01.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.27-.26.35-.65.24-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1z"/></g>
+<g id="dialpad"><path d="M12 19c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 1c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="email"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></g>
+<g id="forum"><path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"/></g>
+<g id="import-contacts"><path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.25-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/></g>
+<g id="import-export"><path d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/></g>
+<g id="invert-colors-off"><path d="M20.65 20.87l-2.35-2.35-6.3-6.29-3.56-3.57-1.42-1.41L4.27 4.5 3 5.77l2.78 2.78c-2.55 3.14-2.36 7.76.56 10.69C7.9 20.8 9.95 21.58 12 21.58c1.79 0 3.57-.59 5.03-1.78l2.7 2.7L21 21.23l-.35-.36zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59c0-1.32.43-2.57 1.21-3.6L12 14.77v4.82zM12 5.1v4.58l7.25 7.26c1.37-2.96.84-6.57-1.6-9.01L12 2.27l-3.7 3.7 1.41 1.41L12 5.1z"/></g>
+<g id="live-help"><path d="M19 2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 16h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 11.9 13 12.5 13 14h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></g>
+<g id="location-off"><path d="M12 6.5c1.38 0 2.5 1.12 2.5 2.5 0 .74-.33 1.39-.83 1.85l3.63 3.63c.98-1.86 1.7-3.8 1.7-5.48 0-3.87-3.13-7-7-7-1.98 0-3.76.83-5.04 2.15l3.19 3.19c.46-.52 1.11-.84 1.85-.84zm4.37 9.6l-4.63-4.63-.11-.11L3.27 3 2 4.27l3.18 3.18C5.07 7.95 5 8.47 5 9c0 5.25 7 13 7 13s1.67-1.85 3.38-4.35L18.73 21 20 19.73l-3.63-3.63z"/></g>
+<g id="location-on"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g>
+<g id="mail-outline"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H4V8l8 5 8-5v10zm-8-7L4 6h16l-8 5z"/></g>
+<g id="message"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/></g>
+<g id="no-sim"><path d="M18.99 5c0-1.1-.89-2-1.99-2h-7L7.66 5.34 19 16.68 18.99 5zM3.65 3.88L2.38 5.15 5 7.77V19c0 1.1.9 2 2 2h10.01c.35 0 .67-.1.96-.26l1.88 1.88 1.27-1.27L3.65 3.88z"/></g>
+<g id="phone"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></g>
+<g id="phonelink-erase"><path d="M13 8.2l-1-1-4 4-4-4-1 1 4 4-4 4 1 1 4-4 4 4 1-1-4-4 4-4zM19 1H9c-1.1 0-2 .9-2 2v3h2V4h10v16H9v-2H7v3c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2z"/></g>
+<g id="phonelink-lock"><path d="M19 1H9c-1.1 0-2 .9-2 2v3h2V4h10v16H9v-2H7v3c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm-8.2 10V9.5C10.8 8.1 9.4 7 8 7S5.2 8.1 5.2 9.5V11c-.6 0-1.2.6-1.2 1.2v3.5c0 .7.6 1.3 1.2 1.3h5.5c.7 0 1.3-.6 1.3-1.2v-3.5c0-.7-.6-1.3-1.2-1.3zm-1.3 0h-3V9.5c0-.8.7-1.3 1.5-1.3s1.5.5 1.5 1.3V11z"/></g>
+<g id="phonelink-ring"><path d="M20.1 7.7l-1 1c1.8 1.8 1.8 4.6 0 6.5l1 1c2.5-2.3 2.5-6.1 0-8.5zM18 9.8l-1 1c.5.7.5 1.6 0 2.3l1 1c1.2-1.2 1.2-3 0-4.3zM14 1H4c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 19H4V4h10v16z"/></g>
+<g id="phonelink-setup"><path d="M11.8 12.5v-1l1.1-.8c.1-.1.1-.2.1-.3l-1-1.7c-.1-.1-.2-.2-.3-.1l-1.3.4c-.3-.2-.6-.4-.9-.5l-.2-1.3c0-.1-.1-.2-.3-.2H7c-.1 0-.2.1-.3.2l-.2 1.3c-.3.1-.6.3-.9.5l-1.3-.5c-.1 0-.2 0-.3.1l-1 1.7c-.1.1 0 .2.1.3l1.1.8v1l-1.1.8c-.1.2-.1.3-.1.4l1 1.7c.1.1.2.2.3.1l1.4-.4c.3.2.6.4.9.5l.2 1.3c-.1.1.1.2.2.2h2c.1 0 .2-.1.3-.2l.2-1.3c.3-.1.6-.3.9-.5l1.3.5c.1 0 .2 0 .3-.1l1-1.7c.1-.1 0-.2-.1-.3l-1.1-.9zM8 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM19 1H9c-1.1 0-2 .9-2 2v3h2V4h10v16H9v-2H7v3c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2z"/></g>
+<g id="portable-wifi-off"><path d="M17.56 14.24c.28-.69.44-1.45.44-2.24 0-3.31-2.69-6-6-6-.79 0-1.55.16-2.24.44l1.62 1.62c.2-.03.41-.06.62-.06 2.21 0 4 1.79 4 4 0 .21-.02.42-.05.63l1.61 1.61zM12 4c4.42 0 8 3.58 8 8 0 1.35-.35 2.62-.95 3.74l1.47 1.47C21.46 15.69 22 13.91 22 12c0-5.52-4.48-10-10-10-1.91 0-3.69.55-5.21 1.47l1.46 1.46C9.37 4.34 10.65 4 12 4zM3.27 2.5L2 3.77l2.1 2.1C2.79 7.57 2 9.69 2 12c0 3.7 2.01 6.92 4.99 8.65l1-1.73C5.61 17.53 4 14.96 4 12c0-1.76.57-3.38 1.53-4.69l1.43 1.44C6.36 9.68 6 10.8 6 12c0 2.22 1.21 4.15 3 5.19l1-1.74c-1.19-.7-2-1.97-2-3.45 0-.65.17-1.25.44-1.79l1.58 1.58L10 12c0 1.1.9 2 2 2l.21-.02.01.01 7.51 7.51L21 20.23 4.27 3.5l-1-1z"/></g>
+<g id="present-to-all"><path d="M21 3H3c-1.11 0-2 .89-2 2v14c0 1.11.89 2 2 2h18c1.11 0 2-.89 2-2V5c0-1.11-.89-2-2-2zm0 16.02H3V4.98h18v14.04zM10 12H8l4-4 4 4h-2v4h-4v-4z"/></g>
+<g id="ring-volume"><path d="M23.71 16.67C20.66 13.78 16.54 12 12 12 7.46 12 3.34 13.78.29 16.67c-.18.18-.29.43-.29.71 0 .28.11.53.29.71l2.48 2.48c.18.18.43.29.71.29.27 0 .52-.11.7-.28.79-.74 1.69-1.36 2.66-1.85.33-.16.56-.5.56-.9v-3.1c1.45-.48 3-.73 4.6-.73s3.15.25 4.6.72v3.1c0 .39.23.74.56.9.98.49 1.87 1.12 2.66 1.85.18.18.43.28.7.28.28 0 .53-.11.71-.29l2.48-2.48c.18-.18.29-.43.29-.71 0-.27-.11-.52-.29-.7zM21.16 6.26l-1.41-1.41-3.56 3.55 1.41 1.41s3.45-3.52 3.56-3.55zM13 2h-2v5h2V2zM6.4 9.81L7.81 8.4 4.26 4.84 2.84 6.26c.11.03 3.56 3.55 3.56 3.55z"/></g>
+<g id="screen-share"><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.11-.9-2-2-2H4c-1.11 0-2 .89-2 2v10c0 1.1.89 2 2 2H0v2h24v-2h-4zm-7-3.53v-2.19c-2.78 0-4.61.85-6 2.72.56-2.67 2.11-5.33 6-5.87V7l4 3.73-4 3.74z"/></g>
+<g id="speaker-phone"><path d="M7 7.07L8.43 8.5c.91-.91 2.18-1.48 3.57-1.48s2.66.57 3.57 1.48L17 7.07C15.72 5.79 13.95 5 12 5s-3.72.79-5 2.07zM12 1C8.98 1 6.24 2.23 4.25 4.21l1.41 1.41C7.28 4 9.53 3 12 3s4.72 1 6.34 2.62l1.41-1.41C17.76 2.23 15.02 1 12 1zm2.86 9.01L9.14 10C8.51 10 8 10.51 8 11.14v9.71c0 .63.51 1.14 1.14 1.14h5.71c.63 0 1.14-.51 1.14-1.14v-9.71c.01-.63-.5-1.13-1.13-1.13zM15 20H9v-8h6v8z"/></g>
+<g id="stay-current-landscape"><path d="M1.01 7L1 17c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2H3c-1.1 0-1.99.9-1.99 2zM19 7v10H5V7h14z"/></g>
+<g id="stay-current-portrait"><path d="M17 1.01L7 1c-1.1 0-1.99.9-1.99 2v18c0 1.1.89 2 1.99 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></g>
+<g id="stay-primary-landscape"><path d="M1.01 7L1 17c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2H3c-1.1 0-1.99.9-1.99 2zM19 7v10H5V7h14z"/></g>
+<g id="stay-primary-portrait"><path d="M17 1.01L7 1c-1.1 0-1.99.9-1.99 2v18c0 1.1.89 2 1.99 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></g>
+<g id="stop-screen-share"><path d="M21.22 18.02l2 2H24v-2h-2.78zm.77-2l.01-10c0-1.11-.9-2-2-2H7.22l5.23 5.23c.18-.04.36-.07.55-.1V7.02l4 3.73-1.58 1.47 5.54 5.54c.61-.33 1.03-.99 1.03-1.74zM2.39 1.73L1.11 3l1.54 1.54c-.4.36-.65.89-.65 1.48v10c0 1.1.89 2 2 2H0v2h18.13l2.71 2.71 1.27-1.27L2.39 1.73zM7 15.02c.31-1.48.92-2.95 2.07-4.06l1.59 1.59c-1.54.38-2.7 1.18-3.66 2.47z"/></g>
+<g id="swap-calls"><path d="M18 4l-4 4h3v7c0 1.1-.9 2-2 2s-2-.9-2-2V8c0-2.21-1.79-4-4-4S5 5.79 5 8v7H2l4 4 4-4H7V8c0-1.1.9-2 2-2s2 .9 2 2v7c0 2.21 1.79 4 4 4s4-1.79 4-4V8h3l-4-4z"/></g>
+<g id="textsms"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z"/></g>
+<g id="voicemail"><path d="M18.5 6C15.46 6 13 8.46 13 11.5c0 1.33.47 2.55 1.26 3.5H9.74c.79-.95 1.26-2.17 1.26-3.5C11 8.46 8.54 6 5.5 6S0 8.46 0 11.5 2.46 17 5.5 17h13c3.04 0 5.5-2.46 5.5-5.5S21.54 6 18.5 6zm-13 9C3.57 15 2 13.43 2 11.5S3.57 8 5.5 8 9 9.57 9 11.5 7.43 15 5.5 15zm13 0c-1.93 0-3.5-1.57-3.5-3.5S16.57 8 18.5 8 22 9.57 22 11.5 20.43 15 18.5 15z"/></g>
+<g id="vpn-key"><path d="M12.65 10C11.83 7.67 9.61 6 7 6c-3.31 0-6 2.69-6 6s2.69 6 6 6c2.61 0 4.83-1.67 5.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/demo/index.html
new file mode 100644
index 00000000000..acfbf36cc7d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/demo/index.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<!--
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-icons demo</title>
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../iron-flex-layout/iron-flex-layout.html">
+
+ <!-- load default iconset -->
+ <link rel="import" href="../iron-icons.html">
+
+ <!-- load the rest -->
+ <link rel="import" href="../av-icons.html">
+ <link rel="import" href="../communication-icons.html">
+ <link rel="import" href="../device-icons.html">
+ <link rel="import" href="../editor-icons.html">
+ <link rel="import" href="../hardware-icons.html">
+ <link rel="import" href="../image-icons.html">
+ <link rel="import" href="../maps-icons.html">
+ <link rel="import" href="../notification-icons.html">
+ <link rel="import" href="../social-icons.html">
+ <link rel="import" href="../places-icons.html">
+
+ <style is="custom-style">
+
+ h2 {
+ text-transform: capitalize;
+ }
+
+ iron-icon {
+ transition: all 0.2s;
+ -webkit-transition: all 0.2s;
+ }
+
+ iron-icon:hover {
+ fill: var(--google-yellow-700);
+ }
+
+ .set {
+ margin: auto;
+ padding: 1em 0;
+ border-bottom: 1px solid silver;
+ @apply(--layout-horizontal);
+ @apply(--layout-wrap);
+ }
+
+ .set:last-of-type {
+ border-bottom: none;
+ }
+
+ .set:nth-of-type(4n-3) {
+ color: var(--paper-grey-700);
+ }
+
+ .set:nth-of-type(4n-2) {
+ color: var(--paper-pink-500);
+ }
+
+ .set:nth-of-type(4n-1) {
+ color: var(--google-green-500);
+ }
+
+ .set:nth-of-type(4n) {
+ color: var( --google-blue-500);
+ }
+
+ .container {
+ min-width: 10em;
+ padding: 1em 0.5em;
+ text-align: center;
+ @apply(--layout-vertical);
+ @apply(--layout-center);
+ @apply(--layout-flex-1);
+ }
+
+ .container > div {
+ margin-top: 0.5em;
+ color: black;
+ font-size: 10px;
+ }
+
+ </style>
+
+</head>
+<body>
+
+ <template is="dom-bind">
+
+ <iron-meta type="iconset" list="{{iconsets}}"></iron-meta>
+
+ <template is="dom-repeat" items="{{iconsets}}">
+
+ <h2>{{item.name}}</h2>
+
+ <div class="set">
+
+ <template is="dom-repeat" items="{{getIconNames(item)}}">
+
+ <span class="container">
+ <iron-icon icon="{{item}}"></iron-icon>
+ <div>{{item}}</div>
+ </span>
+
+ </template>
+
+ </div>
+
+ </template>
+
+ </template>
+
+ <script>
+
+ document.querySelector('[is=dom-bind]').getIconNames = function(iconset) {
+ return iconset.getIconNames();
+ };
+
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/device-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/device-icons.html
new file mode 100644
index 00000000000..03809ee5171
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/device-icons.html
@@ -0,0 +1,94 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="device" size="24">
+<svg><defs>
+<g id="access-alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="access-alarms"><path d="M22 5.7l-4.6-3.9-1.3 1.5 4.6 3.9L22 5.7zM7.9 3.4L6.6 1.9 2 5.7l1.3 1.5 4.6-3.8zM12.5 8H11v6l4.7 2.9.8-1.2-4-2.4V8zM12 4c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/></g>
+<g id="access-time"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></g>
+<g id="add-alarm"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"/></g>
+<g id="airplanemode-active"><path d="M10.18 9"/><path d="M21 16v-2l-8-5V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></g>
+<g id="airplanemode-inactive"><path d="M13 9V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v3.68l7.83 7.83L21 16v-2l-8-5zM3 5.27l4.99 4.99L2 14v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-3.73L18.73 21 20 19.73 4.27 4 3 5.27z"/></g>
+<g id="battery-20"><path d="M7 17v3.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V17H7z"/><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V17h10V5.33z"/></g>
+<g id="battery-30"><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V15h10V5.33z"/><path d="M7 15v5.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V15H7z"/></g>
+<g id="battery-50"><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V13h10V5.33z"/><path d="M7 13v7.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V13H7z"/></g>
+<g id="battery-60"><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V11h10V5.33z"/><path d="M7 11v9.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V11H7z"/></g>
+<g id="battery-80"><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V9h10V5.33z"/><path d="M7 9v11.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V9H7z"/></g>
+<g id="battery-90"><path fill-opacity=".3" d="M17 5.33C17 4.6 16.4 4 15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V8h10V5.33z"/><path d="M7 8v12.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V8H7z"/></g>
+<g id="battery-alert"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4zM13 18h-2v-2h2v2zm0-4h-2V9h2v5z"/></g>
+<g id="battery-charging-20"><path d="M11 20v-3H7v3.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V17h-4.4L11 20z"/><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V17h4v-2.5H9L13 7v5.5h2L12.6 17H17V5.33C17 4.6 16.4 4 15.67 4z"/></g>
+<g id="battery-charging-30"><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v9.17h2L13 7v5.5h2l-1.07 2H17V5.33C17 4.6 16.4 4 15.67 4z"/><path d="M11 20v-5.5H7v6.17C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V14.5h-3.07L11 20z"/></g>
+<g id="battery-charging-50"><path d="M14.47 13.5L11 20v-5.5H9l.53-1H7v7.17C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V13.5h-2.53z"/><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v8.17h2.53L13 7v5.5h2l-.53 1H17V5.33C17 4.6 16.4 4 15.67 4z"/></g>
+<g id="battery-charging-60"><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V11h3.87L13 7v4h4V5.33C17 4.6 16.4 4 15.67 4z"/><path d="M13 12.5h2L11 20v-5.5H9l1.87-3.5H7v9.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V11h-4v1.5z"/></g>
+<g id="battery-charging-80"><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V9h4.93L13 7v2h4V5.33C17 4.6 16.4 4 15.67 4z"/><path d="M13 12.5h2L11 20v-5.5H9L11.93 9H7v11.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V9h-4v3.5z"/></g>
+<g id="battery-charging-90"><path fill-opacity=".3" d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V8h5.47L13 7v1h4V5.33C17 4.6 16.4 4 15.67 4z"/><path d="M13 12.5h2L11 20v-5.5H9L12.47 8H7v12.67C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V8h-4v4.5z"/></g>
+<g id="battery-charging-full"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4zM11 20v-5.5H9L13 7v5.5h2L11 20z"/></g>
+<g id="battery-full"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4z"/></g>
+<g id="battery-std"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4z"/></g>
+<g id="battery-unknown"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4zm-2.72 13.95h-1.9v-1.9h1.9v1.9zm1.35-5.26s-.38.42-.67.71c-.48.48-.83 1.15-.83 1.6h-1.6c0-.83.46-1.52.93-2l.93-.94c.27-.27.44-.65.44-1.06 0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5H9c0-1.66 1.34-3 3-3s3 1.34 3 3c0 .66-.27 1.26-.7 1.69z"/></g>
+<g id="bluetooth"><path d="M17.71 7.71L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88z"/></g>
+<g id="bluetooth-connected"><path d="M7 12l-2-2-2 2 2 2 2-2zm10.71-4.29L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88zM19 10l-2 2 2 2 2-2-2-2z"/></g>
+<g id="bluetooth-disabled"><path d="M13 5.83l1.88 1.88-1.6 1.6 1.41 1.41 3.02-3.02L12 2h-1v5.03l2 2v-3.2zM5.41 4L4 5.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l4.29-4.29 2.3 2.29L20 18.59 5.41 4zM13 18.17v-3.76l1.88 1.88L13 18.17z"/></g>
+<g id="bluetooth-searching"><path d="M14.24 12.01l2.32 2.32c.28-.72.44-1.51.44-2.33 0-.82-.16-1.59-.43-2.31l-2.33 2.32zm5.29-5.3l-1.26 1.26c.63 1.21.98 2.57.98 4.02s-.36 2.82-.98 4.02l1.2 1.2c.97-1.54 1.54-3.36 1.54-5.31-.01-1.89-.55-3.67-1.48-5.19zm-3.82 1L10 2H9v7.59L4.41 5 3 6.41 8.59 12 3 17.59 4.41 19 9 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM11 5.83l1.88 1.88L11 9.59V5.83zm1.88 10.46L11 18.17v-3.76l1.88 1.88z"/></g>
+<g id="brightness-auto"><path d="M10.85 12.65h2.3L12 9l-1.15 3.65zM20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM14.3 16l-.7-2h-3.2l-.7 2H7.8L11 7h2l3.2 9h-1.9z"/></g>
+<g id="brightness-high"><path d="M20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-10c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"/></g>
+<g id="brightness-low"><path d="M20 15.31L23.31 12 20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"/></g>
+<g id="brightness-medium"><path d="M20 15.31L23.31 12 20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69zM12 18V6c3.31 0 6 2.69 6 6s-2.69 6-6 6z"/></g>
+<g id="data-usage"><path d="M13 2.05v3.03c3.39.49 6 3.39 6 6.92 0 .9-.18 1.75-.48 2.54l2.6 1.53c.56-1.24.88-2.62.88-4.07 0-5.18-3.95-9.45-9-9.95zM12 19c-3.87 0-7-3.13-7-7 0-3.53 2.61-6.43 6-6.92V2.05c-5.06.5-9 4.76-9 9.95 0 5.52 4.47 10 9.99 10 3.31 0 6.24-1.61 8.06-4.09l-2.6-1.53C16.17 17.98 14.21 19 12 19z"/></g>
+<g id="developer-mode"><path d="M7 5h10v2h2V3c0-1.1-.9-1.99-2-1.99L7 1c-1.1 0-2 .9-2 2v4h2V5zm8.41 11.59L20 12l-4.59-4.59L14 8.83 17.17 12 14 15.17l1.41 1.42zM10 15.17L6.83 12 10 8.83 8.59 7.41 4 12l4.59 4.59L10 15.17zM17 19H7v-2H5v4c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-4h-2v2z"/></g>
+<g id="devices"><path d="M4 6h18V4H4c-1.1 0-2 .9-2 2v11H0v3h14v-3H4V6zm19 2h-6c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zm-1 9h-4v-7h4v7z"/></g>
+<g id="dvr"><path d="M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12zm-2-9H8v2h11V8zm0 4H8v2h11v-2zM7 8H5v2h2V8zm0 4H5v2h2v-2z"/></g>
+<g id="gps-fixed"><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="gps-not-fixed"><path d="M20.94 11c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="gps-off"><path d="M20.94 11c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06c-1.13.12-2.19.46-3.16.97l1.5 1.5C10.16 5.19 11.06 5 12 5c3.87 0 7 3.13 7 7 0 .94-.19 1.84-.52 2.65l1.5 1.5c.5-.96.84-2.02.97-3.15H23v-2h-2.06zM3 4.27l2.04 2.04C3.97 7.62 3.25 9.23 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c1.77-.2 3.38-.91 4.69-1.98L19.73 21 21 19.73 4.27 3 3 4.27zm13.27 13.27C15.09 18.45 13.61 19 12 19c-3.87 0-7-3.13-7-7 0-1.61.55-3.09 1.46-4.27l9.81 9.81z"/></g>
+<g id="graphic-eq"><path d="M7 18h2V6H7v12zm4 4h2V2h-2v20zm-8-8h2v-4H3v4zm12 4h2V6h-2v12zm4-8v4h2v-4h-2z"/></g>
+<g id="location-disabled"><path d="M20.94 11c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06c-1.13.12-2.19.46-3.16.97l1.5 1.5C10.16 5.19 11.06 5 12 5c3.87 0 7 3.13 7 7 0 .94-.19 1.84-.52 2.65l1.5 1.5c.5-.96.84-2.02.97-3.15H23v-2h-2.06zM3 4.27l2.04 2.04C3.97 7.62 3.25 9.23 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c1.77-.2 3.38-.91 4.69-1.98L19.73 21 21 19.73 4.27 3 3 4.27zm13.27 13.27C15.09 18.45 13.61 19 12 19c-3.87 0-7-3.13-7-7 0-1.61.55-3.09 1.46-4.27l9.81 9.81z"/></g>
+<g id="location-searching"><path d="M20.94 11c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="network-cell"><path fill-opacity=".3" d="M2 22h20V2z"/><path d="M17 7L2 22h15z"/></g>
+<g id="network-wifi"><path fill-opacity=".3" d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/><path d="M3.53 10.95l8.46 10.54.01.01.01-.01 8.46-10.54C20.04 10.62 16.81 8 12 8c-4.81 0-8.04 2.62-8.47 2.95z"/></g>
+<g id="nfc"><path d="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z"/></g>
+<g id="screen-lock-landscape"><path d="M21 5H3c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-2 12H5V7h14v10zm-9-1h4c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1v-1c0-1.11-.9-2-2-2-1.11 0-2 .9-2 2v1c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1zm.8-6c0-.66.54-1.2 1.2-1.2.66 0 1.2.54 1.2 1.2v1h-2.4v-1z"/></g>
+<g id="screen-lock-portrait"><path d="M10 16h4c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1v-1c0-1.11-.9-2-2-2-1.11 0-2 .9-2 2v1c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1zm.8-6c0-.66.54-1.2 1.2-1.2.66 0 1.2.54 1.2 1.2v1h-2.4v-1zM17 1H7c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 18H7V5h10v14z"/></g>
+<g id="screen-lock-rotation"><path d="M23.25 12.77l-2.57-2.57-1.41 1.41 2.22 2.22-5.66 5.66L4.51 8.17l5.66-5.66 2.1 2.1 1.41-1.41L11.23.75c-.59-.59-1.54-.59-2.12 0L2.75 7.11c-.59.59-.59 1.54 0 2.12l12.02 12.02c.59.59 1.54.59 2.12 0l6.36-6.36c.59-.59.59-1.54 0-2.12zM8.47 20.48C5.2 18.94 2.86 15.76 2.5 12H1c.51 6.16 5.66 11 11.95 11l.66-.03-3.81-3.82-1.33 1.33zM16 9h5c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1v-.5C21 1.12 19.88 0 18.5 0S16 1.12 16 2.5V3c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1zm.8-6.5c0-.94.76-1.7 1.7-1.7s1.7.76 1.7 1.7V3h-3.4v-.5z"/></g>
+<g id="screen-rotation"><path d="M16.48 2.52c3.27 1.55 5.61 4.72 5.97 8.48h1.5C23.44 4.84 18.29 0 12 0l-.66.03 3.81 3.81 1.33-1.32zm-6.25-.77c-.59-.59-1.54-.59-2.12 0L1.75 8.11c-.59.59-.59 1.54 0 2.12l12.02 12.02c.59.59 1.54.59 2.12 0l6.36-6.36c.59-.59.59-1.54 0-2.12L10.23 1.75zm4.6 19.44L2.81 9.17l6.36-6.36 12.02 12.02-6.36 6.36zm-7.31.29C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32z"/></g>
+<g id="sd-storage"><path d="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 6h-2V4h2v4zm3 0h-2V4h2v4zm3 0h-2V4h2v4z"/></g>
+<g id="settings-system-daydream"><path d="M9 16h6.5c1.38 0 2.5-1.12 2.5-2.5S16.88 11 15.5 11h-.05c-.24-1.69-1.69-3-3.45-3-1.4 0-2.6.83-3.16 2.02h-.16C7.17 10.18 6 11.45 6 13c0 1.66 1.34 3 3 3zM21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"/></g>
+<g id="signal-cellular-0-bar"><path fill-opacity=".3" d="M2 22h20V2z"/></g>
+<g id="signal-cellular-1-bar"><path fill-opacity=".3" d="M2 22h20V2z"/><path d="M12 12L2 22h10z"/></g>
+<g id="signal-cellular-2-bar"><path fill-opacity=".3" d="M2 22h20V2z"/><path d="M14 10L2 22h12z"/></g>
+<g id="signal-cellular-3-bar"><path fill-opacity=".3" d="M2 22h20V2z"/><path d="M17 7L2 22h15z"/></g>
+<g id="signal-cellular-4-bar"><path d="M2 22h20V2z"/></g>
+<g id="signal-cellular-connected-no-internet-0-bar"><path fill-opacity=".3" d="M22 8V2L2 22h16V8z"/><path d="M20 22h2v-2h-2v2zm0-12v8h2v-8h-2z"/></g>
+<g id="signal-cellular-connected-no-internet-1-bar"><path fill-opacity=".3" d="M22 8V2L2 22h16V8z"/><path d="M20 10v8h2v-8h-2zm-8 12V12L2 22h10zm8 0h2v-2h-2v2z"/></g>
+<g id="signal-cellular-connected-no-internet-2-bar"><path fill-opacity=".3" d="M22 8V2L2 22h16V8z"/><path d="M14 22V10L2 22h12zm6-12v8h2v-8h-2zm0 12h2v-2h-2v2z"/></g>
+<g id="signal-cellular-connected-no-internet-3-bar"><path fill-opacity=".3" d="M22 8V2L2 22h16V8z"/><path d="M17 22V7L2 22h15zm3-12v8h2v-8h-2zm0 12h2v-2h-2v2z"/></g>
+<g id="signal-cellular-connected-no-internet-4-bar"><path d="M20 18h2v-8h-2v8zm0 4h2v-2h-2v2zM2 22h16V8h4V2L2 22z"/></g>
+<g id="signal-cellular-no-sim"><path d="M18.99 5c0-1.1-.89-2-1.99-2h-7L7.66 5.34 19 16.68 18.99 5zM3.65 3.88L2.38 5.15 5 7.77V19c0 1.1.9 2 2 2h10.01c.35 0 .67-.1.96-.26l1.88 1.88 1.27-1.27L3.65 3.88z"/></g>
+<g id="signal-cellular-null"><path d="M20 6.83V20H6.83L20 6.83M22 2L2 22h20V2z"/></g>
+<g id="signal-cellular-off"><path d="M21 1l-8.59 8.59L21 18.18V1zM4.77 4.5L3.5 5.77l6.36 6.36L1 21h17.73l2 2L22 21.73 4.77 4.5z"/></g>
+<g id="signal-wifi-0-bar"><path fill-opacity=".3" d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/></g>
+<g id="signal-wifi-1-bar"><path fill-opacity=".3" d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/><path d="M6.67 14.86L12 21.49v.01l.01-.01 5.33-6.63C17.06 14.65 15.03 13 12 13s-5.06 1.65-5.33 1.86z"/></g>
+<g id="signal-wifi-1-bar-lock"><path d="M23 16v-1.5c0-1.4-1.1-2.5-2.5-2.5S18 13.1 18 14.5V16c-.5 0-1 .5-1 1v4c0 .5.5 1 1 1h5c.5 0 1-.5 1-1v-4c0-.5-.5-1-1-1zm-1 0h-3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V16z"/><path d="M15.5 14.5c0-2.8 2.2-5 5-5 .4 0 .7 0 1 .1L23.6 7c-.4-.3-4.9-4-11.6-4C5.3 3 .8 6.7.4 7L12 21.5l3.5-4.3v-2.7z" opacity=".3"/><path d="M6.7 14.9l5.3 6.6 3.5-4.3v-2.6c0-.2 0-.5.1-.7-.9-.5-2.2-.9-3.6-.9-3 0-5.1 1.7-5.3 1.9z"/></g>
+<g id="signal-wifi-2-bar"><path fill-opacity=".3" d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/><path d="M4.79 12.52l7.2 8.98H12l.01-.01 7.2-8.98C18.85 12.24 16.1 10 12 10s-6.85 2.24-7.21 2.52z"/></g>
+<g id="signal-wifi-2-bar-lock"><path d="M23 16v-1.5c0-1.4-1.1-2.5-2.5-2.5S18 13.1 18 14.5V16c-.5 0-1 .5-1 1v4c0 .5.5 1 1 1h5c.5 0 1-.5 1-1v-4c0-.5-.5-1-1-1zm-1 0h-3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V16z"/><path d="M15.5 14.5c0-2.8 2.2-5 5-5 .4 0 .7 0 1 .1L23.6 7c-.4-.3-4.9-4-11.6-4C5.3 3 .8 6.7.4 7L12 21.5l3.5-4.3v-2.7z" opacity=".3"/><path d="M4.8 12.5l7.2 9 3.5-4.4v-2.6c0-1.3.5-2.5 1.4-3.4C15.6 10.5 14 10 12 10c-4.1 0-6.8 2.2-7.2 2.5z"/></g>
+<g id="signal-wifi-3-bar"><path fill-opacity=".3" d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/><path d="M3.53 10.95l8.46 10.54.01.01.01-.01 8.46-10.54C20.04 10.62 16.81 8 12 8c-4.81 0-8.04 2.62-8.47 2.95z"/></g>
+<g id="signal-wifi-3-bar-lock"><path opacity=".3" d="M12 3C5.3 3 .8 6.7.4 7l3.2 3.9L12 21.5l3.5-4.3v-2.6c0-2.2 1.4-4 3.3-4.7.3-.1.5-.2.8-.2.3-.1.6-.1.9-.1.4 0 .7 0 1 .1L23.6 7c-.4-.3-4.9-4-11.6-4z"/><path d="M23 16v-1.5c0-1.4-1.1-2.5-2.5-2.5S18 13.1 18 14.5V16c-.5 0-1 .5-1 1v4c0 .5.5 1 1 1h5c.5 0 1-.5 1-1v-4c0-.5-.5-1-1-1zm-1 0h-3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V16zm-10 5.5l3.5-4.3v-2.6c0-2.2 1.4-4 3.3-4.7C17.3 9 14.9 8 12 8c-4.8 0-8 2.6-8.5 2.9"/></g>
+<g id="signal-wifi-4-bar"><path d="M12.01 21.49L23.64 7c-.45-.34-4.93-4-11.64-4C5.28 3 .81 6.66.36 7l11.63 14.49.01.01.01-.01z"/></g>
+<g id="signal-wifi-4-bar-lock"><path d="M23 16v-1.5c0-1.4-1.1-2.5-2.5-2.5S18 13.1 18 14.5V16c-.5 0-1 .5-1 1v4c0 .5.5 1 1 1h5c.5 0 1-.5 1-1v-4c0-.5-.5-1-1-1zm-1 0h-3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V16zm-6.5-1.5c0-2.8 2.2-5 5-5 .4 0 .7 0 1 .1L23.6 7c-.4-.3-4.9-4-11.6-4C5.3 3 .8 6.7.4 7L12 21.5l3.5-4.4v-2.6z"/></g>
+<g id="signal-wifi-off"><path d="M23.64 7c-.45-.34-4.93-4-11.64-4-1.5 0-2.89.19-4.15.48L18.18 13.8 23.64 7zm-6.6 8.22L3.27 1.44 2 2.72l2.05 2.06C1.91 5.76.59 6.82.36 7l11.63 14.49.01.01.01-.01 3.9-4.86 3.32 3.32 1.27-1.27-3.46-3.46z"/></g>
+<g id="storage"><path d="M2 20h20v-4H2v4zm2-3h2v2H4v-2zM2 4v4h20V4H2zm4 3H4V5h2v2zm-4 7h20v-4H2v4zm2-3h2v2H4v-2z"/></g>
+<g id="usb"><path d="M15 7v4h1v2h-3V5h2l-3-4-3 4h2v8H8v-2.07c.7-.37 1.2-1.08 1.2-1.93 0-1.21-.99-2.2-2.2-2.2-1.21 0-2.2.99-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37-1.2 1.1-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2-.98 2.2-2.2 0-.85-.49-1.58-1.2-1.95V15h3c1.11 0 2-.89 2-2v-2h1V7h-4z"/></g>
+<g id="wallpaper"><path d="M4 4h7V2H4c-1.1 0-2 .9-2 2v7h2V4zm6 9l-4 5h12l-3-4-2.03 2.71L10 13zm7-4.5c0-.83-.67-1.5-1.5-1.5S14 7.67 14 8.5s.67 1.5 1.5 1.5S17 9.33 17 8.5zM20 2h-7v2h7v7h2V4c0-1.1-.9-2-2-2zm0 18h-7v2h7c1.1 0 2-.9 2-2v-7h-2v7zM4 13H2v7c0 1.1.9 2 2 2h7v-2H4v-7z"/></g>
+<g id="widgets"><path d="M13 13v8h8v-8h-8zM3 21h8v-8H3v8zM3 3v8h8V3H3zm13.66-1.31L11 7.34 16.66 13l5.66-5.66-5.66-5.65z"/></g>
+<g id="wifi-lock"><path d="M20.5 9.5c.28 0 .55.04.81.08L24 6c-3.34-2.51-7.5-4-12-4S3.34 3.49 0 6l12 16 3.5-4.67V14.5c0-2.76 2.24-5 5-5zM23 16v-1.5c0-1.38-1.12-2.5-2.5-2.5S18 13.12 18 14.5V16c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1zm-1 0h-3v-1.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V16z"/></g>
+<g id="wifi-tethering"><path d="M12 11c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 2c0-3.31-2.69-6-6-6s-6 2.69-6 6c0 2.22 1.21 4.15 3 5.19l1-1.74c-1.19-.7-2-1.97-2-3.45 0-2.21 1.79-4 4-4s4 1.79 4 4c0 1.48-.81 2.75-2 3.45l1 1.74c1.79-1.04 3-2.97 3-5.19zM12 3C6.48 3 2 7.48 2 13c0 3.7 2.01 6.92 4.99 8.65l1-1.73C5.61 18.53 4 15.96 4 13c0-4.42 3.58-8 8-8s8 3.58 8 8c0 2.96-1.61 5.53-4 6.92l1 1.73c2.99-1.73 5-4.95 5-8.65 0-5.52-4.48-10-10-10z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/editor-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/editor-icons.html
new file mode 100644
index 00000000000..cb6ea04ae17
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/editor-icons.html
@@ -0,0 +1,76 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="editor" size="24">
+<svg><defs>
+<g id="attach-file"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"/></g>
+<g id="attach-money"><path d="M11.8 10.9c-2.27-.59-3-1.2-3-2.15 0-1.09 1.01-1.85 2.7-1.85 1.78 0 2.44.85 2.5 2.1h2.21c-.07-1.72-1.12-3.3-3.21-3.81V3h-3v2.16c-1.94.42-3.5 1.68-3.5 3.61 0 2.31 1.91 3.46 4.7 4.13 2.5.6 3 1.48 3 2.41 0 .69-.49 1.79-2.7 1.79-2.06 0-2.87-.92-2.98-2.1h-2.2c.12 2.19 1.76 3.42 3.68 3.83V21h3v-2.15c1.95-.37 3.5-1.5 3.5-3.55 0-2.84-2.43-3.81-4.7-4.4z"/></g>
+<g id="border-all"><path d="M3 3v18h18V3H3zm8 16H5v-6h6v6zm0-8H5V5h6v6zm8 8h-6v-6h6v6zm0-8h-6V5h6v6z"/></g>
+<g id="border-bottom"><path d="M9 11H7v2h2v-2zm4 4h-2v2h2v-2zM9 3H7v2h2V3zm4 8h-2v2h2v-2zM5 3H3v2h2V3zm8 4h-2v2h2V7zm4 4h-2v2h2v-2zm-4-8h-2v2h2V3zm4 0h-2v2h2V3zm2 10h2v-2h-2v2zm0 4h2v-2h-2v2zM5 7H3v2h2V7zm14-4v2h2V3h-2zm0 6h2V7h-2v2zM5 11H3v2h2v-2zM3 21h18v-2H3v2zm2-6H3v2h2v-2z"/></g>
+<g id="border-clear"><path d="M7 5h2V3H7v2zm0 8h2v-2H7v2zm0 8h2v-2H7v2zm4-4h2v-2h-2v2zm0 4h2v-2h-2v2zm-8 0h2v-2H3v2zm0-4h2v-2H3v2zm0-4h2v-2H3v2zm0-4h2V7H3v2zm0-4h2V3H3v2zm8 8h2v-2h-2v2zm8 4h2v-2h-2v2zm0-4h2v-2h-2v2zm0 8h2v-2h-2v2zm0-12h2V7h-2v2zm-8 0h2V7h-2v2zm8-6v2h2V3h-2zm-8 2h2V3h-2v2zm4 16h2v-2h-2v2zm0-8h2v-2h-2v2zm0-8h2V3h-2v2z"/></g>
+<g id="border-color"><path d="M17.75 7L14 3.25l-10 10V17h3.75l10-10zm2.96-2.96c.39-.39.39-1.02 0-1.41L18.37.29c-.39-.39-1.02-.39-1.41 0L15 2.25 18.75 6l1.96-1.96z"/><path fill-opacity=".36" d="M0 20h24v4H0z"/></g>
+<g id="border-horizontal"><path d="M3 21h2v-2H3v2zM5 7H3v2h2V7zM3 17h2v-2H3v2zm4 4h2v-2H7v2zM5 3H3v2h2V3zm4 0H7v2h2V3zm8 0h-2v2h2V3zm-4 4h-2v2h2V7zm0-4h-2v2h2V3zm6 14h2v-2h-2v2zm-8 4h2v-2h-2v2zm-8-8h18v-2H3v2zM19 3v2h2V3h-2zm0 6h2V7h-2v2zm-8 8h2v-2h-2v2zm4 4h2v-2h-2v2zm4 0h2v-2h-2v2z"/></g>
+<g id="border-inner"><path d="M3 21h2v-2H3v2zm4 0h2v-2H7v2zM5 7H3v2h2V7zM3 17h2v-2H3v2zM9 3H7v2h2V3zM5 3H3v2h2V3zm12 0h-2v2h2V3zm2 6h2V7h-2v2zm0-6v2h2V3h-2zm-4 18h2v-2h-2v2zM13 3h-2v8H3v2h8v8h2v-8h8v-2h-8V3zm6 18h2v-2h-2v2zm0-4h2v-2h-2v2z"/></g>
+<g id="border-left"><path d="M11 21h2v-2h-2v2zm0-4h2v-2h-2v2zm0-12h2V3h-2v2zm0 4h2V7h-2v2zm0 4h2v-2h-2v2zm-4 8h2v-2H7v2zM7 5h2V3H7v2zm0 8h2v-2H7v2zm-4 8h2V3H3v18zM19 9h2V7h-2v2zm-4 12h2v-2h-2v2zm4-4h2v-2h-2v2zm0-14v2h2V3h-2zm0 10h2v-2h-2v2zm0 8h2v-2h-2v2zm-4-8h2v-2h-2v2zm0-8h2V3h-2v2z"/></g>
+<g id="border-outer"><path d="M13 7h-2v2h2V7zm0 4h-2v2h2v-2zm4 0h-2v2h2v-2zM3 3v18h18V3H3zm16 16H5V5h14v14zm-6-4h-2v2h2v-2zm-4-4H7v2h2v-2z"/></g>
+<g id="border-right"><path d="M7 21h2v-2H7v2zM3 5h2V3H3v2zm4 0h2V3H7v2zm0 8h2v-2H7v2zm-4 8h2v-2H3v2zm8 0h2v-2h-2v2zm-8-8h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm8 8h2v-2h-2v2zm4-4h2v-2h-2v2zm4-10v18h2V3h-2zm-4 18h2v-2h-2v2zm0-16h2V3h-2v2zm-4 8h2v-2h-2v2zm0-8h2V3h-2v2zm0 4h2V7h-2v2z"/></g>
+<g id="border-style"><path d="M15 21h2v-2h-2v2zm4 0h2v-2h-2v2zM7 21h2v-2H7v2zm4 0h2v-2h-2v2zm8-4h2v-2h-2v2zm0-4h2v-2h-2v2zM3 3v18h2V5h16V3H3zm16 6h2V7h-2v2z"/></g>
+<g id="border-top"><path d="M7 21h2v-2H7v2zm0-8h2v-2H7v2zm4 0h2v-2h-2v2zm0 8h2v-2h-2v2zm-8-4h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2v-2H3v2zm0-4h2V7H3v2zm8 8h2v-2h-2v2zm8-8h2V7h-2v2zm0 4h2v-2h-2v2zM3 3v2h18V3H3zm16 14h2v-2h-2v2zm-4 4h2v-2h-2v2zM11 9h2V7h-2v2zm8 12h2v-2h-2v2zm-4-8h2v-2h-2v2z"/></g>
+<g id="border-vertical"><path d="M3 9h2V7H3v2zm0-4h2V3H3v2zm4 16h2v-2H7v2zm0-8h2v-2H7v2zm-4 0h2v-2H3v2zm0 8h2v-2H3v2zm0-4h2v-2H3v2zM7 5h2V3H7v2zm12 12h2v-2h-2v2zm-8 4h2V3h-2v18zm8 0h2v-2h-2v2zm0-8h2v-2h-2v2zm0-10v2h2V3h-2zm0 6h2V7h-2v2zm-4-4h2V3h-2v2zm0 16h2v-2h-2v2zm0-8h2v-2h-2v2z"/></g>
+<g id="drag-handle"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></g>
+<g id="format-align-center"><path d="M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z"/></g>
+<g id="format-align-justify"><path d="M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zm0-6v2h18V3H3z"/></g>
+<g id="format-align-left"><path d="M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z"/></g>
+<g id="format-align-right"><path d="M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z"/></g>
+<g id="format-bold"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/></g>
+<g id="format-clear"><path d="M3.27 5L2 6.27l6.97 6.97L6.5 19h3l1.57-3.66L16.73 21 18 19.73 3.55 5.27 3.27 5zM6 5v.18L8.82 8h2.4l-.72 1.68 2.1 2.1L14.21 8H20V5H6z"/></g>
+<g id="format-color-fill"><path d="M16.56 8.94L7.62 0 6.21 1.41l2.38 2.38-5.15 5.15c-.59.59-.59 1.54 0 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10L10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5z"/><path fill-opacity=".36" d="M0 20h24v4H0z"/></g>
+<g id="format-color-reset"><path d="M18 14c0-4-6-10.8-6-10.8s-1.33 1.51-2.73 3.52l8.59 8.59c.09-.42.14-.86.14-1.31zm-.88 3.12L12.5 12.5 5.27 5.27 4 6.55l3.32 3.32C6.55 11.32 6 12.79 6 14c0 3.31 2.69 6 6 6 1.52 0 2.9-.57 3.96-1.5l2.63 2.63 1.27-1.27-2.74-2.74z"/></g>
+<g id="format-color-text"><path fill-opacity=".36" d="M0 20h24v4H0z"/><path d="M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z"/></g>
+<g id="format-indent-decrease"><path d="M11 17h10v-2H11v2zm-8-5l4 4V8l-4 4zm0 9h18v-2H3v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z"/></g>
+<g id="format-indent-increase"><path d="M3 21h18v-2H3v2zM3 8v8l4-4-4-4zm8 9h10v-2H11v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z"/></g>
+<g id="format-italic"><path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z"/></g>
+<g id="format-line-spacing"><path d="M6 7h2.5L5 3.5 1.5 7H4v10H1.5L5 20.5 8.5 17H6V7zm4-2v2h12V5H10zm0 14h12v-2H10v2zm0-6h12v-2H10v2z"/></g>
+<g id="format-list-bulleted"><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12.17c-.74 0-1.33.6-1.33 1.33s.6 1.33 1.33 1.33 1.33-.6 1.33-1.33-.59-1.33-1.33-1.33zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></g>
+<g id="format-list-numbered"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></g>
+<g id="format-paint"><path d="M18 4V3c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6h1v4H9v11c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-9h8V4h-3z"/></g>
+<g id="format-quote"><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></g>
+<g id="format-shapes"><path d="M23 7V1h-6v2H7V1H1v6h2v10H1v6h6v-2h10v2h6v-6h-2V7h2zM3 3h2v2H3V3zm2 18H3v-2h2v2zm12-2H7v-2H5V7h2V5h10v2h2v10h-2v2zm4 2h-2v-2h2v2zM19 5V3h2v2h-2zm-5.27 9h-3.49l-.73 2H7.89l3.4-9h1.4l3.41 9h-1.63l-.74-2zm-3.04-1.26h2.61L12 8.91l-1.31 3.83z"/></g>
+<g id="format-size"><path d="M9 4v3h5v12h3V7h5V4H9zm-6 8h3v7h3v-7h3V9H3v3z"/></g>
+<g id="format-strikethrough"><path d="M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z"/></g>
+<g id="format-textdirection-l-to-r"><path d="M9 10v5h2V4h2v11h2V4h2V2H9C6.79 2 5 3.79 5 6s1.79 4 4 4zm12 8l-4-4v3H5v2h12v3l4-4z"/></g>
+<g id="format-textdirection-r-to-l"><path d="M10 10v5h2V4h2v11h2V4h2V2h-8C7.79 2 6 3.79 6 6s1.79 4 4 4zm-2 7v-3l-4 4 4 4v-3h12v-2H8z"/></g>
+<g id="format-underlined"><path d="M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z"/></g>
+<g id="functions"><path d="M18 4H6v2l6.5 6L6 18v2h12v-3h-7l5-5-5-5h7z"/></g>
+<g id="highlight"><path d="M6 14l3 3v5h6v-5l3-3V9H6zm5-12h2v3h-2zM3.5 5.875L4.914 4.46l2.12 2.122L5.62 7.997zm13.46.71l2.123-2.12 1.414 1.414L18.375 8z"/></g>
+<g id="insert-chart"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></g>
+<g id="insert-comment"><path d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/></g>
+<g id="insert-drive-file"><path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/></g>
+<g id="insert-emoticon"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></g>
+<g id="insert-invitation"><path d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"/></g>
+<g id="insert-link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></g>
+<g id="insert-photo"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></g>
+<g id="linear-scale"><path d="M19.5 9.5c-1.03 0-1.9.62-2.29 1.5h-2.92c-.39-.88-1.26-1.5-2.29-1.5s-1.9.62-2.29 1.5H6.79c-.39-.88-1.26-1.5-2.29-1.5C3.12 9.5 2 10.62 2 12s1.12 2.5 2.5 2.5c1.03 0 1.9-.62 2.29-1.5h2.92c.39.88 1.26 1.5 2.29 1.5s1.9-.62 2.29-1.5h2.92c.39.88 1.26 1.5 2.29 1.5 1.38 0 2.5-1.12 2.5-2.5s-1.12-2.5-2.5-2.5z"/></g>
+<g id="merge-type"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></g>
+<g id="mode-comment"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"/></g>
+<g id="mode-edit"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></g>
+<g id="money-off"><path d="M12.5 6.9c1.78 0 2.44.85 2.5 2.1h2.21c-.07-1.72-1.12-3.3-3.21-3.81V3h-3v2.16c-.53.12-1.03.3-1.48.54l1.47 1.47c.41-.17.91-.27 1.51-.27zM5.33 4.06L4.06 5.33 7.5 8.77c0 2.08 1.56 3.21 3.91 3.91l3.51 3.51c-.34.48-1.05.91-2.42.91-2.06 0-2.87-.92-2.98-2.1h-2.2c.12 2.19 1.76 3.42 3.68 3.83V21h3v-2.15c.96-.18 1.82-.55 2.45-1.12l2.22 2.22 1.27-1.27L5.33 4.06z"/></g>
+<g id="publish"><path d="M5 4v2h14V4H5zm0 10h4v6h6v-6h4l-7-7-7 7z"/></g>
+<g id="short-text"><path d="M4 9h16v2H4zm0 4h10v2H4z"/></g>
+<g id="space-bar"><path d="M18 9v4H6V9H4v6h16V9z"/></g>
+<g id="strikethrough-s"><path d="M7.24 8.75c-.26-.48-.39-1.03-.39-1.67 0-.61.13-1.16.4-1.67.26-.5.63-.93 1.11-1.29.48-.35 1.05-.63 1.7-.83.66-.19 1.39-.29 2.18-.29.81 0 1.54.11 2.21.34.66.22 1.23.54 1.69.94.47.4.83.88 1.08 1.43.25.55.38 1.15.38 1.81h-3.01c0-.31-.05-.59-.15-.85-.09-.27-.24-.49-.44-.68-.2-.19-.45-.33-.75-.44-.3-.1-.66-.16-1.06-.16-.39 0-.74.04-1.03.13-.29.09-.53.21-.72.36-.19.16-.34.34-.44.55-.1.21-.15.43-.15.66 0 .48.25.88.74 1.21.38.25.77.48 1.41.7H7.39c-.05-.08-.11-.17-.15-.25zM21 12v-2H3v2h9.62c.18.07.4.14.55.2.37.17.66.34.87.51.21.17.35.36.43.57.07.2.11.43.11.69 0 .23-.05.45-.14.66-.09.2-.23.38-.42.53-.19.15-.42.26-.71.35-.29.08-.63.13-1.01.13-.43 0-.83-.04-1.18-.13s-.66-.23-.91-.42c-.25-.19-.45-.44-.59-.75-.14-.31-.25-.76-.25-1.21H6.4c0 .55.08 1.13.24 1.58.16.45.37.85.65 1.21.28.35.6.66.98.92.37.26.78.48 1.22.65.44.17.9.3 1.38.39.48.08.96.13 1.44.13.8 0 1.53-.09 2.18-.28s1.21-.45 1.67-.79c.46-.34.82-.77 1.07-1.27s.38-1.07.38-1.71c0-.6-.1-1.14-.31-1.61-.05-.11-.11-.23-.17-.33H21z"/></g>
+<g id="text-fields"><path d="M2.5 4v3h5v12h3V7h5V4h-13zm19 5h-9v3h3v7h3v-7h3V9z"/></g>
+<g id="vertical-align-bottom"><path d="M16 13h-3V3h-2v10H8l4 4 4-4zM4 19v2h16v-2H4z"/></g>
+<g id="vertical-align-center"><path d="M8 19h3v4h2v-4h3l-4-4-4 4zm8-14h-3V1h-2v4H8l4 4 4-4zM4 11v2h16v-2H4z"/></g>
+<g id="vertical-align-top"><path d="M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z"/></g>
+<g id="wrap-text"><path d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3 3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hardware-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hardware-icons.html
new file mode 100644
index 00000000000..ddaddbdae6c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hardware-icons.html
@@ -0,0 +1,63 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="hardware" size="24">
+<svg><defs>
+<g id="cast"><path d="M21 3H3c-1.1 0-2 .9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM1 18v3h3c0-1.66-1.34-3-3-3zm0-4v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm0-4v2c4.97 0 9 4.03 9 9h2c0-6.08-4.93-11-11-11z"/></g>
+<g id="cast-connected"><path d="M1 18v3h3c0-1.66-1.34-3-3-3zm0-4v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm18-7H5v1.63c3.96 1.28 7.09 4.41 8.37 8.37H19V7zM1 10v2c4.97 0 9 4.03 9 9h2c0-6.08-4.93-11-11-11zm20-7H3c-1.1 0-2 .9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="computer"><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z"/></g>
+<g id="desktop-mac"><path d="M21 2H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7l-2 3v1h8v-1l-2-3h7c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 12H3V4h18v10z"/></g>
+<g id="desktop-windows"><path d="M21 2H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7v2H8v2h8v-2h-2v-2h7c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H3V4h18v12z"/></g>
+<g id="developer-board"><path d="M22 9V7h-2V5c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-2h2v-2h-2v-2h2v-2h-2V9h2zm-4 10H4V5h14v14zM6 13h5v4H6zm6-6h4v3h-4zM6 7h5v5H6zm6 4h4v6h-4z"/></g>
+<g id="device-hub"><path d="M17 16l-4-4V8.82C14.16 8.4 15 7.3 15 6c0-1.66-1.34-3-3-3S9 4.34 9 6c0 1.3.84 2.4 2 2.82V12l-4 4H3v5h5v-3.05l4-4.2 4 4.2V21h5v-5h-4z"/></g>
+<g id="devices-other"><path d="M3 6h18V4H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4v-2H3V6zm10 6H9v1.78c-.61.55-1 1.33-1 2.22s.39 1.67 1 2.22V20h4v-1.78c.61-.55 1-1.34 1-2.22s-.39-1.67-1-2.22V12zm-2 5.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM22 8h-6c-.5 0-1 .5-1 1v10c0 .5.5 1 1 1h6c.5 0 1-.5 1-1V9c0-.5-.5-1-1-1zm-1 10h-4v-8h4v8z"/></g>
+<g id="dock"><path d="M8 23h8v-2H8v2zm8-21.99L8 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM16 15H8V5h8v10z"/></g>
+<g id="gamepad"><path d="M15 7.5V2H9v5.5l3 3 3-3zM7.5 9H2v6h5.5l3-3-3-3zM9 16.5V22h6v-5.5l-3-3-3 3zM16.5 9l-3 3 3 3H22V9h-5.5z"/></g>
+<g id="headset"><path d="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h3c1.66 0 3-1.34 3-3v-7c0-4.97-4.03-9-9-9z"/></g>
+<g id="headset-mic"><path d="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h4v1h-7v2h6c1.66 0 3-1.34 3-3V10c0-4.97-4.03-9-9-9z"/></g>
+<g id="keyboard"><path d="M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"/></g>
+<g id="keyboard-arrow-down"><path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z"/></g>
+<g id="keyboard-arrow-left"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/></g>
+<g id="keyboard-arrow-right"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/></g>
+<g id="keyboard-arrow-up"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></g>
+<g id="keyboard-backspace"><path d="M21 11H6.83l3.58-3.59L9 6l-6 6 6 6 1.41-1.41L6.83 13H21z"/></g>
+<g id="keyboard-capslock"><path d="M12 8.41L16.59 13 18 11.59l-6-6-6 6L7.41 13 12 8.41zM6 18h12v-2H6v2z"/></g>
+<g id="keyboard-hide"><path d="M20 3H4c-1.1 0-1.99.9-1.99 2L2 15c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9 3h2v2h-2V6zm0 3h2v2h-2V9zM8 6h2v2H8V6zm0 3h2v2H8V9zm-1 2H5V9h2v2zm0-3H5V6h2v2zm9 7H8v-2h8v2zm0-4h-2V9h2v2zm0-3h-2V6h2v2zm3 3h-2V9h2v2zm0-3h-2V6h2v2zm-7 15l4-4H8l4 4z"/></g>
+<g id="keyboard-return"><path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/></g>
+<g id="keyboard-tab"><path d="M11.59 7.41L15.17 11H1v2h14.17l-3.59 3.59L13 18l6-6-6-6-1.41 1.41zM20 6v12h2V6h-2z"/></g>
+<g id="keyboard-voice"><path d="M12 15c1.66 0 2.99-1.34 2.99-3L15 6c0-1.66-1.34-3-3-3S9 4.34 9 6v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 15 6.7 12H5c0 3.42 2.72 6.23 6 6.72V22h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/></g>
+<g id="laptop"><path d="M20 18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z"/></g>
+<g id="laptop-chromebook"><path d="M22 18V3H2v15H0v2h24v-2h-2zm-8 0h-4v-1h4v1zm6-3H4V5h16v10z"/></g>
+<g id="laptop-mac"><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 5c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2H0c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2h-4zM4 5h16v11H4V5zm8 14c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></g>
+<g id="laptop-windows"><path d="M20 18v-1c1.1 0 1.99-.9 1.99-2L22 5c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2v1H0v2h24v-2h-4zM4 5h16v10H4V5z"/></g>
+<g id="memory"><path d="M15 9H9v6h6V9zm-2 4h-2v-2h2v2zm8-2V9h-2V7c0-1.1-.9-2-2-2h-2V3h-2v2h-2V3H9v2H7c-1.1 0-2 .9-2 2v2H3v2h2v2H3v2h2v2c0 1.1.9 2 2 2h2v2h2v-2h2v2h2v-2h2c1.1 0 2-.9 2-2v-2h2v-2h-2v-2h2zm-4 6H7V7h10v10z"/></g>
+<g id="mouse"><path d="M13 1.07V9h7c0-4.08-3.05-7.44-7-7.93zM4 15c0 4.42 3.58 8 8 8s8-3.58 8-8v-4H4v4zm7-13.93C7.05 1.56 4 4.92 4 9h7V1.07z"/></g>
+<g id="phone-android"><path d="M16 1H8C6.34 1 5 2.34 5 4v16c0 1.66 1.34 3 3 3h8c1.66 0 3-1.34 3-3V4c0-1.66-1.34-3-3-3zm-2 20h-4v-1h4v1zm3.25-3H6.75V4h10.5v14z"/></g>
+<g id="phone-iphone"><path d="M15.5 1h-8C6.12 1 5 2.12 5 3.5v17C5 21.88 6.12 23 7.5 23h8c1.38 0 2.5-1.12 2.5-2.5v-17C18 2.12 16.88 1 15.5 1zm-4 21c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4.5-4H7V4h9v14z"/></g>
+<g id="phonelink"><path d="M4 6h18V4H4c-1.1 0-2 .9-2 2v11H0v3h14v-3H4V6zm19 2h-6c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zm-1 9h-4v-7h4v7z"/></g>
+<g id="phonelink-off"><path d="M22 6V4H6.82l2 2H22zM1.92 1.65L.65 2.92l1.82 1.82C2.18 5.08 2 5.52 2 6v11H0v3h17.73l2.35 2.35 1.27-1.27L3.89 3.62 1.92 1.65zM4 6.27L14.73 17H4V6.27zM23 8h-6c-.55 0-1 .45-1 1v4.18l2 2V10h4v7h-2.18l3 3H23c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1z"/></g>
+<g id="power-input"><path d="M2 9v2h19V9H2zm0 6h5v-2H2v2zm7 0h5v-2H9v2zm7 0h5v-2h-5v2z"/></g>
+<g id="router"><path d="M20.2 5.9l.8-.8C19.6 3.7 17.8 3 16 3s-3.6.7-5 2.1l.8.8C13 4.8 14.5 4.2 16 4.2s3 .6 4.2 1.7zm-.9.8c-.9-.9-2.1-1.4-3.3-1.4s-2.4.5-3.3 1.4l.8.8c.7-.7 1.6-1 2.5-1 .9 0 1.8.3 2.5 1l.8-.8zM19 13h-2V9h-2v4H5c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM8 18H6v-2h2v2zm3.5 0h-2v-2h2v2zm3.5 0h-2v-2h2v2z"/></g>
+<g id="scanner"><path d="M19.8 10.7L4.2 5l-.7 1.9L17.6 12H5c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-5.5c0-.8-.5-1.6-1.2-1.8zM7 17H5v-2h2v2zm12 0H9v-2h10v2z"/></g>
+<g id="security"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"/></g>
+<g id="sim-card"><path d="M19.99 4c0-1.1-.89-2-1.99-2h-8L4 8v12c0 1.1.9 2 2 2h12.01c1.1 0 1.99-.9 1.99-2l-.01-16zM9 19H7v-2h2v2zm8 0h-2v-2h2v2zm-8-4H7v-4h2v4zm4 4h-2v-4h2v4zm0-6h-2v-2h2v2zm4 2h-2v-4h2v4z"/></g>
+<g id="smartphone"><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></g>
+<g id="speaker"><path d="M17 2H7c-1.1 0-2 .9-2 2v16c0 1.1.9 1.99 2 1.99L17 22c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5 2c1.1 0 2 .9 2 2s-.9 2-2 2c-1.11 0-2-.9-2-2s.89-2 2-2zm0 16c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></g>
+<g id="speaker-group"><path d="M18.2 1H9.8C8.81 1 8 1.81 8 2.8v14.4c0 .99.81 1.79 1.8 1.79l8.4.01c.99 0 1.8-.81 1.8-1.8V2.8c0-.99-.81-1.8-1.8-1.8zM14 3c1.1 0 2 .89 2 2s-.9 2-2 2-2-.89-2-2 .9-2 2-2zm0 13.5c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z"/><circle cx="14" cy="12.5" r="2.5"/><path d="M6 5H4v16c0 1.1.89 2 2 2h10v-2H6V5z"/></g>
+<g id="tablet"><path d="M21 4H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h18c1.1 0 1.99-.9 1.99-2L23 6c0-1.1-.9-2-2-2zm-2 14H5V6h14v12z"/></g>
+<g id="tablet-android"><path d="M18 0H6C4.34 0 3 1.34 3 3v18c0 1.66 1.34 3 3 3h12c1.66 0 3-1.34 3-3V3c0-1.66-1.34-3-3-3zm-4 22h-4v-1h4v1zm5.25-3H4.75V3h14.5v16z"/></g>
+<g id="tablet-mac"><path d="M18.5 0h-14C3.12 0 2 1.12 2 2.5v19C2 22.88 3.12 24 4.5 24h14c1.38 0 2.5-1.12 2.5-2.5v-19C21 1.12 19.88 0 18.5 0zm-7 23c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm7.5-4H4V3h15v16z"/></g>
+<g id="toys"><path d="M12 12c0-3 2.5-5.5 5.5-5.5S23 9 23 12H12zm0 0c0 3-2.5 5.5-5.5 5.5S1 15 1 12h11zm0 0c-3 0-5.5-2.5-5.5-5.5S9 1 12 1v11zm0 0c3 0 5.5 2.5 5.5 5.5S15 23 12 23V12z"/></g>
+<g id="tv"><path d="M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12z"/></g>
+<g id="videogame-asset"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-10 7H8v3H6v-3H3v-2h3V8h2v3h3v2zm4.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4-3c-.83 0-1.5-.67-1.5-1.5S18.67 9 19.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="watch"><path d="M20 12c0-2.54-1.19-4.81-3.04-6.27L16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73C18.81 16.81 20 14.54 20 12zM6 12c0-3.31 2.69-6 6-6s6 2.69 6 6-2.69 6-6 6-6-2.69-6-6z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hero.svg
new file mode 100755
index 00000000000..167321c9422
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/hero.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <circle cx="73" cy="24" r="4"/>
+ <path d="M82,33H64V15h18V33z M66,31h14V17H66V31z"/>
+ <circle cx="112.5" cy="24" r="4"/>
+ <circle cx="151" cy="24" r="4"/>
+ <path d="M121,33h-18V15h18V33z M105,31h14V17h-14V31z"/>
+ <path d="M160,33h-18V15h18V33z M144,31h14V17h-14V31z"/>
+ <circle cx="73" cy="62" r="4"/>
+ <path d="M82,71H64V53h18V71z M66,69h14V55H66V69z"/>
+ <circle cx="112.5" cy="62" r="4"/>
+ <path d="M121,71h-18V53h18V71z M105,69h14V55h-14V69z"/>
+ <circle cx="151" cy="62" r="4"/>
+ <path d="M160,71h-18V53h18V71z M144,69h14V55h-14V69z"/>
+ <circle cx="73" cy="102" r="4"/>
+ <path d="M82,111H64V93h18V111z M66,109h14V95H66V109z"/>
+ <circle cx="112.5" cy="102" r="4"/>
+ <path d="M121,111h-18V93h18V111z M105,109h14V95h-14V109z"/>
+ <circle cx="151" cy="102" r="4"/>
+ <path d="M160,111h-18V93h18V111z M144,109h14V95h-14V109z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/image-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/image-icons.html
new file mode 100644
index 00000000000..96dee0697db
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/image-icons.html
@@ -0,0 +1,169 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="image" size="24">
+<svg><defs>
+<g id="add-a-photo"><path d="M3 4V1h2v3h3v2H5v3H3V6H0V4h3zm3 6V7h3V4h7l1.83 2H21c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V10h3zm7 9c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-3.2-5c0 1.77 1.43 3.2 3.2 3.2s3.2-1.43 3.2-3.2-1.43-3.2-3.2-3.2-3.2 1.43-3.2 3.2z"/></g>
+<g id="add-to-photos"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z"/></g>
+<g id="adjust"><path d="M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3-8c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3z"/></g>
+<g id="assistant"><path d="M19 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5.12 10.88L12 17l-1.88-4.12L6 11l4.12-1.88L12 5l1.88 4.12L18 11l-4.12 1.88z"/></g>
+<g id="assistant-photo"><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/></g>
+<g id="audiotrack"><path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/></g>
+<g id="blur-circular"><path d="M10 9c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0 4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zM7 9.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm3 7c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm-3-3c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm3-6c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM14 9c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0-1.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zm3 6c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm0-4c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm2-3.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm0-3.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></g>
+<g id="blur-linear"><path d="M5 17.5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5.67 1.5 1.5 1.5zM9 13c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0-4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zM3 21h18v-2H3v2zM5 9.5c.83 0 1.5-.67 1.5-1.5S5.83 6.5 5 6.5 3.5 7.17 3.5 8 4.17 9.5 5 9.5zm0 4c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5.67 1.5 1.5 1.5zM9 17c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm8-.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM3 3v2h18V3H3zm14 5.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zm0 4c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM13 9c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0 4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0 4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1z"/></g>
+<g id="blur-off"><path d="M14 7c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-.2 4.48l.2.02c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5l.02.2c.09.67.61 1.19 1.28 1.28zM14 3.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zm-4 0c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zm11 7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM10 7c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm8 8c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0-4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0-4c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-4 13.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM2.5 5.27l3.78 3.78L6 9c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1c0-.1-.03-.19-.06-.28l2.81 2.81c-.71.11-1.25.73-1.25 1.47 0 .83.67 1.5 1.5 1.5.74 0 1.36-.54 1.47-1.25l2.81 2.81c-.09-.03-.18-.06-.28-.06-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1c0-.1-.03-.19-.06-.28l3.78 3.78L20 20.23 3.77 4 2.5 5.27zM10 17c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm11-3.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM6 13c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zM3 9.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm7 11c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM6 17c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm-3-3.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5z"/></g>
+<g id="blur-on"><path d="M6 13c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0 4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0-8c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm-3 .5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM6 5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm15 5.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM14 7c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0-3.5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zm-11 10c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm7 7c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm0-17c.28 0 .5-.22.5-.5s-.22-.5-.5-.5-.5.22-.5.5.22.5.5.5zM10 7c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm0 5.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm8 .5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0 4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0-8c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0-4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm3 8.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zM14 17c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm0 3.5c-.28 0-.5.22-.5.5s.22.5.5.5.5-.22.5-.5-.22-.5-.5-.5zm-4-12c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0 8.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1zm4-4.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-4c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"/></g>
+<g id="brightness-1"><circle cx="12" cy="12" r="10"/></g>
+<g id="brightness-2"><path d="M10 2c-1.82 0-3.53.5-5 1.35C7.99 5.08 10 8.3 10 12s-2.01 6.92-5 8.65C6.47 21.5 8.18 22 10 22c5.52 0 10-4.48 10-10S15.52 2 10 2z"/></g>
+<g id="brightness-3"><path d="M9 2c-1.05 0-2.05.16-3 .46 4.06 1.27 7 5.06 7 9.54 0 4.48-2.94 8.27-7 9.54.95.3 1.95.46 3 .46 5.52 0 10-4.48 10-10S14.52 2 9 2z"/></g>
+<g id="brightness-4"><path d="M20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6c3.31 0 6 2.69 6 6s-2.69 6-6 6z"/></g>
+<g id="brightness-5"><path d="M20 15.31L23.31 12 20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"/></g>
+<g id="brightness-6"><path d="M20 15.31L23.31 12 20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69zM12 18V6c3.31 0 6 2.69 6 6s-2.69 6-6 6z"/></g>
+<g id="brightness-7"><path d="M20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-10c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"/></g>
+<g id="broken-image"><path d="M21 5v6.59l-3-3.01-4 4.01-4-4-4 4-3-3.01V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2zm-3 6.42l3 3.01V19c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2v-6.58l3 2.99 4-4 4 4 4-3.99z"/></g>
+<g id="brush"><path d="M7 14c-1.66 0-3 1.34-3 3 0 1.31-1.16 2-2 2 .92 1.22 2.49 2 4 2 2.21 0 4-1.79 4-4 0-1.66-1.34-3-3-3zm13.71-9.37l-1.34-1.34c-.39-.39-1.02-.39-1.41 0L9 12.25 11.75 15l8.96-8.96c.39-.39.39-1.02 0-1.41z"/></g>
+<g id="camera"><path d="M9.4 10.5l4.77-8.26C13.47 2.09 12.75 2 12 2c-2.4 0-4.6.85-6.32 2.25l3.66 6.35.06-.1zM21.54 9c-.92-2.92-3.15-5.26-6-6.34L11.88 9h9.66zm.26 1h-7.49l.29.5 4.76 8.25C21 16.97 22 14.61 22 12c0-.69-.07-1.35-.2-2zM8.54 12l-3.9-6.75C3.01 7.03 2 9.39 2 12c0 .69.07 1.35.2 2h7.49l-1.15-2zm-6.08 3c.92 2.92 3.15 5.26 6 6.34L12.12 15H2.46zm11.27 0l-3.9 6.76c.7.15 1.42.24 2.17.24 2.4 0 4.6-.85 6.32-2.25l-3.66-6.35-.93 1.6z"/></g>
+<g id="camera-alt"><circle cx="12" cy="12" r="3.2"/><path d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/></g>
+<g id="camera-front"><path d="M10 20H5v2h5v2l3-3-3-3v2zm4 0v2h5v-2h-5zM12 8c1.1 0 2-.9 2-2s-.9-2-2-2-1.99.9-1.99 2S10.9 8 12 8zm5-8H7C5.9 0 5 .9 5 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zM7 2h10v10.5c0-1.67-3.33-2.5-5-2.5s-5 .83-5 2.5V2z"/></g>
+<g id="camera-rear"><path d="M10 20H5v2h5v2l3-3-3-3v2zm4 0v2h5v-2h-5zm3-20H7C5.9 0 5 .9 5 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm-5 6c-1.11 0-2-.9-2-2s.89-2 1.99-2 2 .9 2 2C14 5.1 13.1 6 12 6z"/></g>
+<g id="camera-roll"><path d="M14 5c0-1.1-.9-2-2-2h-1V2c0-.55-.45-1-1-1H6c-.55 0-1 .45-1 1v1H4c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2h8V5h-8zm-2 13h-2v-2h2v2zm0-9h-2V7h2v2zm4 9h-2v-2h2v2zm0-9h-2V7h2v2zm4 9h-2v-2h2v2zm0-9h-2V7h2v2z"/></g>
+<g id="center-focus-strong"><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-7 7H3v4c0 1.1.9 2 2 2h4v-2H5v-4zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4z"/></g>
+<g id="center-focus-weak"><path d="M5 15H3v4c0 1.1.9 2 2 2h4v-2H5v-4zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="collections"><path d="M22 16V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2zm-11-4l2.03 2.71L16 11l4 5H8l3-4zM2 6v14c0 1.1.9 2 2 2h14v-2H4V6H2z"/></g>
+<g id="collections-bookmark"><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 10l-2.5-1.5L15 12V4h5v8z"/></g>
+<g id="color-lens"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="colorize"><path d="M20.71 5.63l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z"/></g>
+<g id="compare"><path d="M10 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h5v2h2V1h-2v2zm0 15H5l5-6v6zm9-15h-5v2h5v13l-5-6v9h5c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="control-point"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="control-point-duplicate"><path d="M16 8h-2v3h-3v2h3v3h2v-3h3v-2h-3zM2 12c0-2.79 1.64-5.2 4.01-6.32V3.52C2.52 4.76 0 8.09 0 12s2.52 7.24 6.01 8.48v-2.16C3.64 17.2 2 14.79 2 12zm13-9c-4.96 0-9 4.04-9 9s4.04 9 9 9 9-4.04 9-9-4.04-9-9-9zm0 16c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7z"/></g>
+<g id="crop"><path d="M17 15h2V7c0-1.1-.9-2-2-2H9v2h8v8zM7 17V1H5v4H1v2h4v10c0 1.1.9 2 2 2h10v4h2v-4h4v-2H7z"/></g>
+<g id="crop-16-9"><path d="M19 6H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H5V8h14v8z"/></g>
+<g id="crop-3-2"><path d="M19 4H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H5V6h14v12z"/></g>
+<g id="crop-5-4"><path d="M19 5H5c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 12H5V7h14v10z"/></g>
+<g id="crop-7-5"><path d="M19 7H5c-1.1 0-2 .9-2 2v6c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm0 8H5V9h14v6z"/></g>
+<g id="crop-din"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"/></g>
+<g id="crop-free"><path d="M3 5v4h2V5h4V3H5c-1.1 0-2 .9-2 2zm2 10H3v4c0 1.1.9 2 2 2h4v-2H5v-4zm14 4h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zm0-16h-4v2h4v4h2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="crop-landscape"><path d="M19 5H5c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 12H5V7h14v10z"/></g>
+<g id="crop-original"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5.04-6.71l-2.75 3.54-1.96-2.36L6.5 17h11l-3.54-4.71z"/></g>
+<g id="crop-portrait"><path d="M17 3H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H7V5h10v14z"/></g>
+<g id="crop-rotate"><path d="M7.47 21.49C4.2 19.93 1.86 16.76 1.5 13H0c.51 6.16 5.66 11 11.95 11 .23 0 .44-.02.66-.03L8.8 20.15l-1.33 1.34zM12.05 0c-.23 0-.44.02-.66.04l3.81 3.81 1.33-1.33C19.8 4.07 22.14 7.24 22.5 11H24c-.51-6.16-5.66-11-11.95-11zM16 14h2V8c0-1.11-.9-2-2-2h-6v2h6v6zm-8 2V4H6v2H4v2h2v8c0 1.1.89 2 2 2h8v2h2v-2h2v-2H8z"/></g>
+<g id="crop-square"><path d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H6V6h12v12z"/></g>
+<g id="dehaze"><path d="M2 15.5v2h20v-2H2zm0-5v2h20v-2H2zm0-5v2h20v-2H2z"/></g>
+<g id="details"><path d="M3 4l9 16 9-16H3zm3.38 2h11.25L12 16 6.38 6z"/></g>
+<g id="edit"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></g>
+<g id="exposure"><path d="M15 17v2h2v-2h2v-2h-2v-2h-2v2h-2v2h2zm5-15H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM5 5h6v2H5V5zm15 15H4L20 4v16z"/></g>
+<g id="exposure-neg-1"><path d="M4 11v2h8v-2H4zm15 7h-2V7.38L14 8.4V6.7L18.7 5h.3v13z"/></g>
+<g id="exposure-neg-2"><path d="M15.05 16.29l2.86-3.07c.38-.39.72-.79 1.04-1.18.32-.39.59-.78.82-1.17.23-.39.41-.78.54-1.17s.19-.79.19-1.18c0-.53-.09-1.02-.27-1.46-.18-.44-.44-.81-.78-1.11-.34-.31-.77-.54-1.26-.71-.51-.16-1.08-.24-1.72-.24-.69 0-1.31.11-1.85.32-.54.21-1 .51-1.36.88-.37.37-.65.8-.84 1.3-.18.47-.27.97-.28 1.5h2.14c.01-.31.05-.6.13-.87.09-.29.23-.54.4-.75.18-.21.41-.37.68-.49.27-.12.6-.18.96-.18.31 0 .58.05.81.15.23.1.43.25.59.43.16.18.28.4.37.65.08.25.13.52.13.81 0 .22-.03.43-.08.65-.06.22-.15.45-.29.7-.14.25-.32.53-.56.83-.23.3-.52.65-.88 1.03l-4.17 4.55V18H21v-1.71h-5.95zM2 11v2h8v-2H2z"/></g>
+<g id="exposure-plus-1"><path d="M10 7H8v4H4v2h4v4h2v-4h4v-2h-4V7zm10 11h-2V7.38L15 8.4V6.7L19.7 5h.3v13z"/></g>
+<g id="exposure-plus-2"><path d="M16.05 16.29l2.86-3.07c.38-.39.72-.79 1.04-1.18.32-.39.59-.78.82-1.17.23-.39.41-.78.54-1.17.13-.39.19-.79.19-1.18 0-.53-.09-1.02-.27-1.46-.18-.44-.44-.81-.78-1.11-.34-.31-.77-.54-1.26-.71-.51-.16-1.08-.24-1.72-.24-.69 0-1.31.11-1.85.32-.54.21-1 .51-1.36.88-.37.37-.65.8-.84 1.3-.18.47-.27.97-.28 1.5h2.14c.01-.31.05-.6.13-.87.09-.29.23-.54.4-.75.18-.21.41-.37.68-.49.27-.12.6-.18.96-.18.31 0 .58.05.81.15.23.1.43.25.59.43.16.18.28.4.37.65.08.25.13.52.13.81 0 .22-.03.43-.08.65-.06.22-.15.45-.29.7-.14.25-.32.53-.56.83-.23.3-.52.65-.88 1.03l-4.17 4.55V18H22v-1.71h-5.95zM8 7H6v4H2v2h4v4h2v-4h4v-2H8V7z"/></g>
+<g id="exposure-zero"><path d="M16.14 12.5c0 1-.1 1.85-.3 2.55-.2.7-.48 1.27-.83 1.7-.36.44-.79.75-1.3.95-.51.2-1.07.3-1.7.3-.62 0-1.18-.1-1.69-.3-.51-.2-.95-.51-1.31-.95-.36-.44-.65-1.01-.85-1.7-.2-.7-.3-1.55-.3-2.55v-2.04c0-1 .1-1.85.3-2.55.2-.7.48-1.26.84-1.69.36-.43.8-.74 1.31-.93C10.81 5.1 11.38 5 12 5c.63 0 1.19.1 1.7.29.51.19.95.5 1.31.93.36.43.64.99.84 1.69.2.7.3 1.54.3 2.55v2.04zm-2.11-2.36c0-.64-.05-1.18-.13-1.62-.09-.44-.22-.79-.4-1.06-.17-.27-.39-.46-.64-.58-.25-.13-.54-.19-.86-.19-.32 0-.61.06-.86.18s-.47.31-.64.58c-.17.27-.31.62-.4 1.06s-.13.98-.13 1.62v2.67c0 .64.05 1.18.14 1.62.09.45.23.81.4 1.09s.39.48.64.61.54.19.87.19c.33 0 .62-.06.87-.19s.46-.33.63-.61c.17-.28.3-.64.39-1.09.09-.45.13-.99.13-1.62v-2.66z"/></g>
+<g id="filter"><path d="M15.96 10.29l-2.75 3.54-1.96-2.36L8.5 15h11l-3.54-4.71zM3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14z"/></g>
+<g id="filter-1"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm11 10h2V5h-4v2h2v8zm7-14H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14z"/></g>
+<g id="filter-2"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zm-4-4h-4v-2h2c1.1 0 2-.89 2-2V7c0-1.11-.9-2-2-2h-4v2h4v2h-2c-1.1 0-2 .89-2 2v4h6v-2z"/></g>
+<g id="filter-3"><path d="M21 1H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zM3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm14 8v-1.5c0-.83-.67-1.5-1.5-1.5.83 0 1.5-.67 1.5-1.5V7c0-1.11-.9-2-2-2h-4v2h4v2h-2v2h2v2h-4v2h4c1.1 0 2-.89 2-2z"/></g>
+<g id="filter-4"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm12 10h2V5h-2v4h-2V5h-2v6h4v4zm6-14H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14z"/></g>
+<g id="filter-5"><path d="M21 1H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zM3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm14 8v-2c0-1.11-.9-2-2-2h-2V7h4V5h-6v6h4v2h-4v2h4c1.1 0 2-.89 2-2z"/></g>
+<g id="filter-6"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zm-8-2h2c1.1 0 2-.89 2-2v-2c0-1.11-.9-2-2-2h-2V7h4V5h-4c-1.1 0-2 .89-2 2v6c0 1.11.9 2 2 2zm0-4h2v2h-2v-2z"/></g>
+<g id="filter-7"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zm-8-2l4-8V5h-6v2h4l-4 8h2z"/></g>
+<g id="filter-8"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zm-8-2h2c1.1 0 2-.89 2-2v-1.5c0-.83-.67-1.5-1.5-1.5.83 0 1.5-.67 1.5-1.5V7c0-1.11-.9-2-2-2h-2c-1.1 0-2 .89-2 2v1.5c0 .83.67 1.5 1.5 1.5-.83 0-1.5.67-1.5 1.5V13c0 1.11.9 2 2 2zm0-8h2v2h-2V7zm0 4h2v2h-2v-2z"/></g>
+<g id="filter-9"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14zM15 5h-2c-1.1 0-2 .89-2 2v2c0 1.11.9 2 2 2h2v2h-4v2h4c1.1 0 2-.89 2-2V7c0-1.11-.9-2-2-2zm0 4h-2V7h2v2z"/></g>
+<g id="filter-9-plus"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm11 7V8c0-1.11-.9-2-2-2h-1c-1.1 0-2 .89-2 2v1c0 1.11.9 2 2 2h1v1H9v2h3c1.1 0 2-.89 2-2zm-3-3V8h1v1h-1zm10-8H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 8h-2V7h-2v2h-2v2h2v2h2v-2h2v6H7V3h14v6z"/></g>
+<g id="filter-b-and-w"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16l-7-8v8H5l7-8V5h7v14z"/></g>
+<g id="filter-center-focus"><path d="M5 15H3v4c0 1.1.9 2 2 2h4v-2H5v-4zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zM12 9c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></g>
+<g id="filter-drama"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.61 5.64 5.36 8.04 2.35 8.36 0 10.9 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4h2c0-2.76-1.86-5.08-4.4-5.78C8.61 6.88 10.2 6 12 6c3.03 0 5.5 2.47 5.5 5.5v.5H19c1.65 0 3 1.35 3 3s-1.35 3-3 3z"/></g>
+<g id="filter-frames"><path d="M20 4h-4l-4-4-4 4H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H4V6h4.52l3.52-3.5L15.52 6H20v14zM18 8H6v10h12"/></g>
+<g id="filter-hdr"><path d="M14 6l-3.75 5 2.85 3.8-1.6 1.2C9.81 13.75 7 10 7 10l-6 8h22L14 6z"/></g>
+<g id="filter-none"><path d="M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14z"/></g>
+<g id="filter-tilt-shift"><path d="M11 4.07V2.05c-2.01.2-3.84 1-5.32 2.21L7.1 5.69c1.11-.86 2.44-1.44 3.9-1.62zm7.32.19C16.84 3.05 15.01 2.25 13 2.05v2.02c1.46.18 2.79.76 3.9 1.62l1.42-1.43zM19.93 11h2.02c-.2-2.01-1-3.84-2.21-5.32L18.31 7.1c.86 1.11 1.44 2.44 1.62 3.9zM5.69 7.1L4.26 5.68C3.05 7.16 2.25 8.99 2.05 11h2.02c.18-1.46.76-2.79 1.62-3.9zM4.07 13H2.05c.2 2.01 1 3.84 2.21 5.32l1.43-1.43c-.86-1.1-1.44-2.43-1.62-3.89zM15 12c0-1.66-1.34-3-3-3s-3 1.34-3 3 1.34 3 3 3 3-1.34 3-3zm3.31 4.9l1.43 1.43c1.21-1.48 2.01-3.32 2.21-5.32h-2.02c-.18 1.45-.76 2.78-1.62 3.89zM13 19.93v2.02c2.01-.2 3.84-1 5.32-2.21l-1.43-1.43c-1.1.86-2.43 1.44-3.89 1.62zm-7.32-.19C7.16 20.95 9 21.75 11 21.95v-2.02c-1.46-.18-2.79-.76-3.9-1.62l-1.42 1.43z"/></g>
+<g id="filter-vintage"><path d="M18.7 12.4c-.28-.16-.57-.29-.86-.4.29-.11.58-.24.86-.4 1.92-1.11 2.99-3.12 3-5.19-1.79-1.03-4.07-1.11-6 0-.28.16-.54.35-.78.54.05-.31.08-.63.08-.95 0-2.22-1.21-4.15-3-5.19C10.21 1.85 9 3.78 9 6c0 .32.03.64.08.95-.24-.2-.5-.39-.78-.55-1.92-1.11-4.2-1.03-6 0 0 2.07 1.07 4.08 3 5.19.28.16.57.29.86.4-.29.11-.58.24-.86.4-1.92 1.11-2.99 3.12-3 5.19 1.79 1.03 4.07 1.11 6 0 .28-.16.54-.35.78-.54-.05.32-.08.64-.08.96 0 2.22 1.21 4.15 3 5.19 1.79-1.04 3-2.97 3-5.19 0-.32-.03-.64-.08-.95.24.2.5.38.78.54 1.92 1.11 4.2 1.03 6 0-.01-2.07-1.08-4.08-3-5.19zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z"/></g>
+<g id="flare"><path d="M7 11H1v2h6v-2zm2.17-3.24L7.05 5.64 5.64 7.05l2.12 2.12 1.41-1.41zM13 1h-2v6h2V1zm5.36 6.05l-1.41-1.41-2.12 2.12 1.41 1.41 2.12-2.12zM17 11v2h6v-2h-6zm-5-2c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3zm2.83 7.24l2.12 2.12 1.41-1.41-2.12-2.12-1.41 1.41zm-9.19.71l1.41 1.41 2.12-2.12-1.41-1.41-2.12 2.12zM11 23h2v-6h-2v6z"/></g>
+<g id="flash-auto"><path d="M3 2v12h3v9l7-12H9l4-9H3zm16 0h-2l-3.2 9h1.9l.7-2h3.2l.7 2h1.9L19 2zm-2.15 5.65L18 4l1.15 3.65h-2.3z"/></g>
+<g id="flash-off"><path d="M3.27 3L2 4.27l5 5V13h3v9l3.58-6.14L17.73 20 19 18.73 3.27 3zM17 10h-4l4-8H7v2.18l8.46 8.46L17 10z"/></g>
+<g id="flash-on"><path d="M7 2v11h3v9l7-12h-4l4-8z"/></g>
+<g id="flip"><path d="M15 21h2v-2h-2v2zm4-12h2V7h-2v2zM3 5v14c0 1.1.9 2 2 2h4v-2H5V5h4V3H5c-1.1 0-2 .9-2 2zm16-2v2h2c0-1.1-.9-2-2-2zm-8 20h2V1h-2v22zm8-6h2v-2h-2v2zM15 5h2V3h-2v2zm4 8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2z"/></g>
+<g id="gradient"><path d="M11 9h2v2h-2zm-2 2h2v2H9zm4 0h2v2h-2zm2-2h2v2h-2zM7 9h2v2H7zm12-6H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 18H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm2-7h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V5h14v6z"/></g>
+<g id="grain"><path d="M10 12c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-4 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="grid-off"><path d="M8 4v1.45l2 2V4h4v4h-3.45l2 2H14v1.45l2 2V10h4v4h-3.45l2 2H20v1.45l2 2V4c0-1.1-.9-2-2-2H4.55l2 2H8zm8 0h4v4h-4V4zM1.27 1.27L0 2.55l2 2V20c0 1.1.9 2 2 2h15.46l2 2 1.27-1.27L1.27 1.27zM10 12.55L11.45 14H10v-1.45zm-6-6L5.45 8H4V6.55zM8 20H4v-4h4v4zm0-6H4v-4h3.45l.55.55V14zm6 6h-4v-4h3.45l.55.54V20zm2 0v-1.46L17.46 20H16z"/></g>
+<g id="grid-on"><path d="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM8 20H4v-4h4v4zm0-6H4v-4h4v4zm0-6H4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4z"/></g>
+<g id="hdr-off"><path d="M17.5 15v-2h1.1l.9 2H21l-.9-2.1c.5-.2.9-.8.9-1.4v-1c0-.8-.7-1.5-1.5-1.5H16v4.9l1.1 1.1h.4zm0-4.5h2v1h-2v-1zm-4.5 0v.4l1.5 1.5v-1.9c0-.8-.7-1.5-1.5-1.5h-1.9l1.5 1.5h.4zm-3.5-1l-7-7-1.1 1L6.9 9h-.4v2h-2V9H3v6h1.5v-2.5h2V15H8v-4.9l1.5 1.5V15h3.4l7.6 7.6 1.1-1.1-12.1-12z"/></g>
+<g id="hdr-on"><path d="M21 11.5v-1c0-.8-.7-1.5-1.5-1.5H16v6h1.5v-2h1.1l.9 2H21l-.9-2.1c.5-.3.9-.8.9-1.4zm-1.5 0h-2v-1h2v1zm-13-.5h-2V9H3v6h1.5v-2.5h2V15H8V9H6.5v2zM13 9H9.5v6H13c.8 0 1.5-.7 1.5-1.5v-3c0-.8-.7-1.5-1.5-1.5zm0 4.5h-2v-3h2v3z"/></g>
+<g id="hdr-strong"><path d="M17 6c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zM5 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="hdr-weak"><path d="M5 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm12-2c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm0 10c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z"/></g>
+<g id="healing"><path d="M17.73 12.02l3.98-3.98c.39-.39.39-1.02 0-1.41l-4.34-4.34c-.39-.39-1.02-.39-1.41 0l-3.98 3.98L8 2.29C7.8 2.1 7.55 2 7.29 2c-.25 0-.51.1-.7.29L2.25 6.63c-.39.39-.39 1.02 0 1.41l3.98 3.98L2.25 16c-.39.39-.39 1.02 0 1.41l4.34 4.34c.39.39 1.02.39 1.41 0l3.98-3.98 3.98 3.98c.2.2.45.29.71.29.26 0 .51-.1.71-.29l4.34-4.34c.39-.39.39-1.02 0-1.41l-3.99-3.98zM12 9c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-4.71 1.96L3.66 7.34l3.63-3.63 3.62 3.62-3.62 3.63zM10 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm2 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm2-4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2.66 9.34l-3.63-3.62 3.63-3.63 3.62 3.62-3.62 3.63z"/></g>
+<g id="image"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></g>
+<g id="image-aspect-ratio"><path d="M16 10h-2v2h2v-2zm0 4h-2v2h2v-2zm-8-4H6v2h2v-2zm4 0h-2v2h2v-2zm8-6H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H4V6h16v12z"/></g>
+<g id="iso"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5.5 7.5h2v-2H9v2h2V9H9v2H7.5V9h-2V7.5zM19 19H5L19 5v14zm-2-2v-1.5h-5V17h5z"/></g>
+<g id="landscape"><path d="M14 6l-3.75 5 2.85 3.8-1.6 1.2C9.81 13.75 7 10 7 10l-6 8h22L14 6z"/></g>
+<g id="leak-add"><path d="M6 3H3v3c1.66 0 3-1.34 3-3zm8 0h-2c0 4.97-4.03 9-9 9v2c6.08 0 11-4.93 11-11zm-4 0H8c0 2.76-2.24 5-5 5v2c3.87 0 7-3.13 7-7zm0 18h2c0-4.97 4.03-9 9-9v-2c-6.07 0-11 4.93-11 11zm8 0h3v-3c-1.66 0-3 1.34-3 3zm-4 0h2c0-2.76 2.24-5 5-5v-2c-3.87 0-7 3.13-7 7z"/></g>
+<g id="leak-remove"><path d="M10 3H8c0 .37-.04.72-.12 1.06l1.59 1.59C9.81 4.84 10 3.94 10 3zM3 4.27l2.84 2.84C5.03 7.67 4.06 8 3 8v2c1.61 0 3.09-.55 4.27-1.46L8.7 9.97C7.14 11.24 5.16 12 3 12v2c2.71 0 5.19-.99 7.11-2.62l2.5 2.5C10.99 15.81 10 18.29 10 21h2c0-2.16.76-4.14 2.03-5.69l1.43 1.43C14.55 17.91 14 19.39 14 21h2c0-1.06.33-2.03.89-2.84L19.73 21 21 19.73 4.27 3 3 4.27zM14 3h-2c0 1.5-.37 2.91-1.02 4.16l1.46 1.46C13.42 6.98 14 5.06 14 3zm5.94 13.12c.34-.08.69-.12 1.06-.12v-2c-.94 0-1.84.19-2.66.52l1.6 1.6zm-4.56-4.56l1.46 1.46C18.09 12.37 19.5 12 21 12v-2c-2.06 0-3.98.58-5.62 1.56z"/></g>
+<g id="lens"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"/></g>
+<g id="linked-camera"><circle cx="12" cy="14" r="3.2"/><path d="M16 3.33c2.58 0 4.67 2.09 4.67 4.67H22c0-3.31-2.69-6-6-6v1.33M16 6c1.11 0 2 .89 2 2h1.33c0-1.84-1.49-3.33-3.33-3.33V6"/><path d="M17 9c0-1.11-.89-2-2-2V4H9L7.17 6H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9h-5zm-5 10c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/></g>
+<g id="looks"><path d="M12 10c-3.86 0-7 3.14-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.86-3.14-7-7-7zm0-4C5.93 6 1 10.93 1 17h2c0-4.96 4.04-9 9-9s9 4.04 9 9h2c0-6.07-4.93-11-11-11z"/></g>
+<g id="looks-3"><path d="M19.01 3h-14c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 7.5c0 .83-.67 1.5-1.5 1.5.83 0 1.5.67 1.5 1.5V15c0 1.11-.9 2-2 2h-4v-2h4v-2h-2v-2h2V9h-4V7h4c1.1 0 2 .89 2 2v1.5z"/></g>
+<g id="looks-4"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 14h-2v-4H9V7h2v4h2V7h2v10z"/></g>
+<g id="looks-5"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 6h-4v2h2c1.1 0 2 .89 2 2v2c0 1.11-.9 2-2 2H9v-2h4v-2H9V7h6v2z"/></g>
+<g id="looks-6"><path d="M11 15h2v-2h-2v2zm8-12H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 6h-4v2h2c1.1 0 2 .89 2 2v2c0 1.11-.9 2-2 2h-2c-1.1 0-2-.89-2-2V9c0-1.11.9-2 2-2h4v2z"/></g>
+<g id="looks-one"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14h-2V9h-2V7h4v10z"/></g>
+<g id="looks-two"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 8c0 1.11-.9 2-2 2h-2v2h4v2H9v-4c0-1.11.9-2 2-2h2V9H9V7h4c1.1 0 2 .89 2 2v2z"/></g>
+<g id="loupe"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.49 2 2 6.49 2 12s4.49 10 10 10h8c1.1 0 2-.9 2-2v-8c0-5.51-4.49-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="monochrome-photos"><path d="M20 5h-3.2L15 3H9L7.2 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 14h-8v-1c-2.8 0-5-2.2-5-5s2.2-5 5-5V7h8v12zm-3-6c0-2.8-2.2-5-5-5v1.8c1.8 0 3.2 1.4 3.2 3.2s-1.4 3.2-3.2 3.2V18c2.8 0 5-2.2 5-5zm-8.2 0c0 1.8 1.4 3.2 3.2 3.2V9.8c-1.8 0-3.2 1.4-3.2 3.2z"/></g>
+<g id="movie-creation"><path d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4h-4z"/></g>
+<g id="movie-filter"><path d="M18 4l2 4h-3l-2-4h-2l2 4h-3l-2-4H8l2 4H7L5 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4h-4zm-6.58 11.68L10.37 18l-1.05-2.32L7 14.63l2.32-1.05 1.05-2.32 1.05 2.32 2.32 1.05-2.32 1.05zm3.69-3.47l-.53 1.16-.53-1.16-1.16-.53 1.16-.53.53-1.15.53 1.16 1.16.53-1.16.52z"/></g>
+<g id="music-note"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></g>
+<g id="nature"><path d="M13 16.12c3.47-.41 6.17-3.36 6.17-6.95 0-3.87-3.13-7-7-7s-7 3.13-7 7c0 3.47 2.52 6.34 5.83 6.89V20H5v2h14v-2h-6v-3.88z"/></g>
+<g id="nature-people"><path d="M22.17 9.17c0-3.87-3.13-7-7-7s-7 3.13-7 7c0 3.47 2.52 6.34 5.83 6.89V20H6v-3h1v-4c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v4h1v5h16v-2h-3v-3.88c3.47-.41 6.17-3.36 6.17-6.95zM4.5 11c.83 0 1.5-.67 1.5-1.5S5.33 8 4.5 8 3 8.67 3 9.5 3.67 11 4.5 11z"/></g>
+<g id="navigate-before"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></g>
+<g id="navigate-next"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></g>
+<g id="palette"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="panorama"><path d="M23 18V6c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zM8.5 12.5l2.5 3.01L14.5 11l4.5 6H5l3.5-4.5z"/></g>
+<g id="panorama-fish-eye"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="panorama-horizontal"><path d="M20 6.54v10.91c-2.6-.77-5.28-1.16-8-1.16-2.72 0-5.4.39-8 1.16V6.54c2.6.77 5.28 1.16 8 1.16 2.72.01 5.4-.38 8-1.16M21.43 4c-.1 0-.2.02-.31.06C18.18 5.16 15.09 5.7 12 5.7c-3.09 0-6.18-.55-9.12-1.64-.11-.04-.22-.06-.31-.06-.34 0-.57.23-.57.63v14.75c0 .39.23.62.57.62.1 0 .2-.02.31-.06 2.94-1.1 6.03-1.64 9.12-1.64 3.09 0 6.18.55 9.12 1.64.11.04.21.06.31.06.33 0 .57-.23.57-.63V4.63c0-.4-.24-.63-.57-.63z"/></g>
+<g id="panorama-vertical"><path d="M19.94 21.12c-1.1-2.94-1.64-6.03-1.64-9.12 0-3.09.55-6.18 1.64-9.12.04-.11.06-.22.06-.31 0-.34-.23-.57-.63-.57H4.63c-.4 0-.63.23-.63.57 0 .1.02.2.06.31C5.16 5.82 5.71 8.91 5.71 12c0 3.09-.55 6.18-1.64 9.12-.05.11-.07.22-.07.31 0 .33.23.57.63.57h14.75c.39 0 .63-.24.63-.57-.01-.1-.03-.2-.07-.31zM6.54 20c.77-2.6 1.16-5.28 1.16-8 0-2.72-.39-5.4-1.16-8h10.91c-.77 2.6-1.16 5.28-1.16 8 0 2.72.39 5.4 1.16 8H6.54z"/></g>
+<g id="panorama-wide-angle"><path d="M12 6c2.45 0 4.71.2 7.29.64.47 1.78.71 3.58.71 5.36 0 1.78-.24 3.58-.71 5.36-2.58.44-4.84.64-7.29.64s-4.71-.2-7.29-.64C4.24 15.58 4 13.78 4 12c0-1.78.24-3.58.71-5.36C7.29 6.2 9.55 6 12 6m0-2c-2.73 0-5.22.24-7.95.72l-.93.16-.25.9C2.29 7.85 2 9.93 2 12s.29 4.15.87 6.22l.25.89.93.16c2.73.49 5.22.73 7.95.73s5.22-.24 7.95-.72l.93-.16.25-.89c.58-2.08.87-4.16.87-6.23s-.29-4.15-.87-6.22l-.25-.89-.93-.16C17.22 4.24 14.73 4 12 4z"/></g>
+<g id="photo"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></g>
+<g id="photo-album"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4zm0 15l3-3.86 2.14 2.58 3-3.86L18 19H6z"/></g>
+<g id="photo-camera"><circle cx="12" cy="12" r="3.2"/><path d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/></g>
+<g id="photo-filter"><path d="M17.13 8.9l.59-1.3 1.3-.6-1.3-.59-.59-1.3-.59 1.3-1.31.59 1.31.6zm-4.74-2.37l-1.18 2.61-2.61 1.18 2.61 1.18 1.18 2.61 1.19-2.61 2.6-1.18-2.6-1.18zM19.02 10v9H5V5h9V3H5.02c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-9h-2z"/></g>
+<g id="photo-library"><path d="M22 16V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2zm-11-4l2.03 2.71L16 11l4 5H8l3-4zM2 6v14c0 1.1.9 2 2 2h14v-2H4V6H2z"/></g>
+<g id="photo-size-select-actual"><path d="M21 3H3C2 3 1 4 1 5v14c0 1.1.9 2 2 2h18c1 0 2-1 2-2V5c0-1-1-2-2-2zM5 17l3.5-4.5 2.5 3.01L14.5 11l4.5 6H5z"/></g>
+<g id="photo-size-select-large"><path d="M21 15h2v2h-2v-2zm0-4h2v2h-2v-2zm2 8h-2v2c1 0 2-1 2-2zM13 3h2v2h-2V3zm8 4h2v2h-2V7zm0-4v2h2c0-1-1-2-2-2zM1 7h2v2H1V7zm16-4h2v2h-2V3zm0 16h2v2h-2v-2zM3 3C2 3 1 4 1 5h2V3zm6 0h2v2H9V3zM5 3h2v2H5V3zm-4 8v8c0 1.1.9 2 2 2h12V11H1zm2 8l2.5-3.21 1.79 2.15 2.5-3.22L13 19H3z"/></g>
+<g id="photo-size-select-small"><path d="M23 15h-2v2h2v-2zm0-4h-2v2h2v-2zm0 8h-2v2c1 0 2-1 2-2zM15 3h-2v2h2V3zm8 4h-2v2h2V7zm-2-4v2h2c0-1-1-2-2-2zM3 21h8v-6H1v4c0 1.1.9 2 2 2zM3 7H1v2h2V7zm12 12h-2v2h2v-2zm4-16h-2v2h2V3zm0 16h-2v2h2v-2zM3 3C2 3 1 4 1 5h2V3zm0 8H1v2h2v-2zm8-8H9v2h2V3zM7 3H5v2h2V3z"/></g>
+<g id="picture-as-pdf"><path d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z"/></g>
+<g id="portrait"><path d="M12 12.25c1.24 0 2.25-1.01 2.25-2.25S13.24 7.75 12 7.75 9.75 8.76 9.75 10s1.01 2.25 2.25 2.25zm4.5 4c0-1.5-3-2.25-4.5-2.25s-4.5.75-4.5 2.25V17h9v-.75zM19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"/></g>
+<g id="remove-red-eye"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></g>
+<g id="rotate-90-degrees-ccw"><path d="M7.34 6.41L.86 12.9l6.49 6.48 6.49-6.48-6.5-6.49zM3.69 12.9l3.66-3.66L11 12.9l-3.66 3.66-3.65-3.66zm15.67-6.26C17.61 4.88 15.3 4 13 4V.76L8.76 5 13 9.24V6c1.79 0 3.58.68 4.95 2.05 2.73 2.73 2.73 7.17 0 9.9C16.58 19.32 14.79 20 13 20c-.97 0-1.94-.21-2.84-.61l-1.49 1.49C10.02 21.62 11.51 22 13 22c2.3 0 4.61-.88 6.36-2.64 3.52-3.51 3.52-9.21 0-12.72z"/></g>
+<g id="rotate-left"><path d="M7.11 8.53L5.7 7.11C4.8 8.27 4.24 9.61 4.07 11h2.02c.14-.87.49-1.72 1.02-2.47zM6.09 13H4.07c.17 1.39.72 2.73 1.62 3.89l1.41-1.42c-.52-.75-.87-1.59-1.01-2.47zm1.01 5.32c1.16.9 2.51 1.44 3.9 1.61V17.9c-.87-.15-1.71-.49-2.46-1.03L7.1 18.32zM13 4.07V1L8.45 5.55 13 10V6.09c2.84.48 5 2.94 5 5.91s-2.16 5.43-5 5.91v2.02c3.95-.49 7-3.85 7-7.93s-3.05-7.44-7-7.93z"/></g>
+<g id="rotate-right"><path d="M15.55 5.55L11 1v3.07C7.06 4.56 4 7.92 4 12s3.05 7.44 7 7.93v-2.02c-2.84-.48-5-2.94-5-5.91s2.16-5.43 5-5.91V10l4.55-4.45zM19.93 11c-.17-1.39-.72-2.73-1.62-3.89l-1.42 1.42c.54.75.88 1.6 1.02 2.47h2.02zM13 17.9v2.02c1.39-.17 2.74-.71 3.9-1.61l-1.44-1.44c-.75.54-1.59.89-2.46 1.03zm3.89-2.42l1.42 1.41c.9-1.16 1.45-2.5 1.62-3.89h-2.02c-.14.87-.48 1.72-1.02 2.48z"/></g>
+<g id="slideshow"><path d="M10 8v8l5-4-5-4zm9-5H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"/></g>
+<g id="straighten"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z"/></g>
+<g id="style"><path d="M2.53 19.65l1.34.56v-9.03l-2.43 5.86c-.41 1.02.08 2.19 1.09 2.61zm19.5-3.7L17.07 3.98c-.31-.75-1.04-1.21-1.81-1.23-.26 0-.53.04-.79.15L7.1 5.95c-.75.31-1.21 1.03-1.23 1.8-.01.27.04.54.15.8l4.96 11.97c.31.76 1.05 1.22 1.83 1.23.26 0 .52-.05.77-.15l7.36-3.05c1.02-.42 1.51-1.59 1.09-2.6zM7.88 8.75c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-2 11c0 1.1.9 2 2 2h1.45l-3.45-8.34v6.34z"/></g>
+<g id="switch-camera"><path d="M20 4h-3.17L15 2H9L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-5 11.5V13H9v2.5L5.5 12 9 8.5V11h6V8.5l3.5 3.5-3.5 3.5z"/></g>
+<g id="switch-video"><path d="M18 9.5V6c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-3.5l4 4v-13l-4 4zm-5 6V13H7v2.5L3.5 12 7 8.5V11h6V8.5l3.5 3.5-3.5 3.5z"/></g>
+<g id="tag-faces"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></g>
+<g id="texture"><path d="M19.51 3.08L3.08 19.51c.09.34.27.65.51.9.25.24.56.42.9.51L20.93 4.49c-.19-.69-.73-1.23-1.42-1.41zM11.88 3L3 11.88v2.83L14.71 3h-2.83zM5 3c-1.1 0-2 .9-2 2v2l4-4H5zm14 18c.55 0 1.05-.22 1.41-.59.37-.36.59-.86.59-1.41v-2l-4 4h2zm-9.71 0h2.83L21 12.12V9.29L9.29 21z"/></g>
+<g id="timelapse"><path d="M16.24 7.76C15.07 6.59 13.54 6 12 6v6l-4.24 4.24c2.34 2.34 6.14 2.34 8.49 0 2.34-2.34 2.34-6.14-.01-8.48zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g>
+<g id="timer"><path d="M15 1H9v2h6V1zm-4 13h2V8h-2v6zm8.03-6.61l1.42-1.42c-.43-.51-.9-.99-1.41-1.41l-1.42 1.42C16.07 4.74 14.12 4 12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9 9-4.03 9-9c0-2.12-.74-4.07-1.97-5.61zM12 20c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="timer-10"><path d="M0 7.72V9.4l3-1V18h2V6h-.25L0 7.72zm23.78 6.65c-.14-.28-.35-.53-.63-.74-.28-.21-.61-.39-1.01-.53s-.85-.27-1.35-.38c-.35-.07-.64-.15-.87-.23-.23-.08-.41-.16-.55-.25-.14-.09-.23-.19-.28-.3-.05-.11-.08-.24-.08-.39 0-.14.03-.28.09-.41.06-.13.15-.25.27-.34.12-.1.27-.18.45-.24s.4-.09.64-.09c.25 0 .47.04.66.11.19.07.35.17.48.29.13.12.22.26.29.42.06.16.1.32.1.49h1.95c0-.39-.08-.75-.24-1.09-.16-.34-.39-.63-.69-.88-.3-.25-.66-.44-1.09-.59C21.49 9.07 21 9 20.46 9c-.51 0-.98.07-1.39.21-.41.14-.77.33-1.06.57-.29.24-.51.52-.67.84-.16.32-.23.65-.23 1.01s.08.69.23.96c.15.28.36.52.64.73.27.21.6.38.98.53.38.14.81.26 1.27.36.39.08.71.17.95.26s.43.19.57.29c.13.1.22.22.27.34.05.12.07.25.07.39 0 .32-.13.57-.4.77-.27.2-.66.29-1.17.29-.22 0-.43-.02-.64-.08-.21-.05-.4-.13-.56-.24-.17-.11-.3-.26-.41-.44-.11-.18-.17-.41-.18-.67h-1.89c0 .36.08.71.24 1.05.16.34.39.65.7.93.31.27.69.49 1.15.66.46.17.98.25 1.58.25.53 0 1.01-.06 1.44-.19.43-.13.8-.31 1.11-.54.31-.23.54-.51.71-.83.17-.32.25-.67.25-1.06-.02-.4-.09-.74-.24-1.02zm-9.96-7.32c-.34-.4-.75-.7-1.23-.88-.47-.18-1.01-.27-1.59-.27-.58 0-1.11.09-1.59.27-.48.18-.89.47-1.23.88-.34.41-.6.93-.79 1.59-.18.65-.28 1.45-.28 2.39v1.92c0 .94.09 1.74.28 2.39.19.66.45 1.19.8 1.6.34.41.75.71 1.23.89.48.18 1.01.28 1.59.28.59 0 1.12-.09 1.59-.28.48-.18.88-.48 1.22-.89.34-.41.6-.94.78-1.6.18-.65.28-1.45.28-2.39v-1.92c0-.94-.09-1.74-.28-2.39-.18-.66-.44-1.19-.78-1.59zm-.92 6.17c0 .6-.04 1.11-.12 1.53-.08.42-.2.76-.36 1.02-.16.26-.36.45-.59.57-.23.12-.51.18-.82.18-.3 0-.58-.06-.82-.18s-.44-.31-.6-.57c-.16-.26-.29-.6-.38-1.02-.09-.42-.13-.93-.13-1.53v-2.5c0-.6.04-1.11.13-1.52.09-.41.21-.74.38-1 .16-.25.36-.43.6-.55.24-.11.51-.17.81-.17.31 0 .58.06.81.17.24.11.44.29.6.55.16.25.29.58.37.99.08.41.13.92.13 1.52v2.51z"/></g>
+<g id="timer-3"><path d="M11.61 12.97c-.16-.24-.36-.46-.62-.65-.25-.19-.56-.35-.93-.48.3-.14.57-.3.8-.5.23-.2.42-.41.57-.64.15-.23.27-.46.34-.71.08-.24.11-.49.11-.73 0-.55-.09-1.04-.28-1.46-.18-.42-.44-.77-.78-1.06-.33-.28-.73-.5-1.2-.64-.45-.13-.97-.2-1.53-.2-.55 0-1.06.08-1.52.24-.47.17-.87.4-1.2.69-.33.29-.6.63-.78 1.03-.2.39-.29.83-.29 1.29h1.98c0-.26.05-.49.14-.69.09-.2.22-.38.38-.52.17-.14.36-.25.58-.33.22-.08.46-.12.73-.12.61 0 1.06.16 1.36.47.3.31.44.75.44 1.32 0 .27-.04.52-.12.74-.08.22-.21.41-.38.57-.17.16-.38.28-.63.37-.25.09-.55.13-.89.13H6.72v1.57H7.9c.34 0 .64.04.91.11.27.08.5.19.69.35.19.16.34.36.44.61.1.24.16.54.16.87 0 .62-.18 1.09-.53 1.42-.35.33-.84.49-1.45.49-.29 0-.56-.04-.8-.13-.24-.08-.44-.2-.61-.36-.17-.16-.3-.34-.39-.56-.09-.22-.14-.46-.14-.72H4.19c0 .55.11 1.03.32 1.45.21.42.5.77.86 1.05s.77.49 1.24.63.96.21 1.48.21c.57 0 1.09-.08 1.58-.23.49-.15.91-.38 1.26-.68.36-.3.64-.66.84-1.1.2-.43.3-.93.3-1.48 0-.29-.04-.58-.11-.86-.08-.25-.19-.51-.35-.76zm9.26 1.4c-.14-.28-.35-.53-.63-.74-.28-.21-.61-.39-1.01-.53s-.85-.27-1.35-.38c-.35-.07-.64-.15-.87-.23-.23-.08-.41-.16-.55-.25-.14-.09-.23-.19-.28-.3-.05-.11-.08-.24-.08-.39s.03-.28.09-.41c.06-.13.15-.25.27-.34.12-.1.27-.18.45-.24s.4-.09.64-.09c.25 0 .47.04.66.11.19.07.35.17.48.29.13.12.22.26.29.42.06.16.1.32.1.49h1.95c0-.39-.08-.75-.24-1.09-.16-.34-.39-.63-.69-.88-.3-.25-.66-.44-1.09-.59-.43-.15-.92-.22-1.46-.22-.51 0-.98.07-1.39.21-.41.14-.77.33-1.06.57-.29.24-.51.52-.67.84-.16.32-.23.65-.23 1.01s.08.68.23.96c.15.28.37.52.64.73.27.21.6.38.98.53.38.14.81.26 1.27.36.39.08.71.17.95.26s.43.19.57.29c.13.1.22.22.27.34.05.12.07.25.07.39 0 .32-.13.57-.4.77-.27.2-.66.29-1.17.29-.22 0-.43-.02-.64-.08-.21-.05-.4-.13-.56-.24-.17-.11-.3-.26-.41-.44-.11-.18-.17-.41-.18-.67h-1.89c0 .36.08.71.24 1.05.16.34.39.65.7.93.31.27.69.49 1.15.66.46.17.98.25 1.58.25.53 0 1.01-.06 1.44-.19.43-.13.8-.31 1.11-.54.31-.23.54-.51.71-.83.17-.32.25-.67.25-1.06-.02-.4-.09-.74-.24-1.02z"/></g>
+<g id="timer-off"><path d="M19.04 4.55l-1.42 1.42C16.07 4.74 14.12 4 12 4c-1.83 0-3.53.55-4.95 1.48l1.46 1.46C9.53 6.35 10.73 6 12 6c3.87 0 7 3.13 7 7 0 1.27-.35 2.47-.94 3.49l1.45 1.45C20.45 16.53 21 14.83 21 13c0-2.12-.74-4.07-1.97-5.61l1.42-1.42-1.41-1.42zM15 1H9v2h6V1zm-4 8.44l2 2V8h-2v1.44zM3.02 4L1.75 5.27 4.5 8.03C3.55 9.45 3 11.16 3 13c0 4.97 4.02 9 9 9 1.84 0 3.55-.55 4.98-1.5l2.5 2.5 1.27-1.27-7.71-7.71L3.02 4zM12 20c-3.87 0-7-3.13-7-7 0-1.28.35-2.48.95-3.52l9.56 9.56c-1.03.61-2.23.96-3.51.96z"/></g>
+<g id="tonality"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.94-.49-7-3.85-7-7.93s3.05-7.44 7-7.93v15.86zm2-15.86c1.03.13 2 .45 2.87.93H13v-.93zM13 7h5.24c.25.31.48.65.68 1H13V7zm0 3h6.74c.08.33.15.66.19 1H13v-1zm0 9.93V19h2.87c-.87.48-1.84.8-2.87.93zM18.24 17H13v-1h5.92c-.2.35-.43.69-.68 1zm1.5-3H13v-1h6.93c-.04.34-.11.67-.19 1z"/></g>
+<g id="transform"><path d="M22 18v-2H8V4h2L7 1 4 4h2v2H2v2h4v8c0 1.1.9 2 2 2h8v2h-2l3 3 3-3h-2v-2h4zM10 8h6v6h2V8c0-1.1-.9-2-2-2h-6v2z"/></g>
+<g id="tune"><path d="M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z"/></g>
+<g id="view-comfy"><path d="M3 9h4V5H3v4zm0 5h4v-4H3v4zm5 0h4v-4H8v4zm5 0h4v-4h-4v4zM8 9h4V5H8v4zm5-4v4h4V5h-4zm5 9h4v-4h-4v4zM3 19h4v-4H3v4zm5 0h4v-4H8v4zm5 0h4v-4h-4v4zm5 0h4v-4h-4v4zm0-14v4h4V5h-4z"/></g>
+<g id="view-compact"><path d="M3 19h6v-7H3v7zm7 0h12v-7H10v7zM3 5v6h19V5H3z"/></g>
+<g id="vignette"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9 15c-4.42 0-8-2.69-8-6s3.58-6 8-6 8 2.69 8 6-3.58 6-8 6z"/></g>
+<g id="wb-auto"><path d="M6.85 12.65h2.3L8 9l-1.15 3.65zM22 7l-1.2 6.29L19.3 7h-1.6l-1.49 6.29L15 7h-.76C12.77 5.17 10.53 4 8 4c-4.42 0-8 3.58-8 8s3.58 8 8 8c3.13 0 5.84-1.81 7.15-4.43l.1.43H17l1.5-6.1L20 16h1.75l2.05-9H22zm-11.7 9l-.7-2H6.4l-.7 2H3.8L7 7h2l3.2 9h-1.9z"/></g>
+<g id="wb-cloudy"><path d="M19.36 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.64-4.96z"/></g>
+<g id="wb-incandescent"><path d="M3.55 18.54l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8zM11 22.45h2V19.5h-2v2.95zM4 10.5H1v2h3v-2zm11-4.19V1.5H9v4.81C7.21 7.35 6 9.28 6 11.5c0 3.31 2.69 6 6 6s6-2.69 6-6c0-2.22-1.21-4.15-3-5.19zm5 4.19v2h3v-2h-3zm-2.76 7.66l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4z"/></g>
+<g id="wb-iridescent"><path d="M5 14.5h14v-6H5v6zM11 .55V3.5h2V.55h-2zm8.04 2.5l-1.79 1.79 1.41 1.41 1.8-1.79-1.42-1.41zM13 22.45V19.5h-2v2.95h2zm7.45-3.91l-1.8-1.79-1.41 1.41 1.79 1.8 1.42-1.42zM3.55 4.46l1.79 1.79 1.41-1.41-1.79-1.79-1.41 1.41zm1.41 15.49l1.79-1.8-1.41-1.41-1.79 1.79 1.41 1.42z"/></g>
+<g id="wb-sunny"><path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/index.html
new file mode 100644
index 00000000000..cea02f96d91
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/index.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/iron-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/iron-icons.html
new file mode 100644
index 00000000000..c219575b3bc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/iron-icons.html
@@ -0,0 +1,338 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!--
+
+`iron-icons` is a utility import that includes the definition for the `iron-icon` element, `iron-iconset-svg` element, as well as an import for the default icon set.
+
+The `iron-icons` directory also includes imports for additional icon sets that can be loaded into your project.
+
+Example loading icon set:
+
+ <link rel="import" href="../iron-icons/maps-icons.html">
+
+To use an icon from one of these sets, first prefix your `iron-icon` with the icon set name, followed by a colon, ":", and then the icon id.
+
+Example using the directions-bus icon from the maps icon set:
+
+ <iron-icon icon="maps:directions-bus"></iron-icon>
+
+
+See [iron-icon](#iron-icon) for more information about working with icons.
+
+See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for more information about how to create a custom iconset.
+
+@group Iron Elements
+@pseudoElement iron-icons
+@demo demo/index.html
+-->
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="icons" size="24">
+<svg><defs>
+<g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"/></g>
+<g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"/></g>
+<g id="accessible"><circle cx="12" cy="4" r="2"/><path d="M19 13v-2c-1.54.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.01H13c-.35-.2-.75-.3-1.19-.26C10.76 7.11 10 8.04 10 9.09V15c0 1.1.9 2 2 2h5v5h2v-5.5c0-1.1-.9-2-2-2h-3v-3.45c1.29 1.07 3.25 1.94 5 1.95zm-6.17 5c-.41 1.16-1.52 2-2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.41 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.76 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07z"/></g>
+<g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"/></g>
+<g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"/></g>
+<g id="account-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></g>
+<g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
+<g id="add-alert"><path d="M10.01 21.01c0 1.1.89 1.99 1.99 1.99s1.99-.89 1.99-1.99h-3.98zm8.87-4.19V11c0-3.25-2.25-5.97-5.29-6.69v-.72C13.59 2.71 12.88 2 12 2s-1.59.71-1.59 1.59v.72C7.37 5.03 5.12 7.75 5.12 11v5.82L3 18.94V20h18v-1.06l-2.12-2.12zM16 13.01h-3v3h-2v-3H8V11h3V8h2v3h3v2.01z"/></g>
+<g id="add-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
+<g id="add-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
+<g id="add-circle-outline"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"/></g>
+<g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"/></g>
+<g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C10.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1.65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"/></g>
+<g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"/></g>
+<g id="all-out"><path d="M16.21 4.16l4 4v-4zm4 12l-4 4h4zm-12 4l-4-4v4zm-4-12l4-4h-4zm12.95-.95c-2.73-2.73-7.17-2.73-9.9 0s-2.73 7.17 0 9.9 7.17 2.73 9.9 0 2.73-7.16 0-9.9zm-1.1 8.8c-2.13 2.13-5.57 2.13-7.7 0s-2.13-5.57 0-7.7 5.57-2.13 7.7 0 2.13 5.57 0 7.7z"/></g>
+<g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g>
+<g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"/></g>
+<g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></g>
+<g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"/></g>
+<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></g>
+<g id="arrow-downward"><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"/></g>
+<g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"/></g>
+<g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"/></g>
+<g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"/></g>
+<g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></g>
+<g id="arrow-upward"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></g>
+<g id="aspect-ratio"><path d="M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"/></g>
+<g id="assessment"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></g>
+<g id="assignment"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/></g>
+<g id="assignment-ind"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 4c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1.4c0-2 4-3.1 6-3.1s6 1.1 6 3.1V19z"/></g>
+<g id="assignment-late"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-6 15h-2v-2h2v2zm0-4h-2V8h2v6zm-1-9c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></g>
+<g id="assignment-return"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm4 12h-4v3l-5-5 5-5v3h4v4z"/></g>
+<g id="assignment-returned"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 15l-5-5h3V9h4v4h3l-5 5z"/></g>
+<g id="assignment-turned-in"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 14l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"/></g>
+<g id="attachment"><path d="M2 12.5C2 9.46 4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v2H9.41c-.55 0-.55 1 0 1H18c1.1 0 2-.9 2-2s-.9-2-2-2H7.5C5.57 9 4 10.57 4 12.5S5.57 16 7.5 16H17v2H7.5C4.46 18 2 15.54 2 12.5z"/></g>
+<g id="autorenew"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/></g>
+<g id="backspace"><path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z"/></g>
+<g id="backup"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"/></g>
+<g id="block"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z"/></g>
+<g id="book"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"/></g>
+<g id="bookmark"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></g>
+<g id="bookmark-border"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"/></g>
+<g id="bug-report"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></g>
+<g id="build"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></g>
+<g id="cached"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z"/></g>
+<g id="camera-enhance"><path d="M9 3L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2h-3.17L15 3H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-1l1.25-2.75L16 13l-2.75-1.25L12 9l-1.25 2.75L8 13l2.75 1.25z"/></g>
+<g id="cancel"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></g>
+<g id="card-giftcard"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"/></g>
+<g id="card-membership"><path d="M20 2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h4v5l4-2 4 2v-5h4c1.11 0 2-.89 2-2V4c0-1.11-.89-2-2-2zm0 13H4v-2h16v2zm0-5H4V4h16v6z"/></g>
+<g id="card-travel"><path d="M20 6h-3V4c0-1.11-.89-2-2-2H9c-1.11 0-2 .89-2 2v2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zM9 4h6v2H9V4zm11 15H4v-2h16v2zm0-5H4V8h3v2h2V8h6v2h2V8h3v6z"/></g>
+<g id="change-history"><path d="M12 7.77L18.39 18H5.61L12 7.77M12 4L2 20h20L12 4z"/></g>
+<g id="check"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></g>
+<g id="check-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></g>
+<g id="check-box-outline-blank"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="check-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></g>
+<g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></g>
+<g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></g>
+<g id="chrome-reader-mode"><path d="M13 12h7v1.5h-7zm0-2.5h7V11h-7zm0 5h7V16h-7zM21 4H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 15h-9V6h9v13z"/></g>
+<g id="class"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"/></g>
+<g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></g>
+<g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></g>
+<g id="cloud"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></g>
+<g id="cloud-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.5 14H8c-1.66 0-3-1.34-3-3s1.34-3 3-3l.14.01C8.58 8.28 10.13 7 12 7c2.21 0 4 1.79 4 4h.5c1.38 0 2.5 1.12 2.5 2.5S17.88 16 16.5 16z"/></g>
+<g id="cloud-done"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM10 17l-3.5-3.5 1.41-1.41L10 14.17 15.18 9l1.41 1.41L10 17z"/></g>
+<g id="cloud-download"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"/></g>
+<g id="cloud-off"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4c-1.48 0-2.85.43-4.01 1.17l1.46 1.46C10.21 6.23 11.08 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45C23.16 18.16 24 16.68 24 15c0-2.64-2.05-4.78-4.65-4.96zM3 5.27l2.75 2.74C2.56 8.15 0 10.77 0 14c0 3.31 2.69 6 6 6h11.73l2 2L21 20.73 4.27 4 3 5.27zM7.73 10l8 8H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h1.73z"/></g>
+<g id="cloud-queue"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71C7.37 7.69 9.48 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3s-1.34 3-3 3z"/></g>
+<g id="cloud-upload"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"/></g>
+<g id="code"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></g>
+<g id="compare-arrows"><path d="M9.01 14H2v2h7.01v3L13 15l-3.99-4v3zm5.98-1v-3H22V8h-7.01V5L11 9l3.99 4z"/></g>
+<g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></g>
+<g id="content-cut"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z"/></g>
+<g id="content-paste"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/></g>
+<g id="copyright"><path d="M10.08 10.86c.05-.33.16-.62.3-.87s.34-.46.59-.62c.24-.15.54-.22.91-.23.23.01.44.05.63.13.2.09.38.21.52.36s.25.33.34.53.13.42.14.64h1.79c-.02-.47-.11-.9-.28-1.29s-.4-.73-.7-1.01-.66-.5-1.08-.66-.88-.23-1.39-.23c-.65 0-1.22.11-1.7.34s-.88.53-1.2.92-.56.84-.71 1.36S8 11.29 8 11.87v.27c0 .58.08 1.12.23 1.64s.39.97.71 1.35.72.69 1.2.91 1.05.34 1.7.34c.47 0 .91-.08 1.32-.23s.77-.36 1.08-.63.56-.58.74-.94.29-.74.3-1.15h-1.79c-.01.21-.06.4-.15.58s-.21.33-.36.46-.32.23-.52.3c-.19.07-.39.09-.6.1-.36-.01-.66-.08-.89-.23-.25-.16-.45-.37-.59-.62s-.25-.55-.3-.88-.08-.67-.08-1v-.27c0-.35.03-.68.08-1.01zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="create"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></g>
+<g id="create-new-folder"><path d="M20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-1 8h-3v3h-2v-3h-3v-2h3V9h2v3h3v2z"/></g>
+<g id="credit-card"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/></g>
+<g id="dashboard"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/></g>
+<g id="date-range"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"/></g>
+<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></g>
+<g id="description"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></g>
+<g id="dns"><path d="M20 13H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7 19c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></g>
+<g id="done-all"><path d="M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z"/></g>
+<g id="donut-large"><path d="M11 5.08V2c-5 .5-9 4.81-9 10s4 9.5 9 10v-3.08c-3-.48-6-3.4-6-6.92s3-6.44 6-6.92zM18.97 11H22c-.47-5-4-8.53-9-9v3.08C16 5.51 18.54 8 18.97 11zM13 18.92V22c5-.47 8.53-4 9-9h-3.03c-.43 3-2.97 5.49-5.97 5.92z"/></g>
+<g id="donut-small"><path d="M11 9.16V2c-5 .5-9 4.79-9 10s4 9.5 9 10v-7.16c-1-.41-2-1.52-2-2.84s1-2.43 2-2.84zM14.86 11H22c-.48-4.75-4-8.53-9-9v7.16c1 .3 1.52.98 1.86 1.84zM13 14.84V22c5-.47 8.52-4.25 9-9h-7.14c-.34.86-.86 1.54-1.86 1.84z"/></g>
+<g id="drafts"><path d="M21.99 8c0-.72-.37-1.35-.94-1.7L12 1 2.95 6.3C2.38 6.65 2 7.28 2 8v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zM12 13L3.74 7.84 12 3l8.26 4.84L12 13z"/></g>
+<g id="eject"><path d="M5 17h14v2H5zm7-12L5.33 15h13.34z"/></g>
+<g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></g>
+<g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g>
+<g id="event"><path d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"/></g>
+<g id="event-seat"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v3h-3zM2 10h3v3H2zm15 3H7V5c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2v8z"/></g>
+<g id="exit-to-app"><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g>
+<g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"/></g>
+<g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"/></g>
+<g id="explore"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z"/></g>
+<g id="extension"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></g>
+<g id="face"><path d="M9 11.75c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.25 1.25-.56 1.25-1.25-.56-1.25-1.25-1.25zm6 0c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.25 1.25-.56 1.25-1.25-.56-1.25-1.25-1.25zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8 0-.29.02-.58.05-.86 2.36-1.05 4.23-2.98 5.21-5.37C11.07 8.33 14.05 10 17.42 10c.78 0 1.53-.09 2.25-.26.21.71.33 1.47.33 2.26 0 4.41-3.59 8-8 8z"/></g>
+<g id="favorite"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></g>
+<g id="favorite-border"><path d="M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"/></g>
+<g id="feedback"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z"/></g>
+<g id="file-download"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></g>
+<g id="file-upload"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/></g>
+<g id="filter-list"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/></g>
+<g id="find-in-page"><path d="M20 19.59V8l-6-6H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c.45 0 .85-.15 1.19-.4l-4.43-4.43c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z"/></g>
+<g id="find-replace"><path d="M11 6c1.38 0 2.63.56 3.54 1.46L12 10h6V4l-2.05 2.05C14.68 4.78 12.93 4 11 4c-3.53 0-6.43 2.61-6.92 6H6.1c.46-2.28 2.48-4 4.9-4zm5.64 9.14c.66-.9 1.12-1.97 1.28-3.14H15.9c-.46 2.28-2.48 4-4.9 4-1.38 0-2.63-.56-3.54-1.46L10 12H4v6l2.05-2.05C7.32 17.22 9.07 18 11 18c1.55 0 2.98-.51 4.14-1.36L20 21.49 21.49 20l-4.85-4.86z"/></g>
+<g id="fingerprint"><path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"/></g>
+<g id="flag"><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/></g>
+<g id="flight-land"><path d="M2.5 19h19v2h-19zm7.18-5.73l4.35 1.16 5.31 1.42c.8.21 1.62-.26 1.84-1.06.21-.8-.26-1.62-1.06-1.84l-5.31-1.42-2.76-9.02L10.12 2v8.28L5.15 8.95l-.93-2.32-1.45-.39v5.17l1.6.43 5.31 1.43z"/></g>
+<g id="flight-takeoff"><path d="M2.5 19h19v2h-19zm19.57-9.36c-.21-.8-1.04-1.28-1.84-1.06L14.92 10l-6.9-6.43-1.93.51 4.14 7.17-4.97 1.33-1.97-1.54-1.45.39 1.82 3.16.77 1.33 1.6-.43 5.31-1.42 4.35-1.16L21 11.49c.81-.23 1.28-1.05 1.07-1.85z"/></g>
+<g id="flip-to-back"><path d="M9 7H7v2h2V7zm0 4H7v2h2v-2zm0-8c-1.11 0-2 .9-2 2h2V3zm4 12h-2v2h2v-2zm6-12v2h2c0-1.1-.9-2-2-2zm-6 0h-2v2h2V3zM9 17v-2H7c0 1.1.89 2 2 2zm10-4h2v-2h-2v2zm0-4h2V7h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zM5 7H3v12c0 1.1.89 2 2 2h12v-2H5V7zm10-2h2V3h-2v2zm0 12h2v-2h-2v2z"/></g>
+<g id="flip-to-front"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z"/></g>
+<g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></g>
+<g id="folder-open"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"/></g>
+<g id="folder-shared"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4 8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z"/></g>
+<g id="font-download"><path d="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-4.05 16.5l-1.14-3H9.17l-1.12 3H5.96l5.11-13h1.86l5.11 13h-2.09z"/></g>
+<g id="forward"><path d="M12 8V4l8 8-8 8v-4H4V8z"/></g>
+<g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></g>
+<g id="fullscreen-exit"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/></g>
+<g id="gavel"><path d="M1 21h12v2H1zM5.245 8.07l2.83-2.827 14.14 14.142-2.828 2.828zM12.317 1l5.657 5.656-2.83 2.83-5.654-5.66zM3.825 9.485l5.657 5.657-2.828 2.828-5.657-5.657z"/></g>
+<g id="gesture"><path d="M4.59 6.89c.7-.71 1.4-1.35 1.71-1.22.5.2 0 1.03-.3 1.52-.25.42-2.86 3.89-2.86 6.31 0 1.28.48 2.34 1.34 2.98.75.56 1.74.73 2.64.46 1.07-.31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79-3.78.64-5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1H21v-2.5h-2.47c-.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-.58.73-2.06 2.48-2.29 2.72-.25.3-.68.84-1.11.84-.45 0-.72-.83-.36-1.92.35-1.09 1.4-2.86 1.85-3.52.78-1.14 1.3-1.92 1.3-3.28C8.95 3.69 7.31 3 6.44 3 5.12 3 3.97 4 3.72 4.25c-.36.36-.66.66-.88.93l1.75 1.71zm9.29 11.66c-.31 0-.74-.26-.74-.72 0-.6.73-2.2 2.87-2.76-.3 2.69-1.43 3.48-2.13 3.48z"/></g>
+<g id="get-app"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></g>
+<g id="gif"><path d="M11.5 9H13v6h-1.5zM9 9H6c-.6 0-1 .5-1 1v4c0 .5.4 1 1 1h3c.6 0 1-.5 1-1v-2H8.5v1.5h-2v-3H10V10c0-.5-.4-1-1-1zm10 1.5V9h-4.5v6H16v-2h2v-1.5h-2v-1z"/></g>
+<g id="grade"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></g>
+<g id="group-work"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM8 17.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zM9.5 8c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5S9.5 9.38 9.5 8zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g>
+<g id="help"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></g>
+<g id="help-outline"><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/></g>
+<g id="highlight-off"><path d="M14.59 8L12 10.59 9.41 8 8 9.41 10.59 12 8 14.59 9.41 16 12 13.41 14.59 16 16 14.59 13.41 12 16 9.41 14.59 8zM12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="history"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/></g>
+<g id="home"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></g>
+<g id="hourglass-empty"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6zm10 14.5V20H8v-3.5l4-4 4 4zm-4-5l-4-4V4h8v3.5l-4 4z"/></g>
+<g id="hourglass-full"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"/></g>
+<g id="http"><path d="M4.5 11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5v2zm2.5-.5h1.5V15H10v-4.5h1.5V9H7v1.5zm5.5 0H14V15h1.5v-4.5H17V9h-4.5v1.5zm9-1.5H18v6h1.5v-2h2c.8 0 1.5-.7 1.5-1.5v-1c0-.8-.7-1.5-1.5-1.5zm0 2.5h-2v-1h2v1z"/></g>
+<g id="https"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/></g>
+<g id="important-devices"><path d="M23 11.01L18 11c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-9c0-.55-.45-.99-1-.99zM23 20h-5v-7h5v7zM20 2H2C.89 2 0 2.89 0 4v12c0 1.1.89 2 2 2h7v2H7v2h8v-2h-2v-2h2v-2H2V4h18v5h2V4c0-1.11-.9-2-2-2zm-8.03 7L11 6l-.97 3H7l2.47 1.76-.94 2.91 2.47-1.8 2.47 1.8-.94-2.91L15 9h-3.03z"/></g>
+<g id="inbox"><path d="M19 3H4.99c-1.11 0-1.98.89-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.11-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10z"/></g>
+<g id="indeterminate-check-box"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"/></g>
+<g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></g>
+<g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"/></g>
+<g id="input"><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1v2h10v3z"/></g>
+<g id="invert-colors"><path d="M17.66 7.93L12 2.27 6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58c2.05 0 4.1-.78 5.66-2.34 3.12-3.12 3.12-8.19 0-11.31zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></g>
+<g id="label"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></g>
+<g id="label-outline"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></g>
+<g id="language"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/></g>
+<g id="launch"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></g>
+<g id="lightbulb-outline"><path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z"/></g>
+<g id="line-style"><path d="M3 16h5v-2H3v2zm6.5 0h5v-2h-5v2zm6.5 0h5v-2h-5v2zM3 20h2v-2H3v2zm4 0h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM3 12h8v-2H3v2zm10 0h8v-2h-8v2zM3 4v4h18V4H3z"/></g>
+<g id="line-weight"><path d="M3 17h18v-2H3v2zm0 3h18v-1H3v1zm0-7h18v-3H3v3zm0-9v4h18V4H3z"/></g>
+<g id="link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></g>
+<g id="list"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></g>
+<g id="lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/></g>
+<g id="lock-open"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"/></g>
+<g id="lock-outline"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H8.9V6zM18 20H6V10h12v10z"/></g>
+<g id="loyalty"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7zm11.77 8.27L13 19.54l-4.27-4.27C8.28 14.81 8 14.19 8 13.5c0-1.38 1.12-2.5 2.5-2.5.69 0 1.32.28 1.77.74l.73.72.73-.73c.45-.45 1.08-.73 1.77-.73 1.38 0 2.5 1.12 2.5 2.5 0 .69-.28 1.32-.73 1.77z"/></g>
+<g id="mail"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></g>
+<g id="markunread"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></g>
+<g id="markunread-mailbox"><path d="M20 6H10v6H8V4h6V0H6v6H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2z"/></g>
+<g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></g>
+<g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="motorcycle"><path d="M19.44 9.03L15.41 5H11v2h3.59l2 2H5c-2.8 0-5 2.2-5 5s2.2 5 5 5c2.46 0 4.45-1.69 4.9-4h1.65l2.77-2.77c-.21.54-.32 1.14-.32 1.77 0 2.8 2.2 5 5 5s5-2.2 5-5c0-2.65-1.97-4.77-4.56-4.97zM7.82 15C7.4 16.15 6.28 17 5 17c-1.63 0-3-1.37-3-3s1.37-3 3-3c1.28 0 2.4.85 2.82 2H5v2h2.82zM19 17c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"/></g>
+<g id="move-to-inbox"><path d="M19 3H4.99c-1.11 0-1.98.9-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10zm-3-5h-2V7h-4v3H8l4 4 4-4z"/></g>
+<g id="next-week"><path d="M20 7h-4V5c0-.55-.22-1.05-.59-1.41C15.05 3.22 14.55 3 14 3h-4c-1.1 0-2 .9-2 2v2H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zM10 5h4v2h-4V5zm1 13.5l-1-1 3-3-3-3 1-1 4 4-4 4z"/></g>
+<g id="note-add"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 14h-3v3h-2v-3H8v-2h3v-3h2v3h3v2zm-3-7V3.5L18.5 9H13z"/></g>
+<g id="offline-pin"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm5 16H7v-2h10v2zm-6.7-4L7 10.7l1.4-1.4 1.9 1.9 5.3-5.3L17 7.3 10.3 14z"/></g>
+<g id="opacity"><path d="M17.66 8L12 2.35 6.34 8C4.78 9.56 4 11.64 4 13.64s.78 4.11 2.34 5.67 3.61 2.35 5.66 2.35 4.1-.79 5.66-2.35S20 15.64 20 13.64 19.22 9.56 17.66 8zM6 14c.01-2 .62-3.27 1.76-4.4L12 5.27l4.24 4.38C17.38 10.77 17.99 12 18 14H6z"/></g>
+<g id="open-in-browser"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"/></g>
+<g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></g>
+<g id="open-with"><path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/></g>
+<g id="pageview"><path d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13.99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1.42z"/></g>
+<g id="pan-tool"><path d="M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z"/></g>
+<g id="payment"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/></g>
+<g id="perm-camera-mic"><path d="M20 5h-3.17L15 3H9L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7v-2.09c-2.83-.48-5-2.94-5-5.91h2c0 2.21 1.79 4 4 4s4-1.79 4-4h2c0 2.97-2.17 5.43-5 5.91V21h7c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-6 8c0 1.1-.9 2-2 2s-2-.9-2-2V9c0-1.1.9-2 2-2s2 .9 2 2v4z"/></g>
+<g id="perm-contact-calendar"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1z"/></g>
+<g id="perm-data-setting"><path d="M18.99 11.5c.34 0 .67.03 1 .07L20 0 0 20h11.56c-.04-.33-.07-.66-.07-1 0-4.14 3.36-7.5 7.5-7.5zm3.71 7.99c.02-.16.04-.32.04-.49 0-.17-.01-.33-.04-.49l1.06-.83c.09-.08.12-.21.06-.32l-1-1.73c-.06-.11-.19-.15-.31-.11l-1.24.5c-.26-.2-.54-.37-.85-.49l-.19-1.32c-.01-.12-.12-.21-.24-.21h-2c-.12 0-.23.09-.25.21l-.19 1.32c-.3.13-.59.29-.85.49l-1.24-.5c-.11-.04-.24 0-.31.11l-1 1.73c-.06.11-.04.24.06.32l1.06.83c-.02.16-.03.32-.03.49 0 .17.01.33.03.49l-1.06.83c-.09.08-.12.21-.06.32l1 1.73c.06.11.19.15.31.11l1.24-.5c.26.2.54.37.85.49l.19 1.32c.02.12.12.21.25.21h2c.12 0 .23-.09.25-.21l.19-1.32c.3-.13.59-.29.84-.49l1.25.5c.11.04.24 0 .31-.11l1-1.73c.06-.11.03-.24-.06-.32l-1.07-.83zm-3.71 1.01c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="perm-device-information"><path d="M13 7h-2v2h2V7zm0 4h-2v6h2v-6zm4-9.99L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></g>
+<g id="perm-identity"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/></g>
+<g id="perm-media"><path d="M2 6H0v5h.01L0 20c0 1.1.9 2 2 2h18v-2H2V6zm20-2h-8l-2-2H6c-1.1 0-1.99.9-1.99 2L4 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7 15l4.5-6 3.5 4.51 2.5-3.01L21 15H7z"/></g>
+<g id="perm-phone-msg"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM12 3v10l3-3h6V3h-9z"/></g>
+<g id="perm-scan-wifi"><path d="M12 3C6.95 3 3.15 4.85 0 7.23L12 22 24 7.25C20.85 4.87 17.05 3 12 3zm1 13h-2v-6h2v6zm-2-8V6h2v2h-2z"/></g>
+<g id="pets"><circle cx="4.5" cy="9.5" r="2.5"/><circle cx="9" cy="5.5" r="2.5"/><circle cx="15" cy="5.5" r="2.5"/><circle cx="19.5" cy="9.5" r="2.5"/><path d="M17.34 14.86c-.87-1.02-1.6-1.89-2.48-2.91-.46-.54-1.05-1.08-1.75-1.32-.11-.04-.22-.07-.33-.09-.25-.04-.52-.04-.78-.04s-.53 0-.79.05c-.11.02-.22.05-.33.09-.7.24-1.28.78-1.75 1.32-.87 1.02-1.6 1.89-2.48 2.91-1.31 1.31-2.92 2.76-2.62 4.79.29 1.02 1.02 2.03 2.33 2.32.73.15 3.06-.44 5.54-.44h.18c2.48 0 4.81.58 5.54.44 1.31-.29 2.04-1.31 2.33-2.32.31-2.04-1.3-3.49-2.61-4.8z"/></g>
+<g id="picture-in-picture"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"/></g>
+<g id="picture-in-picture-alt"><path d="M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3c-1.1 0-2 .88-2 1.98V19c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h18v14.05z"/></g>
+<g id="play-for-work"><path d="M11 5v5.59H7.5l4.5 4.5 4.5-4.5H13V5h-2zm-5 9c0 3.31 2.69 6 6 6s6-2.69 6-6h-2c0 2.21-1.79 4-4 4s-4-1.79-4-4H6z"/></g>
+<g id="polymer"><path d="M19 4h-4L7.11 16.63 4.5 12 9 4H5L.5 12 5 20h4l7.89-12.63L19.5 12 15 20h4l4.5-8z"/></g>
+<g id="power-settings-new"><path d="M13 3h-2v10h2V3zm4.83 2.17l-1.42 1.42C17.99 7.86 19 9.81 19 12c0 3.87-3.13 7-7 7s-7-3.13-7-7c0-2.19 1.01-4.14 2.58-5.42L6.17 5.17C4.23 6.82 3 9.26 3 12c0 4.97 4.03 9 9 9s9-4.03 9-9c0-2.74-1.23-5.18-3.17-6.83z"/></g>
+<g id="pregnant-woman"><path d="M9 4c0-1.11.89-2 2-2s2 .89 2 2-.89 2-2 2-2-.89-2-2zm7 9c-.01-1.34-.83-2.51-2-3 0-1.66-1.34-3-3-3s-3 1.34-3 3v7h2v5h3v-5h3v-4z"/></g>
+<g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/></g>
+<g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></g>
+<g id="question-answer"><path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"/></g>
+<g id="radio-button-checked"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g>
+<g id="radio-button-unchecked"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g>
+<g id="receipt"><path d="M18 17H6v-2h12v2zm0-4H6v-2h12v2zm0-4H6V7h12v2zM3 22l1.5-1.5L6 22l1.5-1.5L9 22l1.5-1.5L12 22l1.5-1.5L15 22l1.5-1.5L18 22l1.5-1.5L21 22V2l-1.5 1.5L18 2l-1.5 1.5L15 2l-1.5 1.5L12 2l-1.5 1.5L9 2 7.5 3.5 6 2 4.5 3.5 3 2v20z"/></g>
+<g id="record-voice-over"><circle cx="9" cy="9" r="4"/><path d="M9 15c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4zm7.76-9.64l-1.68 1.69c.84 1.18.84 2.71 0 3.89l1.68 1.69c2.02-2.02 2.02-5.07 0-7.27zM20.07 2l-1.63 1.63c2.77 3.02 2.77 7.56 0 10.74L20.07 16c3.9-3.89 3.91-9.95 0-14z"/></g>
+<g id="redeem"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"/></g>
+<g id="redo"><path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"/></g>
+<g id="refresh"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></g>
+<g id="remove"><path d="M19 13H5v-2h14v2z"/></g>
+<g id="remove-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z"/></g>
+<g id="remove-circle-outline"><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
+<g id="reorder"><path d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z"/></g>
+<g id="reply"><path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/></g>
+<g id="reply-all"><path d="M7 8V5l-7 7 7 7v-3l-4-4 4-4zm6 1V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/></g>
+<g id="report"><path d="M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15.73 3zM12 17.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2V7h2v6z"/></g>
+<g id="report-problem"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></g>
+<g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/></g>
+<g id="room"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g>
+<g id="rounded-corner"><path d="M19 19h2v2h-2v-2zm0-2h2v-2h-2v2zM3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm0-4h2V3H3v2zm4 0h2V3H7v2zm8 16h2v-2h-2v2zm-4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm-8 0h2v-2H7v2zm-4 0h2v-2H3v2zM21 8c0-2.76-2.24-5-5-5h-5v2h5c1.65 0 3 1.35 3 3v5h2V8z"/></g>
+<g id="rowing"><path d="M8.5 14.5L4 19l1.5 1.5L9 17h2l-2.5-2.5zM15 1c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 20.01L18 24l-2.99-3.01V19.5l-7.1-7.09c-.31.05-.61.07-.91.07v-2.16c1.66.03 3.61-.87 4.67-2.04l1.4-1.55c.19-.21.43-.38.69-.5.29-.14.62-.23.96-.23h.03C15.99 6.01 17 7.02 17 8.26v5.75c0 .84-.35 1.61-.92 2.16l-3.58-3.58v-2.27c-.63.52-1.43 1.02-2.29 1.39L16.5 18H18l3 3.01z"/></g>
+<g id="save"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></g>
+<g id="schedule"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></g>
+<g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></g>
+<g id="select-all"><path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z"/></g>
+<g id="send"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></g>
+<g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></g>
+<g id="settings-applications"><path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm7-7H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-1.75 9c0 .23-.02.46-.05.68l1.48 1.16c.13.11.17.3.08.45l-1.4 2.42c-.09.15-.27.21-.43.15l-1.74-.7c-.36.28-.76.51-1.18.69l-.26 1.85c-.03.17-.18.3-.35.3h-2.8c-.17 0-.32-.13-.35-.29l-.26-1.85c-.43-.18-.82-.41-1.18-.69l-1.74.7c-.16.06-.34 0-.43-.15l-1.4-2.42c-.09-.15-.05-.34.08-.45l1.48-1.16c-.03-.23-.05-.46-.05-.69 0-.23.02-.46.05-.68l-1.48-1.16c-.13-.11-.17-.3-.08-.45l1.4-2.42c.09-.15.27-.21.43-.15l1.74.7c.36-.28.76-.51 1.18-.69l.26-1.85c.03-.17.18-.3.35-.3h2.8c.17 0 .32.13.35.29l.26 1.85c.43.18.82.41 1.18.69l1.74-.7c.16-.06.34 0 .43.15l1.4 2.42c.09.15.05.34-.08.45l-1.48 1.16c.03.23.05.46.05.69z"/></g>
+<g id="settings-backup-restore"><path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9H0l4 4 4-4H5c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44C8.04 20.3 9.94 21 12 21c4.97 0 9-4.03 9-9s-4.03-9-9-9z"/></g>
+<g id="settings-bluetooth"><path d="M11 24h2v-2h-2v2zm-4 0h2v-2H7v2zm8 0h2v-2h-2v2zm2.71-18.29L12 0h-1v7.59L6.41 3 5 4.41 10.59 10 5 15.59 6.41 17 11 12.41V20h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 3.83l1.88 1.88L13 7.59V3.83zm1.88 10.46L13 16.17v-3.76l1.88 1.88z"/></g>
+<g id="settings-brightness"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02zM8 16h2.5l1.5 1.5 1.5-1.5H16v-2.5l1.5-1.5-1.5-1.5V8h-2.5L12 6.5 10.5 8H8v2.5L6.5 12 8 13.5V16zm4-7c1.66 0 3 1.34 3 3s-1.34 3-3 3V9z"/></g>
+<g id="settings-cell"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM16 .01L8 0C6.9 0 6 .9 6 2v16c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V2c0-1.1-.9-1.99-2-1.99zM16 16H8V4h8v12z"/></g>
+<g id="settings-ethernet"><path d="M7.77 6.76L6.23 5.48.82 12l5.41 6.52 1.54-1.28L3.42 12l4.35-5.24zM7 13h2v-2H7v2zm10-2h-2v2h2v-2zm-6 2h2v-2h-2v2zm6.77-7.52l-1.54 1.28L20.58 12l-4.35 5.24 1.54 1.28L23.18 12l-5.41-6.52z"/></g>
+<g id="settings-input-antenna"><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.12-2.5-2.5-2.5S9.5 10.62 9.5 12c0 1.02.62 1.9 1.5 2.29v3.3L7.59 21 9 22.41l3-3 3 3L16.41 21 13 17.59v-3.3zM12 1C5.93 1 1 5.93 1 12h2c0-4.97 4.03-9 9-9s9 4.03 9 9h2c0-6.07-4.93-11-11-11z"/></g>
+<g id="settings-input-component"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"/></g>
+<g id="settings-input-composite"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"/></g>
+<g id="settings-input-hdmi"><path d="M18 7V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v3H5v6l3 6v3h8v-3l3-6V7h-1zM8 4h8v3h-2V5h-1v2h-2V5h-1v2H8V4z"/></g>
+<g id="settings-input-svideo"><path d="M8 11.5c0-.83-.67-1.5-1.5-1.5S5 10.67 5 11.5 5.67 13 6.5 13 8 12.33 8 11.5zm7-5c0-.83-.67-1.5-1.5-1.5h-3C9.67 5 9 5.67 9 6.5S9.67 8 10.5 8h3c.83 0 1.5-.67 1.5-1.5zM8.5 15c-.83 0-1.5.67-1.5 1.5S7.67 18 8.5 18s1.5-.67 1.5-1.5S9.33 15 8.5 15zM12 1C5.93 1 1 5.93 1 12s4.93 11 11 11 11-4.93 11-11S18.07 1 12 1zm0 20c-4.96 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9zm5.5-11c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm-2 5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"/></g>
+<g id="settings-overscan"><path d="M12.01 5.5L10 8h4l-1.99-2.5zM18 10v4l2.5-1.99L18 10zM6 10l-2.5 2.01L6 14v-4zm8 6h-4l2.01 2.5L14 16zm7-13H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"/></g>
+<g id="settings-phone"><path d="M13 9h-2v2h2V9zm4 0h-2v2h2V9zm3 6.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 9v2h2V9h-2z"/></g>
+<g id="settings-power"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm2-22h-2v10h2V2zm3.56 2.44l-1.45 1.45C16.84 6.94 18 8.83 18 11c0 3.31-2.69 6-6 6s-6-2.69-6-6c0-2.17 1.16-4.06 2.88-5.12L7.44 4.44C5.36 5.88 4 8.28 4 11c0 4.42 3.58 8 8 8s8-3.58 8-8c0-2.72-1.36-5.12-3.44-6.56zM15 24h2v-2h-2v2z"/></g>
+<g id="settings-remote"><path d="M15 9H9c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V10c0-.55-.45-1-1-1zm-3 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM7.05 6.05l1.41 1.41C9.37 6.56 10.62 6 12 6s2.63.56 3.54 1.46l1.41-1.41C15.68 4.78 13.93 4 12 4s-3.68.78-4.95 2.05zM12 0C8.96 0 6.21 1.23 4.22 3.22l1.41 1.41C7.26 3.01 9.51 2 12 2s4.74 1.01 6.36 2.64l1.41-1.41C17.79 1.23 15.04 0 12 0z"/></g>
+<g id="settings-voice"><path d="M7 24h2v-2H7v2zm5-11c1.66 0 2.99-1.34 2.99-3L15 4c0-1.66-1.34-3-3-3S9 2.34 9 4v6c0 1.66 1.34 3 3 3zm-1 11h2v-2h-2v2zm4 0h2v-2h-2v2zm4-14h-1.7c0 3-2.54 5.1-5.3 5.1S6.7 13 6.7 10H5c0 3.41 2.72 6.23 6 6.72V20h2v-3.28c3.28-.49 6-3.31 6-6.72z"/></g>
+<g id="shop"><path d="M16 6V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H2v13c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6h-6zm-6-2h4v2h-4V4zM9 18V9l7.5 4L9 18z"/></g>
+<g id="shop-two"><path d="M3 9H1v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2H3V9zm15-4V3c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H5v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2V5h-5zm-6-2h4v2h-4V3zm0 12V8l5.5 3-5.5 4z"/></g>
+<g id="shopping-basket"><path d="M17.21 9l-4.38-6.56c-.19-.28-.51-.42-.83-.42-.32 0-.64.14-.83.43L6.79 9H2c-.55 0-1 .45-1 1 0 .09.01.18.04.27l2.54 9.27c.23.84 1 1.46 1.92 1.46h13c.92 0 1.69-.62 1.93-1.46l2.54-9.27L23 10c0-.55-.45-1-1-1h-4.79zM9 9l3-4.4L15 9H9zm3 8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="shopping-cart"><path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="sort"><path d="M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z"/></g>
+<g id="speaker-notes"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM8 14H6v-2h2v2zm0-3H6V9h2v2zm0-3H6V6h2v2zm7 6h-5v-2h5v2zm3-3h-8V9h8v2zm0-3h-8V6h8v2z"/></g>
+<g id="spellcheck"><path d="M12.45 16h2.09L9.43 3H7.57L2.46 16h2.09l1.12-3h5.64l1.14 3zm-6.02-5L8.5 5.48 10.57 11H6.43zm15.16.59l-8.09 8.09L9.83 16l-1.41 1.41 5.09 5.09L23 13l-1.41-1.41z"/></g>
+<g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></g>
+<g id="star-border"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"/></g>
+<g id="star-half"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4V6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"/></g>
+<g id="stars"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm4.24 16L12 15.45 7.77 18l1.12-4.81-3.73-3.23 4.92-.42L12 5l1.92 4.53 4.92.42-3.73 3.23L16.23 18z"/></g>
+<g id="store"><path d="M20 4H4v2h16V4zm1 10v-2l-1-5H4l-1 5v2h1v6h10v-6h4v6h2v-6h1zm-9 4H6v-4h6v4z"/></g>
+<g id="subdirectory-arrow-left"><path d="M11 9l1.42 1.42L8.83 14H18V4h2v12H8.83l3.59 3.58L11 21l-6-6 6-6z"/></g>
+<g id="subdirectory-arrow-right"><path d="M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z"/></g>
+<g id="subject"><path d="M14 17H4v2h10v-2zm6-8H4v2h16V9zM4 15h16v-2H4v2zM4 5v2h16V5H4z"/></g>
+<g id="supervisor-account"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5S17.88 7 16.5 7C15.12 7 14 8.12 14 9.5s1.12 2.5 2.5 2.5zM9 11c1.66 0 2.99-1.34 2.99-3S10.66 5 9 5C7.34 5 6 6.34 6 8s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75V19h11v-2.25c0-1.83-3.67-2.75-5.5-2.75zM9 13c-2.33 0-7 1.17-7 3.5V19h7v-2.25c0-.85.33-2.34 2.37-3.47C10.5 13.1 9.66 13 9 13z"/></g>
+<g id="swap-horiz"><path d="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z"/></g>
+<g id="swap-vert"><path d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z"/></g>
+<g id="swap-vertical-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM6.5 9L10 5.5 13.5 9H11v4H9V9H6.5zm11 6L14 18.5 10.5 15H13v-4h2v4h2.5z"/></g>
+<g id="system-update-alt"><path d="M12 16.5l4-4h-3v-9h-2v9H8l4 4zm9-13h-6v1.99h6v14.03H3V5.49h6V3.5H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2z"/></g>
+<g id="tab"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h10v4h8v10z"/></g>
+<g id="tab-unselected"><path d="M1 9h2V7H1v2zm0 4h2v-2H1v2zm0-8h2V3c-1.1 0-2 .9-2 2zm8 16h2v-2H9v2zm-8-4h2v-2H1v2zm2 4v-2H1c0 1.1.9 2 2 2zM21 3h-8v6h10V5c0-1.1-.9-2-2-2zm0 14h2v-2h-2v2zM9 5h2V3H9v2zM5 21h2v-2H5v2zM5 5h2V3H5v2zm16 16c1.1 0 2-.9 2-2h-2v2zm0-8h2v-2h-2v2zm-8 8h2v-2h-2v2zm4 0h2v-2h-2v2z"/></g>
+<g id="text-format"><path d="M5 17v2h14v-2H5zm4.5-4.2h5l.9 2.2h2.1L12.75 4h-1.5L6.5 15h2.1l.9-2.2zM12 5.98L13.87 11h-3.74L12 5.98z"/></g>
+<g id="theaters"><path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z"/></g>
+<g id="thumb-down"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></g>
+<g id="thumb-up"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"/></g>
+<g id="thumbs-up-down"><path d="M12 6c0-.55-.45-1-1-1H5.82l.66-3.18.02-.23c0-.31-.13-.59-.33-.8L5.38 0 .44 4.94C.17 5.21 0 5.59 0 6v6.5c0 .83.67 1.5 1.5 1.5h6.75c.62 0 1.15-.38 1.38-.91l2.26-5.29c.07-.17.11-.36.11-.55V6zm10.5 4h-6.75c-.62 0-1.15.38-1.38.91l-2.26 5.29c-.07.17-.11.36-.11.55V18c0 .55.45 1 1 1h5.18l-.66 3.18-.02.24c0 .31.13.59.33.8l.79.78 4.94-4.94c.27-.27.44-.65.44-1.06v-6.5c0-.83-.67-1.5-1.5-1.5z"/></g>
+<g id="timeline"><path d="M23 8c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c.05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16.05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2-2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55-3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2z"/></g>
+<g id="toc"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"/></g>
+<g id="today"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"/></g>
+<g id="toll"><path d="M15 4c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zM3 12c0-2.61 1.67-4.83 4-5.65V4.26C3.55 5.15 1 8.27 1 12s2.55 6.85 6 7.74v-2.09c-2.33-.82-4-3.04-4-5.65z"/></g>
+<g id="touch-app"><path d="M9 11.24V7.5C9 6.12 10.12 5 11.5 5S14 6.12 14 7.5v3.74c1.21-.81 2-2.18 2-3.74C16 5.01 13.99 3 11.5 3S7 5.01 7 7.5c0 1.56.79 2.93 2 3.74zm9.84 4.63l-4.54-2.26c-.17-.07-.35-.11-.54-.11H13v-6c0-.83-.67-1.5-1.5-1.5S10 6.67 10 7.5v10.74l-3.43-.72c-.08-.01-.15-.03-.24-.03-.31 0-.59.13-.79.33l-.79.8 4.94 4.94c.27.27.65.44 1.06.44h6.79c.75 0 1.33-.55 1.44-1.28l.75-5.27c.01-.07.02-.14.02-.2 0-.62-.38-1.16-.91-1.38z"/></g>
+<g id="track-changes"><path d="M19.07 4.93l-1.41 1.41C19.1 7.79 20 9.79 20 12c0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02C8.16 6.57 6 9.03 6 12c0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41C15.55 9.9 16 10.9 16 12c0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V2h-1C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"/></g>
+<g id="translate"><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"/></g>
+<g id="trending-down"><path d="M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z"/></g>
+<g id="trending-flat"><path d="M22 12l-4-4v3H3v2h15v3z"/></g>
+<g id="trending-up"><path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z"/></g>
+<g id="turned-in"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></g>
+<g id="turned-in-not"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"/></g>
+<g id="unarchive"><path d="M20.55 5.22l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.15.55L3.46 5.22C3.17 5.57 3 6.01 3 6.5V19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.49-.17-.93-.45-1.28zM12 9.5l5.5 5.5H14v2h-4v-2H6.5L12 9.5zM5.12 5l.82-1h12l.93 1H5.12z"/></g>
+<g id="undo"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"/></g>
+<g id="unfold-less"><path d="M7.41 18.59L8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"/></g>
+<g id="unfold-more"><path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"/></g>
+<g id="update"><path d="M21 10.12h-6.78l2.74-2.82c-2.73-2.7-7.15-2.8-9.88-.1-2.73 2.71-2.73 7.08 0 9.79 2.73 2.71 7.15 2.71 9.88 0C18.32 15.65 19 14.08 19 12.1h2c0 1.98-.88 4.55-2.64 6.29-3.51 3.48-9.21 3.48-12.72 0-3.5-3.47-3.53-9.11-.02-12.58 3.51-3.47 9.14-3.47 12.65 0L21 3v7.12zM12.5 8v4.25l3.5 2.08-.72 1.21L11 13V8h1.5z"/></g>
+<g id="verified-user"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"/></g>
+<g id="view-agenda"><path d="M20 13H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm0-10H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1z"/></g>
+<g id="view-array"><path d="M4 18h3V5H4v13zM18 5v13h3V5h-3zM8 18h9V5H8v13z"/></g>
+<g id="view-carousel"><path d="M7 19h10V4H7v15zm-5-2h4V6H2v11zM18 6v11h4V6h-4z"/></g>
+<g id="view-column"><path d="M10 18h5V5h-5v13zm-6 0h5V5H4v13zM16 5v13h5V5h-5z"/></g>
+<g id="view-day"><path d="M2 21h19v-3H2v3zM20 8H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zM2 3v3h19V3H2z"/></g>
+<g id="view-headline"><path d="M4 15h16v-2H4v2zm0 4h16v-2H4v2zm0-8h16V9H4v2zm0-6v2h16V5H4z"/></g>
+<g id="view-list"><path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z"/></g>
+<g id="view-module"><path d="M4 11h5V5H4v6zm0 7h5v-6H4v6zm6 0h5v-6h-5v6zm6 0h5v-6h-5v6zm-6-7h5V5h-5v6zm6-6v6h5V5h-5z"/></g>
+<g id="view-quilt"><path d="M10 18h5v-6h-5v6zm-6 0h5V5H4v13zm12 0h5v-6h-5v6zM10 5v6h11V5H10z"/></g>
+<g id="view-stream"><path d="M4 18h17v-6H4v6zM4 5v6h17V5H4z"/></g>
+<g id="view-week"><path d="M6 5H3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zm14 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zm-7 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1z"/></g>
+<g id="visibility"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></g>
+<g id="visibility-off"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/></g>
+<g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></g>
+<g id="watch-later"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"/></g>
+<g id="weekend"><path d="M21 10c-1.1 0-2 .9-2 2v3H5v-3c0-1.1-.9-2-2-2s-2 .9-2 2v5c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-5c0-1.1-.9-2-2-2zm-3-5H6c-1.1 0-2 .9-2 2v2.15c1.16.41 2 1.51 2 2.82V14h12v-2.03c0-1.3.84-2.4 2-2.82V7c0-1.1-.9-2-2-2z"/></g>
+<g id="work"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"/></g>
+<g id="youtube-searched-for"><path d="M17.01 14h-.8l-.27-.27c.98-1.14 1.57-2.61 1.57-4.23 0-3.59-2.91-6.5-6.5-6.5s-6.5 3-6.5 6.5H2l3.84 4 4.16-4H6.51C6.51 7 8.53 5 11.01 5s4.5 2.01 4.5 4.5c0 2.48-2.02 4.5-4.5 4.5-.65 0-1.26-.14-1.82-.38L7.71 15.1c.97.57 2.09.9 3.3.9 1.61 0 3.08-.59 4.22-1.57l.27.27v.79l5.01 4.99L22 19l-4.99-5z"/></g>
+<g id="zoom-in"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zm2.5-4h-2v2H9v-2H7V9h2V7h1v2h2v1z"/></g>
+<g id="zoom-out"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/maps-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/maps-icons.html
new file mode 100644
index 00000000000..059ae91d4b5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/maps-icons.html
@@ -0,0 +1,76 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="maps" size="24">
+<svg><defs>
+<g id="add-location"><path d="M12 2C8.14 2 5 5.14 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.86-3.14-7-7-7zm4 8h-3v3h-2v-3H8V8h3V5h2v3h3v2z"/></g>
+<g id="beenhere"><path d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z"/></g>
+<g id="directions"><path d="M21.71 11.29l-9-9c-.39-.39-1.02-.39-1.41 0l-9 9c-.39.39-.39 1.02 0 1.41l9 9c.39.39 1.02.39 1.41 0l9-9c.39-.38.39-1.01 0-1.41zM14 14.5V12h-4v3H8v-4c0-.55.45-1 1-1h5V7.5l3.5 3.5-3.5 3.5z"/></g>
+<g id="directions-bike"><path d="M15.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM5 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5zm5.8-10l2.4-2.4.8.8c1.3 1.3 3 2.1 5.1 2.1V9c-1.5 0-2.7-.6-3.6-1.5l-1.9-1.9c-.5-.4-1-.6-1.6-.6s-1.1.2-1.4.6L7.8 8.4c-.4.4-.6.9-.6 1.4 0 .6.2 1.1.6 1.4L11 14v5h2v-6.2l-2.2-2.3zM19 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5z"/></g>
+<g id="directions-boat"><path d="M20 21c-1.39 0-2.78-.47-4-1.32-2.44 1.71-5.56 1.71-8 0C6.78 20.53 5.39 21 4 21H2v2h2c1.38 0 2.74-.35 4-.99 2.52 1.29 5.48 1.29 8 0 1.26.65 2.62.99 4 .99h2v-2h-2zM3.95 19H4c1.6 0 3.02-.88 4-2 .98 1.12 2.4 2 4 2s3.02-.88 4-2c.98 1.12 2.4 2 4 2h.05l1.89-6.68c.08-.26.06-.54-.06-.78s-.34-.42-.6-.5L20 10.62V6c0-1.1-.9-2-2-2h-3V1H9v3H6c-1.1 0-2 .9-2 2v4.62l-1.29.42c-.26.08-.48.26-.6.5s-.15.52-.06.78L3.95 19zM6 6h12v3.97L12 8 6 9.97V6z"/></g>
+<g id="directions-bus"><path d="M4 16c0 .88.39 1.67 1 2.22V20c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h8v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1.78c.61-.55 1-1.34 1-2.22V6c0-3.5-3.58-4-8-4s-8 .5-8 4v10zm3.5 1c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></g>
+<g id="directions-car"><path d="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21.42-1.42 1.01L3 12v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5.67 1.5 1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z"/></g>
+<g id="directions-railway"><path d="M4 15.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h12v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V5c0-3.5-3.58-4-8-4s-8 .5-8 4v10.5zm8 1.5c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm6-7H6V5h12v5z"/></g>
+<g id="directions-run"><path d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z"/></g>
+<g id="directions-subway"><path d="M12 2c-4.42 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h12v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm3.5-6H6V6h5v5zm5.5 6c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6h-5V6h5v5z"/></g>
+<g id="directions-transit"><path d="M12 2c-4.42 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h12v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm3.5-6H6V6h5v5zm5.5 6c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6h-5V6h5v5z"/></g>
+<g id="directions-walk"><path d="M13.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM9.8 8.9L7 23h2.1l1.8-8 2.1 2v6h2v-7.5l-2.1-2 .6-3C14.8 12 16.8 13 19 13v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1L6 8.3V13h2V9.6l1.8-.7"/></g>
+<g id="edit-location"><path d="M12 2C8.14 2 5 5.14 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.86-3.14-7-7-7zm-1.56 10H9v-1.44l3.35-3.34 1.43 1.43L10.44 12zm4.45-4.45l-.7.7-1.44-1.44.7-.7c.15-.15.39-.15.54 0l.9.9c.15.15.15.39 0 .54z"/></g>
+<g id="flight"><path d="M10.18 9"/><path d="M21 16v-2l-8-5V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></g>
+<g id="hotel"><path d="M7 13c1.66 0 3-1.34 3-3S8.66 7 7 7s-3 1.34-3 3 1.34 3 3 3zm12-6h-8v7H3V5H1v15h2v-3h18v3h2v-9c0-2.21-1.79-4-4-4z"/></g>
+<g id="layers"><path d="M11.99 18.54l-7.37-5.73L3 14.07l9 7 9-7-1.63-1.27-7.38 5.74zM12 16l7.36-5.73L21 9l-9-7-9 7 1.63 1.27L12 16z"/></g>
+<g id="layers-clear"><path d="M19.81 14.99l1.19-.92-1.43-1.43-1.19.92 1.43 1.43zm-.45-4.72L21 9l-9-7-2.91 2.27 7.87 7.88 2.4-1.88zM3.27 1L2 2.27l4.22 4.22L3 9l1.63 1.27L12 16l2.1-1.63 1.43 1.43L12 18.54l-7.37-5.73L3 14.07l9 7 4.95-3.85L20.73 21 22 19.73 3.27 1z"/></g>
+<g id="local-activity"><path d="M20 12c0-1.1.9-2 2-2V6c0-1.1-.9-2-2-2H4c-1.1 0-1.99.9-1.99 2v4c1.1 0 1.99.9 1.99 2s-.89 2-2 2v4c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-4c-1.1 0-2-.9-2-2zm-4.42 4.8L12 14.5l-3.58 2.3 1.08-4.12-3.29-2.69 4.24-.25L12 5.8l1.54 3.95 4.24.25-3.29 2.69 1.09 4.11z"/></g>
+<g id="local-airport"><path d="M21 16v-2l-8-5V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z"/></g>
+<g id="local-atm"><path d="M11 17h2v-1h1c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1h-3v-1h4V8h-2V7h-2v1h-1c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1h3v1H9v2h2v1zm9-13H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4V6h16v12z"/></g>
+<g id="local-bar"><path d="M21 5V3H3v2l8 9v5H6v2h12v-2h-5v-5l8-9zM7.43 7L5.66 5h12.69l-1.78 2H7.43z"/></g>
+<g id="local-cafe"><path d="M20 3H4v10c0 2.21 1.79 4 4 4h6c2.21 0 4-1.79 4-4v-3h2c1.11 0 2-.89 2-2V5c0-1.11-.89-2-2-2zm0 5h-2V5h2v3zM2 21h18v-2H2v2z"/></g>
+<g id="local-car-wash"><path d="M17 5c.83 0 1.5-.67 1.5-1.5 0-1-1.5-2.7-1.5-2.7s-1.5 1.7-1.5 2.7c0 .83.67 1.5 1.5 1.5zm-5 0c.83 0 1.5-.67 1.5-1.5 0-1-1.5-2.7-1.5-2.7s-1.5 1.7-1.5 2.7c0 .83.67 1.5 1.5 1.5zM7 5c.83 0 1.5-.67 1.5-1.5C8.5 2.5 7 .8 7 .8S5.5 2.5 5.5 3.5C5.5 4.33 6.17 5 7 5zm11.92 3.01C18.72 7.42 18.16 7 17.5 7h-11c-.66 0-1.21.42-1.42 1.01L3 14v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 18c-.83 0-1.5-.67-1.5-1.5S5.67 15 6.5 15s1.5.67 1.5 1.5S7.33 18 6.5 18zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 13l1.5-4.5h11L19 13H5z"/></g>
+<g id="local-convenience-store"><path d="M19 7V4H5v3H2v13h8v-4h4v4h8V7h-3zm-8 3H9v1h2v1H8V9h2V8H8V7h3v3zm5 2h-1v-2h-2V7h1v2h1V7h1v5z"/></g>
+<g id="local-dining"><path d="M8.1 13.34l2.83-2.83L3.91 3.5c-1.56 1.56-1.56 4.09 0 5.66l4.19 4.18zm6.78-1.81c1.53.71 3.68.21 5.27-1.38 1.91-1.91 2.28-4.65.81-6.12-1.46-1.46-4.2-1.1-6.12.81-1.59 1.59-2.09 3.74-1.38 5.27L3.7 19.87l1.41 1.41L12 14.41l6.88 6.88 1.41-1.41L13.41 13l1.47-1.47z"/></g>
+<g id="local-drink"><path d="M3 2l2.01 18.23C5.13 21.23 5.97 22 7 22h10c1.03 0 1.87-.77 1.99-1.77L21 2H3zm9 17c-1.66 0-3-1.34-3-3 0-2 3-5.4 3-5.4s3 3.4 3 5.4c0 1.66-1.34 3-3 3zm6.33-11H5.67l-.44-4h13.53l-.43 4z"/></g>
+<g id="local-florist"><path d="M12 22c4.97 0 9-4.03 9-9-4.97 0-9 4.03-9 9zM5.6 10.25c0 1.38 1.12 2.5 2.5 2.5.53 0 1.01-.16 1.42-.44l-.02.19c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5l-.02-.19c.4.28.89.44 1.42.44 1.38 0 2.5-1.12 2.5-2.5 0-1-.59-1.85-1.43-2.25.84-.4 1.43-1.25 1.43-2.25 0-1.38-1.12-2.5-2.5-2.5-.53 0-1.01.16-1.42.44l.02-.19C14.5 2.12 13.38 1 12 1S9.5 2.12 9.5 3.5l.02.19c-.4-.28-.89-.44-1.42-.44-1.38 0-2.5 1.12-2.5 2.5 0 1 .59 1.85 1.43 2.25-.84.4-1.43 1.25-1.43 2.25zM12 5.5c1.38 0 2.5 1.12 2.5 2.5s-1.12 2.5-2.5 2.5S9.5 9.38 9.5 8s1.12-2.5 2.5-2.5zM3 13c0 4.97 4.03 9 9 9 0-4.97-4.03-9-9-9z"/></g>
+<g id="local-gas-station"><path d="M19.77 7.23l.01-.01-3.72-3.72L15 4.56l2.11 2.11c-.94.36-1.61 1.26-1.61 2.33 0 1.38 1.12 2.5 2.5 2.5.36 0 .69-.08 1-.21v7.21c0 .55-.45 1-1 1s-1-.45-1-1V14c0-1.1-.9-2-2-2h-1V5c0-1.1-.9-2-2-2H6c-1.1 0-2 .9-2 2v16h10v-7.5h1.5v5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V9c0-.69-.28-1.32-.73-1.77zM12 10H6V5h6v5zm6 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></g>
+<g id="local-grocery-store"><path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/></g>
+<g id="local-hospital"><path d="M19 3H5c-1.1 0-1.99.9-1.99 2L3 19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 11h-4v4h-4v-4H6v-4h4V6h4v4h4v4z"/></g>
+<g id="local-hotel"><path d="M7 13c1.66 0 3-1.34 3-3S8.66 7 7 7s-3 1.34-3 3 1.34 3 3 3zm12-6h-8v7H3V5H1v15h2v-3h18v3h2v-9c0-2.21-1.79-4-4-4z"/></g>
+<g id="local-laundry-service"><path d="M9.17 16.83c1.56 1.56 4.1 1.56 5.66 0 1.56-1.56 1.56-4.1 0-5.66l-5.66 5.66zM18 2.01L6 2c-1.11 0-2 .89-2 2v16c0 1.11.89 2 2 2h12c1.11 0 2-.89 2-2V4c0-1.11-.89-1.99-2-1.99zM10 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM7 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm5 16c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"/></g>
+<g id="local-library"><path d="M12 11.55C9.64 9.35 6.48 8 3 8v11c3.48 0 6.64 1.35 9 3.55 2.36-2.19 5.52-3.55 9-3.55V8c-3.48 0-6.64 1.35-9 3.55zM12 8c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3z"/></g>
+<g id="local-mall"><path d="M19 6h-2c0-2.76-2.24-5-5-5S7 3.24 7 6H5c-1.1 0-1.99.9-1.99 2L3 20c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-7-3c1.66 0 3 1.34 3 3H9c0-1.66 1.34-3 3-3zm0 10c-2.76 0-5-2.24-5-5h2c0 1.66 1.34 3 3 3s3-1.34 3-3h2c0 2.76-2.24 5-5 5z"/></g>
+<g id="local-movies"><path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z"/></g>
+<g id="local-offer"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/></g>
+<g id="local-parking"><path d="M13 3H6v18h4v-6h3c3.31 0 6-2.69 6-6s-2.69-6-6-6zm.2 8H10V7h3.2c1.1 0 2 .9 2 2s-.9 2-2 2z"/></g>
+<g id="local-pharmacy"><path d="M21 5h-2.64l1.14-3.14L17.15 1l-1.46 4H3v2l2 6-2 6v2h18v-2l-2-6 2-6V5zm-5 9h-3v3h-2v-3H8v-2h3V9h2v3h3v2z"/></g>
+<g id="local-phone"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></g>
+<g id="local-pizza"><path d="M12 2C8.43 2 5.23 3.54 3.01 6L12 22l8.99-16C18.78 3.55 15.57 2 12 2zM7 7c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm5 8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="local-play"><path d="M20 12c0-1.1.9-2 2-2V6c0-1.1-.9-2-2-2H4c-1.1 0-1.99.9-1.99 2v4c1.1 0 1.99.9 1.99 2s-.89 2-2 2v4c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-4c-1.1 0-2-.9-2-2zm-4.42 4.8L12 14.5l-3.58 2.3 1.08-4.12-3.29-2.69 4.24-.25L12 5.8l1.54 3.95 4.24.25-3.29 2.69 1.09 4.11z"/></g>
+<g id="local-post-office"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></g>
+<g id="local-printshop"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/></g>
+<g id="local-see"><circle cx="12" cy="12" r="3.2"/><path d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/></g>
+<g id="local-shipping"><path d="M20 8h-3V4H3c-1.1 0-2 .9-2 2v11h2c0 1.66 1.34 3 3 3s3-1.34 3-3h6c0 1.66 1.34 3 3 3s3-1.34 3-3h2v-5l-3-4zM6 18.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm13.5-9l1.96 2.5H17V9.5h2.5zm-1.5 9c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="local-taxi"><path d="M18.92 6.01C18.72 5.42 18.16 5 17.5 5H15V3H9v2H6.5c-.66 0-1.21.42-1.42 1.01L3 12v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5.67 1.5 1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z"/></g>
+<g id="map"><path d="M20.5 3l-.16.03L15 5.1 9 3 3.36 4.9c-.21.07-.36.25-.36.48V20.5c0 .28.22.5.5.5l.16-.03L9 18.9l6 2.1 5.64-1.9c.21-.07.36-.25.36-.48V3.5c0-.28-.22-.5-.5-.5zM15 19l-6-2.11V5l6 2.11V19z"/></g>
+<g id="my-location"><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
+<g id="navigation"><path d="M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71z"/></g>
+<g id="near-me"><path d="M21 3L3 10.53v.98l6.84 2.65L12.48 21h.98L21 3z"/></g>
+<g id="person-pin"><path d="M19 2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 3.3c1.49 0 2.7 1.21 2.7 2.7 0 1.49-1.21 2.7-2.7 2.7-1.49 0-2.7-1.21-2.7-2.7 0-1.49 1.21-2.7 2.7-2.7zM18 16H6v-.9c0-2 4-3.1 6-3.1s6 1.1 6 3.1v.9z"/></g>
+<g id="person-pin-circle"><path d="M12 2C8.14 2 5 5.14 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.86-3.14-7-7-7zm0 2c1.1 0 2 .9 2 2 0 1.11-.9 2-2 2s-2-.89-2-2c0-1.1.9-2 2-2zm0 10c-1.67 0-3.14-.85-4-2.15.02-1.32 2.67-2.05 4-2.05s3.98.73 4 2.05c-.86 1.3-2.33 2.15-4 2.15z"/></g>
+<g id="pin-drop"><path d="M18 8c0-3.31-2.69-6-6-6S6 4.69 6 8c0 4.5 6 11 6 11s6-6.5 6-11zm-8 0c0-1.1.9-2 2-2s2 .9 2 2-.89 2-2 2c-1.1 0-2-.9-2-2zM5 20v2h14v-2H5z"/></g>
+<g id="place"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g>
+<g id="rate-review"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 14v-2.47l6.88-6.88c.2-.2.51-.2.71 0l1.77 1.77c.2.2.2.51 0 .71L8.47 14H6zm12 0h-7.5l2-2H18v2z"/></g>
+<g id="restaurant-menu"><path d="M8.1 13.34l2.83-2.83L3.91 3.5c-1.56 1.56-1.56 4.09 0 5.66l4.19 4.18zm6.78-1.81c1.53.71 3.68.21 5.27-1.38 1.91-1.91 2.28-4.65.81-6.12-1.46-1.46-4.2-1.1-6.12.81-1.59 1.59-2.09 3.74-1.38 5.27L3.7 19.87l1.41 1.41L12 14.41l6.88 6.88 1.41-1.41L13.41 13l1.47-1.47z"/></g>
+<g id="satellite"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.99h3C8 6.65 6.66 8 5 8V4.99zM5 12v-2c2.76 0 5-2.25 5-5.01h2C12 8.86 8.87 12 5 12zm0 6l3.5-4.5 2.5 3.01L14.5 12l4.5 6H5z"/></g>
+<g id="store-mall-directory"><path d="M20 4H4v2h16V4zm1 10v-2l-1-5H4l-1 5v2h1v6h10v-6h4v6h2v-6h1zm-9 4H6v-4h6v4z"/></g>
+<g id="terrain"><path d="M14 6l-3.75 5 2.85 3.8-1.6 1.2C9.81 13.75 7 10 7 10l-6 8h22L14 6z"/></g>
+<g id="traffic"><path d="M20 10h-3V8.86c1.72-.45 3-2 3-3.86h-3V4c0-.55-.45-1-1-1H8c-.55 0-1 .45-1 1v1H4c0 1.86 1.28 3.41 3 3.86V10H4c0 1.86 1.28 3.41 3 3.86V15H4c0 1.86 1.28 3.41 3 3.86V20c0 .55.45 1 1 1h8c.55 0 1-.45 1-1v-1.14c1.72-.45 3-2 3-3.86h-3v-1.14c1.72-.45 3-2 3-3.86zm-8 9c-1.11 0-2-.9-2-2s.89-2 2-2c1.1 0 2 .9 2 2s-.89 2-2 2zm0-5c-1.11 0-2-.9-2-2s.89-2 2-2c1.1 0 2 .9 2 2s-.89 2-2 2zm0-5c-1.11 0-2-.9-2-2 0-1.11.89-2 2-2 1.1 0 2 .89 2 2 0 1.1-.89 2-2 2z"/></g>
+<g id="zoom-out-map"><path d="M15 3l2.3 2.3-2.89 2.87 1.42 1.42L18.7 6.7 21 9V3zM3 9l2.3-2.3 2.87 2.89 1.42-1.42L6.7 5.3 9 3H3zm6 12l-2.3-2.3 2.89-2.87-1.42-1.42L5.3 17.3 3 15v6zm12-6l-2.3 2.3-2.87-2.89-1.42 1.42 2.89 2.87L15 21h6z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/notification-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/notification-icons.html
new file mode 100644
index 00000000000..ac6744a2031
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/notification-icons.html
@@ -0,0 +1,66 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="notification" size="24">
+<svg><defs>
+<g id="adb"><path d="M5 16c0 3.87 3.13 7 7 7s7-3.13 7-7v-4H5v4zM16.12 4.37l2.1-2.1-.82-.83-2.3 2.31C14.16 3.28 13.12 3 12 3s-2.16.28-3.09.75L6.6 1.44l-.82.83 2.1 2.1C6.14 5.64 5 7.68 5 10v1h14v-1c0-2.32-1.14-4.36-2.88-5.63zM9 9c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm6 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></g>
+<g id="airline-seat-flat"><path d="M22 11v2H9V7h9c2.21 0 4 1.79 4 4zM2 14v2h6v2h8v-2h6v-2H2zm5.14-1.9c1.16-1.19 1.14-3.08-.04-4.24-1.19-1.16-3.08-1.14-4.24.04-1.16 1.19-1.14 3.08.04 4.24 1.19 1.16 3.08 1.14 4.24-.04z"/></g>
+<g id="airline-seat-flat-angled"><path d="M22.25 14.29l-.69 1.89L9.2 11.71l2.08-5.66 8.56 3.09c2.1.76 3.18 3.06 2.41 5.15zM1.5 12.14L8 14.48V19h8v-1.63L20.52 19l.69-1.89-19.02-6.86-.69 1.89zm5.8-1.94c1.49-.72 2.12-2.51 1.41-4C7.99 4.71 6.2 4.08 4.7 4.8c-1.49.71-2.12 2.5-1.4 4 .71 1.49 2.5 2.12 4 1.4z"/></g>
+<g id="airline-seat-individual-suite"><path d="M7 13c1.65 0 3-1.35 3-3S8.65 7 7 7s-3 1.35-3 3 1.35 3 3 3zm12-6h-8v7H3V7H1v10h22v-6c0-2.21-1.79-4-4-4z"/></g>
+<g id="airline-seat-legroom-extra"><path d="M4 12V3H2v9c0 2.76 2.24 5 5 5h6v-2H7c-1.66 0-3-1.34-3-3zm18.83 5.24c-.38-.72-1.29-.97-2.03-.63l-1.09.5-3.41-6.98c-.34-.68-1.03-1.12-1.79-1.12L11 9V3H5v8c0 1.66 1.34 3 3 3h7l3.41 7 3.72-1.7c.77-.36 1.1-1.3.7-2.06z"/></g>
+<g id="airline-seat-legroom-normal"><path d="M5 12V3H3v9c0 2.76 2.24 5 5 5h6v-2H8c-1.66 0-3-1.34-3-3zm15.5 6H19v-7c0-1.1-.9-2-2-2h-5V3H6v8c0 1.65 1.35 3 3 3h7v7h4.5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5z"/></g>
+<g id="airline-seat-legroom-reduced"><path d="M19.97 19.2c.18.96-.55 1.8-1.47 1.8H14v-3l1-4H9c-1.65 0-3-1.35-3-3V3h6v6h5c1.1 0 2 .9 2 2l-2 7h1.44c.73 0 1.39.49 1.53 1.2zM5 12V3H3v9c0 2.76 2.24 5 5 5h4v-2H8c-1.66 0-3-1.34-3-3z"/></g>
+<g id="airline-seat-recline-extra"><path d="M5.35 5.64c-.9-.64-1.12-1.88-.49-2.79.63-.9 1.88-1.12 2.79-.49.9.64 1.12 1.88.49 2.79-.64.9-1.88 1.12-2.79.49zM16 19H8.93c-1.48 0-2.74-1.08-2.96-2.54L4 7H2l1.99 9.76C4.37 19.2 6.47 21 8.94 21H16v-2zm.23-4h-4.88l-1.03-4.1c1.58.89 3.28 1.54 5.15 1.22V9.99c-1.63.31-3.44-.27-4.69-1.25L9.14 7.47c-.23-.18-.49-.3-.76-.38-.32-.09-.66-.12-.99-.06h-.02c-1.23.22-2.05 1.39-1.84 2.61l1.35 5.92C7.16 16.98 8.39 18 9.83 18h6.85l3.82 3 1.5-1.5-5.77-4.5z"/></g>
+<g id="airline-seat-recline-normal"><path d="M7.59 5.41c-.78-.78-.78-2.05 0-2.83.78-.78 2.05-.78 2.83 0 .78.78.78 2.05 0 2.83-.79.79-2.05.79-2.83 0zM6 16V7H4v9c0 2.76 2.24 5 5 5h6v-2H9c-1.66 0-3-1.34-3-3zm14 4.07L14.93 15H11.5v-3.68c1.4 1.15 3.6 2.16 5.5 2.16v-2.16c-1.66.02-3.61-.87-4.67-2.04l-1.4-1.55c-.19-.21-.43-.38-.69-.5-.29-.14-.62-.23-.96-.23h-.03C8.01 7 7 8.01 7 9.25V15c0 1.66 1.34 3 3 3h5.07l3.5 3.5L20 20.07z"/></g>
+<g id="bluetooth-audio"><path d="M14.24 12.01l2.32 2.32c.28-.72.44-1.51.44-2.33 0-.82-.16-1.59-.43-2.31l-2.33 2.32zm5.29-5.3l-1.26 1.26c.63 1.21.98 2.57.98 4.02s-.36 2.82-.98 4.02l1.2 1.2c.97-1.54 1.54-3.36 1.54-5.31-.01-1.89-.55-3.67-1.48-5.19zm-3.82 1L10 2H9v7.59L4.41 5 3 6.41 8.59 12 3 17.59 4.41 19 9 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM11 5.83l1.88 1.88L11 9.59V5.83zm1.88 10.46L11 18.17v-3.76l1.88 1.88z"/></g>
+<g id="confirmation-number"><path d="M22 10V6c0-1.11-.9-2-2-2H4c-1.1 0-1.99.89-1.99 2v4c1.1 0 1.99.9 1.99 2s-.89 2-2 2v4c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-4c-1.1 0-2-.9-2-2s.9-2 2-2zm-9 7.5h-2v-2h2v2zm0-4.5h-2v-2h2v2zm0-4.5h-2v-2h2v2z"/></g>
+<g id="disc-full"><path d="M20 16h2v-2h-2v2zm0-9v5h2V7h-2zM10 4c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm0 10c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g>
+<g id="do-not-disturb"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31C15.55 19.37 13.85 20 12 20zm6.31-3.1L7.1 5.69C8.45 4.63 10.15 4 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9z"/></g>
+<g id="do-not-disturb-alt"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zM4 12c0-4.4 3.6-8 8-8 1.8 0 3.5.6 4.9 1.7L5.7 16.9C4.6 15.5 4 13.8 4 12zm8 8c-1.8 0-3.5-.6-4.9-1.7L18.3 7.1C19.4 8.5 20 10.2 20 12c0 4.4-3.6 8-8 8z"/></g>
+<g id="drive-eta"><path d="M18.92 5.01C18.72 4.42 18.16 4 17.5 4h-11c-.66 0-1.21.42-1.42 1.01L3 11v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 15c-.83 0-1.5-.67-1.5-1.5S5.67 12 6.5 12s1.5.67 1.5 1.5S7.33 15 6.5 15zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 10l1.5-4.5h11L19 10H5z"/></g>
+<g id="enhanced-encryption"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H8.9V6zM16 16h-3v3h-2v-3H8v-2h3v-3h2v3h3v2z"/></g>
+<g id="event-available"><path d="M16.53 11.06L15.47 10l-4.88 4.88-2.12-2.12-1.06 1.06L10.59 17l5.94-5.94zM19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11z"/></g>
+<g id="event-busy"><path d="M9.31 17l2.44-2.44L14.19 17l1.06-1.06-2.44-2.44 2.44-2.44L14.19 10l-2.44 2.44L9.31 10l-1.06 1.06 2.44 2.44-2.44 2.44L9.31 17zM19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11z"/></g>
+<g id="event-note"><path d="M17 10H7v2h10v-2zm2-7h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zm-5-5H7v2h7v-2z"/></g>
+<g id="folder-special"><path d="M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-2.06 11L15 15.28 12.06 17l.78-3.33-2.59-2.24 3.41-.29L15 8l1.34 3.14 3.41.29-2.59 2.24.78 3.33z"/></g>
+<g id="live-tv"><path d="M21 6h-7.59l3.29-3.29L16 2l-4 4-4-4-.71.71L10.59 6H3c-1.1 0-2 .89-2 2v12c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.11-.9-2-2-2zm0 14H3V8h18v12zM9 10v8l7-4z"/></g>
+<g id="mms"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM5 14l3.5-4.5 2.5 3.01L14.5 8l4.5 6H5z"/></g>
+<g id="more"><path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.97.89 1.66.89H22c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 13.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm5 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm5 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
+<g id="network-check"><path d="M15.9 5c-.17 0-.32.09-.41.23l-.07.15-5.18 11.65c-.16.29-.26.61-.26.96 0 1.11.9 2.01 2.01 2.01.96 0 1.77-.68 1.96-1.59l.01-.03L16.4 5.5c0-.28-.22-.5-.5-.5zM1 9l2 2c2.88-2.88 6.79-4.08 10.53-3.62l1.19-2.68C9.89 3.84 4.74 5.27 1 9zm20 2l2-2c-1.64-1.64-3.55-2.82-5.59-3.57l-.53 2.82c1.5.62 2.9 1.53 4.12 2.75zm-4 4l2-2c-.8-.8-1.7-1.42-2.66-1.89l-.55 2.92c.42.27.83.59 1.21.97zM5 13l2 2c1.13-1.13 2.56-1.79 4.03-2l1.28-2.88c-2.63-.08-5.3.87-7.31 2.88z"/></g>
+<g id="network-locked"><path d="M19.5 10c.17 0 .33.03.5.05V1L1 20h13v-3c0-.89.39-1.68 1-2.23v-.27c0-2.48 2.02-4.5 4.5-4.5zm2.5 6v-1.5c0-1.38-1.12-2.5-2.5-2.5S17 13.12 17 14.5V16c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1zm-1 0h-3v-1.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V16z"/></g>
+<g id="no-encryption"><path d="M21 21.78L4.22 5 3 6.22l2.04 2.04C4.42 8.6 4 9.25 4 10v10c0 1.1.9 2 2 2h12c.23 0 .45-.05.66-.12L19.78 23 21 21.78zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H9.66L20 18.34V10c0-1.1-.9-2-2-2h-1V6c0-2.76-2.24-5-5-5-2.56 0-4.64 1.93-4.94 4.4L8.9 7.24V6z"/></g>
+<g id="ondemand-video"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"/></g>
+<g id="personal-video"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12z"/></g>
+<g id="phone-bluetooth-speaker"><path d="M14.71 9.5L17 7.21V11h.5l2.85-2.85L18.21 6l2.15-2.15L17.5 1H17v3.79L14.71 2.5l-.71.71L16.79 6 14 8.79l.71.71zM18 2.91l.94.94-.94.94V2.91zm0 4.3l.94.94-.94.94V7.21zm2 8.29c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1z"/></g>
+<g id="phone-forwarded"><path d="M18 11l5-5-5-5v3h-4v4h4v3zm2 4.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1z"/></g>
+<g id="phone-in-talk"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z"/></g>
+<g id="phone-locked"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM20 4v-.5C20 2.12 18.88 1 17.5 1S15 2.12 15 3.5V4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h5c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zm-.8 0h-3.4v-.5c0-.94.76-1.7 1.7-1.7s1.7.76 1.7 1.7V4z"/></g>
+<g id="phone-missed"><path d="M6.5 5.5L12 11l7-7-1-1-6 6-4.5-4.5H11V3H5v6h1.5V5.5zm17.21 11.17C20.66 13.78 16.54 12 12 12 7.46 12 3.34 13.78.29 16.67c-.18.18-.29.43-.29.71s.11.53.29.71l2.48 2.48c.18.18.43.29.71.29.27 0 .52-.11.7-.28.79-.74 1.69-1.36 2.66-1.85.33-.16.56-.5.56-.9v-3.1c1.45-.48 3-.73 4.6-.73 1.6 0 3.15.25 4.6.72v3.1c0 .39.23.74.56.9.98.49 1.87 1.12 2.67 1.85.18.18.43.28.7.28.28 0 .53-.11.71-.29l2.48-2.48c.18-.18.29-.43.29-.71s-.12-.52-.3-.7z"/></g>
+<g id="phone-paused"><path d="M17 3h-2v7h2V3zm3 12.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 3v7h2V3h-2z"/></g>
+<g id="power"><path d="M16.01 7L16 3h-2v4h-4V3H8v4h-.01C7 6.99 6 7.99 6 8.99v5.49L9.5 18v3h5v-3l3.5-3.51v-5.5c0-1-1-2-1.99-1.99z"/></g>
+<g id="rv-hookup"><path d="M20 17v-6c0-1.1-.9-2-2-2H7V7l-3 3 3 3v-2h4v3H4v3c0 1.1.9 2 2 2h2c0 1.66 1.34 3 3 3s3-1.34 3-3h8v-2h-2zm-9 3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm7-6h-4v-3h4v3zM17 2v2H9v2h8v2l3-3z"/></g>
+<g id="sd-card"><path d="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 6h-2V4h2v4zm3 0h-2V4h2v4zm3 0h-2V4h2v4z"/></g>
+<g id="sim-card-alert"><path d="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5 15h-2v-2h2v2zm0-4h-2V8h2v5z"/></g>
+<g id="sms"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z"/></g>
+<g id="sms-failed"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z"/></g>
+<g id="sync"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></g>
+<g id="sync-disabled"><path d="M10 6.35V4.26c-.8.21-1.55.54-2.23.96l1.46 1.46c.25-.12.5-.24.77-.33zm-7.14-.94l2.36 2.36C4.45 8.99 4 10.44 4 12c0 2.21.91 4.2 2.36 5.64L4 20h6v-6l-2.24 2.24C6.68 15.15 6 13.66 6 12c0-1 .25-1.94.68-2.77l8.08 8.08c-.25.13-.5.25-.77.34v2.09c.8-.21 1.55-.54 2.23-.96l2.36 2.36 1.27-1.27L4.14 4.14 2.86 5.41zM20 4h-6v6l2.24-2.24C17.32 8.85 18 10.34 18 12c0 1-.25 1.94-.68 2.77l1.46 1.46C19.55 15.01 20 13.56 20 12c0-2.21-.91-4.2-2.36-5.64L20 4z"/></g>
+<g id="sync-problem"><path d="M3 12c0 2.21.91 4.2 2.36 5.64L3 20h6v-6l-2.24 2.24C5.68 15.15 5 13.66 5 12c0-2.61 1.67-4.83 4-5.65V4.26C5.55 5.15 3 8.27 3 12zm8 5h2v-2h-2v2zM21 4h-6v6l2.24-2.24C18.32 8.85 19 10.34 19 12c0 2.61-1.67 4.83-4 5.65v2.09c3.45-.89 6-4.01 6-7.74 0-2.21-.91-4.2-2.36-5.64L21 4zm-10 9h2V7h-2v6z"/></g>
+<g id="system-update"><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14zm-1-6h-3V8h-2v5H8l4 4 4-4z"/></g>
+<g id="tap-and-play"><path d="M2 16v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm0 4v3h3c0-1.66-1.34-3-3-3zm0-8v2c4.97 0 9 4.03 9 9h2c0-6.08-4.92-11-11-11zM17 1.01L7 1c-1.1 0-2 .9-2 2v7.37c.69.16 1.36.37 2 .64V5h10v13h-3.03c.52 1.25.84 2.59.95 4H17c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99z"/></g>
+<g id="time-to-leave"><path d="M18.92 5.01C18.72 4.42 18.16 4 17.5 4h-11c-.66 0-1.21.42-1.42 1.01L3 11v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 15c-.83 0-1.5-.67-1.5-1.5S5.67 12 6.5 12s1.5.67 1.5 1.5S7.33 15 6.5 15zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 10l1.5-4.5h11L19 10H5z"/></g>
+<g id="vibration"><path d="M0 15h2V9H0v6zm3 2h2V7H3v10zm19-8v6h2V9h-2zm-3 8h2V7h-2v10zM16.5 3h-9C6.67 3 6 3.67 6 4.5v15c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-15c0-.83-.67-1.5-1.5-1.5zM16 19H8V5h8v14z"/></g>
+<g id="voice-chat"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12l-4-3.2V14H6V6h8v3.2L18 6v8z"/></g>
+<g id="vpn-lock"><path d="M22 4v-.5C22 2.12 20.88 1 19.5 1S17 2.12 17 3.5V4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h5c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zm-.8 0h-3.4v-.5c0-.94.76-1.7 1.7-1.7s1.7.76 1.7 1.7V4zm-2.28 8c.04.33.08.66.08 1 0 2.08-.8 3.97-2.1 5.39-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H7v-2h2c.55 0 1-.45 1-1V8h2c1.1 0 2-.9 2-2V3.46c-.95-.3-1.95-.46-3-.46C5.48 3 1 7.48 1 13s4.48 10 10 10 10-4.48 10-10c0-.34-.02-.67-.05-1h-2.03zM10 20.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L8 16v1c0 1.1.9 2 2 2v1.93z"/></g>
+<g id="wc"><path d="M5.5 22v-7.5H4V9c0-1.1.9-2 2-2h3c1.1 0 2 .9 2 2v5.5H9.5V22h-4zM18 22v-6h3l-2.54-7.63C18.18 7.55 17.42 7 16.56 7h-.12c-.86 0-1.63.55-1.9 1.37L12 16h3v6h3zM7.5 6c1.11 0 2-.89 2-2s-.89-2-2-2-2 .89-2 2 .89 2 2 2zm9 0c1.11 0 2-.89 2-2s-.89-2-2-2-2 .89-2 2 .89 2 2 2z"/></g>
+<g id="wifi"><path d="M1 9l2 2c4.97-4.97 13.03-4.97 18 0l2-2C16.93 2.93 7.08 2.93 1 9zm8 8l3 3 3-3c-1.65-1.66-4.34-1.66-6 0zm-4-4l2 2c2.76-2.76 7.24-2.76 10 0l2-2C15.14 9.14 8.87 9.14 5 13z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/places-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/places-icons.html
new file mode 100644
index 00000000000..5084b8c54d2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/places-icons.html
@@ -0,0 +1,33 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="places" size="24">
+<svg><defs>
+<g id="ac-unit"><path d="M22 11h-4.17l3.24-3.24-1.41-1.42L15 11h-2V9l4.66-4.66-1.42-1.41L13 6.17V2h-2v4.17L7.76 2.93 6.34 4.34 11 9v2H9L4.34 6.34 2.93 7.76 6.17 11H2v2h4.17l-3.24 3.24 1.41 1.42L9 13h2v2l-4.66 4.66 1.42 1.41L11 17.83V22h2v-4.17l3.24 3.24 1.42-1.41L13 15v-2h2l4.66 4.66 1.41-1.42L17.83 13H22z"/></g>
+<g id="airport-shuttle"><path d="M17 5H3c-1.1 0-2 .89-2 2v9h2c0 1.65 1.34 3 3 3s3-1.35 3-3h5.5c0 1.65 1.34 3 3 3s3-1.35 3-3H23v-5l-6-6zM3 11V7h4v4H3zm3 6.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm7-6.5H9V7h4v4zm4.5 6.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM15 11V7h1l4 4h-5z"/></g>
+<g id="all-inclusive"><path d="M18.6 6.62c-1.44 0-2.8.56-3.77 1.53L12 10.66 10.48 12h.01L7.8 14.39c-.64.64-1.49.99-2.4.99-1.87 0-3.39-1.51-3.39-3.38S3.53 8.62 5.4 8.62c.91 0 1.76.35 2.44 1.03l1.13 1 1.51-1.34L9.22 8.2C8.2 7.18 6.84 6.62 5.4 6.62 2.42 6.62 0 9.04 0 12s2.42 5.38 5.4 5.38c1.44 0 2.8-.56 3.77-1.53l2.83-2.5.01.01L13.52 12h-.01l2.69-2.39c.64-.64 1.49-.99 2.4-.99 1.87 0 3.39 1.51 3.39 3.38s-1.52 3.38-3.39 3.38c-.9 0-1.76-.35-2.44-1.03l-1.14-1.01-1.51 1.34 1.27 1.12c1.02 1.01 2.37 1.57 3.82 1.57 2.98 0 5.4-2.41 5.4-5.38s-2.42-5.37-5.4-5.37z"/></g>
+<g id="beach-access"><path d="M13.127 14.56l1.43-1.43 6.44 6.443L19.57 21zm4.293-5.73l2.86-2.86c-3.95-3.95-10.35-3.96-14.3-.02 3.93-1.3 8.31-.25 11.44 2.88zM5.95 5.98c-3.94 3.95-3.93 10.35.02 14.3l2.86-2.86C5.7 14.29 4.65 9.91 5.95 5.98zm.02-.02l-.01.01c-.38 3.01 1.17 6.88 4.3 10.02l5.73-5.73c-3.13-3.13-7.01-4.68-10.02-4.3z"/></g>
+<g id="business-center"><path d="M10 16v-1H3.01L3 19c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2v-4h-7v1h-4zm10-9h-4.01V5l-2-2h-4l-2 2v2H4c-1.1 0-2 .9-2 2v3c0 1.11.89 2 2 2h6v-2h4v2h6c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm-6 0h-4V5h4v2z"/></g>
+<g id="casino"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM7.5 18c-.83 0-1.5-.67-1.5-1.5S6.67 15 7.5 15s1.5.67 1.5 1.5S8.33 18 7.5 18zm0-9C6.67 9 6 8.33 6 7.5S6.67 6 7.5 6 9 6.67 9 7.5 8.33 9 7.5 9zm4.5 4.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4.5 4.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm0-9c-.83 0-1.5-.67-1.5-1.5S15.67 6 16.5 6s1.5.67 1.5 1.5S17.33 9 16.5 9z"/></g>
+<g id="child-care"><circle cx="14.5" cy="10.5" r="1.25"/><circle cx="9.5" cy="10.5" r="1.25"/><path d="M22.94 12.66c.04-.21.06-.43.06-.66s-.02-.45-.06-.66c-.25-1.51-1.36-2.74-2.81-3.17-.53-1.12-1.28-2.1-2.19-2.91C16.36 3.85 14.28 3 12 3s-4.36.85-5.94 2.26c-.92.81-1.67 1.8-2.19 2.91-1.45.43-2.56 1.65-2.81 3.17-.04.21-.06.43-.06.66s.02.45.06.66c.25 1.51 1.36 2.74 2.81 3.17.52 1.11 1.27 2.09 2.17 2.89C7.62 20.14 9.71 21 12 21s4.38-.86 5.97-2.28c.9-.8 1.65-1.79 2.17-2.89 1.44-.43 2.55-1.65 2.8-3.17zM19 14c-.1 0-.19-.02-.29-.03-.2.67-.49 1.29-.86 1.86C16.6 17.74 14.45 19 12 19s-4.6-1.26-5.85-3.17c-.37-.57-.66-1.19-.86-1.86-.1.01-.19.03-.29.03-1.1 0-2-.9-2-2s.9-2 2-2c.1 0 .19.02.29.03.2-.67.49-1.29.86-1.86C7.4 6.26 9.55 5 12 5s4.6 1.26 5.85 3.17c.37.57.66 1.19.86 1.86.1-.01.19-.03.29-.03 1.1 0 2 .9 2 2s-.9 2-2 2zM7.5 14c.76 1.77 2.49 3 4.5 3s3.74-1.23 4.5-3h-9z"/></g>
+<g id="child-friendly"><path d="M13 2v8h8c0-4.42-3.58-8-8-8zm6.32 13.89C20.37 14.54 21 12.84 21 11H6.44l-.95-2H2v2h2.22s1.89 4.07 2.12 4.42c-1.1.59-1.84 1.75-1.84 3.08C4.5 20.43 6.07 22 8 22c1.76 0 3.22-1.3 3.46-3h2.08c.24 1.7 1.7 3 3.46 3 1.93 0 3.5-1.57 3.5-3.5 0-1.04-.46-1.97-1.18-2.61zM8 20c-.83 0-1.5-.67-1.5-1.5S7.17 17 8 17s1.5.67 1.5 1.5S8.83 20 8 20zm9 0c-.83 0-1.5-.67-1.5-1.5S16.17 17 17 17s1.5.67 1.5 1.5S17.83 20 17 20z"/></g>
+<g id="fitness-center"><path d="M20.57 14.86L22 13.43 20.57 12 17 15.57 8.43 7 12 3.43 10.57 2 9.14 3.43 7.71 2 5.57 4.14 4.14 2.71 2.71 4.14l1.43 1.43L2 7.71l1.43 1.43L2 10.57 3.43 12 7 8.43 15.57 17 12 20.57 13.43 22l1.43-1.43L16.29 22l2.14-2.14 1.43 1.43 1.43-1.43-1.43-1.43L22 16.29z"/></g>
+<g id="free-breakfast"><path d="M20 3H4v10c0 2.21 1.79 4 4 4h6c2.21 0 4-1.79 4-4v-3h2c1.11 0 2-.9 2-2V5c0-1.11-.89-2-2-2zm0 5h-2V5h2v3zM4 19h16v2H4z"/></g>
+<g id="golf-course"><circle cx="19.5" cy="19.5" r="1.5"/><path d="M17 5.92L9 2v18H7v-1.73c-1.79.35-3 .99-3 1.73 0 1.1 2.69 2 6 2s6-.9 6-2c0-.99-2.16-1.81-5-1.97V8.98l6-3.06z"/></g>
+<g id="hot-tub"><circle cx="7" cy="6" r="2"/><path d="M11.15 12c-.31-.22-.59-.46-.82-.72l-1.4-1.55c-.19-.21-.43-.38-.69-.5-.29-.14-.62-.23-.96-.23h-.03C6.01 9 5 10.01 5 11.25V12H2v8c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-8H11.15zM7 20H5v-6h2v6zm4 0H9v-6h2v6zm4 0h-2v-6h2v6zm4 0h-2v-6h2v6zm-.35-14.14l-.07-.07c-.57-.62-.82-1.41-.67-2.2L18 3h-1.89l-.06.43c-.2 1.36.27 2.71 1.3 3.72l.07.06c.57.62.82 1.41.67 2.2l-.11.59h1.91l.06-.43c.21-1.36-.27-2.71-1.3-3.71zm-4 0l-.07-.07c-.57-.62-.82-1.41-.67-2.2L14 3h-1.89l-.06.43c-.2 1.36.27 2.71 1.3 3.72l.07.06c.57.62.82 1.41.67 2.2l-.11.59h1.91l.06-.43c.21-1.36-.27-2.71-1.3-3.71z"/></g>
+<g id="kitchen"><path d="M18 2.01L6 2c-1.1 0-2 .89-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.11-.9-1.99-2-1.99zM18 20H6v-9.02h12V20zm0-11H6V4h12v5zM8 5h2v3H8zm0 7h2v5H8z"/></g>
+<g id="pool"><path d="M22 21c-1.11 0-1.73-.37-2.18-.64-.37-.22-.6-.36-1.15-.36-.56 0-.78.13-1.15.36-.46.27-1.07.64-2.18.64s-1.73-.37-2.18-.64c-.37-.22-.6-.36-1.15-.36-.56 0-.78.13-1.15.36-.46.27-1.08.64-2.19.64-1.11 0-1.73-.37-2.18-.64-.37-.23-.6-.36-1.15-.36s-.78.13-1.15.36c-.46.27-1.08.64-2.19.64v-2c.56 0 .78-.13 1.15-.36.46-.27 1.08-.64 2.19-.64s1.73.37 2.18.64c.37.23.59.36 1.15.36.56 0 .78-.13 1.15-.36.46-.27 1.08-.64 2.19-.64 1.11 0 1.73.37 2.18.64.37.22.6.36 1.15.36s.78-.13 1.15-.36c.45-.27 1.07-.64 2.18-.64s1.73.37 2.18.64c.37.23.59.36 1.15.36v2zm0-4.5c-1.11 0-1.73-.37-2.18-.64-.37-.22-.6-.36-1.15-.36-.56 0-.78.13-1.15.36-.45.27-1.07.64-2.18.64s-1.73-.37-2.18-.64c-.37-.22-.6-.36-1.15-.36-.56 0-.78.13-1.15.36-.45.27-1.07.64-2.18.64s-1.73-.37-2.18-.64c-.37-.22-.6-.36-1.15-.36s-.78.13-1.15.36c-.47.27-1.09.64-2.2.64v-2c.56 0 .78-.13 1.15-.36.45-.27 1.07-.64 2.18-.64s1.73.37 2.18.64c.37.22.6.36 1.15.36.56 0 .78-.13 1.15-.36.45-.27 1.07-.64 2.18-.64s1.73.37 2.18.64c.37.22.6.36 1.15.36s.78-.13 1.15-.36c.45-.27 1.07-.64 2.18-.64s1.73.37 2.18.64c.37.22.6.36 1.15.36v2zM8.67 12c.56 0 .78-.13 1.15-.36.46-.27 1.08-.64 2.19-.64 1.11 0 1.73.37 2.18.64.37.22.6.36 1.15.36s.78-.13 1.15-.36c.12-.07.26-.15.41-.23L10.48 5C8.93 3.45 7.5 2.99 5 3v2.5c1.82-.01 2.89.39 4 1.5l1 1-3.25 3.25c.31.12.56.27.77.39.37.23.59.36 1.15.36z"/><circle cx="16.5" cy="5.5" r="2.5"/></g>
+<g id="room-service"><path d="M2 17h20v2H2zm11.84-9.21c.1-.24.16-.51.16-.79 0-1.1-.9-2-2-2s-2 .9-2 2c0 .28.06.55.16.79C6.25 8.6 3.27 11.93 3 16h18c-.27-4.07-3.25-7.4-7.16-8.21z"/></g>
+<g id="smoke-free"><path d="M2 6l6.99 7H2v3h9.99l7 7 1.26-1.25-17-17zm18.5 7H22v3h-1.5zM18 13h1.5v3H18zm.85-8.12c.62-.61 1-1.45 1-2.38h-1.5c0 1.02-.83 1.85-1.85 1.85v1.5c2.24 0 4 1.83 4 4.07V12H22V9.92c0-2.23-1.28-4.15-3.15-5.04zM14.5 8.7h1.53c1.05 0 1.97.74 1.97 2.05V12h1.5v-1.59c0-1.8-1.6-3.16-3.47-3.16H14.5c-1.02 0-1.85-.98-1.85-2s.83-1.75 1.85-1.75V2c-1.85 0-3.35 1.5-3.35 3.35s1.5 3.35 3.35 3.35zm2.5 7.23V13h-2.93z"/></g>
+<g id="smoking-rooms"><path d="M2 16h15v3H2zm18.5 0H22v3h-1.5zM18 16h1.5v3H18zm.85-8.27c.62-.61 1-1.45 1-2.38C19.85 3.5 18.35 2 16.5 2v1.5c1.02 0 1.85.83 1.85 1.85S17.52 7.2 16.5 7.2v1.5c2.24 0 4 1.83 4 4.07V15H22v-2.24c0-2.22-1.28-4.14-3.15-5.03zm-2.82 2.47H14.5c-1.02 0-1.85-.98-1.85-2s.83-1.75 1.85-1.75v-1.5c-1.85 0-3.35 1.5-3.35 3.35s1.5 3.35 3.35 3.35h1.53c1.05 0 1.97.74 1.97 2.05V15h1.5v-1.64c0-1.81-1.6-3.16-3.47-3.16z"/></g>
+<g id="spa"><path d="M8.55 12c-1.07-.71-2.25-1.27-3.53-1.61 1.28.34 2.46.9 3.53 1.61zm10.43-1.61c-1.29.34-2.49.91-3.57 1.64 1.08-.73 2.28-1.3 3.57-1.64z"/><path d="M15.49 9.63c-.18-2.79-1.31-5.51-3.43-7.63-2.14 2.14-3.32 4.86-3.55 7.63 1.28.68 2.46 1.56 3.49 2.63 1.03-1.06 2.21-1.94 3.49-2.63zm-6.5 2.65c-.14-.1-.3-.19-.45-.29.15.11.31.19.45.29zm6.42-.25c-.13.09-.27.16-.4.26.13-.1.27-.17.4-.26zM12 15.45C9.85 12.17 6.18 10 2 10c0 5.32 3.36 9.82 8.03 11.49.63.23 1.29.4 1.97.51.68-.12 1.33-.29 1.97-.51C18.64 19.82 22 15.32 22 10c-4.18 0-7.85 2.17-10 5.45z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-icons/social-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/social-icons.html
new file mode 100644
index 00000000000..8848395ef9c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-icons/social-icons.html
@@ -0,0 +1,40 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="social" size="24">
+<svg><defs>
+<g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g>
+<g id="domain"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></g>
+<g id="group"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></g>
+<g id="group-add"><path d="M8 10H5V7H3v3H0v2h3v3h2v-3h3v-2zm10 1c1.66 0 2.99-1.34 2.99-3S19.66 5 18 5c-.32 0-.63.05-.91.14.57.81.9 1.79.9 2.86s-.34 2.04-.9 2.86c.28.09.59.14.91.14zm-5 0c1.66 0 2.99-1.34 2.99-3S14.66 5 13 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm6.62 2.16c.83.73 1.38 1.66 1.38 2.84v2h3v-2c0-1.54-2.37-2.49-4.38-2.84zM13 13c-2 0-6 1-6 3v2h12v-2c0-2-4-3-6-3z"/></g>
+<g id="location-city"><path d="M15 11V5l-3-3-3 3v2H3v14h18V11h-6zm-8 8H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm6 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm6 12h-2v-2h2v2zm0-4h-2v-2h2v2z"/></g>
+<g id="mood"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></g>
+<g id="mood-bad"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 3c-2.33 0-4.31 1.46-5.11 3.5h10.22c-.8-2.04-2.78-3.5-5.11-3.5z"/></g>
+<g id="notifications"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></g>
+<g id="notifications-active"><path d="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"/></g>
+<g id="notifications-none"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z"/></g>
+<g id="notifications-off"><path d="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z"/></g>
+<g id="notifications-paused"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.93 6 11v5l-2 2v1h16v-1l-2-2zm-3.5-6.2l-2.8 3.4h2.8V15h-5v-1.8l2.8-3.4H9.5V8h5v1.8z"/></g>
+<g id="pages"><path d="M3 5v6h5L7 7l4 1V3H5c-1.1 0-2 .9-2 2zm5 8H3v6c0 1.1.9 2 2 2h6v-5l-4 1 1-4zm9 4l-4-1v5h6c1.1 0 2-.9 2-2v-6h-5l1 4zm2-14h-6v5l4-1-1 4h5V5c0-1.1-.9-2-2-2z"/></g>
+<g id="party-mode"><path d="M20 4h-3.17L15 2H9L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 3c1.63 0 3.06.79 3.98 2H12c-1.66 0-3 1.34-3 3 0 .35.07.69.18 1H7.1c-.06-.32-.1-.66-.1-1 0-2.76 2.24-5 5-5zm0 10c-1.63 0-3.06-.79-3.98-2H12c1.66 0 3-1.34 3-3 0-.35-.07-.69-.18-1h2.08c.07.32.1.66.1 1 0 2.76-2.24 5-5 5z"/></g>
+<g id="people"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></g>
+<g id="people-outline"><path d="M16.5 13c-1.2 0-3.07.34-4.5 1-1.43-.67-3.3-1-4.5-1C5.33 13 1 14.08 1 16.25V19h22v-2.75c0-2.17-4.33-3.25-6.5-3.25zm-4 4.5h-10v-1.25c0-.54 2.56-1.75 5-1.75s5 1.21 5 1.75v1.25zm9 0H14v-1.25c0-.46-.2-.86-.52-1.22.88-.3 1.96-.53 3.02-.53 2.44 0 5 1.21 5 1.75v1.25zM7.5 12c1.93 0 3.5-1.57 3.5-3.5S9.43 5 7.5 5 4 6.57 4 8.5 5.57 12 7.5 12zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 5.5c1.93 0 3.5-1.57 3.5-3.5S18.43 5 16.5 5 13 6.57 13 8.5s1.57 3.5 3.5 3.5zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z"/></g>
+<g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></g>
+<g id="person-add"><path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></g>
+<g id="person-outline"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/></g>
+<g id="plus-one"><path d="M10 8H8v4H4v2h4v4h2v-4h4v-2h-4zm4.5-1.92V7.9l2.5-.5V18h2V5z"/></g>
+<g id="poll"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></g>
+<g id="public"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></g>
+<g id="school"><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></g>
+<g id="share"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z"/></g>
+<g id="whatshot"><path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.bower.json
new file mode 100644
index 00000000000..b142eb2262c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.bower.json
@@ -0,0 +1,43 @@
+{
+ "name": "iron-iconset-svg",
+ "description": "Manages a set of svg icons",
+ "version": "1.0.9",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-iconset-svg.git"
+ },
+ "dependencies": {
+ "polymer": "polymer/polymer#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "promise-polyfill": "polymerlabs/promise-polyfill#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "*"
+ },
+ "main": "iron-iconset-svg.html",
+ "homepage": "https://github.com/polymerelements/iron-iconset-svg",
+ "_release": "1.0.9",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.9",
+ "commit": "ce9b2ea1f73d936cffdd05f3fe34b1f69d1d32db"
+ },
+ "_source": "git://github.com/polymerelements/iron-iconset-svg.git",
+ "_target": "^1.0.0",
+ "_originalSource": "polymerelements/iron-iconset-svg"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.travis.yml
new file mode 100644
index 00000000000..d4e78c40f20
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/.travis.yml
@@ -0,0 +1,28 @@
+language: node_js
+sudo: false
+matrix:
+ include:
+ - node_js: stable
+ script: xvfb-run wct
+ addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ - node_js: node
+ script:
+ - |
+ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
+ wct -s 'default'
+ fi
+before_script:
+- npm install web-component-tester
+- npm install bower
+- export PATH=$PWD/node_modules/.bin:$PATH
+- bower install
+env:
+ global:
+ - secure: UR1rxThVZH+l6fFHhAlgNIWs9wHmC5A102oAQBtCuQqKiXPZCDAPQHdjufX8z6hH93JkR+Esh2VPv0baSXFrHteKTRN6bsNDTMFDdHJ5BiRAdhVoV6bsdNH2GTgRXQ+ACMgrh4sXLA5+2Z+JGq7m0zaHehDfNZqmo/1U59qImP8=
+ - secure: PmWDypBdjKlUGPn9UoBEkjoYiyJFQGe2QiACmdOgueOLSLeA6xW+/1521uFIBHpwuWn29mxVYv5gS1D8hafWhZdXn4OYQl550RrT092jXIO6+mMKZXPmUaKCkPMY6QYJJ5j9ZOC36KgF//IpoE7OCxpLReYOD2KBR3mhw0jOYJA=
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/README.md
new file mode 100644
index 00000000000..f5b7e563e34
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/README.md
@@ -0,0 +1,50 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-iconset-svg.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-iconset-svg.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-iconset-svg)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-iconset-svg)_
+
+
+##&lt;iron-iconset-svg&gt;
+
+
+The `iron-iconset-svg` element allows users to define their own icon sets
+that contain svg icons. The svg icon elements should be children of the
+`iron-iconset-svg` element. Multiple icons should be given distinct id's.
+
+Using svg elements to create icons has a few advantages over traditional
+bitmap graphics like jpg or png. Icons that use svg are vector based so
+they are resolution independent and should look good on any device. They
+are stylable via css. Icons can be themed, colorized, and even animated.
+
+Example:
+
+ <iron-iconset-svg name="my-svg-icons" size="24">
+ <svg>
+ <defs>
+ <g id="shape">
+ <rect x="50" y="50" width="50" height="50" />
+ <circle cx="50" cy="50" r="50" />
+ </g>
+ </defs>
+ </svg>
+ </iron-iconset-svg>
+
+This will automatically register the icon set "my-svg-icons" to the iconset
+database. To use these icons from within another element, make a
+`iron-iconset` element and call the `byId` method
+to retrieve a given iconset. To apply a particular icon inside an
+element use the `applyIcon` method. For example:
+
+ iconset.applyIcon(iconNode, 'car');
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/bower.json
new file mode 100644
index 00000000000..8467a3b7e5d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-iconset-svg",
+ "description": "Manages a set of svg icons",
+ "version": "1.0.9",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "icon"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-iconset-svg.git"
+ },
+ "dependencies": {
+ "polymer": "polymer/polymer#^1.0.0",
+ "iron-meta": "polymerelements/iron-meta#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "promise-polyfill": "polymerlabs/promise-polyfill#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "*"
+ },
+ "main": "iron-iconset-svg.html"
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/index.html
new file mode 100644
index 00000000000..53b291aa357
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/index.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-iconset-svg</title>
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link href="../../paper-styles/demo-pages.html" rel="import">
+
+ <link rel="import" href="svg-sample-icons.html">
+ <style is="custom-style">
+
+ .centered {
+ text-align: center;
+ }
+
+ iron-icon {
+ height: 64px;
+ width: 64px;
+ margin: auto 1em;
+ }
+
+ iron-icon:nth-of-type(1) {
+ fill: orange;
+ }
+
+ iron-icon:nth-of-type(2) {
+ fill: green;
+ }
+
+ iron-icon:nth-of-type(3) {
+ fill: navy;
+ }
+
+ iron-icon:nth-of-type(4) {
+ fill: red;
+ }
+
+ iron-icon {
+ transition: all 0.5s;
+ -webkit-transition: all 0.5s;
+ }
+
+ iron-icon:hover {
+ -webkit-filter: drop-shadow( 2px 2px 2px var(--google-grey-700) );
+ filter: drop-shadow( 2px 2px 2px var(--google-grey-700) );
+ }
+ </style>
+</head>
+<body>
+
+ <div class="vertical-section vertical-section-container centered">
+ <iron-icon icon="svg-sample-icons:codepen"></iron-icon>
+ <iron-icon icon="svg-sample-icons:twitter"></iron-icon>
+ <iron-icon icon="svg-sample-icons:youtube"></iron-icon>
+ <iron-icon icon="inline:shape"></iron-icon>
+ </div>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/svg-sample-icons.html b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/svg-sample-icons.html
new file mode 100644
index 00000000000..3eed843f098
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/demo/svg-sample-icons.html
@@ -0,0 +1,81 @@
+
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-iconset-svg.html">
+
+<iron-iconset-svg name="svg-sample-icons" size="100">
+ <svg>
+ <defs>
+ <g id="codepen">
+ <path class="outer-ring" d="M50,0C22.385,0,0,22.385,0,50c0,27.615,22.385,50,50,50c27.614,0,50-22.385,50-50C100,22.385,77.615,0,50,0z M50,91.789
+ C26.958,91.789,8.212,73.042,8.212,50C8.212,26.958,26.958,8.212,50,8.212c23.042,0,41.788,18.747,41.788,41.789
+ C91.788,73.042,73.042,91.789,50,91.789z"></path>
+ <path class="inner-logo" d="M80.893,40.234c-0.006-0.039-0.016-0.076-0.022-0.115c-0.013-0.075-0.027-0.15-0.046-0.223
+ c-0.012-0.044-0.028-0.086-0.042-0.128c-0.021-0.065-0.042-0.13-0.068-0.193c-0.018-0.044-0.039-0.088-0.059-0.13
+ c-0.028-0.06-0.057-0.119-0.09-0.175c-0.024-0.042-0.051-0.083-0.076-0.124c-0.036-0.055-0.073-0.109-0.112-0.161
+ c-0.029-0.039-0.06-0.078-0.091-0.115c-0.042-0.049-0.086-0.098-0.132-0.143c-0.035-0.036-0.069-0.072-0.106-0.104
+ c-0.049-0.044-0.099-0.086-0.15-0.127c-0.04-0.031-0.079-0.062-0.12-0.091c-0.016-0.01-0.029-0.023-0.044-0.033L51.474,19.531
+ c-0.893-0.595-2.055-0.595-2.947,0L20.267,38.371c-0.015,0.01-0.028,0.023-0.044,0.033c-0.042,0.029-0.081,0.06-0.12,0.091
+ c-0.052,0.041-0.102,0.083-0.15,0.127c-0.037,0.032-0.071,0.068-0.106,0.104c-0.046,0.045-0.09,0.094-0.132,0.143
+ c-0.031,0.038-0.062,0.077-0.092,0.115c-0.039,0.052-0.076,0.106-0.111,0.161c-0.027,0.041-0.052,0.082-0.076,0.124
+ c-0.033,0.057-0.062,0.115-0.09,0.175c-0.021,0.042-0.042,0.086-0.06,0.13c-0.026,0.063-0.047,0.128-0.068,0.193
+ c-0.014,0.042-0.029,0.084-0.042,0.128c-0.02,0.073-0.032,0.148-0.046,0.223c-0.006,0.039-0.016,0.076-0.021,0.115
+ c-0.016,0.114-0.024,0.229-0.024,0.346V59.42c0,0.117,0.009,0.233,0.024,0.348c0.005,0.038,0.015,0.077,0.021,0.114
+ c0.014,0.075,0.027,0.149,0.046,0.223c0.012,0.043,0.028,0.086,0.042,0.128c0.021,0.065,0.042,0.13,0.068,0.195
+ c0.018,0.044,0.039,0.086,0.06,0.129c0.028,0.06,0.058,0.118,0.09,0.177c0.024,0.041,0.049,0.082,0.076,0.122
+ c0.035,0.056,0.072,0.109,0.111,0.161c0.029,0.041,0.061,0.078,0.092,0.115c0.042,0.049,0.086,0.098,0.132,0.144
+ c0.035,0.036,0.069,0.071,0.106,0.104c0.048,0.044,0.099,0.086,0.15,0.127c0.039,0.031,0.078,0.062,0.12,0.091
+ c0.016,0.01,0.029,0.023,0.044,0.032l28.259,18.84c0.446,0.297,0.96,0.447,1.474,0.447c0.513,0,1.027-0.149,1.473-0.447
+ l28.259-18.84c0.015-0.009,0.028-0.022,0.044-0.032c0.042-0.029,0.081-0.06,0.12-0.091c0.051-0.041,0.102-0.083,0.15-0.127
+ c0.037-0.033,0.071-0.068,0.106-0.104c0.046-0.046,0.09-0.095,0.132-0.144c0.031-0.037,0.062-0.075,0.091-0.115
+ c0.04-0.052,0.076-0.105,0.112-0.161c0.025-0.041,0.051-0.081,0.076-0.122c0.033-0.059,0.062-0.117,0.09-0.177
+ c0.02-0.042,0.041-0.085,0.059-0.129c0.026-0.065,0.047-0.13,0.068-0.195c0.014-0.042,0.03-0.085,0.042-0.128
+ c0.02-0.074,0.033-0.148,0.046-0.223c0.006-0.037,0.016-0.076,0.022-0.114c0.014-0.115,0.023-0.231,0.023-0.348V40.581
+ C80.916,40.464,80.907,40.348,80.893,40.234z M52.657,26.707l20.817,13.877l-9.298,6.221l-11.519-7.706V26.707z M47.343,26.707
+ v12.393l-11.518,7.706l-9.299-6.221L47.343,26.707z M24.398,45.554L31.046,50l-6.648,4.446V45.554z M47.343,73.294L26.525,59.417
+ l9.299-6.219l11.518,7.704V73.294z M50,56.286L40.603,50L50,43.715L59.397,50L50,56.286z M52.657,73.294V60.902l11.519-7.704
+ l9.298,6.219L52.657,73.294z M75.602,54.447L68.955,50l6.647-4.446V54.447z"></path>
+ </g>
+
+ <path id="twitter" d="M100.001,17.942c-3.681,1.688-7.633,2.826-11.783,3.339
+ c4.236-2.624,7.49-6.779,9.021-11.73c-3.965,2.432-8.354,4.193-13.026,5.146C80.47,10.575,75.138,8,69.234,8
+ c-11.33,0-20.518,9.494-20.518,21.205c0,1.662,0.183,3.281,0.533,4.833c-17.052-0.884-32.168-9.326-42.288-22.155
+ c-1.767,3.133-2.778,6.773-2.778,10.659c0,7.357,3.622,13.849,9.127,17.65c-3.363-0.109-6.525-1.064-9.293-2.651
+ c-0.002,0.089-0.002,0.178-0.002,0.268c0,10.272,7.072,18.845,16.458,20.793c-1.721,0.484-3.534,0.744-5.405,0.744
+ c-1.322,0-2.606-0.134-3.859-0.379c2.609,8.424,10.187,14.555,19.166,14.726c-7.021,5.688-15.867,9.077-25.48,9.077
+ c-1.656,0-3.289-0.102-4.895-0.297C9.08,88.491,19.865,92,31.449,92c37.737,0,58.374-32.312,58.374-60.336
+ c0-0.92-0.02-1.834-0.059-2.743C93.771,25.929,97.251,22.195,100.001,17.942L100.001,17.942z"></path>
+
+ <g id="youtube">
+ <path class="youtube" d="M98.77,27.492c-1.225-5.064-5.576-8.799-10.811-9.354C75.561,16.818,63.01,15.993,50.514,16
+ c-12.495-0.007-25.045,0.816-37.446,2.139c-5.235,0.557-9.583,4.289-10.806,9.354C0.522,34.704,0.5,42.574,0.5,50.001
+ c0,7.426,0,15.296,1.741,22.509c1.224,5.061,5.572,8.799,10.807,9.352c12.399,1.32,24.949,2.145,37.446,2.14
+ c12.494,0.005,25.047-0.817,37.443-2.14c5.234-0.555,9.586-4.291,10.81-9.352c1.741-7.213,1.753-15.083,1.753-22.509
+ S100.51,34.704,98.77,27.492 M67.549,52.203L43.977,64.391c-2.344,1.213-4.262,0.119-4.262-2.428V38.036
+ c0-2.548,1.917-3.644,4.262-2.429l23.572,12.188C69.896,49.008,69.896,50.992,67.549,52.203"></path>
+ </g>
+
+ </defs>
+
+ </svg>
+</iron-iconset-svg>
+
+<iron-iconset-svg name="inline" size="24">
+ <svg>
+ <defs>
+ <g id="shape">
+ <rect x="12" y="0" width="12" height="24" />
+ <circle cx="12" cy="12" r="12" />
+ </g>
+ </defs>
+ </svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/index.html
new file mode 100644
index 00000000000..e871f17d98d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/index.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/iron-iconset-svg.html b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/iron-iconset-svg.html
new file mode 100644
index 00000000000..5bd143ad6b6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-iconset-svg/iron-iconset-svg.html
@@ -0,0 +1,194 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-meta/iron-meta.html">
+
+<script>
+ /**
+ * The `iron-iconset-svg` element allows users to define their own icon sets
+ * that contain svg icons. The svg icon elements should be children of the
+ * `iron-iconset-svg` element. Multiple icons should be given distinct id's.
+ *
+ * Using svg elements to create icons has a few advantages over traditional
+ * bitmap graphics like jpg or png. Icons that use svg are vector based so
+ * they are resolution independent and should look good on any device. They
+ * are stylable via css. Icons can be themed, colorized, and even animated.
+ *
+ * Example:
+ *
+ * <iron-iconset-svg name="my-svg-icons" size="24">
+ * <svg>
+ * <defs>
+ * <g id="shape">
+ * <rect x="12" y="0" width="12" height="24" />
+ * <circle cx="12" cy="12" r="12" />
+ * </g>
+ * </defs>
+ * </svg>
+ * </iron-iconset-svg>
+ *
+ * This will automatically register the icon set "my-svg-icons" to the iconset
+ * database. To use these icons from within another element, make a
+ * `iron-iconset` element and call the `byId` method
+ * to retrieve a given iconset. To apply a particular icon inside an
+ * element use the `applyIcon` method. For example:
+ *
+ * iconset.applyIcon(iconNode, 'car');
+ *
+ * @element iron-iconset-svg
+ * @demo demo/index.html
+ * @implements {Polymer.Iconset}
+ */
+ Polymer({
+ is: 'iron-iconset-svg',
+
+ properties: {
+
+ /**
+ * The name of the iconset.
+ */
+ name: {
+ type: String,
+ observer: '_nameChanged'
+ },
+
+ /**
+ * The size of an individual icon. Note that icons must be square.
+ */
+ size: {
+ type: Number,
+ value: 24
+ }
+
+ },
+
+ attached: function() {
+ this.style.display = 'none';
+ },
+
+ /**
+ * Construct an array of all icon names in this iconset.
+ *
+ * @return {!Array} Array of icon names.
+ */
+ getIconNames: function() {
+ this._icons = this._createIconMap();
+ return Object.keys(this._icons).map(function(n) {
+ return this.name + ':' + n;
+ }, this);
+ },
+
+ /**
+ * Applies an icon to the given element.
+ *
+ * An svg icon is prepended to the element's shadowRoot if it exists,
+ * otherwise to the element itself.
+ *
+ * @method applyIcon
+ * @param {Element} element Element to which the icon is applied.
+ * @param {string} iconName Name of the icon to apply.
+ * @return {?Element} The svg element which renders the icon.
+ */
+ applyIcon: function(element, iconName) {
+ // insert svg element into shadow root, if it exists
+ element = element.root || element;
+ // Remove old svg element
+ this.removeIcon(element);
+ // install new svg element
+ var svg = this._cloneIcon(iconName);
+ if (svg) {
+ var pde = Polymer.dom(element);
+ pde.insertBefore(svg, pde.childNodes[0]);
+ return element._svgIcon = svg;
+ }
+ return null;
+ },
+
+ /**
+ * Remove an icon from the given element by undoing the changes effected
+ * by `applyIcon`.
+ *
+ * @param {Element} element The element from which the icon is removed.
+ */
+ removeIcon: function(element) {
+ // Remove old svg element
+ if (element._svgIcon) {
+ Polymer.dom(element).removeChild(element._svgIcon);
+ element._svgIcon = null;
+ }
+ },
+
+ /**
+ *
+ * When name is changed, register iconset metadata
+ *
+ */
+ _nameChanged: function() {
+ new Polymer.IronMeta({type: 'iconset', key: this.name, value: this});
+ this.async(function() {
+ this.fire('iron-iconset-added', this, {node: window});
+ });
+ },
+
+ /**
+ * Create a map of child SVG elements by id.
+ *
+ * @return {!Object} Map of id's to SVG elements.
+ */
+ _createIconMap: function() {
+ // Objects chained to Object.prototype (`{}`) have members. Specifically,
+ // on FF there is a `watch` method that confuses the icon map, so we
+ // need to use a null-based object here.
+ var icons = Object.create(null);
+ Polymer.dom(this).querySelectorAll('[id]')
+ .forEach(function(icon) {
+ icons[icon.id] = icon;
+ });
+ return icons;
+ },
+
+ /**
+ * Produce installable clone of the SVG element matching `id` in this
+ * iconset, or `undefined` if there is no matching element.
+ *
+ * @return {Element} Returns an installable clone of the SVG element
+ * matching `id`.
+ */
+ _cloneIcon: function(id) {
+ // create the icon map on-demand, since the iconset itself has no discrete
+ // signal to know when it's children are fully parsed
+ this._icons = this._icons || this._createIconMap();
+ return this._prepareSvgClone(this._icons[id], this.size);
+ },
+
+ /**
+ * @param {Element} sourceSvg
+ * @param {number} size
+ * @return {Element}
+ */
+ _prepareSvgClone: function(sourceSvg, size) {
+ if (sourceSvg) {
+ var content = sourceSvg.cloneNode(true),
+ svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
+ viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
+ svg.setAttribute('viewBox', viewBox);
+ svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
+ // TODO(dfreedm): `pointer-events: none` works around https://crbug.com/370136
+ // TODO(sjmiles): inline style may not be ideal, but avoids requiring a shadow-root
+ svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
+ svg.appendChild(content).removeAttribute('id');
+ return svg;
+ }
+ return null;
+ }
+
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/.github/ISSUE_TEMPLATE.md b/chromium/third_party/catapult/third_party/polymer/components/iron-image/.github/ISSUE_TEMPLATE.md
new file mode 100755
index 00000000000..d7459c59a5b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+<!-- Instructions: https://github.com/PolymerElements/iron-image/CONTRIBUTING.md#filing-issues -->
+### Description
+<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
+
+### Expected outcome
+
+<!-- Example: The page stays the same color. -->
+
+### Actual outcome
+
+<!-- Example: The page turns pink. -->
+
+### Live Demo
+<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
+
+### Steps to reproduce
+
+<!-- Example
+1. Put a `paper-foo` element in the page.
+2. Open the page in a web browser.
+3. Click the `paper-foo` element.
+-->
+
+### Browsers Affected
+<!-- Check all that apply -->
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari 9
+- [ ] Safari 8
+- [ ] Safari 7
+- [ ] Edge
+- [ ] IE 11
+- [ ] IE 10
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-image/.travis.yml
new file mode 100755
index 00000000000..74afb74311c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: citR35FLXNRA4C4o5Gl7gb6yvFhOq3rTd9+IQ8i9Zcf2TV2Ip2wCNANNXOvJV8szsu2fhZLttSclpW+MVePsW3ORYWOVm9neZeTczzNZkUExRKOztAyaujzzIgRd+f5ClJOsjUfGVLWKKWgKMJ8UT4pNRgqwKe4V73oW7LhYpto=
+ - secure: bWeuwHFJSBQu3v2K5I2++tCWh3K05I8NEfi6mywbrxuiOCGNvCWFLTO42+aqUp/yAnolNIKYR5NJFtty5CX2YD4oaRbryk2gzv7UtpIXRx9Jqhe7b/UBzfHIxPoT12TFS/iub+oRnZPAVPPoDrXwwoHkWltZHZwpOVTp86T6DPI=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-image/CONTRIBUTING.md
new file mode 100755
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-image/README.md
new file mode 100755
index 00000000000..379796269f0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/README.md
@@ -0,0 +1,86 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-image.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-image.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-image)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-image)_
+
+
+##&lt;iron-image&gt;
+
+`iron-image` is an element for displaying an image that provides useful sizing and
+preloading options not found on the standard `<img>` tag.
+
+The `sizing` option allows the image to be either cropped (`cover`) or
+letterboxed (`contain`) to fill a fixed user-size placed on the element.
+
+The `preload` option prevents the browser from rendering the image until the
+image is fully loaded. In the interim, either the element's CSS `background-color`
+can be be used as the placeholder, or the `placeholder` property can be
+set to a URL (preferably a data-URI, for instant rendering) for an
+placeholder image.
+
+The `fade` option (only valid when `preload` is set) will cause the placeholder
+image/color to be faded out once the image is rendered.
+
+Examples:
+
+ Basically identical to `<img src="...">` tag:
+
+```html
+<iron-image src="http://lorempixel.com/400/400"></iron-image>
+```
+
+ Will letterbox the image to fit:
+
+```html
+<iron-image style="width:400px; height:400px;" sizing="contain"
+ src="http://lorempixel.com/600/400"></iron-image>
+```
+
+ Will crop the image to fit:
+
+```html
+<iron-image style="width:400px; height:400px;" sizing="cover"
+ src="http://lorempixel.com/600/400"></iron-image>
+```
+
+ Will show light-gray background until the image loads:
+
+```html
+<iron-image style="width:400px; height:400px; background-color: lightgray;"
+ sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image>
+```
+
+ Will show a base-64 encoded placeholder image until the image loads:
+
+```html
+<iron-image style="width:400px; height:400px;" placeholder="data:image/gif;base64,..."
+ sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image>
+```
+
+ Will fade the light-gray background out once the image is loaded:
+
+```html
+<iron-image style="width:400px; height:400px; background-color: lightgray;"
+ sizing="cover" preload fade src="http://lorempixel.com/600/400"></iron-image>
+```
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-image-placeholder` | Mixin applied to #placeholder | `{}` |
+| `--iron-image-width` | Sets the width of the wrapped image | `auto` |
+| `--iron-image-height` | Sets the height of the wrapped image | `auto` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-image/bower.json
new file mode 100755
index 00000000000..9ac7b5d6552
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-image",
+ "version": "1.2.3",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "An image-displaying element with lots of convenient features",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "media"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-image.git"
+ },
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.4",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": "iron-image.html",
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/index.html
new file mode 100755
index 00000000000..06c533cf0b5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/index.html
@@ -0,0 +1,266 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <title>iron-image demo</title>
+
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../polymer/polymer.html">
+ <link rel="import" href="../iron-image.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ .example {
+ margin: 4px;
+ flex: 1;
+ }
+
+ code {
+ white-space: nowrap;
+ }
+ </style>
+
+ <script>
+ function load(id) {
+ document.getElementById(id).src = "./polymer.svg?" + Math.random();
+ }
+ </script>
+
+ </head>
+ <body unresolved>
+
+ <div class="vertical-section-container centered">
+
+ <h3>A plain <code>iron-image</code>.</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <iron-image alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ <code>sizing="cover"</code> expands the image to cover all of its
+ specified size.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ #example-sizing-cover {
+ width: 150px;
+ height: 150px;
+ background: #ddd;
+ }
+ </style>
+
+ <iron-image sizing="cover" id="example-sizing-cover" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ <code>sizing="contain"</code> expands the image to fit within its
+ specified size.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ #example-sizing-contain {
+ width: 150px;
+ height: 150px;
+ background: #ddd;
+ }
+ </style>
+
+ <iron-image sizing="contain" id="example-sizing-contain" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ Use the <code>--iron-image-width</code> property to set the width of
+ the image wrapped by the <code>iron-image</code>.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ #example-full-width-container {
+ width: 200px;
+ border: 2px solid #444;
+ background: #444;
+ }
+
+ #example-full-width-container iron-image {
+ background: #ddd;
+ }
+
+ #example-full-width {
+ width: 100%;
+ --iron-image-width: 100%;
+ }
+
+ #example-half-width {
+ width: 50%;
+ --iron-image-width: 100%;
+ }
+ </style>
+
+
+ <div id="example-full-width-container">
+ <iron-image id="example-full-width" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ <iron-image id="example-half-width" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ Use the <code>--iron-image-height</code> property to set the height of
+ the image wrapped by the <code>iron-image</code>.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ #example-full-height-container {
+ height: 150px;
+ border: 2px solid #444;
+ background: #444;
+ }
+
+ #example-full-height-container iron-image{
+ background: #ddd;
+ }
+
+ #example-full-height {
+ height: 100%;
+ --iron-image-height: 100%;
+ }
+
+ #example-half-height {
+ height: 50%;
+ --iron-image-height: 100%;
+ }
+ </style>
+
+
+ <div id="example-full-height-container">
+ <iron-image id="example-full-height" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ <iron-image id="example-half-height" alt="The Polymer logo." src="./polymer.svg"></iron-image>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ No placeholder is shown by default.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ .example.without-preload iron-image {
+ width: 150px;
+ height: 150px;
+ background: #ddd;
+ }
+ </style>
+
+ <div class="example without-preload">
+ <button onclick="load('example-without-preload-1')">
+ Load image
+ </button>
+ <br>
+ <iron-image sizing="contain" alt="The Polymer logo." id="example-without-preload-1"></iron-image>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ The <code>preload</code> attribute shows a placeholder element in front
+ of the image before it has loaded. Use the
+ <code>--iron-image-placeholder</code> CSS mixin to style it.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ .example.preload iron-image {
+ width: 150px;
+ height: 150px;
+ background: #ddd;
+ --iron-image-placeholder: {
+ background: #939ed5;
+ };
+ }
+ </style>
+
+ <div class="example preload">
+ <button onclick="load('example-preload-1')">
+ Load image
+ </button>
+ <br>
+ <iron-image preload id="example-preload-1" alt="The Polymer logo." class="sized" sizing="contain"></iron-image>
+ <br>
+ Without the <code>fade</code> attribute, the placeholder element is
+ hidden with no transition when the image loads.
+ </div>
+ <div class="example preload">
+ <button onclick="load('example-preload-2')">
+ Load image
+ </button>
+ <br>
+ <iron-image preload fade id="example-preload-2" alt="The Polymer logo." class="sized" sizing="contain"></iron-image>
+ <br>
+ With the <code>fade</code> attribute, the placeholder element is
+ fades away when the image loads.
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>
+ Use the <code>placeholder</code> attribute to specify a background image
+ for the placeholder element.
+ </h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ .example.preload-image iron-image {
+ width: 150px;
+ height: 150px;
+ background: #ddd;
+ }
+ </style>
+
+ <div class="example preload-image">
+ <button onclick="load('example-preload-image-1')">
+ Load image
+ </button>
+ <br>
+ <iron-image preload placeholder="./loading.png" id="example-preload-image-1" alt="The Polymer logo." class="sized" sizing="contain"></iron-image>
+ <br>
+ (without <code>fade</code> attribute)
+ </div>
+ <div class="example preload-image">
+ <button onclick="load('example-preload-image-2')">
+ Load image
+ </button>
+ <br>
+ <iron-image preload placeholder="./loading.png" fade id="example-preload-image-2" alt="The Polymer logo." class="sized" sizing="contain"></iron-image>
+ <br>
+ (with <code>fade</code> attribute)
+ </div>
+ </template>
+ </demo-snippet>
+
+ </div>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/loading.png b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/loading.png
new file mode 100644
index 00000000000..a87e1719d8c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/loading.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/polymer.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/polymer.svg
new file mode 100755
index 00000000000..f7a815dda5b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/demo/polymer.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="208px" height="143px" viewBox="0 0 416 286" enable-background="new 0 0 416 286" xml:space="preserve">
+<g>
+ <g>
+ <polygon fill="#303F9F" points="84.157,143 42.878,214.5 84.157,286 125.436,214.5 "/>
+ <polygon fill="#3F51B5" points="331.842,0 290.561,71.5 331.842,143 373.121,71.5 "/>
+ <polygon fill="#7986CB" points="373.121,71.5 249.278,286 331.842,286 414.4,143 "/>
+ <polygon fill="#FF4081" points="249.278,0 84.157,286 166.721,286 331.842,0 "/>
+ <polygon fill="#536DFE" points="84.157,0 1.596,143 42.878,214.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="249.278,0 290.561,71.5 331.842,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="208,71.5 249.278,0 290.561,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="208,71.5 249.278,143 290.561,71.5 "/>
+ <polygon fill-opacity="0.1" points="166.721,143 208,71.5 249.278,143 "/>
+ <polygon fill-opacity="0.2" points="166.721,143 208,214.5 249.278,143 "/>
+ <polygon fill-opacity="0.3" points="125.438,214.5 166.721,143 208,214.5 "/>
+ <polygon fill-opacity="0.4" points="125.438,214.5 166.721,286 208,214.5 "/>
+ <polygon fill-opacity="0.5" points="84.157,286 125.438,214.5 166.721,286 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="84.157,0 125.438,71.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="42.878,71.5 84.157,0 125.438,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="42.878,71.5 84.157,143 125.438,71.5 "/>
+ <polygon fill-opacity="0.1" points="1.598,143 42.878,71.5 84.157,143 "/>
+ <polygon fill-opacity="0.2" points="1.598,143 42.878,214.5 84.157,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="125.438,214.5 84.157,143 42.878,214.5 "/>
+ <polygon fill-opacity="0.2" points="125.438,214.5 84.157,286 42.878,214.5 "/>
+ <polygon fill-opacity="0.2" points="373.121,71.5 331.842,0 290.561,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="373.121,71.5 331.842,143 290.561,71.5 "/>
+ <g>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="331.842,143 373.121,71.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="331.842,143 373.121,214.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="290.561,214.5 331.842,143 373.121,214.5 "/>
+ <polygon fill-opacity="0.1" points="290.561,214.5 331.842,286 373.121,214.5 "/>
+ <polygon fill-opacity="0.2" points="249.278,286 290.561,214.5 331.842,286 "/>
+ </g>
+ </g>
+ <rect y="-65" fill="none" width="416" height="416"/>
+</g>
+<g display="none">
+ <g display="inline">
+ <polygon fill="#303F9F" points="84.157,143 42.878,214.5 84.157,286 166.721,286 "/>
+ <polygon fill="#3F51B5" points="331.842,0 249.278,0 331.842,143 373.121,71.5 "/>
+ <polygon fill="#7986CB" points="373.121,71.5 249.278,286 331.842,286 414.4,143 "/>
+ <polygon fill="#536DFE" points="84.157,0 1.596,143 42.878,214.5 166.721,0 "/>
+ <polygon fill-opacity="0.5" points="249.278,0 290.561,71.5 331.842,0 "/>
+ <polygon fill-opacity="0.5" points="84.157,286 125.438,214.5 166.721,286 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="84.157,0 125.438,71.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="42.878,71.5 84.157,0 125.438,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="42.878,71.5 84.157,143 125.438,71.5 "/>
+ <polygon fill-opacity="0.1" points="1.598,143 42.878,71.5 84.157,143 "/>
+ <polygon fill-opacity="0.2" points="1.598,143 42.878,214.5 84.157,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="125.438,214.5 84.157,143 42.878,214.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="373.121,71.5 331.842,143 290.561,71.5 "/>
+ <g>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="331.842,143 373.121,71.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="331.842,143 373.121,214.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="290.561,214.5 331.842,143 373.121,214.5 "/>
+ <polygon fill-opacity="0.1" points="290.561,214.5 331.842,286 373.121,214.5 "/>
+ <polygon fill-opacity="0.2" points="249.278,286 290.561,214.5 331.842,286 "/>
+ </g>
+ <polygon fill-opacity="0.2" points="125.438,214.5 84.157,286 42.878,214.5 "/>
+ <polygon fill-opacity="0.2" points="373.121,71.5 331.842,0 290.561,71.5 "/>
+ </g>
+ <rect y="-65" display="inline" fill="none" width="416" height="416"/>
+</g>
+<g display="none">
+ <g display="inline">
+ <polygon fill="#FF4081" points="249.279,0 84.157,286 166.721,286 331.843,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="249.279,0 290.558,71.5 331.843,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="208,71.5 249.279,0 290.558,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="208,71.5 249.279,143 290.558,71.5 "/>
+ <polygon fill-opacity="0.2" points="166.721,143 208,214.5 249.279,143 "/>
+ <polygon fill-opacity="0.3" points="125.439,214.5 166.721,143 208,214.5 "/>
+ <polygon fill-opacity="0.4" points="125.439,214.5 166.721,286 208,214.5 "/>
+ <polygon fill-opacity="0.5" points="84.157,286 125.439,214.5 166.721,286 "/>
+ <polygon fill-opacity="0.1" points="166.721,143 208,71.5 249.279,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#FF4081" points="331.84,0 166.718,286 249.279,286 373.121,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="290.558,71.5 331.84,0 373.121,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="290.558,71.5 331.84,143 373.121,71.5 "/>
+ <polygon fill-opacity="0.2" points="249.279,143 290.558,214.5 331.84,143 "/>
+ <polygon fill-opacity="0.3" points="208,214.5 249.279,143 290.558,214.5 "/>
+ <polygon fill-opacity="0.4" points="208,214.5 249.279,286 290.558,214.5 "/>
+ <polygon fill-opacity="0.5" points="166.718,286 208,214.5 249.279,286 "/>
+ <polygon fill-opacity="0.1" points="249.279,143 290.558,71.5 331.84,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#FF4081" points="166.718,0 42.878,214.5 84.16,286 249.279,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="166.718,0 208,71.5 249.279,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="125.439,71.5 166.718,0 208,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="125.439,71.5 166.718,143 208,71.5 "/>
+ <polygon fill-opacity="0.2" points="84.16,143 125.439,214.5 166.718,143 "/>
+ <polygon fill-opacity="0.3" points="42.878,214.5 84.16,143 125.439,214.5 "/>
+ <polygon fill-opacity="0.4" points="42.878,214.5 84.16,286 125.439,214.5 "/>
+ <polygon fill-opacity="0.1" points="84.16,143 125.439,71.5 166.718,143 "/>
+ </g>
+ <rect y="-65" display="inline" fill="none" width="416" height="416"/>
+ <g display="inline">
+ <polygon fill="#303F9F" points="84.157,143 42.878,214.5 84.157,286 166.721,286 "/>
+ <polygon fill="#3F51B5" points="331.843,0 249.279,0 331.843,143 373.121,71.5 "/>
+ <polygon fill="#7986CB" points="373.121,71.5 249.279,286 331.843,286 414.4,143 "/>
+ <polygon fill="#536DFE" points="84.157,0 1.597,143 42.878,214.5 166.721,0 "/>
+ <polygon fill-opacity="0.5" points="249.279,0 290.558,71.5 331.843,0 "/>
+ <polygon fill-opacity="0.5" points="84.157,286 125.439,214.5 166.721,286 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="84.157,0 125.439,71.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="42.878,71.5 84.157,0 125.439,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="42.878,71.5 84.157,143 125.439,71.5 "/>
+ <polygon fill-opacity="0.1" points="1.6,143 42.878,71.5 84.157,143 "/>
+ <polygon fill-opacity="0.2" points="1.6,143 42.878,214.5 84.157,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="125.439,214.5 84.157,143 42.878,214.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="373.121,71.5 331.843,143 290.558,71.5 "/>
+ <g>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="331.843,143 373.121,71.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="331.843,143 373.121,214.5 414.4,143 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="290.558,214.5 331.843,143 373.121,214.5 "/>
+ <polygon fill-opacity="0.1" points="290.558,214.5 331.843,286 373.121,214.5 "/>
+ <polygon fill-opacity="0.2" points="249.279,286 290.558,214.5 331.843,286 "/>
+ </g>
+ <polygon fill-opacity="0.2" points="125.439,214.5 84.157,286 42.878,214.5 "/>
+ <polygon fill-opacity="0.2" points="373.121,71.5 331.843,0 290.558,71.5 "/>
+ </g>
+</g>
+<g display="none">
+ <g display="inline">
+ <polygon fill="#9F499B" points="249.279,0 84.157,286 166.721,286 331.843,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="249.279,0 290.558,71.5 331.843,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="208,71.5 249.279,0 290.558,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="208,71.5 249.279,143 290.558,71.5 "/>
+ <polygon fill-opacity="0.2" points="166.721,143 208,214.5 249.279,143 "/>
+ <polygon fill-opacity="0.3" points="125.439,214.5 166.721,143 208,214.5 "/>
+ <polygon fill-opacity="0.4" points="125.439,214.5 166.721,286 208,214.5 "/>
+ <polygon fill-opacity="0.5" points="84.157,286 125.439,214.5 166.721,286 "/>
+ <polygon fill-opacity="0.1" points="166.721,143 208,71.5 249.279,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#9F499B" points="331.84,0 166.718,286 249.279,286 373.121,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="290.558,71.5 331.84,0 373.121,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="290.558,71.5 331.84,143 373.121,71.5 "/>
+ <polygon fill-opacity="0.2" points="249.279,143 290.558,214.5 331.84,143 "/>
+ <polygon fill-opacity="0.3" points="208,214.5 249.279,143 290.558,214.5 "/>
+ <polygon fill-opacity="0.4" points="208,214.5 249.279,286 290.558,214.5 "/>
+ <polygon fill-opacity="0.5" points="166.718,286 208,214.5 249.279,286 "/>
+ <polygon fill-opacity="0.1" points="249.279,143 290.558,71.5 331.84,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#9F499B" points="373.121,71.5 249.279,286 331.843,286 414.4,143 "/>
+ <polygon fill-opacity="0.2" points="331.843,143 373.121,214.5 414.4,143 "/>
+ <polygon fill-opacity="0.3" points="290.558,214.5 331.843,143 373.121,214.5 "/>
+ <polygon fill-opacity="0.4" points="290.558,214.5 331.843,286 373.121,214.5 "/>
+ <polygon fill-opacity="0.5" points="249.279,286 290.558,214.5 331.843,286 "/>
+ <polygon fill-opacity="0.1" points="331.843,143 373.121,71.5 414.4,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#9F499B" points="166.718,0 42.878,214.5 84.16,286 249.279,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="166.718,0 208,71.5 249.279,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="125.439,71.5 166.718,0 208,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="125.439,71.5 166.718,143 208,71.5 "/>
+ <polygon fill-opacity="0.2" points="84.16,143 125.439,214.5 166.718,143 "/>
+ <polygon fill-opacity="0.3" points="42.878,214.5 84.16,143 125.439,214.5 "/>
+ <polygon fill-opacity="0.4" points="42.878,214.5 84.16,286 125.439,214.5 "/>
+ <polygon fill-opacity="0.1" points="84.16,143 125.439,71.5 166.718,143 "/>
+ </g>
+ <g display="inline">
+ <polygon fill="#9F499B" points="84.157,0 1.6,143 42.878,214.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.2" points="84.157,0 125.439,71.5 166.721,0 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0.1" points="42.878,71.5 84.157,0 125.439,71.5 "/>
+ <polygon fill="#FFFFFF" fill-opacity="0" points="42.878,71.5 84.157,143 125.439,71.5 "/>
+ <polygon fill-opacity="0.2" points="1.6,143 42.878,214.5 84.157,143 "/>
+ <polygon fill-opacity="0.1" points="1.6,143 42.878,71.5 84.157,143 "/>
+ </g>
+ <rect y="-65" display="inline" fill="none" width="416" height="416"/>
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-image/index.html
new file mode 100755
index 00000000000..bb7da82e87c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>iron-image</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-image/iron-image.html b/chromium/third_party/catapult/third_party/polymer/components/iron-image/iron-image.html
new file mode 100755
index 00000000000..bf774d6ccbc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-image/iron-image.html
@@ -0,0 +1,403 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+
+<!--
+`iron-image` is an element for displaying an image that provides useful sizing and
+preloading options not found on the standard `<img>` tag.
+
+The `sizing` option allows the image to be either cropped (`cover`) or
+letterboxed (`contain`) to fill a fixed user-size placed on the element.
+
+The `preload` option prevents the browser from rendering the image until the
+image is fully loaded. In the interim, either the element's CSS `background-color`
+can be be used as the placeholder, or the `placeholder` property can be
+set to a URL (preferably a data-URI, for instant rendering) for an
+placeholder image.
+
+The `fade` option (only valid when `preload` is set) will cause the placeholder
+image/color to be faded out once the image is rendered.
+
+Examples:
+
+ Basically identical to `<img src="...">` tag:
+
+ <iron-image src="http://lorempixel.com/400/400"></iron-image>
+
+ Will letterbox the image to fit:
+
+ <iron-image style="width:400px; height:400px;" sizing="contain"
+ src="http://lorempixel.com/600/400"></iron-image>
+
+ Will crop the image to fit:
+
+ <iron-image style="width:400px; height:400px;" sizing="cover"
+ src="http://lorempixel.com/600/400"></iron-image>
+
+ Will show light-gray background until the image loads:
+
+ <iron-image style="width:400px; height:400px; background-color: lightgray;"
+ sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image>
+
+ Will show a base-64 encoded placeholder image until the image loads:
+
+ <iron-image style="width:400px; height:400px;" placeholder="data:image/gif;base64,..."
+ sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image>
+
+ Will fade the light-gray background out once the image is loaded:
+
+ <iron-image style="width:400px; height:400px; background-color: lightgray;"
+ sizing="cover" preload fade src="http://lorempixel.com/600/400"></iron-image>
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--iron-image-placeholder` | Mixin applied to #placeholder | `{}`
+`--iron-image-width` | Sets the width of the wrapped image | `auto`
+`--iron-image-height` | Sets the height of the wrapped image | `auto`
+
+@group Iron Elements
+@element iron-image
+@demo demo/index.html
+-->
+
+<dom-module id="iron-image">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ }
+
+ #sizedImgDiv {
+ @apply(--layout-fit);
+
+ display: none;
+ }
+
+ #img {
+ display: block;
+ width: var(--iron-image-width, auto);
+ height: var(--iron-image-height, auto);
+ }
+
+ :host([sizing]) #sizedImgDiv {
+ display: block;
+ }
+
+ :host([sizing]) #img {
+ display: none;
+ }
+
+ #placeholder {
+ @apply(--layout-fit);
+
+ background-color: inherit;
+ opacity: 1;
+
+ @apply(--iron-image-placeholder);
+ }
+
+ #placeholder.faded-out {
+ transition: opacity 0.5s linear;
+ opacity: 0;
+ }
+ </style>
+
+ <div id="sizedImgDiv"
+ role="img"
+ hidden$="[[_computeImgDivHidden(sizing)]]"
+ aria-hidden$="[[_computeImgDivARIAHidden(alt)]]"
+ aria-label$="[[_computeImgDivARIALabel(alt, src)]]"></div>
+ <img id="img" alt$="[[alt]]" hidden$="[[_computeImgHidden(sizing)]]">
+ <div id="placeholder"
+ hidden$="[[_computePlaceholderHidden(preload, fade, loading, loaded)]]"
+ class$="[[_computePlaceholderClassName(preload, fade, loading, loaded)]]"></div>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'iron-image',
+
+ properties: {
+ /**
+ * The URL of an image.
+ */
+ src: {
+ observer: '_srcChanged',
+ type: String,
+ value: ''
+ },
+
+ /**
+ * A short text alternative for the image.
+ */
+ alt: {
+ type: String,
+ value: null
+ },
+
+ /**
+ * When true, the image is prevented from loading and any placeholder is
+ * shown. This may be useful when a binding to the src property is known to
+ * be invalid, to prevent 404 requests.
+ */
+ preventLoad: {
+ type: Boolean,
+ value: false,
+ observer: '_preventLoadChanged'
+ },
+
+ /**
+ * Sets a sizing option for the image. Valid values are `contain` (full
+ * aspect ratio of the image is contained within the element and
+ * letterboxed) or `cover` (image is cropped in order to fully cover the
+ * bounds of the element), or `null` (default: image takes natural size).
+ */
+ sizing: {
+ type: String,
+ value: null,
+ reflectToAttribute: true
+ },
+
+ /**
+ * When a sizing option is used (`cover` or `contain`), this determines
+ * how the image is aligned within the element bounds.
+ */
+ position: {
+ type: String,
+ value: 'center'
+ },
+
+ /**
+ * When `true`, any change to the `src` property will cause the `placeholder`
+ * image to be shown until the new image has loaded.
+ */
+ preload: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * This image will be used as a background/placeholder until the src image has
+ * loaded. Use of a data-URI for placeholder is encouraged for instant rendering.
+ */
+ placeholder: {
+ type: String,
+ value: null,
+ observer: '_placeholderChanged'
+ },
+
+ /**
+ * When `preload` is true, setting `fade` to true will cause the image to
+ * fade into place.
+ */
+ fade: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Read-only value that is true when the image is loaded.
+ */
+ loaded: {
+ notify: true,
+ readOnly: true,
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Read-only value that tracks the loading state of the image when the `preload`
+ * option is used.
+ */
+ loading: {
+ notify: true,
+ readOnly: true,
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Read-only value that indicates that the last set `src` failed to load.
+ */
+ error: {
+ notify: true,
+ readOnly: true,
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Can be used to set the width of image (e.g. via binding); size may also be
+ * set via CSS.
+ */
+ width: {
+ observer: '_widthChanged',
+ type: Number,
+ value: null
+ },
+
+ /**
+ * Can be used to set the height of image (e.g. via binding); size may also be
+ * set via CSS.
+ *
+ * @attribute height
+ * @type number
+ * @default null
+ */
+ height: {
+ observer: '_heightChanged',
+ type: Number,
+ value: null
+ },
+ },
+
+ observers: [
+ '_transformChanged(sizing, position)'
+ ],
+
+ ready: function() {
+ var img = this.$.img;
+
+ img.onload = function() {
+ if (this.$.img.src !== this._resolveSrc(this.src)) return;
+
+ this._setLoading(false);
+ this._setLoaded(true);
+ this._setError(false);
+ }.bind(this);
+
+ img.onerror = function() {
+ if (this.$.img.src !== this._resolveSrc(this.src)) return;
+
+ this._reset();
+
+ this._setLoading(false);
+ this._setLoaded(false);
+ this._setError(true);
+ }.bind(this);
+
+ this._resolvedSrc = '';
+ },
+
+ _load: function(src) {
+ if (src) {
+ this.$.img.src = src;
+ } else {
+ this.$.img.removeAttribute('src');
+ }
+ this.$.sizedImgDiv.style.backgroundImage = src ? 'url("' + src + '")' : '';
+
+ this._setLoading(!!src);
+ this._setLoaded(false);
+ this._setError(false);
+ },
+
+ _reset: function() {
+ this.$.img.removeAttribute('src');
+ this.$.sizedImgDiv.style.backgroundImage = '';
+
+ this._setLoading(false);
+ this._setLoaded(false);
+ this._setError(false);
+ },
+
+ _computePlaceholderHidden: function() {
+ return !this.preload || (!this.fade && !this.loading && this.loaded);
+ },
+
+ _computePlaceholderClassName: function() {
+ return (this.preload && this.fade && !this.loading && this.loaded) ? 'faded-out' : '';
+ },
+
+ _computeImgDivHidden: function() {
+ return !this.sizing;
+ },
+
+ _computeImgDivARIAHidden: function() {
+ return this.alt === '' ? 'true' : undefined;
+ },
+
+ _computeImgDivARIALabel: function() {
+ if (this.alt !== null) {
+ return this.alt;
+ }
+
+ // Polymer.ResolveUrl.resolveUrl will resolve '' relative to a URL x to
+ // that URL x, but '' is the default for src.
+ if (this.src === '') {
+ return '';
+ }
+
+ var pathComponents = (new URL(this._resolveSrc(this.src))).pathname.split("/");
+ return pathComponents[pathComponents.length - 1];
+ },
+
+ _computeImgHidden: function() {
+ return !!this.sizing;
+ },
+
+ _widthChanged: function() {
+ this.style.width = isNaN(this.width) ? this.width : this.width + 'px';
+ },
+
+ _heightChanged: function() {
+ this.style.height = isNaN(this.height) ? this.height : this.height + 'px';
+ },
+
+ _preventLoadChanged: function() {
+ if (this.preventLoad || this.loaded) return;
+
+ this._reset();
+ this._load(this.src);
+ },
+
+ _srcChanged: function(newSrc, oldSrc) {
+ var newResolvedSrc = this._resolveSrc(newSrc);
+ if (newResolvedSrc === this._resolvedSrc) return;
+ this._resolvedSrc = newResolvedSrc;
+
+ this._reset();
+ if (!this.preventLoad) {
+ this._load(newSrc);
+ }
+ },
+
+ _placeholderChanged: function() {
+ this.$.placeholder.style.backgroundImage =
+ this.placeholder ? 'url("' + this.placeholder + '")' : '';
+ },
+
+ _transformChanged: function() {
+ var sizedImgDivStyle = this.$.sizedImgDiv.style;
+ var placeholderStyle = this.$.placeholder.style;
+
+ sizedImgDivStyle.backgroundSize =
+ placeholderStyle.backgroundSize =
+ this.sizing;
+
+ sizedImgDivStyle.backgroundPosition =
+ placeholderStyle.backgroundPosition =
+ this.sizing ? this.position : '';
+
+ sizedImgDivStyle.backgroundRepeat =
+ placeholderStyle.backgroundRepeat =
+ this.sizing ? 'no-repeat' : '';
+ },
+
+ _resolveSrc: function(testSrc) {
+ return Polymer.ResolveUrl.resolveUrl(testSrc, this.ownerDocument.baseURI);
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-input/.bower.json
new file mode 100644
index 00000000000..28b0a135d8d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/.bower.json
@@ -0,0 +1,44 @@
+{
+ "name": "iron-input",
+ "version": "1.0.10",
+ "description": "An input element with data binding",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input"
+ ],
+ "main": "iron-input.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-input.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-input",
+ "ignore": [],
+ "dependencies": {
+ "iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.0.10",
+ "_resolution": {
+ "type": "version",
+ "tag": "1.0.10",
+ "commit": "01d17407672ad8033ee447c9c7a65162f13c8f49"
+ },
+ "_source": "git://github.com/PolymerElements/iron-input.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-input"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-input/.travis.yml
new file mode 100644
index 00000000000..05aea78b053
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: AnFRDBxxASn2RP4u+CHJS04g2klVTM+YL1fgNfkNIiECChymGRkeBiF7zvWPfodqPGKWhBZPAMxVuFKbztawQ95kWlbPSTNJtWhHhPcRarV5AYvjhyUV372E3REZ4CGt+T8nghD9bdJiMX5x0pXAz+wfBPPpiHwbiSPPjFLFvTs=
+ - secure: SvsE+VQL35CZ967ZVy0+7o5xclnBM8egjhsjNRG7WxVPZQboCQ3Xwm8tIDQSWeagM3ZQRkTGca4ta91F1ZEhm4Jdt5CwKhhSNC6JgS3CX819r9UKgUnSS3nvWdqcZq4GXcMoOZm4qE9ttd3xdoKCfkLRQlEGAvM2TEw69mBhj24=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-input/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-input/README.md
new file mode 100644
index 00000000000..f32ac12e1f6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/README.md
@@ -0,0 +1,59 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-input.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-input.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-input)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-input)_
+
+
+##&lt;iron-input&gt;
+
+`<iron-input>` adds two-way binding and custom validators using `Polymer.IronValidatorBehavior`
+to `<input>`.
+
+### Two-way binding
+
+By default you can only get notified of changes to an `input`'s `value` due to user input:
+
+```html
+<input value="{{myValue::input}}">
+```
+
+`iron-input` adds the `bind-value` property that mirrors the `value` property, and can be used
+for two-way data binding. `bind-value` will notify if it is changed either by user input or by script.
+
+```html
+<input is="iron-input" bind-value="{{myValue}}">
+```
+
+### Custom validators
+
+You can use custom validators that implement `Polymer.IronValidatorBehavior` with `<iron-input>`.
+
+```html
+<input is="iron-input" validator="my-custom-validator">
+```
+
+### Stopping invalid input
+
+It may be desirable to only allow users to enter certain characters. You can use the
+`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
+is separate from validation, and `allowed-pattern` does not affect how the input is validated.
+
+```html
+<!-- only allow characters that match [0-9] -->
+<input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-input/bower.json
new file mode 100644
index 00000000000..018f4a163f3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "iron-input",
+ "version": "1.0.10",
+ "description": "An input element with data binding",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input"
+ ],
+ "main": "iron-input.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-input.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-input",
+ "ignore": [],
+ "dependencies": {
+ "iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-input/demo/index.html
new file mode 100644
index 00000000000..59d37b2d949
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/demo/index.html
@@ -0,0 +1,87 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-input demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../iron-input.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../../paper-styles/typography.html">
+
+ <style is="custom-style">
+
+ .vertical-section {
+ @apply(--paper-font-body1);
+
+ line-height: 40px;
+ }
+
+ code {
+ color: var(--google-grey-700);
+ }
+
+ input[is=iron-input] {
+ width: 100%;
+ box-sizing: border-box;
+ }
+
+ input, button {
+ font-size: 20px;
+ padding: 0.2em;
+ }
+
+ </style>
+</head>
+<body>
+
+ <div class="vertical-section vertical-section-container centered">
+ <template is="dom-bind">
+ <p>
+ <input is="iron-input" bind-value="{{bindValue}}" value="{{value::input}}">
+ <br>
+ bind to <code>bind-value</code>: <b>[[bindValue]]</b>
+ <br>
+ bind to <code>value::input</code>: <b>{{value}}</b>
+ </p>
+
+ <p on-click="setValue">
+ set bind-value to: <input> <button is="paper-button" value="bindValue">set</button>
+ <br>
+ set value to: <input> <button value="value">set</button>
+ </p>
+ </template>
+ <p>only allows these characters:
+ <code>!@#0123456789</code></p>
+ <input is="iron-input" allowed-pattern="[!@#0-9]" prevent-invalid-input>
+
+ </div>
+
+ <script>
+ var scope = document.querySelector('template[is=dom-bind]');
+
+ scope.setValue = function(event) {
+ if (!(event.target instanceof HTMLButtonElement)) {
+ return;
+ }
+ document.querySelector('input[is=iron-input]')[event.target.value] = event.target.previousElementSibling.value;
+ }
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-input/hero.svg
new file mode 100755
index 00000000000..146ffeac67c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/hero.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <rect x="49" y="53" width="2" height="18"/>
+ <path d="M188,78H37V44h151V78z M39,76h147V46H39V76z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-input/index.html
new file mode 100644
index 00000000000..ca0dac066a5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-input</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-input/iron-input.html b/chromium/third_party/catapult/third_party/polymer/components/iron-input/iron-input.html
new file mode 100644
index 00000000000..3424b64a3a4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-input/iron-input.html
@@ -0,0 +1,306 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-announcer/iron-a11y-announcer.html">
+<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
+
+<script>
+
+/*
+`<iron-input>` adds two-way binding and custom validators using `Polymer.IronValidatorBehavior`
+to `<input>`.
+
+### Two-way binding
+
+By default you can only get notified of changes to an `input`'s `value` due to user input:
+
+ <input value="{{myValue::input}}">
+
+`iron-input` adds the `bind-value` property that mirrors the `value` property, and can be used
+for two-way data binding. `bind-value` will notify if it is changed either by user input or by script.
+
+ <input is="iron-input" bind-value="{{myValue}}">
+
+### Custom validators
+
+You can use custom validators that implement `Polymer.IronValidatorBehavior` with `<iron-input>`.
+
+ <input is="iron-input" validator="my-custom-validator">
+
+### Stopping invalid input
+
+It may be desirable to only allow users to enter certain characters. You can use the
+`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
+is separate from validation, and `allowed-pattern` does not affect how the input is validated.
+
+ <!-- only allow characters that match [0-9] -->
+ <input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
+
+@hero hero.svg
+@demo demo/index.html
+*/
+
+ Polymer({
+
+ is: 'iron-input',
+
+ extends: 'input',
+
+ behaviors: [
+ Polymer.IronValidatableBehavior
+ ],
+
+ properties: {
+
+ /**
+ * Use this property instead of `value` for two-way data binding.
+ */
+ bindValue: {
+ observer: '_bindValueChanged',
+ type: String
+ },
+
+ /**
+ * Set to true to prevent the user from entering invalid input. If `allowedPattern` is set,
+ * any character typed by the user will be matched against that pattern, and rejected if it's not a match.
+ * Pasted input will have each character checked individually; if any character
+ * doesn't match `allowedPattern`, the entire pasted string will be rejected.
+ * If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`).
+ */
+ preventInvalidInput: {
+ type: Boolean
+ },
+
+ /**
+ * Regular expression that list the characters allowed as input.
+ * This pattern represents the allowed characters for the field; as the user inputs text,
+ * each individual character will be checked against the pattern (rather than checking
+ * the entire value as a whole). The recommended format should be a list of allowed characters;
+ * for example, `[a-zA-Z0-9.+-!;:]`
+ */
+ allowedPattern: {
+ type: String,
+ observer: "_allowedPatternChanged"
+ },
+
+ _previousValidInput: {
+ type: String,
+ value: ''
+ },
+
+ _patternAlreadyChecked: {
+ type: Boolean,
+ value: false
+ }
+
+ },
+
+ listeners: {
+ 'input': '_onInput',
+ 'keypress': '_onKeypress'
+ },
+
+ /** @suppress {checkTypes} */
+ registered: function() {
+ // Feature detect whether we need to patch dispatchEvent (i.e. on FF and IE).
+ if (!this._canDispatchEventOnDisabled()) {
+ this._origDispatchEvent = this.dispatchEvent;
+ this.dispatchEvent = this._dispatchEventFirefoxIE;
+ }
+ },
+
+ created: function() {
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ },
+
+ _canDispatchEventOnDisabled: function() {
+ var input = document.createElement('input');
+ var canDispatch = false;
+ input.disabled = true;
+
+ input.addEventListener('feature-check-dispatch-event', function() {
+ canDispatch = true;
+ });
+
+ try {
+ input.dispatchEvent(new Event('feature-check-dispatch-event'));
+ } catch(e) {}
+
+ return canDispatch;
+ },
+
+ _dispatchEventFirefoxIE: function() {
+ // Due to Firefox bug, events fired on disabled form controls can throw
+ // errors; furthermore, neither IE nor Firefox will actually dispatch
+ // events from disabled form controls; as such, we toggle disable around
+ // the dispatch to allow notifying properties to notify
+ // See issue #47 for details
+ var disabled = this.disabled;
+ this.disabled = false;
+ this._origDispatchEvent.apply(this, arguments);
+ this.disabled = disabled;
+ },
+
+ get _patternRegExp() {
+ var pattern;
+ if (this.allowedPattern) {
+ pattern = new RegExp(this.allowedPattern);
+ } else {
+ switch (this.type) {
+ case 'number':
+ pattern = /[0-9.,e-]/;
+ break;
+ }
+ }
+ return pattern;
+ },
+
+ ready: function() {
+ this.bindValue = this.value;
+ },
+
+ /**
+ * @suppress {checkTypes}
+ */
+ _bindValueChanged: function() {
+ if (this.value !== this.bindValue) {
+ this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
+ }
+ // manually notify because we don't want to notify until after setting value
+ this.fire('bind-value-changed', {value: this.bindValue});
+ },
+
+ _allowedPatternChanged: function() {
+ // Force to prevent invalid input when an `allowed-pattern` is set
+ this.preventInvalidInput = this.allowedPattern ? true : false;
+ },
+
+ _onInput: function() {
+ // Need to validate each of the characters pasted if they haven't
+ // been validated inside `_onKeypress` already.
+ if (this.preventInvalidInput && !this._patternAlreadyChecked) {
+ var valid = this._checkPatternValidity();
+ if (!valid) {
+ this._announceInvalidCharacter('Invalid string of characters not entered.');
+ this.value = this._previousValidInput;
+ }
+ }
+
+ this.bindValue = this.value;
+ this._previousValidInput = this.value;
+ this._patternAlreadyChecked = false;
+ },
+
+ _isPrintable: function(event) {
+ // What a control/printable character is varies wildly based on the browser.
+ // - most control characters (arrows, backspace) do not send a `keypress` event
+ // in Chrome, but the *do* on Firefox
+ // - in Firefox, when they do send a `keypress` event, control chars have
+ // a charCode = 0, keyCode = xx (for ex. 40 for down arrow)
+ // - printable characters always send a keypress event.
+ // - in Firefox, printable chars always have a keyCode = 0. In Chrome, the keyCode
+ // always matches the charCode.
+ // None of this makes any sense.
+
+ // For these keys, ASCII code == browser keycode.
+ var anyNonPrintable =
+ (event.keyCode == 8) || // backspace
+ (event.keyCode == 9) || // tab
+ (event.keyCode == 13) || // enter
+ (event.keyCode == 27); // escape
+
+ // For these keys, make sure it's a browser keycode and not an ASCII code.
+ var mozNonPrintable =
+ (event.keyCode == 19) || // pause
+ (event.keyCode == 20) || // caps lock
+ (event.keyCode == 45) || // insert
+ (event.keyCode == 46) || // delete
+ (event.keyCode == 144) || // num lock
+ (event.keyCode == 145) || // scroll lock
+ (event.keyCode > 32 && event.keyCode < 41) || // page up/down, end, home, arrows
+ (event.keyCode > 111 && event.keyCode < 124); // fn keys
+
+ return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
+ },
+
+ _onKeypress: function(event) {
+ if (!this.preventInvalidInput && this.type !== 'number') {
+ return;
+ }
+ var regexp = this._patternRegExp;
+ if (!regexp) {
+ return;
+ }
+
+ // Handle special keys and backspace
+ if (event.metaKey || event.ctrlKey || event.altKey)
+ return;
+
+ // Check the pattern either here or in `_onInput`, but not in both.
+ this._patternAlreadyChecked = true;
+
+ var thisChar = String.fromCharCode(event.charCode);
+ if (this._isPrintable(event) && !regexp.test(thisChar)) {
+ event.preventDefault();
+ this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
+ }
+ },
+
+ _checkPatternValidity: function() {
+ var regexp = this._patternRegExp;
+ if (!regexp) {
+ return true;
+ }
+ for (var i = 0; i < this.value.length; i++) {
+ if (!regexp.test(this.value[i])) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Returns true if `value` is valid. The validator provided in `validator` will be used first,
+ * then any constraints.
+ * @return {boolean} True if the value is valid.
+ */
+ validate: function() {
+ // First, check what the browser thinks. Some inputs (like type=number)
+ // behave weirdly and will set the value to "" if something invalid is
+ // entered, but will set the validity correctly.
+ var valid = this.checkValidity();
+
+ // Only do extra checking if the browser thought this was valid.
+ if (valid) {
+ // Empty, required input is invalid
+ if (this.required && this.value === '') {
+ valid = false;
+ } else if (this.hasValidator()) {
+ valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
+ }
+ }
+
+ this.invalid = !valid;
+ this.fire('iron-input-validate');
+ return valid;
+ },
+
+ _announceInvalidCharacter: function(message) {
+ this.fire('iron-announce', { text: message });
+ }
+ });
+
+ /*
+ The `iron-input-validate` event is fired whenever `validate()` is called.
+ @event iron-input-validate
+ */
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.bower.json
new file mode 100644
index 00000000000..dafbede4798
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.bower.json
@@ -0,0 +1,46 @@
+{
+ "name": "iron-menu-behavior",
+ "version": "1.1.7",
+ "description": "Provides accessible menu behavior",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior",
+ "menu"
+ ],
+ "main": [
+ "iron-menu-behavior.html",
+ "iron-menubar-behavior.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-menu-behavior"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-menu-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-selector": "PolymerElements/iron-selector#^1.0.0",
+ "polymer": "Polymer/polymer#^1.2.4",
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.1.7",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.7",
+ "commit": "ea59e6ce5644d8f7a20c22f13f614ea60604a812"
+ },
+ "_source": "git://github.com/PolymerElements/iron-menu-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-menu-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.travis.yml
new file mode 100644
index 00000000000..a6517a39ba0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: QxZD8yzz7s3F6b7h87ztWYiEbD2TrQp1Z1mib5u1wL7EAwsrQVkFhIEo4cJPAsTGS98qgeZAITg0ifwp/jOKVC2QKoPnC1qjm4L0AjlhXBTRbqyS5G8jvfJ8M4DgkQXADh4e+lw9ba3h2AxceJELKTYaQVq/cpTrpPg0/RH7H4o=
+ - secure: i76J23Bpwj6qJ4ybCCsQpGCTT+5s1PA+x0Avjbl1JTS4OsJLDFfvVl0YIWZ5xMIKJtdPC/mGDoZ2LNrh9hz82DBqDnzBlSnNjFbjnU1Aqy5CUmRWzyAF5NOjJGotISZcDYDGZd6gjsOfN0r+rICyRUiOadeyPf0Nm+6HSVQMjfM=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/README.md
new file mode 100644
index 00000000000..f8d90c65a3c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/README.md
@@ -0,0 +1,30 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-menu-behavior.html iron-menubar-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-menu-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-menu-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-menu-behavior)_
+
+
+##Polymer.IronMenuBehavior
+
+`Polymer.IronMenuBehavior` implements accessible menu behavior.
+
+
+
+##Polymer.IronMenubarBehavior
+
+`Polymer.IronMenubarBehavior` implements accessible menubar behavior.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/bower.json
new file mode 100644
index 00000000000..921662cc58d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/bower.json
@@ -0,0 +1,37 @@
+{
+ "name": "iron-menu-behavior",
+ "version": "1.1.7",
+ "description": "Provides accessible menu behavior",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior",
+ "menu"
+ ],
+ "main": [
+ "iron-menu-behavior.html",
+ "iron-menubar-behavior.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-menu-behavior"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-menu-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-selector": "PolymerElements/iron-selector#^1.0.0",
+ "polymer": "Polymer/polymer#^1.2.4",
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.2",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/index.html
new file mode 100644
index 00000000000..7fbd5e780c4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/index.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-menu-behavior demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../../paper-styles/default-theme.html">
+ <link rel="import" href="simple-menu.html">
+ <link rel="import" href="simple-menubar.html">
+
+ <style is="custom-style">
+ simple-menu,
+ simple-menubar {
+ display: inline-block;
+ width: 100%;
+ }
+
+ simple-menu a {
+ display: block;
+ }
+
+ simple-menubar a,
+ simple-menu a {
+ padding: 15px 20px;
+ color: var(--primary-text-color);
+ text-decoration: none;
+ }
+
+ simple-menu a[disabled],
+ simple-menubar a[disabled] {
+ color: var(--google-grey-300);
+ }
+
+ .horizontal-section {
+ padding: 0;
+ margin-bottom: 20px;
+ }
+
+ .row {
+ height: 120px;
+ }
+ </style>
+</head>
+<body unresolved>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h3>Simple menu</h3>
+ <div class="horizontal-section">
+ <simple-menu>
+ <a href="javascript:void(0)" role="menuitem">Item 0</a>
+ <a href="javascript:void(0)" role="menuitem">Item 1</a>
+ <a href="javascript:void(0)" role="menuitem" disabled>Item 2</a>
+ <a href="javascript:void(0)" role="menuitem">Item 3</a>
+ </simple-menu>
+ </div>
+ </div>
+
+ <div>
+ <h3>Multi-select menu</h3>
+ <div class="horizontal-section">
+ <simple-menu multi>
+ <a href="javascript:void(0)" role="menuitem">Item 0</a>
+ <a href="javascript:void(0)" role="menuitem">Item 1</a>
+ <a href="javascript:void(0)" role="menuitem">Item 2</a>
+ <a href="javascript:void(0)" role="menuitem">Item 3</a>
+ </simple-menu>
+ </div>
+ </div>
+
+ <div>
+ <div class="row">
+ <h3>Simple menubar</h3>
+ <div class="horizontal-section">
+ <simple-menubar>
+ <a href="javascript:void(0)" role="menuitem">Item 0</a>
+ <a href="javascript:void(0)" role="menuitem">Item 1</a>
+ <a href="javascript:void(0)" role="menuitem" disabled>Item 2</a>
+ <a href="javascript:void(0)" role="menuitem">Item 3</a>
+ </simple-menubar>
+ </div>
+ </div>
+ <div class="row">
+ <h3>Multi-select menubar</h3>
+ <div class="horizontal-section">
+ <simple-menubar multi>
+ <a href="javascript:void(0)" role="menuitem">Item 0</a>
+ <a href="javascript:void(0)" role="menuitem">Item 1</a>
+ <a href="javascript:void(0)" role="menuitem">Item 2</a>
+ <a href="javascript:void(0)" role="menuitem">Item 3</a>
+ </simple-menubar>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menu.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menu.html
new file mode 100644
index 00000000000..748e1d75cc6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menu.html
@@ -0,0 +1,52 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-menu-behavior.html">
+<link rel="import" href="../../paper-styles/color.html">
+
+<dom-module id="simple-menu">
+
+ <style>
+
+ .content ::content > .iron-selected {
+ color: white;
+ background-color: var(--google-blue-500);
+ }
+
+ </style>
+
+ <template>
+
+ <div class="content">
+ <content></content>
+ </div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+(function() {
+
+ Polymer({
+
+ is: 'simple-menu',
+
+ behaviors: [
+ Polymer.IronMenuBehavior
+ ]
+
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menubar.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menubar.html
new file mode 100644
index 00000000000..0f09cdbd2ad
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/demo/simple-menubar.html
@@ -0,0 +1,56 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-menubar-behavior.html">
+<link rel="import" href="../../paper-styles/color.html">
+
+<dom-module id="simple-menubar">
+
+ <style>
+
+ .content ::content > .iron-selected {
+ color: white;
+ background-color: var(--google-red-500);
+ }
+
+ .content ::content > * {
+ display: inline-block;
+ }
+
+ </style>
+
+ <template>
+
+ <div class="content">
+ <content></content>
+ </div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+(function() {
+
+ Polymer({
+
+ is: 'simple-menubar',
+
+ behaviors: [
+ Polymer.IronMenubarBehavior
+ ]
+
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/index.html
new file mode 100644
index 00000000000..2c643c4a037
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-menu-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page src="iron-menubar-behavior.html"></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menu-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menu-behavior.html
new file mode 100644
index 00000000000..46c06c588b0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menu-behavior.html
@@ -0,0 +1,334 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-selector/iron-multi-selectable.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+
+<script>
+
+ /**
+ * `Polymer.IronMenuBehavior` implements accessible menu behavior.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior Polymer.IronMenuBehavior
+ */
+ Polymer.IronMenuBehaviorImpl = {
+
+ properties: {
+
+ /**
+ * Returns the currently focused item.
+ * @type {?Object}
+ */
+ focusedItem: {
+ observer: '_focusedItemChanged',
+ readOnly: true,
+ type: Object
+ },
+
+ /**
+ * The attribute to use on menu items to look up the item title. Typing the first
+ * letter of an item when the menu is open focuses that item. If unset, `textContent`
+ * will be used.
+ */
+ attrForItemTitle: {
+ type: String
+ }
+ },
+
+ hostAttributes: {
+ 'role': 'menu',
+ 'tabindex': '0'
+ },
+
+ observers: [
+ '_updateMultiselectable(multi)'
+ ],
+
+ listeners: {
+ 'focus': '_onFocus',
+ 'keydown': '_onKeydown',
+ 'iron-items-changed': '_onIronItemsChanged'
+ },
+
+ keyBindings: {
+ 'up': '_onUpKey',
+ 'down': '_onDownKey',
+ 'esc': '_onEscKey',
+ 'shift+tab:keydown': '_onShiftTabDown'
+ },
+
+ attached: function() {
+ this._resetTabindices();
+ },
+
+ /**
+ * Selects the given value. If the `multi` property is true, then the selected state of the
+ * `value` will be toggled; otherwise the `value` will be selected.
+ *
+ * @param {string|number} value the value to select.
+ */
+ select: function(value) {
+ // Cancel automatically focusing a default item if the menu received focus
+ // through a user action selecting a particular item.
+ if (this._defaultFocusAsync) {
+ this.cancelAsync(this._defaultFocusAsync);
+ this._defaultFocusAsync = null;
+ }
+ var item = this._valueToItem(value);
+ if (item && item.hasAttribute('disabled')) return;
+ this._setFocusedItem(item);
+ Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
+ },
+
+ /**
+ * Resets all tabindex attributes to the appropriate value based on the
+ * current selection state. The appropriate value is `0` (focusable) for
+ * the default selected item, and `-1` (not keyboard focusable) for all
+ * other items.
+ */
+ _resetTabindices: function() {
+ var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem;
+
+ this.items.forEach(function(item) {
+ item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
+ }, this);
+ },
+
+ /**
+ * Sets appropriate ARIA based on whether or not the menu is meant to be
+ * multi-selectable.
+ *
+ * @param {boolean} multi True if the menu should be multi-selectable.
+ */
+ _updateMultiselectable: function(multi) {
+ if (multi) {
+ this.setAttribute('aria-multiselectable', 'true');
+ } else {
+ this.removeAttribute('aria-multiselectable');
+ }
+ },
+
+ /**
+ * Given a KeyboardEvent, this method will focus the appropriate item in the
+ * menu (if there is a relevant item, and it is possible to focus it).
+ *
+ * @param {KeyboardEvent} event A KeyboardEvent.
+ */
+ _focusWithKeyboardEvent: function(event) {
+ for (var i = 0, item; item = this.items[i]; i++) {
+ var attr = this.attrForItemTitle || 'textContent';
+ var title = item[attr] || item.getAttribute(attr);
+
+ if (!item.hasAttribute('disabled') && title &&
+ title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
+ this._setFocusedItem(item);
+ break;
+ }
+ }
+ },
+
+ /**
+ * Focuses the previous item (relative to the currently focused item) in the
+ * menu, disabled items will be skipped.
+ */
+ _focusPrevious: function() {
+ var length = this.items.length;
+ var curFocusIndex = Number(this.indexOf(this.focusedItem));
+ for (var i = 1; i < length; i++) {
+ var item = this.items[(curFocusIndex - i + length) % length];
+ if (!item.hasAttribute('disabled')) {
+ this._setFocusedItem(item);
+ return;
+ }
+ }
+ },
+
+ /**
+ * Focuses the next item (relative to the currently focused item) in the
+ * menu, disabled items will be skipped.
+ */
+ _focusNext: function() {
+ var length = this.items.length;
+ var curFocusIndex = Number(this.indexOf(this.focusedItem));
+ for (var i = 1; i < length; i++) {
+ var item = this.items[(curFocusIndex + i) % length];
+ if (!item.hasAttribute('disabled')) {
+ this._setFocusedItem(item);
+ return;
+ }
+ }
+ },
+
+ /**
+ * Mutates items in the menu based on provided selection details, so that
+ * all items correctly reflect selection state.
+ *
+ * @param {Element} item An item in the menu.
+ * @param {boolean} isSelected True if the item should be shown in a
+ * selected state, otherwise false.
+ */
+ _applySelection: function(item, isSelected) {
+ if (isSelected) {
+ item.setAttribute('aria-selected', 'true');
+ } else {
+ item.removeAttribute('aria-selected');
+ }
+ Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
+ },
+
+ /**
+ * Discretely updates tabindex values among menu items as the focused item
+ * changes.
+ *
+ * @param {Element} focusedItem The element that is currently focused.
+ * @param {?Element} old The last element that was considered focused, if
+ * applicable.
+ */
+ _focusedItemChanged: function(focusedItem, old) {
+ old && old.setAttribute('tabindex', '-1');
+ if (focusedItem) {
+ focusedItem.setAttribute('tabindex', '0');
+ focusedItem.focus();
+ }
+ },
+
+ /**
+ * A handler that responds to mutation changes related to the list of items
+ * in the menu.
+ *
+ * @param {CustomEvent} event An event containing mutation records as its
+ * detail.
+ */
+ _onIronItemsChanged: function(event) {
+ if (event.detail.addedNodes.length) {
+ this._resetTabindices();
+ }
+ },
+
+ /**
+ * Handler that is called when a shift+tab keypress is detected by the menu.
+ *
+ * @param {CustomEvent} event A key combination event.
+ */
+ _onShiftTabDown: function(event) {
+ var oldTabIndex = this.getAttribute('tabindex');
+
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
+
+ this._setFocusedItem(null);
+
+ this.setAttribute('tabindex', '-1');
+
+ this.async(function() {
+ this.setAttribute('tabindex', oldTabIndex);
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
+ // NOTE(cdata): polymer/polymer#1305
+ }, 1);
+ },
+
+ /**
+ * Handler that is called when the menu receives focus.
+ *
+ * @param {FocusEvent} event A focus event.
+ */
+ _onFocus: function(event) {
+ if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
+ // do not focus the menu itself
+ return;
+ }
+
+ // Do not focus the selected tab if the deepest target is part of the
+ // menu element's local DOM and is focusable.
+ var rootTarget = /** @type {?HTMLElement} */(
+ Polymer.dom(event).rootTarget);
+ if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
+ return;
+ }
+
+ // clear the cached focus item
+ this._defaultFocusAsync = this.async(function() {
+ // focus the selected item when the menu receives focus, or the first item
+ // if no item is selected
+ var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem;
+
+ this._setFocusedItem(null);
+
+ if (selectedItem) {
+ this._setFocusedItem(selectedItem);
+ } else if (this.items[0]) {
+ // We find the first none-disabled item (if one exists)
+ this._focusNext();
+ }
+ });
+ },
+
+ /**
+ * Handler that is called when the up key is pressed.
+ *
+ * @param {CustomEvent} event A key combination event.
+ */
+ _onUpKey: function(event) {
+ // up and down arrows moves the focus
+ this._focusPrevious();
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ /**
+ * Handler that is called when the down key is pressed.
+ *
+ * @param {CustomEvent} event A key combination event.
+ */
+ _onDownKey: function(event) {
+ this._focusNext();
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ /**
+ * Handler that is called when the esc key is pressed.
+ *
+ * @param {CustomEvent} event A key combination event.
+ */
+ _onEscKey: function(event) {
+ // esc blurs the control
+ this.focusedItem.blur();
+ },
+
+ /**
+ * Handler that is called when a keydown event is detected.
+ *
+ * @param {KeyboardEvent} event A keyboard event.
+ */
+ _onKeydown: function(event) {
+ if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
+ // all other keys focus the menu item starting with that character
+ this._focusWithKeyboardEvent(event);
+ }
+ event.stopPropagation();
+ },
+
+ // override _activateHandler
+ _activateHandler: function(event) {
+ Polymer.IronSelectableBehavior._activateHandler.call(this, event);
+ event.stopPropagation();
+ }
+ };
+
+ Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
+
+ /** @polymerBehavior Polymer.IronMenuBehavior */
+ Polymer.IronMenuBehavior = [
+ Polymer.IronMultiSelectableBehavior,
+ Polymer.IronA11yKeysBehavior,
+ Polymer.IronMenuBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menubar-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menubar-behavior.html
new file mode 100644
index 00000000000..f3b65186104
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-menu-behavior/iron-menubar-behavior.html
@@ -0,0 +1,81 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="iron-menu-behavior.html">
+
+<script>
+
+ /**
+ * `Polymer.IronMenubarBehavior` implements accessible menubar behavior.
+ *
+ * @polymerBehavior Polymer.IronMenubarBehavior
+ */
+ Polymer.IronMenubarBehaviorImpl = {
+
+ hostAttributes: {
+ 'role': 'menubar'
+ },
+
+ keyBindings: {
+ 'left': '_onLeftKey',
+ 'right': '_onRightKey'
+ },
+
+ _onUpKey: function(event) {
+ this.focusedItem.click();
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ _onDownKey: function(event) {
+ this.focusedItem.click();
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ get _isRTL() {
+ return window.getComputedStyle(this)['direction'] === 'rtl';
+ },
+
+ _onLeftKey: function(event) {
+ if (this._isRTL) {
+ this._focusNext();
+ } else {
+ this._focusPrevious();
+ }
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ _onRightKey: function(event) {
+ if (this._isRTL) {
+ this._focusPrevious();
+ } else {
+ this._focusNext();
+ }
+ event.detail.keyboardEvent.preventDefault();
+ },
+
+ _onKeydown: function(event) {
+ if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) {
+ return;
+ }
+
+ // all other keys focus the menu item starting with that character
+ this._focusWithKeyboardEvent(event);
+ }
+
+ };
+
+ /** @polymerBehavior Polymer.IronMenubarBehavior */
+ Polymer.IronMenubarBehavior = [
+ Polymer.IronMenuBehavior,
+ Polymer.IronMenubarBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.bower.json
new file mode 100644
index 00000000000..f4bfef4a7cc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.bower.json
@@ -0,0 +1,39 @@
+{
+ "name": "iron-meta",
+ "version": "1.1.1",
+ "keywords": [
+ "web-components",
+ "polymer"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Useful for sharing information across a DOM tree",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-meta.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.4",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "*",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": "iron-meta.html",
+ "homepage": "https://github.com/polymerelements/iron-meta",
+ "_release": "1.1.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.1",
+ "commit": "e171ee234b482219c9514e6f9551df48ef48bd9f"
+ },
+ "_source": "git://github.com/polymerelements/iron-meta.git",
+ "_target": "^1.0.0",
+ "_originalSource": "polymerelements/iron-meta"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.travis.yml
new file mode 100644
index 00000000000..fd27446be59
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/.travis.yml
@@ -0,0 +1,28 @@
+language: node_js
+sudo: false
+matrix:
+ include:
+ - node_js: stable
+ script: xvfb-run wct
+ addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ - node_js: node
+ script:
+ - |
+ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
+ wct -s 'default'
+ fi
+before_script:
+- npm install web-component-tester
+- npm install bower
+- export PATH=$PWD/node_modules/.bin:$PATH
+- bower install
+env:
+ global:
+ - secure: eGcuDAJt+1GPrC6u95vHufjnSXWbVBZpW7oKQhZjcHrN19l9COdOb7RVkTPsZzEanHaH/D6Psr4WJKyd72Wx5wj+bqGh4nPHTFSnK3+gNT4eJAgLvsxLwHxW8QkYYHEdZe8Wd6sOdal9geeLZ8fG9xELYEtuJR6lww5uLvFv/cw=
+ - secure: DoBz8LDaS4/lQ9sTXE5pnp8fqEvG47mmdQaQ14EnHQ+wLbajIaLk59vRfau5c7mIef8dEgaT40r/kVP5QRr3OiH5UJY3jLnCMVIxWJ3ZTkuGGuU6QDQvoGSSBhdA+b+G94bbK6LtHQxRBrkiyT9d0IzT5ZiHlDlteGbjdDWAgw0=
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/README.md
new file mode 100644
index 00000000000..615c85b6da0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/README.md
@@ -0,0 +1,93 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-meta.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/iron-meta.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-meta)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/iron-meta)_
+
+
+##&lt;iron-meta&gt;
+
+
+`iron-meta` is a generic element you can use for sharing information across the DOM tree.
+It uses [monostate pattern](http://c2.com/cgi/wiki?MonostatePattern) such that any
+instance of iron-meta has access to the shared
+information. You can use `iron-meta` to share whatever you want (or create an extension
+[like x-meta] for enhancements).
+
+The `iron-meta` instances containing your actual data can be loaded in an import,
+or constructed in any way you see fit. The only requirement is that you create them
+before you try to access them.
+
+Examples:
+
+If I create an instance like this:
+
+ <iron-meta key="info" value="foo/bar"></iron-meta>
+
+Note that value="foo/bar" is the metadata I've defined. I could define more
+attributes or use child nodes to define additional metadata.
+
+Now I can access that element (and it's metadata) from any iron-meta instance
+via the byKey method, e.g.
+
+ meta.byKey('info').getAttribute('value');
+
+Pure imperative form would be like:
+
+ document.createElement('iron-meta').byKey('info').getAttribute('value');
+
+Or, in a Polymer element, you can include a meta in your template:
+
+ <iron-meta id="meta"></iron-meta>
+ ...
+ this.$.meta.byKey('info').getAttribute('value');
+
+
+
+##&lt;iron-meta-query&gt;
+
+
+`iron-meta` is a generic element you can use for sharing information across the DOM tree.
+It uses [monostate pattern](http://c2.com/cgi/wiki?MonostatePattern) such that any
+instance of iron-meta has access to the shared
+information. You can use `iron-meta` to share whatever you want (or create an extension
+[like x-meta] for enhancements).
+
+The `iron-meta` instances containing your actual data can be loaded in an import,
+or constructed in any way you see fit. The only requirement is that you create them
+before you try to access them.
+
+Examples:
+
+If I create an instance like this:
+
+ <iron-meta key="info" value="foo/bar"></iron-meta>
+
+Note that value="foo/bar" is the metadata I've defined. I could define more
+attributes or use child nodes to define additional metadata.
+
+Now I can access that element (and it's metadata) from any iron-meta instance
+via the byKey method, e.g.
+
+ meta.byKey('info').getAttribute('value');
+
+Pure imperative form would be like:
+
+ document.createElement('iron-meta').byKey('info').getAttribute('value');
+
+Or, in a Polymer element, you can include a meta in your template:
+
+ <iron-meta id="meta"></iron-meta>
+ ...
+ this.$.meta.byKey('info').getAttribute('value');
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/bower.json
new file mode 100644
index 00000000000..614c5b3a660
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/bower.json
@@ -0,0 +1,29 @@
+{
+ "name": "iron-meta",
+ "version": "1.1.1",
+ "keywords": [
+ "web-components",
+ "polymer"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Useful for sharing information across a DOM tree",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-meta.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "polymerelements/paper-styles#^1.0.4",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "*",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": "iron-meta.html"
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/demo/index.html
new file mode 100644
index 00000000000..3deee3cbd5a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/demo/index.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <title>iron-meta</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../iron-meta.html">
+</head>
+<body>
+
+ <div class="vertical-section vertical-section-container centered">
+ <h1>&lt;iron-meta&gt;</h1>
+ <iron-meta key="info" value="foo/bar"></iron-meta>
+ The <code>value</code> stored at <code>key="info"</code> is <code><meta-test></meta-test></code>.
+ </div>
+
+ <script>
+
+ Polymer({
+
+ is: 'meta-test',
+
+ ready: function() {
+ this.textContent = new Polymer.IronMetaQuery({key: 'info'}).value;
+ }
+
+ });
+
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/hero.svg
new file mode 100755
index 00000000000..ea8548dcecb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/hero.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <circle cx="22" cy="85" r="4"/>
+ <circle cx="88" cy="98" r="4"/>
+ <path d="M87.5,100c-3.8-0.3-5.5-2.8-7-5c-1.4-2.1-2.7-3.9-5.5-4.2c-2.8-0.3-4.4,1.3-6.2,3.1c-1.9,1.9-4,4-7.8,3.7
+ c-3.8-0.3-5.5-2.8-7-5c-1.4-2.1-2.7-3.9-5.5-4.2c-2.8-0.3-4.4,1.3-6.2,3.1c-1.9,1.9-4,4-7.8,3.7c-3.8-0.3-5.5-2.8-7-5
+ c-1.4-2.1-2.7-3.9-5.5-4.2l0.2-2c3.8,0.3,5.5,2.8,7,5c1.4,2.1,2.7,3.9,5.5,4.2c2.8,0.3,4.4-1.3,6.2-3.1c1.9-1.9,4-4,7.8-3.7
+ c3.8,0.3,5.5,2.8,7,5c1.4,2.1,2.7,3.9,5.5,4.2c2.8,0.3,4.4-1.3,6.2-3.1c1.9-1.9,4-4,7.8-3.7c3.8,0.3,5.5,2.8,7,5
+ c1.4,2.1,2.7,3.9,5.5,4.2L87.5,100z"/>
+ <circle cx="96" cy="86" r="4"/>
+ <circle cx="162" cy="98" r="4"/>
+ <rect x="95.5" y="91" transform="matrix(0.9839 0.1789 -0.1789 0.9839 18.5382 -21.5923)" width="67.1" height="2"/>
+ <g>
+ <path d="M27,41.5l4.5,13.4l4.9-13.4h5.4v32h-4.4V61l0.4-13.4l-5.4,14.5h-2L25.6,48L26,61v12.5h-4.4v-32H27z"/>
+ <path d="M67.5,58.7H53.4V70h16.4v3.5H49v-32h20.6V45H53.4v10.2h14.2V58.7z"/>
+ <path d="M98.5,45H88.3v28.5h-4.4V45H73.6v-3.5h24.9V45z"/>
+ <path d="M116.2,65.3H105l-2.6,8.2h-4.5l10.9-32h3.8l10.6,32h-4.5L116.2,65.3z M106.2,61.6h8.9l-4.4-14.2L106.2,61.6z"/>
+ </g>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/index.html
new file mode 100644
index 00000000000..c70dc6e5dae
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/index.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>iron-meta</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-meta/iron-meta.html b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/iron-meta.html
new file mode 100644
index 00000000000..1521be5c0ea
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-meta/iron-meta.html
@@ -0,0 +1,333 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!--
+`iron-meta` is a generic element you can use for sharing information across the DOM tree.
+It uses [monostate pattern](http://c2.com/cgi/wiki?MonostatePattern) such that any
+instance of iron-meta has access to the shared
+information. You can use `iron-meta` to share whatever you want (or create an extension
+[like x-meta] for enhancements).
+
+The `iron-meta` instances containing your actual data can be loaded in an import,
+or constructed in any way you see fit. The only requirement is that you create them
+before you try to access them.
+
+Examples:
+
+If I create an instance like this:
+
+ <iron-meta key="info" value="foo/bar"></iron-meta>
+
+Note that value="foo/bar" is the metadata I've defined. I could define more
+attributes or use child nodes to define additional metadata.
+
+Now I can access that element (and it's metadata) from any iron-meta instance
+via the byKey method, e.g.
+
+ meta.byKey('info').getAttribute('value');
+
+Pure imperative form would be like:
+
+ document.createElement('iron-meta').byKey('info').getAttribute('value');
+
+Or, in a Polymer element, you can include a meta in your template:
+
+ <iron-meta id="meta"></iron-meta>
+ ...
+ this.$.meta.byKey('info').getAttribute('value');
+
+@group Iron Elements
+@demo demo/index.html
+@hero hero.svg
+@element iron-meta
+-->
+
+<script>
+
+ (function() {
+
+ // monostate data
+ var metaDatas = {};
+ var metaArrays = {};
+ var singleton = null;
+
+ Polymer.IronMeta = Polymer({
+
+ is: 'iron-meta',
+
+ properties: {
+
+ /**
+ * The type of meta-data. All meta-data of the same type is stored
+ * together.
+ */
+ type: {
+ type: String,
+ value: 'default',
+ observer: '_typeChanged'
+ },
+
+ /**
+ * The key used to store `value` under the `type` namespace.
+ */
+ key: {
+ type: String,
+ observer: '_keyChanged'
+ },
+
+ /**
+ * The meta-data to store or retrieve.
+ */
+ value: {
+ type: Object,
+ notify: true,
+ observer: '_valueChanged'
+ },
+
+ /**
+ * If true, `value` is set to the iron-meta instance itself.
+ */
+ self: {
+ type: Boolean,
+ observer: '_selfChanged'
+ },
+
+ /**
+ * Array of all meta-data values for the given type.
+ */
+ list: {
+ type: Array,
+ notify: true
+ }
+
+ },
+
+ hostAttributes: {
+ hidden: true
+ },
+
+ /**
+ * Only runs if someone invokes the factory/constructor directly
+ * e.g. `new Polymer.IronMeta()`
+ *
+ * @param {{type: (string|undefined), key: (string|undefined), value}=} config
+ */
+ factoryImpl: function(config) {
+ if (config) {
+ for (var n in config) {
+ switch(n) {
+ case 'type':
+ case 'key':
+ case 'value':
+ this[n] = config[n];
+ break;
+ }
+ }
+ }
+ },
+
+ created: function() {
+ // TODO(sjmiles): good for debugging?
+ this._metaDatas = metaDatas;
+ this._metaArrays = metaArrays;
+ },
+
+ _keyChanged: function(key, old) {
+ this._resetRegistration(old);
+ },
+
+ _valueChanged: function(value) {
+ this._resetRegistration(this.key);
+ },
+
+ _selfChanged: function(self) {
+ if (self) {
+ this.value = this;
+ }
+ },
+
+ _typeChanged: function(type) {
+ this._unregisterKey(this.key);
+ if (!metaDatas[type]) {
+ metaDatas[type] = {};
+ }
+ this._metaData = metaDatas[type];
+ if (!metaArrays[type]) {
+ metaArrays[type] = [];
+ }
+ this.list = metaArrays[type];
+ this._registerKeyValue(this.key, this.value);
+ },
+
+ /**
+ * Retrieves meta data value by key.
+ *
+ * @method byKey
+ * @param {string} key The key of the meta-data to be returned.
+ * @return {*}
+ */
+ byKey: function(key) {
+ return this._metaData && this._metaData[key];
+ },
+
+ _resetRegistration: function(oldKey) {
+ this._unregisterKey(oldKey);
+ this._registerKeyValue(this.key, this.value);
+ },
+
+ _unregisterKey: function(key) {
+ this._unregister(key, this._metaData, this.list);
+ },
+
+ _registerKeyValue: function(key, value) {
+ this._register(key, value, this._metaData, this.list);
+ },
+
+ _register: function(key, value, data, list) {
+ if (key && data && value !== undefined) {
+ data[key] = value;
+ list.push(value);
+ }
+ },
+
+ _unregister: function(key, data, list) {
+ if (key && data) {
+ if (key in data) {
+ var value = data[key];
+ delete data[key];
+ this.arrayDelete(list, value);
+ }
+ }
+ }
+
+ });
+
+ Polymer.IronMeta.getIronMeta = function getIronMeta() {
+ if (singleton === null) {
+ singleton = new Polymer.IronMeta();
+ }
+ return singleton;
+ };
+
+ /**
+ `iron-meta-query` can be used to access infomation stored in `iron-meta`.
+
+ Examples:
+
+ If I create an instance like this:
+
+ <iron-meta key="info" value="foo/bar"></iron-meta>
+
+ Note that value="foo/bar" is the metadata I've defined. I could define more
+ attributes or use child nodes to define additional metadata.
+
+ Now I can access that element (and it's metadata) from any `iron-meta-query` instance:
+
+ var value = new Polymer.IronMetaQuery({key: 'info'}).value;
+
+ @group Polymer Iron Elements
+ @element iron-meta-query
+ */
+ Polymer.IronMetaQuery = Polymer({
+
+ is: 'iron-meta-query',
+
+ properties: {
+
+ /**
+ * The type of meta-data. All meta-data of the same type is stored
+ * together.
+ */
+ type: {
+ type: String,
+ value: 'default',
+ observer: '_typeChanged'
+ },
+
+ /**
+ * Specifies a key to use for retrieving `value` from the `type`
+ * namespace.
+ */
+ key: {
+ type: String,
+ observer: '_keyChanged'
+ },
+
+ /**
+ * The meta-data to store or retrieve.
+ */
+ value: {
+ type: Object,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * Array of all meta-data values for the given type.
+ */
+ list: {
+ type: Array,
+ notify: true
+ }
+
+ },
+
+ /**
+ * Actually a factory method, not a true constructor. Only runs if
+ * someone invokes it directly (via `new Polymer.IronMeta()`);
+ *
+ * @param {{type: (string|undefined), key: (string|undefined)}=} config
+ */
+ factoryImpl: function(config) {
+ if (config) {
+ for (var n in config) {
+ switch(n) {
+ case 'type':
+ case 'key':
+ this[n] = config[n];
+ break;
+ }
+ }
+ }
+ },
+
+ created: function() {
+ // TODO(sjmiles): good for debugging?
+ this._metaDatas = metaDatas;
+ this._metaArrays = metaArrays;
+ },
+
+ _keyChanged: function(key) {
+ this._setValue(this._metaData && this._metaData[key]);
+ },
+
+ _typeChanged: function(type) {
+ this._metaData = metaDatas[type];
+ this.list = metaArrays[type];
+ if (this.key) {
+ this._keyChanged(this.key);
+ }
+ },
+
+ /**
+ * Retrieves meta data value by key.
+ * @param {string} key The key of the meta-data to be returned.
+ * @return {*}
+ */
+ byKey: function(key) {
+ return this._metaData && this._metaData[key];
+ }
+
+ });
+
+ })();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.bower.json
new file mode 100644
index 00000000000..d4e20a5aa1d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.bower.json
@@ -0,0 +1,47 @@
+{
+ "name": "iron-overlay-behavior",
+ "version": "1.8.2",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Provides a behavior for making an element an overlay",
+ "private": true,
+ "main": "iron-overlay-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior",
+ "overlay"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
+ },
+ "dependencies": {
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.2",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/polymerelements/iron-overlay-behavior",
+ "_release": "1.8.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.8.2",
+ "commit": "9d0fc18ed7b6a8d3e9ec244d20897e4803ec3201"
+ },
+ "_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "polymerelements/iron-overlay-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.github/ISSUE_TEMPLATE.md b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000000..9925d374459
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+<!-- Instructions: https://github.com/PolymerElements/iron-overlay-behavior/CONTRIBUTING.md#filing-issues -->
+### Description
+<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
+
+### Expected outcome
+
+<!-- Example: The page stays the same color. -->
+
+### Actual outcome
+
+<!-- Example: The page turns pink. -->
+
+### Live Demo
+<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
+
+### Steps to reproduce
+
+<!-- Example
+1. Put a `paper-foo` element in the page.
+2. Open the page in a web browser.
+3. Click the `paper-foo` element.
+-->
+
+### Browsers Affected
+<!-- Check all that apply -->
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari 9
+- [ ] Safari 8
+- [ ] Safari 7
+- [ ] Edge
+- [ ] IE 11
+- [ ] IE 10
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.travis.yml
new file mode 100644
index 00000000000..73919f91f4a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: H8AA9JkWfG/vc3MiimoIoYi45KD10hKzitLJnExkomgzFI/f5o9SGtwjCii5P8Kvf4xndftDjYwRgbYyJpSg0IJeq8rm1WS89cY8O6/1dlI/tK1j5xbVRrhqmRQncxUb3K4MAT6Z9br1jwEeamRa+NKmq+v+VEpQY5vwuQ/BHJw=
+ - secure: EaE1AUVgWyn0Y6kqkb54z5r39RvTJzAOmeM0lRl7wXzr5k0mq3VGlxTksJqCVd1PdJESXEhy8eldBnlkwZir/imDTNQxKm13k7ZiFC0000XAzpLZElkH2cLlYCRWcuM+vS7dA9hytV0UcGK2VGqbxfpcesB20dPSneDEUuc5X64=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/README.md
new file mode 100644
index 00000000000..7dc5b30df39
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/README.md
@@ -0,0 +1,71 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-overlay-backdrop.html iron-overlay-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-overlay-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-overlay-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-overlay-behavior)_
+
+
+##Polymer.IronOverlayBehavior
+
+Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or shown, and displays
+on top of other content. It includes an optional backdrop, and can be used to implement a variety
+of UI controls including dialogs and drop downs. Multiple overlays may be displayed at once.
+
+### Closing and canceling
+
+A dialog may be hidden by closing or canceling. The difference between close and cancel is user
+intent. Closing generally implies that the user acknowledged the content on the overlay. By default,
+it will cancel whenever the user taps outside it or presses the escape key. This behavior is
+configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
+`close()` should be called explicitly by the implementer when the user interacts with a control
+in the overlay element. When the dialog is canceled, the overlay fires an 'iron-overlay-canceled'
+event. Call `preventDefault` on this event to prevent the overlay from closing.
+
+### Positioning
+
+By default the element is sized and positioned to fit and centered inside the window. You can
+position and size it manually using CSS. See `Polymer.IronFitBehavior`.
+
+### Backdrop
+
+Set the `with-backdrop` attribute to display a backdrop behind the overlay. The backdrop is
+appended to `<body>` and is of type `<iron-overlay-backdrop>`. See its doc page for styling
+options.
+
+### Limitations
+
+The element is styled to appear on top of other content by setting its `z-index` property. You
+must ensure no element has a stacking context with a higher `z-index` than its parent stacking
+context. You should place this element as a child of `<body>` whenever possible.
+
+
+
+##&lt;iron-overlay-backdrop&gt;
+
+`iron-overlay-backdrop` is a backdrop used by `Polymer.IronOverlayBehavior`. It should be a
+singleton.
+
+### Styling
+
+The following custom properties and mixins are available for styling.
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--iron-overlay-backdrop-background-color` | Backdrop background color | #000 |
+| `--iron-overlay-backdrop-opacity` | Backdrop opacity | 0.6 |
+| `--iron-overlay-backdrop` | Mixin applied to `iron-overlay-backdrop`. | {} |
+| `--iron-overlay-backdrop-opened` | Mixin applied to `iron-overlay-backdrop` when it is displayed | {} |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/bower.json
new file mode 100644
index 00000000000..2443076b88c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/bower.json
@@ -0,0 +1,37 @@
+{
+ "name": "iron-overlay-behavior",
+ "version": "1.8.2",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Provides a behavior for making an element an overlay",
+ "private": true,
+ "main": "iron-overlay-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior",
+ "overlay"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
+ },
+ "dependencies": {
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.2",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/index.html
new file mode 100644
index 00000000000..92ed1e052dd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/index.html
@@ -0,0 +1,179 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+
+<head>
+
+ <title>simple-overlay demo</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="simple-overlay.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ demo-snippet {
+ --demo-snippet-code: {
+ max-height: 250px;
+ }
+ }
+ </style>
+
+</head>
+
+<body unresolved class="centered">
+
+ <h3>An element with <code>IronOverlayBehavior</code> can be opened, closed, toggled.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="plain.open()">Plain overlay</button>
+ <simple-overlay id="plain" tabindex=-1>
+ <h2>Hello world!</h2>
+ <p>This can be closed by pressing the ESC key too.</p>
+ <button onclick="plain.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>Use <code>with-backdrop</code> to add a backdrop to your overlay. Tabbing will be trapped within the overlay.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="backdrop.open()">Overlay with backdrop</button>
+ <simple-overlay id="backdrop" with-backdrop>
+ <p>Hello world!</p>
+ <button>Button</button>
+ <button onclick="backdrop.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>Use <code>restore-focus-on-close</code> to return the focus to the element that opened the overlay when it gets closed.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="returnFocus.open()">Overlay that restores focus</button>
+ <simple-overlay id="returnFocus" restore-focus-on-close>
+ <p>Hello world!</p>
+ <button onclick="returnFocus.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>The child with <code>autofocus</code> gets focused when opening the overlay.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="withAutofocus.open()">Overlay with autofocus child</button>
+ <simple-overlay id="withAutofocus">
+ <p>Hello world!</p>
+ <button autofocus>autofocus</button>
+ <button onclick="withAutofocus.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>Multiple overlays can be opened.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="multiple.open()">Open first overlay</button>
+ <simple-overlay id="multiple" tabindex=-1>
+ <p>click to open another overlay</p>
+ <button onclick="multiple2.open()">Open second overlay</button>
+ <button onclick="multiple.close()">Close this</button>
+ </simple-overlay>
+ <simple-overlay id="multiple2" tabindex=-1>
+ <h2>Hi!</h2>
+ <button onclick="multiple2.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>Use <code>always-on-top</code> to keep the overlay on top of others.</h3>
+ <demo-snippet>
+ <template>
+ <button onclick="onTop.open()">Open always-on-top</button>
+ <simple-overlay id="onTop" always-on-top tabindex=-1>
+ <h2>Always on top</h2>
+ <button onclick="backdrop2.open()">Open with backdrop</button>
+ <button onclick="onTop.close()">Close this</button>
+ </simple-overlay>
+ <simple-overlay id="backdrop2" with-backdrop tabindex=-1>
+ <h2>With backdrop</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <button onclick="backdrop2.close()">Close</button>
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+ <h3>An element with <code>IronOverlayBehavior</code> can be scrollable or contain scrollable content.</h3>
+ <demo-snippet>
+ <template>
+ <style>
+ .with-margin {
+ margin: 24px 40px;
+ }
+ .scrollable {
+ max-height: 300px;
+ overflow: auto;
+ }
+ </style>
+ <button onclick="scrolling.open()">Scrolling overlay</button>
+
+ <simple-overlay id="scrolling" class="with-margin scrollable" tabindex=-1>
+ <h2>This dialog scrolls internally.</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <button onclick="scrolling.close()">Close</button>
+ </simple-overlay>
+
+ <button onclick="scrolling2.open()">Scrolling content</button>
+
+ <simple-overlay id="scrolling2" class="with-margin" tabindex=-1>
+ <h2>This dialog has a scrolling child.</h2>
+ <div class="scrollable">
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </div>
+ <p>
+ <button onclick="scrolling2.close()">Close</button>
+ </p>
+
+ </simple-overlay>
+ </template>
+ </demo-snippet>
+
+</body>
+
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/simple-overlay.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/simple-overlay.html
new file mode 100644
index 00000000000..7eab2432ac6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/demo/simple-overlay.html
@@ -0,0 +1,49 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-overlay-behavior.html">
+
+<dom-module id="simple-overlay">
+
+ <style>
+
+ :host {
+ background: white;
+ color: black;
+ padding: 24px;
+ box-shadow: rgba(0, 0, 0, 0.24) -2.3408942051048403px 5.524510324047423px 12.090680100755666px 0px, rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
+ }
+
+ </style>
+
+ <template>
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+(function() {
+
+ Polymer({
+
+ is: 'simple-overlay',
+
+ behaviors: [
+ Polymer.IronOverlayBehavior
+ ]
+
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/index.html
new file mode 100644
index 00000000000..d69e30442ea
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-overlay-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-backdrop.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-backdrop.html
new file mode 100644
index 00000000000..432a57e1132
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-backdrop.html
@@ -0,0 +1,168 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<!--
+`iron-overlay-backdrop` is a backdrop used by `Polymer.IronOverlayBehavior`. It should be a
+singleton.
+
+### Styling
+
+The following custom properties and mixins are available for styling.
+
+Custom property | Description | Default
+-------------------------------------------|------------------------|---------
+`--iron-overlay-backdrop-background-color` | Backdrop background color | #000
+`--iron-overlay-backdrop-opacity` | Backdrop opacity | 0.6
+`--iron-overlay-backdrop` | Mixin applied to `iron-overlay-backdrop`. | {}
+`--iron-overlay-backdrop-opened` | Mixin applied to `iron-overlay-backdrop` when it is displayed | {}
+-->
+
+<dom-module id="iron-overlay-backdrop">
+
+ <template>
+ <style>
+ :host {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--iron-overlay-backdrop-background-color, #000);
+ opacity: 0;
+ transition: opacity 0.2s;
+ pointer-events: none;
+ @apply(--iron-overlay-backdrop);
+ }
+
+ :host(.opened) {
+ opacity: var(--iron-overlay-backdrop-opacity, 0.6);
+ pointer-events: auto;
+ @apply(--iron-overlay-backdrop-opened);
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+(function() {
+'use strict';
+
+ Polymer({
+
+ is: 'iron-overlay-backdrop',
+
+ properties: {
+
+ /**
+ * Returns true if the backdrop is opened.
+ */
+ opened: {
+ reflectToAttribute: true,
+ type: Boolean,
+ value: false,
+ observer: '_openedChanged'
+ }
+
+ },
+
+ listeners: {
+ 'transitionend': '_onTransitionend'
+ },
+
+ created: function() {
+ // Used to cancel previous requestAnimationFrame calls when opened changes.
+ this.__openedRaf = null;
+ },
+
+ attached: function() {
+ this.opened && this._openedChanged(this.opened);
+ },
+
+ /**
+ * Appends the backdrop to document body if needed.
+ */
+ prepare: function() {
+ if (this.opened && !this.parentNode) {
+ Polymer.dom(document.body).appendChild(this);
+ }
+ },
+
+ /**
+ * Shows the backdrop.
+ */
+ open: function() {
+ this.opened = true;
+ },
+
+ /**
+ * Hides the backdrop.
+ */
+ close: function() {
+ this.opened = false;
+ },
+
+ /**
+ * Removes the backdrop from document body if needed.
+ */
+ complete: function() {
+ if (!this.opened && this.parentNode === document.body) {
+ Polymer.dom(this.parentNode).removeChild(this);
+ }
+ },
+
+ _onTransitionend: function(event) {
+ if (event && event.target === this) {
+ this.complete();
+ }
+ },
+
+ /**
+ * @param {boolean} opened
+ * @private
+ */
+ _openedChanged: function(opened) {
+ if (opened) {
+ // Auto-attach.
+ this.prepare();
+ } else {
+ // Animation might be disabled via the mixin or opacity custom property.
+ // If it is disabled in other ways, it's up to the user to call complete.
+ var cs = window.getComputedStyle(this);
+ if (cs.transitionDuration === '0s' || cs.opacity == 0) {
+ this.complete();
+ }
+ }
+
+ if (!this.isAttached) {
+ return;
+ }
+
+ // Always cancel previous requestAnimationFrame.
+ if (this.__openedRaf) {
+ window.cancelAnimationFrame(this.__openedRaf);
+ this.__openedRaf = null;
+ }
+ // Force relayout to ensure proper transitions.
+ this.scrollTop = this.scrollTop;
+ this.__openedRaf = window.requestAnimationFrame(function() {
+ this.__openedRaf = null;
+ this.toggleClass('opened', this.opened);
+ }.bind(this));
+ }
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
new file mode 100644
index 00000000000..b1f2326661e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
@@ -0,0 +1,628 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html">
+<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
+<link rel="import" href="iron-overlay-manager.html">
+
+<script>
+(function() {
+'use strict';
+
+/**
+Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or shown, and displays
+on top of other content. It includes an optional backdrop, and can be used to implement a variety
+of UI controls including dialogs and drop downs. Multiple overlays may be displayed at once.
+
+See the [demo source code](https://github.com/PolymerElements/iron-overlay-behavior/blob/master/demo/simple-overlay.html)
+for an example.
+
+### Closing and canceling
+
+An overlay may be hidden by closing or canceling. The difference between close and cancel is user
+intent. Closing generally implies that the user acknowledged the content on the overlay. By default,
+it will cancel whenever the user taps outside it or presses the escape key. This behavior is
+configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
+`close()` should be called explicitly by the implementer when the user interacts with a control
+in the overlay element. When the dialog is canceled, the overlay fires an 'iron-overlay-canceled'
+event. Call `preventDefault` on this event to prevent the overlay from closing.
+
+### Positioning
+
+By default the element is sized and positioned to fit and centered inside the window. You can
+position and size it manually using CSS. See `Polymer.IronFitBehavior`.
+
+### Backdrop
+
+Set the `with-backdrop` attribute to display a backdrop behind the overlay. The backdrop is
+appended to `<body>` and is of type `<iron-overlay-backdrop>`. See its doc page for styling
+options.
+
+In addition, `with-backdrop` will wrap the focus within the content in the light DOM.
+Override the [`_focusableNodes` getter](#Polymer.IronOverlayBehavior:property-_focusableNodes)
+to achieve a different behavior.
+
+### Limitations
+
+The element is styled to appear on top of other content by setting its `z-index` property. You
+must ensure no element has a stacking context with a higher `z-index` than its parent stacking
+context. You should place this element as a child of `<body>` whenever possible.
+
+@demo demo/index.html
+@polymerBehavior Polymer.IronOverlayBehavior
+*/
+
+ Polymer.IronOverlayBehaviorImpl = {
+
+ properties: {
+
+ /**
+ * True if the overlay is currently displayed.
+ */
+ opened: {
+ observer: '_openedChanged',
+ type: Boolean,
+ value: false,
+ notify: true
+ },
+
+ /**
+ * True if the overlay was canceled when it was last closed.
+ */
+ canceled: {
+ observer: '_canceledChanged',
+ readOnly: true,
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to display a backdrop behind the overlay. It traps the focus
+ * within the light DOM of the overlay.
+ */
+ withBackdrop: {
+ observer: '_withBackdropChanged',
+ type: Boolean
+ },
+
+ /**
+ * Set to true to disable auto-focusing the overlay or child nodes with
+ * the `autofocus` attribute` when the overlay is opened.
+ */
+ noAutoFocus: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable canceling the overlay with the ESC key.
+ */
+ noCancelOnEscKey: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable canceling the overlay by clicking outside it.
+ */
+ noCancelOnOutsideClick: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Contains the reason(s) this overlay was last closed (see `iron-overlay-closed`).
+ * `IronOverlayBehavior` provides the `canceled` reason; implementers of the
+ * behavior can provide other reasons in addition to `canceled`.
+ */
+ closingReason: {
+ // was a getter before, but needs to be a property so other
+ // behaviors can override this.
+ type: Object
+ },
+
+ /**
+ * Set to true to enable restoring of focus when overlay is closed.
+ */
+ restoreFocusOnClose: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to keep overlay always on top.
+ */
+ alwaysOnTop: {
+ type: Boolean
+ },
+
+ /**
+ * Shortcut to access to the overlay manager.
+ * @private
+ * @type {Polymer.IronOverlayManagerClass}
+ */
+ _manager: {
+ type: Object,
+ value: Polymer.IronOverlayManager
+ },
+
+ /**
+ * The node being focused.
+ * @type {?Node}
+ */
+ _focusedChild: {
+ type: Object
+ }
+
+ },
+
+ listeners: {
+ 'iron-resize': '_onIronResize'
+ },
+
+ /**
+ * The backdrop element.
+ * @type {Element}
+ */
+ get backdropElement() {
+ return this._manager.backdropElement;
+ },
+
+ /**
+ * Returns the node to give focus to.
+ * @type {Node}
+ */
+ get _focusNode() {
+ return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
+ },
+
+ /**
+ * Array of nodes that can receive focus (overlay included), ordered by `tabindex`.
+ * This is used to retrieve which is the first and last focusable nodes in order
+ * to wrap the focus for overlays `with-backdrop`.
+ *
+ * If you know what is your content (specifically the first and last focusable children),
+ * you can override this method to return only `[firstFocusable, lastFocusable];`
+ * @type {Array<Node>}
+ * @protected
+ */
+ get _focusableNodes() {
+ // Elements that can be focused even if they have [disabled] attribute.
+ var FOCUSABLE_WITH_DISABLED = [
+ 'a[href]',
+ 'area[href]',
+ 'iframe',
+ '[tabindex]',
+ '[contentEditable=true]'
+ ];
+
+ // Elements that cannot be focused if they have [disabled] attribute.
+ var FOCUSABLE_WITHOUT_DISABLED = [
+ 'input',
+ 'select',
+ 'textarea',
+ 'button'
+ ];
+
+ // Discard elements with tabindex=-1 (makes them not focusable).
+ var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') +
+ ':not([tabindex="-1"]),' +
+ FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') +
+ ':not([disabled]):not([tabindex="-1"])';
+
+ var focusables = Polymer.dom(this).querySelectorAll(selector);
+ if (this.tabIndex >= 0) {
+ // Insert at the beginning because we might have all elements with tabIndex = 0,
+ // and the overlay should be the first of the list.
+ focusables.splice(0, 0, this);
+ }
+ // Sort by tabindex.
+ return focusables.sort(function (a, b) {
+ if (a.tabIndex === b.tabIndex) {
+ return 0;
+ }
+ if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
+ return 1;
+ }
+ return -1;
+ });
+ },
+
+ ready: function() {
+ // Used to skip calls to notifyResize and refit while the overlay is animating.
+ this.__isAnimating = false;
+ // with-backdrop needs tabindex to be set in order to trap the focus.
+ // If it is not set, IronOverlayBehavior will set it, and remove it if with-backdrop = false.
+ this.__shouldRemoveTabIndex = false;
+ // Used for wrapping the focus on TAB / Shift+TAB.
+ this.__firstFocusableNode = this.__lastFocusableNode = null;
+ // Used for requestAnimationFrame when opened changes.
+ this.__openChangedAsync = null;
+ // Used for requestAnimationFrame when iron-resize is fired.
+ this.__onIronResizeAsync = null;
+ this._ensureSetup();
+ },
+
+ attached: function() {
+ // Call _openedChanged here so that position can be computed correctly.
+ if (this.opened) {
+ this._openedChanged();
+ }
+ this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
+ },
+
+ detached: function() {
+ Polymer.dom(this).unobserveNodes(this._observer);
+ this._observer = null;
+ this.opened = false;
+ },
+
+ /**
+ * Toggle the opened state of the overlay.
+ */
+ toggle: function() {
+ this._setCanceled(false);
+ this.opened = !this.opened;
+ },
+
+ /**
+ * Open the overlay.
+ */
+ open: function() {
+ this._setCanceled(false);
+ this.opened = true;
+ },
+
+ /**
+ * Close the overlay.
+ */
+ close: function() {
+ this._setCanceled(false);
+ this.opened = false;
+ },
+
+ /**
+ * Cancels the overlay.
+ * @param {Event=} event The original event
+ */
+ cancel: function(event) {
+ var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: true});
+ if (cancelEvent.defaultPrevented) {
+ return;
+ }
+
+ this._setCanceled(true);
+ this.opened = false;
+ },
+
+ _ensureSetup: function() {
+ if (this._overlaySetup) {
+ return;
+ }
+ this._overlaySetup = true;
+ this.style.outline = 'none';
+ this.style.display = 'none';
+ },
+
+ _openedChanged: function() {
+ if (this.opened) {
+ this.removeAttribute('aria-hidden');
+ } else {
+ this.setAttribute('aria-hidden', 'true');
+ }
+
+ // wait to call after ready only if we're initially open
+ if (!this._overlaySetup) {
+ return;
+ }
+
+ if (this.__openChangedAsync) {
+ window.cancelAnimationFrame(this.__openChangedAsync);
+ }
+
+ // Synchronously remove the overlay.
+ // The adding is done asynchronously to go out of the scope of the event
+ // which might have generated the opening.
+ if (!this.opened) {
+ this._manager.removeOverlay(this);
+ }
+
+ // Defer any animation-related code on attached
+ // (_openedChanged gets called again on attached).
+ if (!this.isAttached) {
+ return;
+ }
+
+ this.__isAnimating = true;
+
+ // requestAnimationFrame for non-blocking rendering
+ this.__openChangedAsync = window.requestAnimationFrame(function() {
+ this.__openChangedAsync = null;
+ if (this.opened) {
+ this._manager.addOverlay(this);
+ this._prepareRenderOpened();
+ this._renderOpened();
+ } else {
+ this._renderClosed();
+ }
+ }.bind(this));
+ },
+
+ _canceledChanged: function() {
+ this.closingReason = this.closingReason || {};
+ this.closingReason.canceled = this.canceled;
+ },
+
+ _withBackdropChanged: function() {
+ // If tabindex is already set, no need to override it.
+ if (this.withBackdrop && !this.hasAttribute('tabindex')) {
+ this.setAttribute('tabindex', '-1');
+ this.__shouldRemoveTabIndex = true;
+ } else if (this.__shouldRemoveTabIndex) {
+ this.removeAttribute('tabindex');
+ this.__shouldRemoveTabIndex = false;
+ }
+ if (this.opened && this.isAttached) {
+ this._manager.trackBackdrop();
+ }
+ },
+
+ /**
+ * tasks which must occur before opening; e.g. making the element visible.
+ * @protected
+ */
+ _prepareRenderOpened: function() {
+
+ // Needed to calculate the size of the overlay so that transitions on its size
+ // will have the correct starting points.
+ this._preparePositioning();
+ this.refit();
+ this._finishPositioning();
+
+ // Safari will apply the focus to the autofocus element when displayed for the first time,
+ // so we blur it. Later, _applyFocus will set the focus if necessary.
+ if (this.noAutoFocus && document.activeElement === this._focusNode) {
+ this._focusNode.blur();
+ }
+ },
+
+ /**
+ * Tasks which cause the overlay to actually open; typically play an animation.
+ * @protected
+ */
+ _renderOpened: function() {
+ this._finishRenderOpened();
+ },
+
+ /**
+ * Tasks which cause the overlay to actually close; typically play an animation.
+ * @protected
+ */
+ _renderClosed: function() {
+ this._finishRenderClosed();
+ },
+
+ /**
+ * Tasks to be performed at the end of open action. Will fire `iron-overlay-opened`.
+ * @protected
+ */
+ _finishRenderOpened: function() {
+ // Focus the child node with [autofocus]
+ this._applyFocus();
+
+ this.notifyResize();
+ this.__isAnimating = false;
+
+ // Store it so we don't query too much.
+ var focusableNodes = this._focusableNodes;
+ this.__firstFocusableNode = focusableNodes[0];
+ this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
+
+ this.fire('iron-overlay-opened');
+ },
+
+ /**
+ * Tasks to be performed at the end of close action. Will fire `iron-overlay-closed`.
+ * @protected
+ */
+ _finishRenderClosed: function() {
+ // Hide the overlay and remove the backdrop.
+ this.style.display = 'none';
+ // Reset z-index only at the end of the animation.
+ this.style.zIndex = '';
+
+ this._applyFocus();
+
+ this.notifyResize();
+ this.__isAnimating = false;
+ this.fire('iron-overlay-closed', this.closingReason);
+ },
+
+ _preparePositioning: function() {
+ this.style.transition = this.style.webkitTransition = 'none';
+ this.style.transform = this.style.webkitTransform = 'none';
+ this.style.display = '';
+ },
+
+ _finishPositioning: function() {
+ // First, make it invisible & reactivate animations.
+ this.style.display = 'none';
+ // Force reflow before re-enabling animations so that they don't start.
+ // Set scrollTop to itself so that Closure Compiler doesn't remove this.
+ this.scrollTop = this.scrollTop;
+ this.style.transition = this.style.webkitTransition = '';
+ this.style.transform = this.style.webkitTransform = '';
+ // Now that animations are enabled, make it visible again
+ this.style.display = '';
+ // Force reflow, so that following animations are properly started.
+ // Set scrollTop to itself so that Closure Compiler doesn't remove this.
+ this.scrollTop = this.scrollTop;
+ },
+
+ /**
+ * Applies focus according to the opened state.
+ * @protected
+ */
+ _applyFocus: function() {
+ if (this.opened) {
+ if (!this.noAutoFocus) {
+ this._focusNode.focus();
+ }
+ } else {
+ this._focusNode.blur();
+ this._focusedChild = null;
+ this._manager.focusOverlay();
+ }
+ },
+
+ /**
+ * Cancels (closes) the overlay. Call when click happens outside the overlay.
+ * @param {!Event} event
+ * @protected
+ */
+ _onCaptureClick: function(event) {
+ if (!this.noCancelOnOutsideClick) {
+ this.cancel(event);
+ }
+ },
+
+ /**
+ * Keeps track of the focused child. If withBackdrop, traps focus within overlay.
+ * @param {!Event} event
+ * @protected
+ */
+ _onCaptureFocus: function (event) {
+ if (!this.withBackdrop) {
+ return;
+ }
+ var path = Polymer.dom(event).path;
+ if (path.indexOf(this) === -1) {
+ event.stopPropagation();
+ this._applyFocus();
+ } else {
+ this._focusedChild = path[0];
+ }
+ },
+
+ /**
+ * Handles the ESC key event and cancels (closes) the overlay.
+ * @param {!Event} event
+ * @protected
+ */
+ _onCaptureEsc: function(event) {
+ if (!this.noCancelOnEscKey) {
+ this.cancel(event);
+ }
+ },
+
+ /**
+ * Handles TAB key events to track focus changes.
+ * Will wrap focus for overlays withBackdrop.
+ * @param {!Event} event
+ * @protected
+ */
+ _onCaptureTab: function(event) {
+ if (!this.withBackdrop) {
+ return;
+ }
+ // TAB wraps from last to first focusable.
+ // Shift + TAB wraps from first to last focusable.
+ var shift = event.shiftKey;
+ var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
+ var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
+ var shouldWrap = false;
+ if (nodeToCheck === nodeToSet) {
+ // If nodeToCheck is the same as nodeToSet, it means we have an overlay
+ // with 0 or 1 focusables; in either case we still need to trap the
+ // focus within the overlay.
+ shouldWrap = true;
+ } else {
+ // In dom=shadow, the manager will receive focus changes on the main
+ // root but not the ones within other shadow roots, so we can't rely on
+ // _focusedChild, but we should check the deepest active element.
+ var focusedNode = this._manager.deepActiveElement;
+ // If the active element is not the nodeToCheck but the overlay itself,
+ // it means the focus is about to go outside the overlay, hence we
+ // should prevent that (e.g. user opens the overlay and hit Shift+TAB).
+ shouldWrap = (focusedNode === nodeToCheck || focusedNode === this);
+ }
+
+ if (shouldWrap) {
+ // When the overlay contains the last focusable element of the document
+ // and it's already focused, pressing TAB would move the focus outside
+ // the document (e.g. to the browser search bar). Similarly, when the
+ // overlay contains the first focusable element of the document and it's
+ // already focused, pressing Shift+TAB would move the focus outside the
+ // document (e.g. to the browser search bar).
+ // In both cases, we would not receive a focus event, but only a blur.
+ // In order to achieve focus wrapping, we prevent this TAB event and
+ // force the focus. This will also prevent the focus to temporarily move
+ // outside the overlay, which might cause scrolling.
+ event.preventDefault();
+ this._focusedChild = nodeToSet;
+ this._applyFocus();
+ }
+ },
+
+ /**
+ * Refits if the overlay is opened and not animating.
+ * @protected
+ */
+ _onIronResize: function() {
+ if (this.__onIronResizeAsync) {
+ window.cancelAnimationFrame(this.__onIronResizeAsync);
+ this.__onIronResizeAsync = null;
+ }
+ if (this.opened && !this.__isAnimating) {
+ this.__onIronResizeAsync = window.requestAnimationFrame(function() {
+ this.__onIronResizeAsync = null;
+ this.refit();
+ }.bind(this));
+ }
+ },
+
+ /**
+ * Will call notifyResize if overlay is opened.
+ * Can be overridden in order to avoid multiple observers on the same node.
+ * @protected
+ */
+ _onNodesChange: function() {
+ if (this.opened && !this.__isAnimating) {
+ this.notifyResize();
+ }
+ }
+ };
+
+ /** @polymerBehavior */
+ Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
+
+ /**
+ * Fired after the overlay opens.
+ * @event iron-overlay-opened
+ */
+
+ /**
+ * Fired when the overlay is canceled, but before it is closed.
+ * @event iron-overlay-canceled
+ * @param {Event} event The closing of the overlay can be prevented
+ * by calling `event.preventDefault()`. The `event.detail` is the original event that
+ * originated the canceling (e.g. ESC keyboard event or click event outside the overlay).
+ */
+
+ /**
+ * Fired after the overlay closes.
+ * @event iron-overlay-closed
+ * @param {Event} event The `event.detail` is the `closingReason` property
+ * (contains `canceled`, whether the overlay was canceled).
+ */
+
+})();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-manager.html b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-manager.html
new file mode 100644
index 00000000000..2462742f0af
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-overlay-behavior/iron-overlay-manager.html
@@ -0,0 +1,398 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="iron-overlay-backdrop.html">
+
+<script>
+
+ /**
+ * @struct
+ * @constructor
+ * @private
+ */
+ Polymer.IronOverlayManagerClass = function() {
+ /**
+ * Used to keep track of the opened overlays.
+ * @private {Array<Element>}
+ */
+ this._overlays = [];
+
+ /**
+ * iframes have a default z-index of 100,
+ * so this default should be at least that.
+ * @private {number}
+ */
+ this._minimumZ = 101;
+
+ /**
+ * Memoized backdrop element.
+ * @private {Element|null}
+ */
+ this._backdropElement = null;
+
+ // Enable document-wide tap recognizer.
+ Polymer.Gestures.add(document, 'tap', null);
+ // Need to have useCapture=true, Polymer.Gestures doesn't offer that.
+ document.addEventListener('tap', this._onCaptureClick.bind(this), true);
+ document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
+ document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
+ };
+
+ Polymer.IronOverlayManagerClass.prototype = {
+
+ constructor: Polymer.IronOverlayManagerClass,
+
+ /**
+ * The shared backdrop element.
+ * @type {!Element} backdropElement
+ */
+ get backdropElement() {
+ if (!this._backdropElement) {
+ this._backdropElement = document.createElement('iron-overlay-backdrop');
+ }
+ return this._backdropElement;
+ },
+
+ /**
+ * The deepest active element.
+ * @type {!Element} activeElement the active element
+ */
+ get deepActiveElement() {
+ // document.activeElement can be null
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
+ // In case of null, default it to document.body.
+ var active = document.activeElement || document.body;
+ while (active.root && Polymer.dom(active.root).activeElement) {
+ active = Polymer.dom(active.root).activeElement;
+ }
+ return active;
+ },
+
+ /**
+ * Brings the overlay at the specified index to the front.
+ * @param {number} i
+ * @private
+ */
+ _bringOverlayAtIndexToFront: function(i) {
+ var overlay = this._overlays[i];
+ if (!overlay) {
+ return;
+ }
+ var lastI = this._overlays.length - 1;
+ var currentOverlay = this._overlays[lastI];
+ // Ensure always-on-top overlay stays on top.
+ if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
+ lastI--;
+ }
+ // If already the top element, return.
+ if (i >= lastI) {
+ return;
+ }
+ // Update z-index to be on top.
+ var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
+ if (this._getZ(overlay) <= minimumZ) {
+ this._applyOverlayZ(overlay, minimumZ);
+ }
+
+ // Shift other overlays behind the new on top.
+ while (i < lastI) {
+ this._overlays[i] = this._overlays[i + 1];
+ i++;
+ }
+ this._overlays[lastI] = overlay;
+ },
+
+ /**
+ * Adds the overlay and updates its z-index if it's opened, or removes it if it's closed.
+ * Also updates the backdrop z-index.
+ * @param {!Element} overlay
+ */
+ addOrRemoveOverlay: function(overlay) {
+ if (overlay.opened) {
+ this.addOverlay(overlay);
+ } else {
+ this.removeOverlay(overlay);
+ }
+ },
+
+ /**
+ * Tracks overlays for z-index and focus management.
+ * Ensures the last added overlay with always-on-top remains on top.
+ * @param {!Element} overlay
+ */
+ addOverlay: function(overlay) {
+ var i = this._overlays.indexOf(overlay);
+ if (i >= 0) {
+ this._bringOverlayAtIndexToFront(i);
+ this.trackBackdrop();
+ return;
+ }
+ var insertionIndex = this._overlays.length;
+ var currentOverlay = this._overlays[insertionIndex - 1];
+ var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
+ var newZ = this._getZ(overlay);
+
+ // Ensure always-on-top overlay stays on top.
+ if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
+ // This bumps the z-index of +2.
+ this._applyOverlayZ(currentOverlay, minimumZ);
+ insertionIndex--;
+ // Update minimumZ to match previous overlay's z-index.
+ var previousOverlay = this._overlays[insertionIndex - 1];
+ minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
+ }
+
+ // Update z-index and insert overlay.
+ if (newZ <= minimumZ) {
+ this._applyOverlayZ(overlay, minimumZ);
+ }
+ this._overlays.splice(insertionIndex, 0, overlay);
+
+ // Get focused node.
+ var element = this.deepActiveElement;
+ overlay.restoreFocusNode = this._overlayParent(element) ? null : element;
+ this.trackBackdrop();
+ },
+
+ /**
+ * @param {!Element} overlay
+ */
+ removeOverlay: function(overlay) {
+ var i = this._overlays.indexOf(overlay);
+ if (i === -1) {
+ return;
+ }
+ this._overlays.splice(i, 1);
+
+ var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null;
+ overlay.restoreFocusNode = null;
+ // Focus back only if still contained in document.body
+ if (node && Polymer.dom(document.body).deepContains(node)) {
+ node.focus();
+ }
+ this.trackBackdrop();
+ },
+
+ /**
+ * Returns the current overlay.
+ * @return {Element|undefined}
+ */
+ currentOverlay: function() {
+ var i = this._overlays.length - 1;
+ return this._overlays[i];
+ },
+
+ /**
+ * Returns the current overlay z-index.
+ * @return {number}
+ */
+ currentOverlayZ: function() {
+ return this._getZ(this.currentOverlay());
+ },
+
+ /**
+ * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
+ * This does not effect the z-index of any existing overlays.
+ * @param {number} minimumZ
+ */
+ ensureMinimumZ: function(minimumZ) {
+ this._minimumZ = Math.max(this._minimumZ, minimumZ);
+ },
+
+ focusOverlay: function() {
+ var current = /** @type {?} */ (this.currentOverlay());
+ // We have to be careful to focus the next overlay _after_ any current
+ // transitions are complete (due to the state being toggled prior to the
+ // transition). Otherwise, we risk infinite recursion when a transitioning
+ // (closed) overlay becomes the current overlay.
+ //
+ // NOTE: We make the assumption that any overlay that completes a transition
+ // will call into focusOverlay to kick the process back off. Currently:
+ // transitionend -> _applyFocus -> focusOverlay.
+ if (current && !current.transitioning) {
+ current._applyFocus();
+ }
+ },
+
+ /**
+ * Updates the backdrop z-index.
+ */
+ trackBackdrop: function() {
+ var overlay = this._overlayWithBackdrop();
+ // Avoid creating the backdrop if there is no overlay with backdrop.
+ if (!overlay && !this._backdropElement) {
+ return;
+ }
+ this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
+ this.backdropElement.opened = !!overlay;
+ },
+
+ /**
+ * @return {Array<Element>}
+ */
+ getBackdrops: function() {
+ var backdrops = [];
+ for (var i = 0; i < this._overlays.length; i++) {
+ if (this._overlays[i].withBackdrop) {
+ backdrops.push(this._overlays[i]);
+ }
+ }
+ return backdrops;
+ },
+
+ /**
+ * Returns the z-index for the backdrop.
+ * @return {number}
+ */
+ backdropZ: function() {
+ return this._getZ(this._overlayWithBackdrop()) - 1;
+ },
+
+ /**
+ * Returns the first opened overlay that has a backdrop.
+ * @return {Element|undefined}
+ * @private
+ */
+ _overlayWithBackdrop: function() {
+ for (var i = 0; i < this._overlays.length; i++) {
+ if (this._overlays[i].withBackdrop) {
+ return this._overlays[i];
+ }
+ }
+ },
+
+ /**
+ * Calculates the minimum z-index for the overlay.
+ * @param {Element=} overlay
+ * @private
+ */
+ _getZ: function(overlay) {
+ var z = this._minimumZ;
+ if (overlay) {
+ var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
+ // Check if is a number
+ // Number.isNaN not supported in IE 10+
+ if (z1 === z1) {
+ z = z1;
+ }
+ }
+ return z;
+ },
+
+ /**
+ * @param {!Element} element
+ * @param {number|string} z
+ * @private
+ */
+ _setZ: function(element, z) {
+ element.style.zIndex = z;
+ },
+
+ /**
+ * @param {!Element} overlay
+ * @param {number} aboveZ
+ * @private
+ */
+ _applyOverlayZ: function(overlay, aboveZ) {
+ this._setZ(overlay, aboveZ + 2);
+ },
+
+ /**
+ * Returns the overlay containing the provided node. If the node is an overlay,
+ * it returns the node.
+ * @param {Element=} node
+ * @return {Element|undefined}
+ * @private
+ */
+ _overlayParent: function(node) {
+ while (node && node !== document.body) {
+ // Check if it is an overlay.
+ if (node._manager === this) {
+ return node;
+ }
+ // Use logical parentNode, or native ShadowRoot host.
+ node = Polymer.dom(node).parentNode || node.host;
+ }
+ },
+
+ /**
+ * Returns the deepest overlay in the path.
+ * @param {Array<Element>=} path
+ * @return {Element|undefined}
+ * @suppress {missingProperties}
+ * @private
+ */
+ _overlayInPath: function(path) {
+ path = path || [];
+ for (var i = 0; i < path.length; i++) {
+ if (path[i]._manager === this) {
+ return path[i];
+ }
+ }
+ },
+
+ /**
+ * Ensures the click event is delegated to the right overlay.
+ * @param {!Event} event
+ * @private
+ */
+ _onCaptureClick: function(event) {
+ var overlay = /** @type {?} */ (this.currentOverlay());
+ // Check if clicked outside of top overlay.
+ if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
+ overlay._onCaptureClick(event);
+ }
+ },
+
+ /**
+ * Ensures the focus event is delegated to the right overlay.
+ * @param {!Event} event
+ * @private
+ */
+ _onCaptureFocus: function(event) {
+ var overlay = /** @type {?} */ (this.currentOverlay());
+ if (overlay) {
+ overlay._onCaptureFocus(event);
+ }
+ },
+
+ /**
+ * Ensures TAB and ESC keyboard events are delegated to the right overlay.
+ * @param {!Event} event
+ * @private
+ */
+ _onCaptureKeyDown: function(event) {
+ var overlay = /** @type {?} */ (this.currentOverlay());
+ if (overlay) {
+ if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
+ overlay._onCaptureEsc(event);
+ } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
+ overlay._onCaptureTab(event);
+ }
+ }
+ },
+
+ /**
+ * Returns if the overlay1 should be behind overlay2.
+ * @param {!Element} overlay1
+ * @param {!Element} overlay2
+ * @return {boolean}
+ * @suppress {missingProperties}
+ * @private
+ */
+ _shouldBeBehindOverlay: function(overlay1, overlay2) {
+ return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
+ }
+ };
+
+ Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/.bower.json
new file mode 100644
index 00000000000..76d8b27a181
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/.bower.json
@@ -0,0 +1,39 @@
+{
+ "name": "iron-range-behavior",
+ "version": "1.0.5",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Provides a behavior for something with a minimum and maximum value",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "main": "iron-range-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-range-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-input": "PolymerElements/iron-input#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-range-behavior",
+ "_release": "1.0.5",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.5",
+ "commit": "645ffc6b39ae4fb0efd23b97016a9c4aac777978"
+ },
+ "_source": "git://github.com/PolymerElements/iron-range-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-range-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/README.md
new file mode 100644
index 00000000000..99202696516
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/README.md
@@ -0,0 +1,24 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-range-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-range-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-range-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-range-behavior)_
+
+
+##Polymer.IronRangeBehavior
+
+`iron-range-behavior` provides the behavior for something with a minimum to maximum range.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/bower.json
new file mode 100644
index 00000000000..a58ad63f132
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/bower.json
@@ -0,0 +1,29 @@
+{
+ "name": "iron-range-behavior",
+ "version": "1.0.5",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Provides a behavior for something with a minimum and maximum value",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "main": "iron-range-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-range-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-input": "PolymerElements/iron-input#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/demo/index.html
new file mode 100644
index 00000000000..ce397365e0d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/demo/index.html
@@ -0,0 +1,79 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html>
+ <head>
+ <title>iron-range-behavior demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../iron-range-behavior.html">
+ <link rel="import" href="../../iron-input/iron-input.html">
+
+ <style>
+
+ body {
+ font-family: sans-serif;
+ }
+
+ </style>
+ </head>
+
+ <body unresolved>
+
+ <dom-module id="x-progressbar">
+ <style>
+ :host {
+ display: block;
+ height: 40px;
+ background-color: #555;
+ border-radius: 4px;
+ padding: 8px;
+ box-shadow: inset 0px 2px 5px rgba(0, 0, 0, 0.5);
+ }
+
+ .progress {
+ background-color: #999;
+ height: 100%;
+ border-radius: 4px;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
+ }
+
+ .progress-value {
+ padding: 0 8px;
+ font-size: 18px;
+ color: #fff;
+ }
+ </style>
+ <template>
+ <div class="progress" horizontal center layout style$="{{_computeStyle(ratio)}}">
+ <div class="progress-value"><span>{{ratio}}</span>%</div>
+ </div>
+ </template>
+ </dom-module>
+
+ <script>
+ HTMLImports.whenReady(function() {
+ Polymer({
+ is: 'x-progressbar',
+
+ behaviors: [Polymer.IronRangeBehavior],
+
+ _computeStyle: function(ratio) {
+ return 'width: ' + ratio + '%;';
+ }
+ });
+ });
+ </script>
+
+ <x-progressbar min="0" max="200" value="120"></x-progressbar>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/index.html
new file mode 100644
index 00000000000..cc77788735d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/iron-range-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/iron-range-behavior.html
new file mode 100644
index 00000000000..96f3c15b02a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-range-behavior/iron-range-behavior.html
@@ -0,0 +1,121 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /**
+ * `iron-range-behavior` provides the behavior for something with a minimum to maximum range.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior
+ */
+ Polymer.IronRangeBehavior = {
+
+ properties: {
+
+ /**
+ * The number that represents the current value.
+ */
+ value: {
+ type: Number,
+ value: 0,
+ notify: true,
+ reflectToAttribute: true
+ },
+
+ /**
+ * The number that indicates the minimum value of the range.
+ */
+ min: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * The number that indicates the maximum value of the range.
+ */
+ max: {
+ type: Number,
+ value: 100,
+ notify: true
+ },
+
+ /**
+ * Specifies the value granularity of the range's value.
+ */
+ step: {
+ type: Number,
+ value: 1,
+ notify: true
+ },
+
+ /**
+ * Returns the ratio of the value.
+ */
+ ratio: {
+ type: Number,
+ value: 0,
+ readOnly: true,
+ notify: true
+ },
+ },
+
+ observers: [
+ '_update(value, min, max, step)'
+ ],
+
+ _calcRatio: function(value) {
+ return (this._clampValue(value) - this.min) / (this.max - this.min);
+ },
+
+ _clampValue: function(value) {
+ return Math.min(this.max, Math.max(this.min, this._calcStep(value)));
+ },
+
+ _calcStep: function(value) {
+ // polymer/issues/2493
+ value = parseFloat(value);
+
+ if (!this.step) {
+ return value;
+ }
+
+ var numSteps = Math.round((value - this.min) / this.step);
+ if (this.step < 1) {
+ /**
+ * For small values of this.step, if we calculate the step using
+ * `Math.round(value / step) * step` we may hit a precision point issue
+ * eg. 0.1 * 0.2 = 0.020000000000000004
+ * http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
+ *
+ * as a work around we can divide by the reciprocal of `step`
+ */
+ return numSteps / (1 / this.step) + this.min;
+ } else {
+ return numSteps * this.step + this.min;
+ }
+ },
+
+ _validateValue: function() {
+ var v = this._clampValue(this.value);
+ this.value = this.oldValue = isNaN(v) ? this.oldValue : v;
+ return this.value !== v;
+ },
+
+ _update: function() {
+ this._validateValue();
+ this._setRatio(this._calcRatio(this.value) * 100);
+ }
+
+};
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/.bower.json
new file mode 100644
index 00000000000..2e765b93245
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "iron-resizable-behavior",
+ "version": "1.0.3",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Coordinates the flow of resizeable elements",
+ "private": true,
+ "main": "iron-resizable-behavior.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-resizable-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-resizable-behavior",
+ "_release": "1.0.3",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.3",
+ "commit": "dda1df6aaf452aedf3e52ff0cf69e72439452216"
+ },
+ "_source": "git://github.com/PolymerElements/iron-resizable-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-resizable-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/README.md
new file mode 100644
index 00000000000..2f37628c126
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/README.md
@@ -0,0 +1,36 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-resizable-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-resizable-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-resizable-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-resizable-behavior)_
+
+
+##Polymer.IronResizableBehavior
+
+`IronResizableBehavior` is a behavior that can be used in Polymer elements to
+coordinate the flow of resize events between "resizers" (elements that control the
+size or hidden state of their children) and "resizables" (elements that need to be
+notified when they are resized or un-hidden by their parents in order to take
+action on their new measurements).
+
+Elements that perform measurement should add the `IronResizableBehavior` behavior to
+their element definition and listen for the `iron-resize` event on themselves.
+This event will be fired when they become showing after having been hidden,
+when they are resized explicitly by another resizable, or when the window has been
+resized.
+
+Note, the `iron-resize` event is non-bubbling.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/bower.json
new file mode 100644
index 00000000000..053bfd0c88a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "iron-resizable-behavior",
+ "version": "1.0.3",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Coordinates the flow of resizeable elements",
+ "private": true,
+ "main": "iron-resizable-behavior.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-resizable-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/index.html
new file mode 100644
index 00000000000..2896c50d256
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/index.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-resizable-behavior demo</title>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="src/x-app.html">
+
+</head>
+<body>
+
+ <x-app></x-app>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/src/x-app.html b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/src/x-app.html
new file mode 100644
index 00000000000..c334ad3d2fa
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/demo/src/x-app.html
@@ -0,0 +1,114 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../iron-resizable-behavior.html">
+
+<dom-module id="x-puck">
+
+ <style>
+
+ :host {
+ display: inline-block;
+ border: 3px solid lightblue;
+ }
+
+ </style>
+
+ <template>
+
+ <b>I'm a resize-aware, thirdifying puck at (<span>{{x}}</span> x <span>{{y}}</span>).</b>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'x-puck',
+
+ behaviors: [
+ Polymer.IronResizableBehavior
+ ],
+
+ properties: {
+ x: {
+ type: Number,
+ value: 0
+ },
+
+ y: {
+ type: Number,
+ value: 0
+ }
+ },
+
+ listeners: {
+ 'iron-resize': '_onIronResize'
+ },
+
+ attached: function() {
+ this.async(this.notifyResize, 1);
+ },
+
+ get parent() {
+ if (this.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+ return this.parentNode.host;
+ }
+
+ return this.parentNode;
+ },
+
+ _onIronResize: function() {
+ var x = this.x = Math.floor(this.parent.offsetWidth / 3);
+ var y = this.y = Math.floor(this.parent.offsetHeight / 3);
+
+ this.translate3d(x + 'px', y + 'px', 0);
+ }
+ });
+
+</script>
+
+<dom-module id="x-app">
+
+ <style>
+
+ :host {
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ </style>
+
+ <template>
+
+ <x-puck></x-puck>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'x-app',
+
+ behaviors: [
+ Polymer.IronResizableBehavior
+ ]
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/index.html
new file mode 100644
index 00000000000..b9b8809560f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/index.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-resizable-behavior</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/iron-resizable-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/iron-resizable-behavior.html
new file mode 100644
index 00000000000..9ac0d3967e8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-resizable-behavior/iron-resizable-behavior.html
@@ -0,0 +1,195 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+ /**
+ * `IronResizableBehavior` is a behavior that can be used in Polymer elements to
+ * coordinate the flow of resize events between "resizers" (elements that control the
+ * size or hidden state of their children) and "resizables" (elements that need to be
+ * notified when they are resized or un-hidden by their parents in order to take
+ * action on their new measurements).
+ *
+ * Elements that perform measurement should add the `IronResizableBehavior` behavior to
+ * their element definition and listen for the `iron-resize` event on themselves.
+ * This event will be fired when they become showing after having been hidden,
+ * when they are resized explicitly by another resizable, or when the window has been
+ * resized.
+ *
+ * Note, the `iron-resize` event is non-bubbling.
+ *
+ * @polymerBehavior Polymer.IronResizableBehavior
+ * @demo demo/index.html
+ **/
+ Polymer.IronResizableBehavior = {
+ properties: {
+ /**
+ * The closest ancestor element that implements `IronResizableBehavior`.
+ */
+ _parentResizable: {
+ type: Object,
+ observer: '_parentResizableChanged'
+ },
+
+ /**
+ * True if this element is currently notifying its descedant elements of
+ * resize.
+ */
+ _notifyingDescendant: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ listeners: {
+ 'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
+ },
+
+ created: function() {
+ // We don't really need property effects on these, and also we want them
+ // to be created before the `_parentResizable` observer fires:
+ this._interestedResizables = [];
+ this._boundNotifyResize = this.notifyResize.bind(this);
+ },
+
+ attached: function() {
+ this.fire('iron-request-resize-notifications', null, {
+ node: this,
+ bubbles: true,
+ cancelable: true
+ });
+
+ if (!this._parentResizable) {
+ window.addEventListener('resize', this._boundNotifyResize);
+ this.notifyResize();
+ }
+ },
+
+ detached: function() {
+ if (this._parentResizable) {
+ this._parentResizable.stopResizeNotificationsFor(this);
+ } else {
+ window.removeEventListener('resize', this._boundNotifyResize);
+ }
+
+ this._parentResizable = null;
+ },
+
+ /**
+ * Can be called to manually notify a resizable and its descendant
+ * resizables of a resize change.
+ */
+ notifyResize: function() {
+ if (!this.isAttached) {
+ return;
+ }
+
+ this._interestedResizables.forEach(function(resizable) {
+ if (this.resizerShouldNotify(resizable)) {
+ this._notifyDescendant(resizable);
+ }
+ }, this);
+
+ this._fireResize();
+ },
+
+ /**
+ * Used to assign the closest resizable ancestor to this resizable
+ * if the ancestor detects a request for notifications.
+ */
+ assignParentResizable: function(parentResizable) {
+ this._parentResizable = parentResizable;
+ },
+
+ /**
+ * Used to remove a resizable descendant from the list of descendants
+ * that should be notified of a resize change.
+ */
+ stopResizeNotificationsFor: function(target) {
+ var index = this._interestedResizables.indexOf(target);
+
+ if (index > -1) {
+ this._interestedResizables.splice(index, 1);
+ this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
+ }
+ },
+
+ /**
+ * This method can be overridden to filter nested elements that should or
+ * should not be notified by the current element. Return true if an element
+ * should be notified, or false if it should not be notified.
+ *
+ * @param {HTMLElement} element A candidate descendant element that
+ * implements `IronResizableBehavior`.
+ * @return {boolean} True if the `element` should be notified of resize.
+ */
+ resizerShouldNotify: function(element) { return true; },
+
+ _onDescendantIronResize: function(event) {
+ if (this._notifyingDescendant) {
+ event.stopPropagation();
+ return;
+ }
+
+ // NOTE(cdata): In ShadowDOM, event retargetting makes echoing of the
+ // otherwise non-bubbling event "just work." We do it manually here for
+ // the case where Polymer is not using shadow roots for whatever reason:
+ if (!Polymer.Settings.useShadow) {
+ this._fireResize();
+ }
+ },
+
+ _fireResize: function() {
+ this.fire('iron-resize', null, {
+ node: this,
+ bubbles: false
+ });
+ },
+
+ _onIronRequestResizeNotifications: function(event) {
+ var target = event.path ? event.path[0] : event.target;
+
+ if (target === this) {
+ return;
+ }
+
+ if (this._interestedResizables.indexOf(target) === -1) {
+ this._interestedResizables.push(target);
+ this.listen(target, 'iron-resize', '_onDescendantIronResize');
+ }
+
+ target.assignParentResizable(this);
+ this._notifyDescendant(target);
+
+ event.stopPropagation();
+ },
+
+ _parentResizableChanged: function(parentResizable) {
+ if (parentResizable) {
+ window.removeEventListener('resize', this._boundNotifyResize);
+ }
+ },
+
+ _notifyDescendant: function(descendant) {
+ // NOTE(cdata): In IE10, attached is fired on children first, so it's
+ // important not to notify them if the parent is not attached yet (or
+ // else they will get redundantly notified when the parent attaches).
+ if (!this.isAttached) {
+ return;
+ }
+
+ this._notifyingDescendant = true;
+ descendant.notifyResize();
+ this._notifyingDescendant = false;
+ }
+ };
+</script>
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.bower.json
new file mode 100644
index 00000000000..955c9dc566d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "iron-selector",
+ "version": "1.5.2",
+ "description": "Manages a set of elements that can be selected",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "main": "iron-selector.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "selector"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-selector.git"
+ },
+ "homepage": "https://github.com/PolymerElements/iron-selector",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.4",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.5.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.5.2",
+ "commit": "18e8e12dcd9a4560de480562f65935feed334b86"
+ },
+ "_source": "git://github.com/PolymerElements/iron-selector.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-selector"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.github/ISSUE_TEMPLATE.md b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000000..07a3448a7ae
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+<!-- Instructions: https://github.com/PolymerElements/iron-selector/CONTRIBUTING.md#filing-issues -->
+### Description
+<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
+
+### Expected outcome
+
+<!-- Example: The page stays the same color. -->
+
+### Actual outcome
+
+<!-- Example: The page turns pink. -->
+
+### Live Demo
+<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
+
+### Steps to reproduce
+
+<!-- Example
+1. Put a `paper-foo` element in the page.
+2. Open the page in a web browser.
+3. Click the `paper-foo` element.
+-->
+
+### Browsers Affected
+<!-- Check all that apply -->
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari 9
+- [ ] Safari 8
+- [ ] Safari 7
+- [ ] Edge
+- [ ] IE 11
+- [ ] IE 10
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.travis.yml
new file mode 100644
index 00000000000..d1b0332b45b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: ltCkwJM0nkTS9WjikyjqBsB5J2hQon4UnVVrINk4y+Vq4v9PQJH3+83nya0jnxilKaeAJs4d2/OS02F9GkqYpsSmDz7OgXPfk0hrHA8UksvvpSALfnukleIAN2YTOcxXJKeNHcfpqCKPk1dGeNQOEM61H+QgTBIyFB3sMugygqs=
+ - secure: TJuu1WdpFLTaBN/prBafm8Pld/BQCySNuuG1nATbF3fqiOpgehXu8Z5URAz5syUhqZAyEmuRMxvXpEVD/t1jrtaXVwkdCFkkQ4ckkP4gTIeSGA/Puw8sveB2q7QAqXyTmeFkocNlh8fxV+B07o0SPWdhcvdZnDVU9VrpSqL+92M=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/README.md
new file mode 100755
index 00000000000..9d2ef310843
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/README.md
@@ -0,0 +1,91 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-multi-selectable.html iron-selectable.html iron-selector.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-selector.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-selector)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-selector)_
+
+
+##&lt;iron-selector&gt;
+
+ `iron-selector` is an element which can be used to manage a list of elements
+ that can be selected. Tapping on the item will make the item selected. The `selected` indicates
+ which item is being selected. The default is to use the index of the item.
+
+ Example:
+
+```html
+ <iron-selector selected="0">
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ </iron-selector>
+```
+
+ If you want to use the attribute value of an element for `selected` instead of the index,
+ set `attrForSelected` to the name of the attribute. For example, if you want to select item by
+ `name`, set `attrForSelected` to `name`.
+
+ Example:
+
+```html
+ <iron-selector attr-for-selected="name" selected="foo">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="zot">Zot</div>
+ </iron-selector>
+```
+
+ You can specify a default fallback with `fallbackSelection` in case the `selected` attribute does
+ not match the `attrForSelected` attribute of any elements.
+
+ Example:
+
+```html
+ <iron-selector attr-for-selected="name" selected="non-existing"
+ fallback-selection="default">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="default">Default</div>
+ </iron-selector>
+```
+
+ Note: When the selector is multi, the selection will set to `fallbackSelection` iff
+ the number of matching elements is zero.
+
+ `iron-selector` is not styled. Use the `iron-selected` CSS class to style the selected element.
+
+ Example:
+
+```html
+ <style>
+ .iron-selected {
+ background: #eee;
+ }
+ </style>
+
+ ...
+
+ <iron-selector selected="0">
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ </iron-selector>
+```
+
+
+
+<!-- No docs for Polymer.IronMultiSelectableBehavior found. -->
+
+<!-- No docs for Polymer.IronSelectableBehavior found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/bower.json
new file mode 100755
index 00000000000..8aad3d47a1e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-selector",
+ "version": "1.5.2",
+ "description": "Manages a set of elements that can be selected",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "main": "iron-selector.html",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "selector"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-selector.git"
+ },
+ "homepage": "https://github.com/PolymerElements/iron-selector",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.4",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/demo/index.html
new file mode 100644
index 00000000000..66724a19fe5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/demo/index.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+ <head>
+
+ <title>iron-selector</title>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../iron-selector.html">
+
+ <style is="custom-style">
+
+ iron-selector > * {
+ padding: 8px;
+ }
+
+ .horizontal-section {
+ padding: 0;
+ }
+
+ .iron-selected {
+ background-color: var(--google-blue-500);
+ color: white;
+ }
+
+ </style>
+
+ </head>
+ <body unresolved>
+
+ <div class="horizontal center-justified layout">
+ <div>
+ <h3>Basic</h3>
+ <div class="horizontal-section">
+ <iron-selector selected="0">
+ <div>Item 0</div>
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ <div>Item 4</div>
+ </iron-selector>
+ </div>
+ </div>
+
+ <div>
+ <h3>Multi-select</h3>
+ <div class="horizontal-section">
+ <iron-selector multi selected-values='[0,2]'>
+ <div>Item 0</div>
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ <div>Item 4</div>
+ </iron-selector>
+ </div>
+ </div>
+
+ <div>
+ <h3>Example with attr-for-selected</h3>
+ <div class="horizontal-section">
+ <iron-selector selected="foo" attr-for-selected="name">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="baz">Baz</div>
+ <div name="qux">Qux</div>
+ <div name="quux">Quux</div>
+ </iron-selector>
+ </div>
+ </div>
+
+ <div>
+ <h3>Example with fallback-selection</h3>
+ <div class="horizontal-section">
+ <iron-selector selected="non-existing" attr-for-selected="name" fallback-selection="default">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="baz">Baz</div>
+ <div name="qux">Qux</div>
+ <div name="quux">Quux</div>
+ <div name="default">Default</div>
+ </iron-selector>
+ </div>
+ </div>
+ </div>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/index.html
new file mode 100755
index 00000000000..741693ce702
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <title>iron-selector</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-multi-selectable.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-multi-selectable.html
new file mode 100644
index 00000000000..9993151da82
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-multi-selectable.html
@@ -0,0 +1,154 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="iron-selectable.html">
+
+<script>
+ /** @polymerBehavior Polymer.IronMultiSelectableBehavior */
+ Polymer.IronMultiSelectableBehaviorImpl = {
+ properties: {
+
+ /**
+ * If true, multiple selections are allowed.
+ */
+ multi: {
+ type: Boolean,
+ value: false,
+ observer: 'multiChanged'
+ },
+
+ /**
+ * Gets or sets the selected elements. This is used instead of `selected` when `multi`
+ * is true.
+ */
+ selectedValues: {
+ type: Array,
+ notify: true
+ },
+
+ /**
+ * Returns an array of currently selected items.
+ */
+ selectedItems: {
+ type: Array,
+ readOnly: true,
+ notify: true
+ },
+
+ },
+
+ observers: [
+ '_updateSelected(selectedValues.splices)'
+ ],
+
+ /**
+ * Selects the given value. If the `multi` property is true, then the selected state of the
+ * `value` will be toggled; otherwise the `value` will be selected.
+ *
+ * @method select
+ * @param {string|number} value the value to select.
+ */
+ select: function(value) {
+ if (this.multi) {
+ if (this.selectedValues) {
+ this._toggleSelected(value);
+ } else {
+ this.selectedValues = [value];
+ }
+ } else {
+ this.selected = value;
+ }
+ },
+
+ multiChanged: function(multi) {
+ this._selection.multi = multi;
+ },
+
+ get _shouldUpdateSelection() {
+ return this.selected != null ||
+ (this.selectedValues != null && this.selectedValues.length);
+ },
+
+ _updateAttrForSelected: function() {
+ if (!this.multi) {
+ Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
+ } else if (this._shouldUpdateSelection) {
+ this.selectedValues = this.selectedItems.map(function(selectedItem) {
+ return this._indexToValue(this.indexOf(selectedItem));
+ }, this).filter(function(unfilteredValue) {
+ return unfilteredValue != null;
+ }, this);
+ }
+ },
+
+ _updateSelected: function() {
+ if (this.multi) {
+ this._selectMulti(this.selectedValues);
+ } else {
+ this._selectSelected(this.selected);
+ }
+ },
+
+ _selectMulti: function(values) {
+ if (values) {
+ var selectedItems = this._valuesToItems(values);
+ // clear all but the current selected items
+ this._selection.clear(selectedItems);
+ // select only those not selected yet
+ for (var i = 0; i < selectedItems.length; i++) {
+ this._selection.setItemSelected(selectedItems[i], true);
+ }
+ // Check for items, since this array is populated only when attached
+ if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
+ var fallback = this._valueToItem(this.fallbackSelection);
+ if (fallback) {
+ this.selectedValues = [this.fallbackSelection];
+ }
+ }
+ } else {
+ this._selection.clear();
+ }
+ },
+
+ _selectionChange: function() {
+ var s = this._selection.get();
+ if (this.multi) {
+ this._setSelectedItems(s);
+ } else {
+ this._setSelectedItems([s]);
+ this._setSelectedItem(s);
+ }
+ },
+
+ _toggleSelected: function(value) {
+ var i = this.selectedValues.indexOf(value);
+ var unselected = i < 0;
+ if (unselected) {
+ this.push('selectedValues',value);
+ } else {
+ this.splice('selectedValues',i,1);
+ }
+ },
+
+ _valuesToItems: function(values) {
+ return (values == null) ? null : values.map(function(value) {
+ return this._valueToItem(value);
+ }, this);
+ }
+ };
+
+ /** @polymerBehavior */
+ Polymer.IronMultiSelectableBehavior = [
+ Polymer.IronSelectableBehavior,
+ Polymer.IronMultiSelectableBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selectable.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selectable.html
new file mode 100644
index 00000000000..25cfe91e3d8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selectable.html
@@ -0,0 +1,388 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="iron-selection.html">
+
+<script>
+
+ /** @polymerBehavior */
+ Polymer.IronSelectableBehavior = {
+
+ /**
+ * Fired when iron-selector is activated (selected or deselected).
+ * It is fired before the selected items are changed.
+ * Cancel the event to abort selection.
+ *
+ * @event iron-activate
+ */
+
+ /**
+ * Fired when an item is selected
+ *
+ * @event iron-select
+ */
+
+ /**
+ * Fired when an item is deselected
+ *
+ * @event iron-deselect
+ */
+
+ /**
+ * Fired when the list of selectable items changes (e.g., items are
+ * added or removed). The detail of the event is a mutation record that
+ * describes what changed.
+ *
+ * @event iron-items-changed
+ */
+
+ properties: {
+
+ /**
+ * If you want to use an attribute value or property of an element for
+ * `selected` instead of the index, set this to the name of the attribute
+ * or property. Hyphenated values are converted to camel case when used to
+ * look up the property of a selectable element. Camel cased values are
+ * *not* converted to hyphenated values for attribute lookup. It's
+ * recommended that you provide the hyphenated form of the name so that
+ * selection works in both cases. (Use `attr-or-property-name` instead of
+ * `attrOrPropertyName`.)
+ */
+ attrForSelected: {
+ type: String,
+ value: null
+ },
+
+ /**
+ * Gets or sets the selected element. The default is to use the index of the item.
+ * @type {string|number}
+ */
+ selected: {
+ type: String,
+ notify: true
+ },
+
+ /**
+ * Returns the currently selected item.
+ *
+ * @type {?Object}
+ */
+ selectedItem: {
+ type: Object,
+ readOnly: true,
+ notify: true
+ },
+
+ /**
+ * The event that fires from items when they are selected. Selectable
+ * will listen for this event from items and update the selection state.
+ * Set to empty string to listen to no events.
+ */
+ activateEvent: {
+ type: String,
+ value: 'tap',
+ observer: '_activateEventChanged'
+ },
+
+ /**
+ * This is a CSS selector string. If this is set, only items that match the CSS selector
+ * are selectable.
+ */
+ selectable: String,
+
+ /**
+ * The class to set on elements when selected.
+ */
+ selectedClass: {
+ type: String,
+ value: 'iron-selected'
+ },
+
+ /**
+ * The attribute to set on elements when selected.
+ */
+ selectedAttribute: {
+ type: String,
+ value: null
+ },
+
+ /**
+ * Default fallback if the selection based on selected with `attrForSelected`
+ * is not found.
+ */
+ fallbackSelection: {
+ type: String,
+ value: null
+ },
+
+ /**
+ * The list of items from which a selection can be made.
+ */
+ items: {
+ type: Array,
+ readOnly: true,
+ notify: true,
+ value: function() {
+ return [];
+ }
+ },
+
+ /**
+ * The set of excluded elements where the key is the `localName`
+ * of the element that will be ignored from the item list.
+ *
+ * @default {template: 1}
+ */
+ _excludedLocalNames: {
+ type: Object,
+ value: function() {
+ return {
+ 'template': 1
+ };
+ }
+ }
+ },
+
+ observers: [
+ '_updateAttrForSelected(attrForSelected)',
+ '_updateSelected(selected)',
+ '_checkFallback(fallbackSelection)'
+ ],
+
+ created: function() {
+ this._bindFilterItem = this._filterItem.bind(this);
+ this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
+ },
+
+ attached: function() {
+ this._observer = this._observeItems(this);
+ this._updateItems();
+ if (!this._shouldUpdateSelection) {
+ this._updateSelected();
+ }
+ this._addListener(this.activateEvent);
+ },
+
+ detached: function() {
+ if (this._observer) {
+ Polymer.dom(this).unobserveNodes(this._observer);
+ }
+ this._removeListener(this.activateEvent);
+ },
+
+ /**
+ * Returns the index of the given item.
+ *
+ * @method indexOf
+ * @param {Object} item
+ * @returns Returns the index of the item
+ */
+ indexOf: function(item) {
+ return this.items.indexOf(item);
+ },
+
+ /**
+ * Selects the given value.
+ *
+ * @method select
+ * @param {string|number} value the value to select.
+ */
+ select: function(value) {
+ this.selected = value;
+ },
+
+ /**
+ * Selects the previous item.
+ *
+ * @method selectPrevious
+ */
+ selectPrevious: function() {
+ var length = this.items.length;
+ var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
+ this.selected = this._indexToValue(index);
+ },
+
+ /**
+ * Selects the next item.
+ *
+ * @method selectNext
+ */
+ selectNext: function() {
+ var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
+ this.selected = this._indexToValue(index);
+ },
+
+ /**
+ * Selects the item at the given index.
+ *
+ * @method selectIndex
+ */
+ selectIndex: function(index) {
+ this.select(this._indexToValue(index));
+ },
+
+ /**
+ * Force a synchronous update of the `items` property.
+ *
+ * NOTE: Consider listening for the `iron-items-changed` event to respond to
+ * updates to the set of selectable items after updates to the DOM list and
+ * selection state have been made.
+ *
+ * WARNING: If you are using this method, you should probably consider an
+ * alternate approach. Synchronously querying for items is potentially
+ * slow for many use cases. The `items` property will update asynchronously
+ * on its own to reflect selectable items in the DOM.
+ */
+ forceSynchronousItemUpdate: function() {
+ this._updateItems();
+ },
+
+ get _shouldUpdateSelection() {
+ return this.selected != null;
+ },
+
+ _checkFallback: function() {
+ if (this._shouldUpdateSelection) {
+ this._updateSelected();
+ }
+ },
+
+ _addListener: function(eventName) {
+ this.listen(this, eventName, '_activateHandler');
+ },
+
+ _removeListener: function(eventName) {
+ this.unlisten(this, eventName, '_activateHandler');
+ },
+
+ _activateEventChanged: function(eventName, old) {
+ this._removeListener(old);
+ this._addListener(eventName);
+ },
+
+ _updateItems: function() {
+ var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
+ nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
+ this._setItems(nodes);
+ },
+
+ _updateAttrForSelected: function() {
+ if (this._shouldUpdateSelection) {
+ this.selected = this._indexToValue(this.indexOf(this.selectedItem));
+ }
+ },
+
+ _updateSelected: function() {
+ this._selectSelected(this.selected);
+ },
+
+ _selectSelected: function(selected) {
+ this._selection.select(this._valueToItem(this.selected));
+ // Check for items, since this array is populated only when attached
+ // Since Number(0) is falsy, explicitly check for undefined
+ if (this.fallbackSelection && this.items.length && (this._selection.get() === undefined)) {
+ this.selected = this.fallbackSelection;
+ }
+ },
+
+ _filterItem: function(node) {
+ return !this._excludedLocalNames[node.localName];
+ },
+
+ _valueToItem: function(value) {
+ return (value == null) ? null : this.items[this._valueToIndex(value)];
+ },
+
+ _valueToIndex: function(value) {
+ if (this.attrForSelected) {
+ for (var i = 0, item; item = this.items[i]; i++) {
+ if (this._valueForItem(item) == value) {
+ return i;
+ }
+ }
+ } else {
+ return Number(value);
+ }
+ },
+
+ _indexToValue: function(index) {
+ if (this.attrForSelected) {
+ var item = this.items[index];
+ if (item) {
+ return this._valueForItem(item);
+ }
+ } else {
+ return index;
+ }
+ },
+
+ _valueForItem: function(item) {
+ var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];
+ return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
+ },
+
+ _applySelection: function(item, isSelected) {
+ if (this.selectedClass) {
+ this.toggleClass(this.selectedClass, isSelected, item);
+ }
+ if (this.selectedAttribute) {
+ this.toggleAttribute(this.selectedAttribute, isSelected, item);
+ }
+ this._selectionChange();
+ this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item});
+ },
+
+ _selectionChange: function() {
+ this._setSelectedItem(this._selection.get());
+ },
+
+ // observe items change under the given node.
+ _observeItems: function(node) {
+ return Polymer.dom(node).observeNodes(function(mutation) {
+ this._updateItems();
+
+ if (this._shouldUpdateSelection) {
+ this._updateSelected();
+ }
+
+ // Let other interested parties know about the change so that
+ // we don't have to recreate mutation observers everywhere.
+ this.fire('iron-items-changed', mutation, {
+ bubbles: false,
+ cancelable: false
+ });
+ });
+ },
+
+ _activateHandler: function(e) {
+ var t = e.target;
+ var items = this.items;
+ while (t && t != this) {
+ var i = items.indexOf(t);
+ if (i >= 0) {
+ var value = this._indexToValue(i);
+ this._itemActivate(value, t);
+ return;
+ }
+ t = t.parentNode;
+ }
+ },
+
+ _itemActivate: function(value, item) {
+ if (!this.fire('iron-activate',
+ {selected: value, item: item}, {cancelable: true}).defaultPrevented) {
+ this.select(value);
+ }
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selection.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selection.html
new file mode 100644
index 00000000000..408ccae9d8b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selection.html
@@ -0,0 +1,119 @@
+
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /**
+ * @param {!Function} selectCallback
+ * @constructor
+ */
+ Polymer.IronSelection = function(selectCallback) {
+ this.selection = [];
+ this.selectCallback = selectCallback;
+ };
+
+ Polymer.IronSelection.prototype = {
+
+ /**
+ * Retrieves the selected item(s).
+ *
+ * @method get
+ * @returns Returns the selected item(s). If the multi property is true,
+ * `get` will return an array, otherwise it will return
+ * the selected item or undefined if there is no selection.
+ */
+ get: function() {
+ return this.multi ? this.selection.slice() : this.selection[0];
+ },
+
+ /**
+ * Clears all the selection except the ones indicated.
+ *
+ * @method clear
+ * @param {Array} excludes items to be excluded.
+ */
+ clear: function(excludes) {
+ this.selection.slice().forEach(function(item) {
+ if (!excludes || excludes.indexOf(item) < 0) {
+ this.setItemSelected(item, false);
+ }
+ }, this);
+ },
+
+ /**
+ * Indicates if a given item is selected.
+ *
+ * @method isSelected
+ * @param {*} item The item whose selection state should be checked.
+ * @returns Returns true if `item` is selected.
+ */
+ isSelected: function(item) {
+ return this.selection.indexOf(item) >= 0;
+ },
+
+ /**
+ * Sets the selection state for a given item to either selected or deselected.
+ *
+ * @method setItemSelected
+ * @param {*} item The item to select.
+ * @param {boolean} isSelected True for selected, false for deselected.
+ */
+ setItemSelected: function(item, isSelected) {
+ if (item != null) {
+ if (isSelected !== this.isSelected(item)) {
+ // proceed to update selection only if requested state differs from current
+ if (isSelected) {
+ this.selection.push(item);
+ } else {
+ var i = this.selection.indexOf(item);
+ if (i >= 0) {
+ this.selection.splice(i, 1);
+ }
+ }
+ if (this.selectCallback) {
+ this.selectCallback(item, isSelected);
+ }
+ }
+ }
+ },
+
+ /**
+ * Sets the selection state for a given item. If the `multi` property
+ * is true, then the selected state of `item` will be toggled; otherwise
+ * the `item` will be selected.
+ *
+ * @method select
+ * @param {*} item The item to select.
+ */
+ select: function(item) {
+ if (this.multi) {
+ this.toggle(item);
+ } else if (this.get() !== item) {
+ this.setItemSelected(this.get(), false);
+ this.setItemSelected(item, true);
+ }
+ },
+
+ /**
+ * Toggles the selection state for `item`.
+ *
+ * @method toggle
+ * @param {*} item The item to toggle.
+ */
+ toggle: function(item) {
+ this.setItemSelected(item, !this.isSelected(item));
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selector.html b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selector.html
new file mode 100644
index 00000000000..0ecc9fbcd19
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-selector/iron-selector.html
@@ -0,0 +1,87 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="iron-multi-selectable.html">
+
+<script>
+ /**
+ `iron-selector` is an element which can be used to manage a list of elements
+ that can be selected. Tapping on the item will make the item selected. The `selected` indicates
+ which item is being selected. The default is to use the index of the item.
+
+ Example:
+
+ <iron-selector selected="0">
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ </iron-selector>
+
+ If you want to use the attribute value of an element for `selected` instead of the index,
+ set `attrForSelected` to the name of the attribute. For example, if you want to select item by
+ `name`, set `attrForSelected` to `name`.
+
+ Example:
+
+ <iron-selector attr-for-selected="name" selected="foo">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="zot">Zot</div>
+ </iron-selector>
+
+ You can specify a default fallback with `fallbackSelection` in case the `selected` attribute does
+ not match the `attrForSelected` attribute of any elements.
+
+ Example:
+
+ <iron-selector attr-for-selected="name" selected="non-existing"
+ fallback-selection="default">
+ <div name="foo">Foo</div>
+ <div name="bar">Bar</div>
+ <div name="default">Default</div>
+ </iron-selector>
+
+ Note: When the selector is multi, the selection will set to `fallbackSelection` iff
+ the number of matching elements is zero.
+
+ `iron-selector` is not styled. Use the `iron-selected` CSS class to style the selected element.
+
+ Example:
+
+ <style>
+ .iron-selected {
+ background: #eee;
+ }
+ </style>
+
+ ...
+
+ <iron-selector selected="0">
+ <div>Item 1</div>
+ <div>Item 2</div>
+ <div>Item 3</div>
+ </iron-selector>
+
+ @demo demo/index.html
+ */
+
+ Polymer({
+
+ is: 'iron-selector',
+
+ behaviors: [
+ Polymer.IronMultiSelectableBehavior
+ ]
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/.bower.json
new file mode 100644
index 00000000000..9b49957bf5d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/.bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "iron-validatable-behavior",
+ "version": "1.1.1",
+ "description": "Provides a behavior for an element that validates user input",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "main": "iron-validatable-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-validatable-behavior.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-validatable-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-meta": "PolymerElements/iron-meta#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.4",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.1.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.1",
+ "commit": "2ecd3f411e298733b29f1660f75cb9b03ea31d77"
+ },
+ "_source": "git://github.com/PolymerElements/iron-validatable-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-validatable-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/README.md
new file mode 100644
index 00000000000..6fff76e42bf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/README.md
@@ -0,0 +1,42 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-validatable-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-validatable-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-validatable-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-validatable-behavior)_
+
+
+##Polymer.IronValidatableBehavior
+
+`Use Polymer.IronValidatableBehavior` to implement an element that validates user input.
+Use the related `Polymer.IronValidatorBehavior` to add custom validation logic to an iron-input.
+
+By default, an `<iron-form>` element validates its fields when the user presses the submit button.
+To validate a form imperatively, call the form's `validate()` method, which in turn will
+call `validate()` on all its children. By using `Polymer.IronValidatableBehavior`, your
+custom element will get a public `validate()`, which
+will return the validity of the element, and a corresponding `invalid` attribute,
+which can be used for styling.
+
+To implement the custom validation logic of your element, you must override
+the protected `_getValidity()` method of this behaviour, rather than `validate()`.
+See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/simple-element.html)
+for an example.
+
+### Accessibility
+
+Changing the `invalid` property, either manually or by calling `validate()` will update the
+`aria-invalid` attribute.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/bower.json
new file mode 100644
index 00000000000..2ebf2bcb7e6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "iron-validatable-behavior",
+ "version": "1.1.1",
+ "description": "Provides a behavior for an element that validates user input",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "iron",
+ "behavior"
+ ],
+ "main": "iron-validatable-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-validatable-behavior.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/iron-validatable-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-meta": "PolymerElements/iron-meta#^1.0.0",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "paper-styles": "PolymerElements/paper-styles#^1.0.4",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/cats-only.html b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/cats-only.html
new file mode 100644
index 00000000000..83ef9ba617f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/cats-only.html
@@ -0,0 +1,46 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../iron-validator-behavior/iron-validator-behavior.html">
+
+<script>
+
+ Polymer({
+
+ is: 'cats-only',
+
+ behaviors: [
+ Polymer.IronValidatorBehavior
+ ],
+
+ validateObject: function(obj) {
+ var valid = true;
+ for (key in obj) {
+ if (obj[key] !== 'cats') {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ },
+
+ validate: function(values) {
+ if (typeof values === 'object') {
+ return this.validateObject(values);
+ } else {
+ var value = Array.isArray(values) ? values.join('') : values;
+ return value.match(/^(c|ca|cat|cats)?$/) !== null;
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/index.html
new file mode 100644
index 00000000000..84b96a8dc25
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/index.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>iron-validatable-behavior demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="cats-only.html">
+ <link rel="import" href="validatable-input.html">
+
+ <style is="custom-style">
+
+ .valid {
+ color: var(--google-green-500);
+ }
+
+ .invalid {
+ color: var(--google-red-500);
+ }
+
+ </style>
+
+</head>
+<body>
+ <div class="vertical-section vertical-section-container centered">
+ <h1>&lt;iron-validatable-behavior&gt;</h1>
+
+ <template is="dom-bind">
+
+ <cats-only></cats-only>
+
+ <section>
+
+ <p>
+ only type <code>cats</code>:
+
+ <input is="validatable-input" invalid="{{invalid}}" validator="cats-only">
+
+ <span class="valid" hidden$="[[invalid]]">valid</span>
+ <span class="invalid" hidden$="[[!invalid]]">invalid</span>
+ </p>
+
+ </section>
+
+ </template>
+
+ </div>
+
+ <script>
+
+ document.querySelector('template[is="dom-bind"]').invalid = false;
+
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/validatable-input.html b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/validatable-input.html
new file mode 100644
index 00000000000..19cf4775989
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/demo/validatable-input.html
@@ -0,0 +1,46 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-validatable-behavior.html">
+
+<script>
+
+ Polymer({
+
+ is: 'validatable-input',
+
+ extends: 'input',
+
+ properties: {
+
+ invalid: {
+ notify: true,
+ type: Boolean,
+ value: false
+ }
+
+ },
+
+ behaviors: [
+ Polymer.IronValidatableBehavior
+ ],
+
+ listeners: {
+ 'input': '_onInput'
+ },
+
+ _onInput: function(event) {
+ this.invalid = !this.validate(event.target.value);
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/index.html
new file mode 100644
index 00000000000..cfaa5b17598
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-validatable-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/iron-validatable-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/iron-validatable-behavior.html
new file mode 100644
index 00000000000..803731be930
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/iron-validatable-behavior/iron-validatable-behavior.html
@@ -0,0 +1,149 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-meta/iron-meta.html">
+
+<script>
+ /**
+ * Singleton IronMeta instance.
+ */
+ Polymer.IronValidatableBehaviorMeta = null;
+
+ /**
+ * `Use Polymer.IronValidatableBehavior` to implement an element that validates user input.
+ * Use the related `Polymer.IronValidatorBehavior` to add custom validation logic to an iron-input.
+ *
+ * By default, an `<iron-form>` element validates its fields when the user presses the submit button.
+ * To validate a form imperatively, call the form's `validate()` method, which in turn will
+ * call `validate()` on all its children. By using `Polymer.IronValidatableBehavior`, your
+ * custom element will get a public `validate()`, which
+ * will return the validity of the element, and a corresponding `invalid` attribute,
+ * which can be used for styling.
+ *
+ * To implement the custom validation logic of your element, you must override
+ * the protected `_getValidity()` method of this behaviour, rather than `validate()`.
+ * See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/simple-element.html)
+ * for an example.
+ *
+ * ### Accessibility
+ *
+ * Changing the `invalid` property, either manually or by calling `validate()` will update the
+ * `aria-invalid` attribute.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior
+ */
+ Polymer.IronValidatableBehavior = {
+
+ properties: {
+
+ /**
+ * Name of the validator to use.
+ */
+ validator: {
+ type: String
+ },
+
+ /**
+ * True if the last call to `validate` is invalid.
+ */
+ invalid: {
+ notify: true,
+ reflectToAttribute: true,
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * This property is deprecated and should not be used. Use the global
+ * validator meta singleton, `Polymer.IronValidatableBehaviorMeta` instead.
+ */
+ _validatorMeta: {
+ type: Object
+ },
+
+ /**
+ * Namespace for this validator. This property is deprecated and should
+ * not be used. For all intents and purposes, please consider it a
+ * read-only, config-time property.
+ */
+ validatorType: {
+ type: String,
+ value: 'validator'
+ },
+
+ _validator: {
+ type: Object,
+ computed: '__computeValidator(validator)'
+ }
+ },
+
+ observers: [
+ '_invalidChanged(invalid)'
+ ],
+
+ registered: function() {
+ Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({type: 'validator'});
+ },
+
+ _invalidChanged: function() {
+ if (this.invalid) {
+ this.setAttribute('aria-invalid', 'true');
+ } else {
+ this.removeAttribute('aria-invalid');
+ }
+ },
+
+ /**
+ * @return {boolean} True if the validator `validator` exists.
+ */
+ hasValidator: function() {
+ return this._validator != null;
+ },
+
+ /**
+ * Returns true if the `value` is valid, and updates `invalid`. If you want
+ * your element to have custom validation logic, do not override this method;
+ * override `_getValidity(value)` instead.
+
+ * @param {Object} value The value to be validated. By default, it is passed
+ * to the validator's `validate()` function, if a validator is set.
+ * @return {boolean} True if `value` is valid.
+ */
+ validate: function(value) {
+ this.invalid = !this._getValidity(value);
+ return !this.invalid;
+ },
+
+ /**
+ * Returns true if `value` is valid. By default, it is passed
+ * to the validator's `validate()` function, if a validator is set. You
+ * should override this method if you want to implement custom validity
+ * logic for your element.
+ *
+ * @param {Object} value The value to be validated.
+ * @return {boolean} True if `value` is valid.
+ */
+
+ _getValidity: function(value) {
+ if (this.hasValidator()) {
+ return this._validator.validate(value);
+ }
+ return true;
+ },
+
+ __computeValidator: function() {
+ return Polymer.IronValidatableBehaviorMeta &&
+ Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
+ }
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.bower.json
new file mode 100644
index 00000000000..2d3a1da519a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.bower.json
@@ -0,0 +1,61 @@
+{
+ "name": "neon-animation",
+ "description": "A system for animating Polymer-based web components",
+ "version": "1.2.3",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "web-animations"
+ ],
+ "main": [
+ "neon-animated-pages.html",
+ "neon-animatable-behavior.html",
+ "neon-animation-behavior.html",
+ "neon-animation-runner-behavior.html",
+ "neon-shared-element-animatable-behavior.html",
+ "neon-shared-element-animation-behavior.html",
+ "neon-animatable.html",
+ "neon-animations.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/neon-animation"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/neon-animation",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-meta": "PolymerElements/iron-meta#^1.0.0",
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "iron-selector": "PolymerElements/iron-selector#^1.0.0",
+ "web-animations-js": "web-animations/web-animations-js#^2.2.0"
+ },
+ "devDependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
+ },
+ "_release": "1.2.3",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.3",
+ "commit": "c50d51e62825f4aa53f10e93f746796a174af232"
+ },
+ "_source": "git://github.com/PolymerElements/neon-animation.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/neon-animation"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.travis.yml
new file mode 100644
index 00000000000..dd1a81e7102
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+env:
+ global:
+ - secure: AnPpB3uzTWU0hmrDmPyOb/3mJZRv4BgPFJrpaT/mQ/9979IBeFfFHJX6MqQlgo894lJWvKSvAjEutgK5Z3LQh6cLB3JuhPBInwKgFPUx/V14VIju+Z7jwx6RycE3flb2f9Y6y5My13ovswsTNnhJEkpDGlbRnJlh5c+HeP+6D0oFPFaGWvULZsAHQnEykir1TMPL2TD8SfuYWifmBj7QYQ2vsYnqZoAkPNedv/OtdoA3rziFXSG3GqXX2NJVnYqlaLj/HiHK7xLlZu/ODfo6En12DMtqJajBP7NfJkEUAF72ScOsYxlwiI1aYcVSUy6upkxxPwkBj5x7wDZ0tRFmlautyq2skDAh/fgIfRw9AMe8kj/YLef+T8bmZNT9IIelNaNcpfTQHpYWcOpPk2uBT3iIOcmp+Ys8RZKqzYmekBtHTwCGmQcfQrjBXjrjz5xlUaoMH7vauh7Ct7SkD7Fu87XSUvks4v2yypxxmHXO8jUilKuUdtAzb3dtOboO0ptsoLuBm/qSeURco4be6KPyVnDxdWdbYOxIZtE8JeY2DbonS45OgFtL1NKeEIhiTQIcOuSs0qwJFFzaBBAfek1tkTvBhMJP3JPWpIbNJhdZWzSd0LUSe892sbiZJY67FA4xcY8vK5JZNWnxFyKX1+A8ljPEd1yBImxMzUDMNS9t0G0=
+ - secure: jdh0G/FDRghnjasav0/8nOZsYgXUd5DLKgD5XrDCVrBvPwXly+AnMXE+Hr/bztEXylcEmcqrWUUfB1ODUdVn1EGk8CJaYpHyKcoMcpJiEjHYS/3i1rXRsnHs2o3dcRO69rA8A5LZeG3yYfiPVUiKlyl7MWOal3pNohDGi8dZcT0CoWnA8UaV//0uXG3GGG3X8KcbVfB2hQvG1mK6wM6W4eHVOplcBaE2xnnFDMxfU2KnRgjLSPw66PeJGczWOBR9fZql9p6kV38ZM2s4qnUsMlTZkNqn0f6CuEPqcG6+S6Tk9+0dvAHet+Ky9fgiyJPq+p6sDGfdm1ZJwOjz5MoyudzGSuHAJHH2nscQf8pUBQ1gxKaGg7GV9LUj0cjLDAFWA2KpxTlabDZhZPIMoMKFpqpvJG49gDVga5gGabom21nd/+E1i/2vvoP16kY9rjf+Gd5+tIzajXCu8Tq06Xz63idZDJbt38GjArfFFqe5k7CqE+m2vpWx/iTwe+cT70wnIq/xigvaNq6CgUuNdzkVnVBj/C7yVqwwZkfbBC7HhRna9Nyzts/j2M2vwy0oYB73WzuhpYSweaAOZq2kcUIQ5ZMGO3UkZRjwWnHxAi5mrvZhRcRIqkvJJhoMQnjwJSTah/3cz0cJh19DL+Ozde24/tuY+vOnhFb+ddo1OKD6FtM=
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/README.md b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/README.md
new file mode 100644
index 00000000000..29c07539967
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/README.md
@@ -0,0 +1,306 @@
+# neon-animation
+
+`neon-animation` is a suite of elements and behaviors to implement pluggable animated transitions for Polymer Elements using [Web Animations](https://w3c.github.io/web-animations/).
+
+*Warning: The API may change.*
+
+* [A basic animatable element](#basic)
+* [Animation configuration](#configuration)
+ * [Animation types](#configuration-types)
+ * [Configuration properties](#configuration-properties)
+ * [Using multiple animations](#configuration-multiple)
+ * [Running animations encapsulated in children nodes](#configuration-encapsulation)
+* [Page transitions](#page-transitions)
+ * [Shared element animations](#shared-element)
+ * [Declarative page transitions](#declarative-page)
+* [Included animations](#animations)
+* [Demos](#demos)
+
+<a name="basic"></a>
+## A basic animatable element
+
+Elements that can be animated should implement the `Polymer.NeonAnimatableBehavior` behavior, or `Polymer.NeonAnimationRunnerBehavior` if they're also responsible for running an animation.
+
+```js
+Polymer({
+ is: 'my-animatable',
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+ properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // provided by neon-animation/animations/scale-down-animation.html
+ name: 'scale-down-animation',
+ node: this
+ }
+ }
+ }
+ },
+ listeners: {
+ // this event is fired when the animation finishes
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+ animate: function() {
+ // run scale-down-animation
+ this.playAnimation();
+ },
+ _onNeonAnimationFinish: function() {
+ console.log('animation done!');
+ }
+});
+```
+
+[Live demo](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/doc/basic.html)
+
+<a name="configuration"></a>
+## Animation configuration
+
+<a name="configuration-types"></a>
+### Animation types
+
+An element might run different animations, for example it might do something different when it enters the view and when it exits from view. You can set the `animationConfig` property to a map from an animation type to configuration.
+
+```js
+Polymer({
+ is: 'my-dialog',
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+ properties: {
+ opened: {
+ type: Boolean
+ },
+ animationConfig: {
+ value: function() {
+ return {
+ 'entry': {
+ // provided by neon-animation/animations/scale-up-animation.html
+ name: 'scale-up-animation',
+ node: this
+ },
+ 'exit': {
+ // provided by neon-animation/animations/fade-out-animation.html
+ name: 'fade-out-animation',
+ node: this
+ }
+ }
+ }
+ }
+ },
+ listeners: {
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+ show: function() {
+ this.opened = true;
+ this.style.display = 'inline-block';
+ // run scale-up-animation
+ this.playAnimation('entry');
+ },
+ hide: function() {
+ this.opened = false;
+ // run fade-out-animation
+ this.playAnimation('exit');
+ },
+ _onNeonAnimationFinish: function() {
+ if (!this.opened) {
+ this.style.display = 'none';
+ }
+ }
+});
+```
+
+[Live demo](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/doc/types.html)
+
+You can also use the convenience properties `entryAnimation` and `exitAnimation` to set `entry` and `exit` animations:
+
+```js
+properties: {
+ entryAnimation: {
+ value: 'scale-up-animation'
+ },
+ exitAnimation: {
+ value: 'fade-out-animation'
+ }
+}
+```
+
+<a name="configuration-properties"></a>
+### Configuration properties
+
+You can pass additional parameters to configure an animation in the animation configuration object.
+All animations should accept the following properties:
+
+ * `name`: The name of an animation, ie. an element implementing `Polymer.NeonAnimationBehavior`.
+ * `node`: The target node to apply the animation to. Defaults to `this`.
+ * `timing`: Timing properties to use in this animation. They match the [Web Animations Animation Effect Timing interface](https://w3c.github.io/web-animations/#the-animationeffecttiming-interface). The
+ properties include the following:
+ * `duration`: The duration of the animation in milliseconds.
+ * `delay`: The delay before the start of the animation in milliseconds.
+ * `easing`: A timing function for the animation. Matches the CSS timing function values.
+
+Animations may define additional configuration properties and they are listed in their documentation.
+
+<a name="configuration-multiple"></a>
+### Using multiple animations
+
+Set the animation configuration to an array to combine animations, like this:
+
+```js
+animationConfig: {
+ value: function() {
+ return {
+ // fade-in-animation is run with a 50ms delay from slide-down-animation
+ 'entry': [{
+ name: 'slide-down-animation',
+ node: this
+ }, {
+ name: 'fade-in-animation',
+ node: this,
+ timing: {delay: 50}
+ }]
+ }
+ }
+}
+```
+
+<a name="configuration-encapsulation"></a>
+### Running animations encapsulated in children nodes
+
+You can include animations in the configuration that are encapsulated in a child element that implement `Polymer.NeonAnimatableBehavior` with the `animatable` property.
+
+```js
+animationConfig: {
+ value: function() {
+ return {
+ // run fade-in-animation on this, and the entry animation on this.$.myAnimatable
+ 'entry': [
+ {name: 'fade-in-animation', node: this},
+ {animatable: this.$.myAnimatable, type: 'entry'}
+ ]
+ }
+ }
+}
+```
+
+<a name="page-transitions"></a>
+## Page transitions
+
+*The artist formerly known as `<core-animated-pages>`*
+
+The `neon-animated-pages` element manages a set of pages to switch between, and runs animations between the page transitions. It implements the `Polymer.IronSelectableBehavior` behavior. Each child node should implement `Polymer.NeonAnimatableBehavior` and define the `entry` and `exit` animations. During a page transition, the `entry` animation is run on the new page and the `exit` animation is run on the old page.
+
+<a name="shared-element"></a>
+### Shared element animations
+
+Shared element animations work on multiple nodes. For example, a "hero" animation is used during a page transition to make two elements from separate pages appear to animate as a single element. Shared element animation configurations have an `id` property that identify they belong in the same animation. Elements containing shared elements also have a `sharedElements` property defines a map from `id` to element, the element involved with the animation.
+
+In the incoming page:
+
+```js
+properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // the incoming page defines the 'entry' animation
+ 'entry': {
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this
+ }
+ }
+ }
+ },
+ sharedElements: {
+ value: function() {
+ return {
+ 'hero': this.$.hero
+ }
+ }
+ }
+}
+```
+
+In the outgoing page:
+
+```js
+properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // the outgoing page defines the 'exit' animation
+ 'exit': {
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }
+ }
+ }
+ },
+ sharedElements: {
+ value: function() {
+ return {
+ 'hero': this.$.otherHero
+ }
+ }
+ }
+}
+```
+
+<a name="declarative-page"></a>
+### Declarative page transitions
+
+For convenience, if you define the `entry-animation` and `exit-animation` attributes on `<neon-animated-pages>`, those animations will apply for all page transitions.
+
+For example:
+
+```js
+<neon-animated-pages id="pages" class="flex" selected="[[selected]]" entry-animation="slide-from-right-animation" exit-animation="slide-left-animation">
+ <neon-animatable>1</neon-animatable>
+ <neon-animatable>2</neon-animatable>
+ <neon-animatable>3</neon-animatable>
+ <neon-animatable>4</neon-animatable>
+ <neon-animatable>5</neon-animatable>
+</neon-animated-pages>
+```
+
+The new page will slide in from the right, and the old page slide away to the left.
+
+<a name="animations"></a>
+## Included animations
+
+Single element animations:
+
+ * `fade-in-animation` Animates opacity from `0` to `1`;
+ * `fade-out-animation` Animates opacity from `1` to `0`;
+ * `scale-down-animation` Animates transform from `scale(1)` to `scale(0)`;
+ * `scale-up-animation` Animates transform from `scale(0)` to `scale(1)`;
+ * `slide-down-animation` Animates transform from `none` to `translateY(100%)`;
+ * `slide-up-animation` Animates transform from `none` to `translateY(-100%)`;
+ * `slide-from-top-animation` Animates transform from `translateY(-100%)` to `none`;
+ * `slide-from-bottom-animation` Animates transform from `translateY(100%)` to `none`;
+ * `slide-left-animation` Animates transform from `none` to `translateX(-100%)`;
+ * `slide-right-animation` Animates transform from `none` to `translateX(100%)`;
+ * `slide-from-left-animation` Animates transform from `translateX(-100%)` to `none`;
+ * `slide-from-right-animation` Animates transform from `translateX(100%)` to `none`;
+ * `transform-animation` Animates a custom transform.
+
+Note that there is a restriction that only one transform animation can be applied on the same element at a time. Use the custom `transform-animation` to combine transform properties.
+
+Shared element animations
+
+ * `hero-animation` Animates an element such that it looks like it scales and transforms from another element.
+ * `ripple-animation` Animates an element to full screen such that it looks like it ripples from another element.
+
+Group animations
+ * `cascaded-animation` Applys an animation to an array of elements with a delay between each.
+
+<a name="demos"></a>
+## Demos
+
+ * [Grid to full screen](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/grid/index.html)
+ * [Animation on load](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/load/index.html)
+ * [List item to detail](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/list/index.html) (For narrow width)
+ * [Dots to squares](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/tiles/index.html)
+ * [Declarative](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/declarative/index.html)
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/cascaded-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/cascaded-animation.html
new file mode 100644
index 00000000000..539975333d1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/cascaded-animation.html
@@ -0,0 +1,95 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<cascaded-animation>` applies an animation on an array of elements with a delay between each.
+the delay defaults to 50ms.
+
+Configuration:
+```
+{
+ name: 'cascaded-animation',
+ animation: <animation-name>,
+ nodes: <array-of-nodes>,
+ nodeDelay: <node-delay-in-ms>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'cascaded-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ /**
+ * @param {{
+ * animation: string,
+ * nodes: !Array<!Element>,
+ * nodeDelay: (number|undefined),
+ * timing: (Object|undefined)
+ * }} config
+ */
+ configure: function(config) {
+ this._animations = [];
+ var nodes = config.nodes;
+ var effects = [];
+ var nodeDelay = config.nodeDelay || 50;
+
+ config.timing = config.timing || {};
+ config.timing.delay = config.timing.delay || 0;
+
+ var oldDelay = config.timing.delay;
+ var abortedConfigure;
+ for (var node, index = 0; node = nodes[index]; index++) {
+ config.timing.delay += nodeDelay;
+ config.node = node;
+
+ var animation = document.createElement(config.animation);
+ if (animation.isNeonAnimation) {
+ var effect = animation.configure(config);
+
+ this._animations.push(animation);
+ effects.push(effect);
+ } else {
+ console.warn(this.is + ':', config.animation, 'not found!');
+ abortedConfigure = true;
+ break;
+ }
+ }
+ config.timing.delay = oldDelay;
+ config.node = null;
+ // if a bad animation was configured, abort config.
+ if (abortedConfigure) {
+ return;
+ }
+
+ this._effect = new GroupEffect(effects);
+ return this._effect;
+ },
+
+ complete: function() {
+ for (var animation, index = 0; animation = this._animations[index]; index++) {
+ animation.complete(animation.config);
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-in-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-in-animation.html
new file mode 100644
index 00000000000..cdb74e30953
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-in-animation.html
@@ -0,0 +1,49 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<fade-in-animation>` animates the opacity of an element from 0 to 1.
+
+Configuration:
+```
+{
+ name: 'fade-in-animation',
+ node: <node>
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'fade-in-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ this._effect = new KeyframeEffect(node, [
+ {'opacity': '0'},
+ {'opacity': '1'}
+ ], this.timingFromConfig(config));
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-out-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-out-animation.html
new file mode 100644
index 00000000000..82cc3997cfb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/fade-out-animation.html
@@ -0,0 +1,49 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<fade-out-animation>` animates the opacity of an element from 1 to 0.
+
+Configuration:
+```
+{
+ name: 'fade-out-animation',
+ node: <node>
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'fade-out-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ this._effect = new KeyframeEffect(node, [
+ {'opacity': '1'},
+ {'opacity': '0'}
+ ], this.timingFromConfig(config));
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/hero-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/hero-animation.html
new file mode 100644
index 00000000000..176bee789e8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/hero-animation.html
@@ -0,0 +1,83 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-shared-element-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<hero-animation>` is a shared element animation that scales and transform an element such that it
+appears to be shared between two pages. Use this in `<neon-animated-pages>`. The source page
+should use this animation in an 'exit' animation and set the `fromPage` configuration property to
+itself, and the destination page should use this animation in an `entry` animation and set the
+`toPage` configuration property to itself. They should also define the hero elements in the
+`sharedElements` property (not a configuration property, see
+`Polymer.NeonSharedElementAnimatableBehavior`).
+
+Configuration:
+```
+{
+ name: 'hero-animation',
+ id: <shared-element-id>,
+ timing: <animation-timing>,
+ toPage: <node>, /* define for the destination page */
+ fromPage: <node>, /* define for the source page */
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'hero-animation',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var shared = this.findSharedElements(config);
+ if (!shared) {
+ return;
+ }
+
+ var fromRect = shared.from.getBoundingClientRect();
+ var toRect = shared.to.getBoundingClientRect();
+
+ var deltaLeft = fromRect.left - toRect.left;
+ var deltaTop = fromRect.top - toRect.top;
+ var deltaWidth = fromRect.width / toRect.width;
+ var deltaHeight = fromRect.height / toRect.height;
+
+ this._effect = new KeyframeEffect(shared.to, [
+ {'transform': 'translate(' + deltaLeft + 'px,' + deltaTop + 'px) scale(' + deltaWidth + ',' + deltaHeight + ')'},
+ {'transform': 'none'}
+ ], this.timingFromConfig(config));
+
+ this.setPrefixedProperty(shared.to, 'transformOrigin', '0 0');
+ shared.to.style.zIndex = 10000;
+ shared.from.style.visibility = 'hidden';
+
+ return this._effect;
+ },
+
+ complete: function(config) {
+ var shared = this.findSharedElements(config);
+ if (!shared) {
+ return null;
+ }
+ shared.to.style.zIndex = '';
+ shared.from.style.visibility = '';
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/opaque-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/opaque-animation.html
new file mode 100644
index 00000000000..e3a007258c9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/opaque-animation.html
@@ -0,0 +1,46 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<opaque-animation>` makes an element `opacity:1` for the duration of the animation. Used to prevent
+webkit/safari from drawing a frame before an animation for elements that animate from display:none.
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'opaque-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ this._effect = new KeyframeEffect(node, [
+ {'opacity': '1'},
+ {'opacity': '1'}
+ ], this.timingFromConfig(config));
+ node.style.opacity = '0';
+ return this._effect;
+ },
+
+ complete: function(config) {
+ config.node.style.opacity = '';
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/reverse-ripple-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/reverse-ripple-animation.html
new file mode 100644
index 00000000000..f1f9de96f83
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/reverse-ripple-animation.html
@@ -0,0 +1,87 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-shared-element-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<reverse-ripple-animation>` scales and transform an element such that it appears to ripple down from this element, to either
+a shared element, or a screen position.
+
+If using as a shared element animation in `<neon-animated-pages>`, use this animation in an `exit`
+animation in the source page and in an `entry` animation in the destination page. Also, define the
+reverse-ripple elements in the `sharedElements` property (not a configuration property, see
+`Polymer.NeonSharedElementAnimatableBehavior`).
+If using a screen position, define the `gesture` property.
+Configuration:
+```
+{
+ name: 'reverse-ripple-animation`.
+ id: <shared-element-id>, /* set this or gesture */
+ gesture: {x: <page-x>, y: <page-y>}, /* set this or id */
+ timing: <animation-timing>,
+ toPage: <node>, /* define for the destination page */
+ fromPage: <node>, /* define for the source page */
+}
+```
+-->
+
+<script>
+ Polymer({
+ is: 'reverse-ripple-animation',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var shared = this.findSharedElements(config);
+ if (!shared) {
+ return null;
+ }
+
+ var translateX, translateY;
+ var fromRect = shared.from.getBoundingClientRect();
+ if (config.gesture) {
+ translateX = config.gesture.x - (fromRect.left + (fromRect.width / 2));
+ translateY = config.gesture.y - (fromRect.top + (fromRect.height / 2));
+ } else {
+ var toRect = shared.to.getBoundingClientRect();
+ translateX = (toRect.left + (toRect.width / 2)) - (fromRect.left + (fromRect.width / 2));
+ translateY = (toRect.top + (toRect.height / 2)) - (fromRect.top + (fromRect.height / 2));
+ }
+ var translate = 'translate(' + translateX + 'px,' + translateY + 'px)';
+
+ var size = Math.max(fromRect.width + Math.abs(translateX) * 2, fromRect.height + Math.abs(translateY) * 2);
+ var diameter = Math.sqrt(2 * size * size);
+ var scaleX = diameter / fromRect.width;
+ var scaleY = diameter / fromRect.height;
+ var scale = 'scale(' + scaleX + ',' + scaleY + ')';
+
+ this._effect = new KeyframeEffect(shared.from, [
+ {'transform': translate + ' ' + scale},
+ {'transform': translate + ' scale(0)'}
+ ], this.timingFromConfig(config));
+
+ this.setPrefixedProperty(shared.from, 'transformOrigin', '50% 50%');
+ shared.from.style.borderRadius = '50%';
+
+ return this._effect;
+ },
+
+ complete: function() {
+ if (this.sharedElements) {
+ this.setPrefixedProperty(this.sharedElements.from, 'transformOrigin', '');
+ this.sharedElements.from.style.borderRadius = '';
+ }
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/ripple-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/ripple-animation.html
new file mode 100644
index 00000000000..d97186c3772
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/ripple-animation.html
@@ -0,0 +1,93 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-shared-element-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<ripple-animation>` scales and transform an element such that it appears to ripple from either
+a shared element, or from a screen position, to full screen.
+
+If using as a shared element animation in `<neon-animated-pages>`, use this animation in an `exit`
+animation in the source page and in an `entry` animation in the destination page. Also, define the
+hero elements in the `sharedElements` property (not a configuration property, see
+`Polymer.NeonSharedElementAnimatableBehavior`).
+
+If using a screen position, define the `gesture` property.
+
+Configuration:
+```
+{
+ name: 'ripple-animation`.
+ id: <shared-element-id>, /* set this or gesture */
+ gesture: {x: <page-x>, y: <page-y>}, /* set this or id */
+ timing: <animation-timing>,
+ toPage: <node>, /* define for the destination page */
+ fromPage: <node>, /* define for the source page */
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'ripple-animation',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var shared = this.findSharedElements(config);
+ if (!shared) {
+ return null;
+ }
+
+ var translateX, translateY;
+ var toRect = shared.to.getBoundingClientRect();
+ if (config.gesture) {
+ translateX = config.gesture.x - (toRect.left + (toRect.width / 2));
+ translateY = config.gesture.y - (toRect.top + (toRect.height / 2));
+ } else {
+ var fromRect = shared.from.getBoundingClientRect();
+ translateX = (fromRect.left + (fromRect.width / 2)) - (toRect.left + (toRect.width / 2));
+ translateY = (fromRect.top + (fromRect.height / 2)) - (toRect.top + (toRect.height / 2));
+ }
+ var translate = 'translate(' + translateX + 'px,' + translateY + 'px)';
+
+ var size = Math.max(toRect.width + Math.abs(translateX) * 2, toRect.height + Math.abs(translateY) * 2);
+ var diameter = Math.sqrt(2 * size * size);
+ var scaleX = diameter / toRect.width;
+ var scaleY = diameter / toRect.height;
+ var scale = 'scale(' + scaleX + ',' + scaleY + ')';
+
+ this._effect = new KeyframeEffect(shared.to, [
+ {'transform': translate + ' scale(0)'},
+ {'transform': translate + ' ' + scale}
+ ], this.timingFromConfig(config));
+
+ this.setPrefixedProperty(shared.to, 'transformOrigin', '50% 50%');
+ shared.to.style.borderRadius = '50%';
+
+ return this._effect;
+ },
+
+ complete: function() {
+ if (this.sharedElements) {
+ this.setPrefixedProperty(this.sharedElements.to, 'transformOrigin', '');
+ this.sharedElements.to.style.borderRadius = '';
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-down-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-down-animation.html
new file mode 100644
index 00000000000..1dcb1713ae4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-down-animation.html
@@ -0,0 +1,65 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<scale-down-animation>` animates the scale transform of an element from 1 to 0. By default it
+scales in both the x and y axes.
+
+Configuration:
+```
+{
+ name: 'scale-down-animation',
+ node: <node>,
+ axis: 'x' | 'y' | '',
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'scale-down-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ var scaleProperty = 'scale(0, 0)';
+ if (config.axis === 'x') {
+ scaleProperty = 'scale(0, 1)';
+ } else if (config.axis === 'y') {
+ scaleProperty = 'scale(1, 0)';
+ }
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'scale(1,1)'},
+ {'transform': scaleProperty}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-up-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-up-animation.html
new file mode 100644
index 00000000000..42ec3f3228f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/scale-up-animation.html
@@ -0,0 +1,65 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<scale-up-animation>` animates the scale transform of an element from 0 to 1. By default it
+scales in both the x and y axes.
+
+Configuration:
+```
+{
+ name: 'scale-up-animation',
+ node: <node>,
+ axis: 'x' | 'y' | '',
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'scale-up-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ var scaleProperty = 'scale(0)';
+ if (config.axis === 'x') {
+ scaleProperty = 'scale(0, 1)';
+ } else if (config.axis === 'y') {
+ scaleProperty = 'scale(1, 0)';
+ }
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': scaleProperty},
+ {'transform': 'scale(1, 1)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-down-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-down-animation.html
new file mode 100644
index 00000000000..9db28dd17e5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-down-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-down-animation>` animates the transform of an element from `none` `translateY(100%)`.
+The `transformOrigin` defaults to `50% 0`.
+
+Configuration:
+```
+{
+ name: 'slide-down-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-down-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translateY(0%)'},
+ {'transform': 'translateY(100%)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-bottom-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-bottom-animation.html
new file mode 100644
index 00000000000..d1156e9353b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-bottom-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-from-bottom-animation>` animates the transform of an element from `none` to `translateY(100%)`.
+The `transformOrigin` defaults to `50% 0`.
+
+Configuration:
+```
+{
+ name: 'slide-from-bottom-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-from-bottom-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translateY(100%)'},
+ {'transform': 'translateY(0)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-left-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-left-animation.html
new file mode 100644
index 00000000000..5386c9b04f8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-left-animation.html
@@ -0,0 +1,60 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-from-left-animation>` animates the transform of an element from
+`translateX(-100%)` to `none`.
+The `transformOrigin` defaults to `0 50%`.
+
+Configuration:
+```
+{
+ name: 'slide-from-left-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-from-left-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translateX(-100%)'},
+ {'transform': 'none'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-right-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-right-animation.html
new file mode 100644
index 00000000000..2afb591f15f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-right-animation.html
@@ -0,0 +1,60 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-from-right-animation>` animates the transform of an element from
+`translateX(100%)` to `none`.
+The `transformOrigin` defaults to `0 50%`.
+
+Configuration:
+```
+{
+ name: 'slide-from-right-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-from-right-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translateX(100%)'},
+ {'transform': 'none'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-top-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-top-animation.html
new file mode 100644
index 00000000000..c0a4881128a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-from-top-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-from-top-animation>` animates the transform of an element from `translateY(-100%)` to
+`none`. The `transformOrigin` defaults to `50% 0`.
+
+Configuration:
+```
+{
+ name: 'slide-from-top-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-from-top-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translateY(-100%)'},
+ {'transform': 'translateY(0%)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-left-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-left-animation.html
new file mode 100644
index 00000000000..da80a6bd7d1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-left-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-left-animation>` animates the transform of an element from `none` to `translateX(-100%)`.
+The `transformOrigin` defaults to `0 50%`.
+
+Configuration:
+```
+{
+ name: 'slide-left-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-left-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'none'},
+ {'transform': 'translateX(-100%)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-right-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-right-animation.html
new file mode 100644
index 00000000000..99b5794e49f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-right-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-right-animation>` animates the transform of an element from `none` to `translateX(100%)`.
+The `transformOrigin` defaults to `0 50%`.
+
+Configuration:
+```
+{
+ name: 'slide-right-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-right-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'none'},
+ {'transform': 'translateX(100%)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-up-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-up-animation.html
new file mode 100644
index 00000000000..6464e78ed33
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/slide-up-animation.html
@@ -0,0 +1,59 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<slide-up-animation>` animates the transform of an element from `translateY(0)` to
+`translateY(-100%)`. The `transformOrigin` defaults to `50% 0`.
+
+Configuration:
+```
+{
+ name: 'slide-up-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'slide-up-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': 'translate(0)'},
+ {'transform': 'translateY(-100%)'}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ } else {
+ this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/transform-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/transform-animation.html
new file mode 100644
index 00000000000..2e5044422ef
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/animations/transform-animation.html
@@ -0,0 +1,70 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../neon-animation-behavior.html">
+<link rel="import" href="../web-animations.html">
+
+<!--
+`<transform-animation>` animates a custom transform on an element. Use this to animate multiple
+transform properties, or to apply a custom transform value.
+
+Configuration:
+```
+{
+ name: 'transform-animation',
+ node: <node>,
+ transformOrigin: <transform-origin>,
+ transformFrom: <transform-from-string>,
+ transformTo: <transform-to-string>,
+ timing: <animation-timing>
+}
+```
+-->
+
+<script>
+
+ Polymer({
+
+ is: 'transform-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ /**
+ * @param {{
+ * node: !Element,
+ * transformOrigin: (string|undefined),
+ * transformFrom: (string|undefined),
+ * transformTo: (string|undefined),
+ * timing: (Object|undefined)
+ * }} config
+ */
+ configure: function(config) {
+ var node = config.node;
+ var transformFrom = config.transformFrom || 'none';
+ var transformTo = config.transformTo || 'none';
+
+ this._effect = new KeyframeEffect(node, [
+ {'transform': transformFrom},
+ {'transform': transformTo}
+ ], this.timingFromConfig(config));
+
+ if (config.transformOrigin) {
+ this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
+ }
+
+ return this._effect;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/bower.json b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/bower.json
new file mode 100644
index 00000000000..29499b822e2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/bower.json
@@ -0,0 +1,52 @@
+{
+ "name": "neon-animation",
+ "description": "A system for animating Polymer-based web components",
+ "version": "1.2.3",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "web-animations"
+ ],
+ "main": [
+ "neon-animated-pages.html",
+ "neon-animatable-behavior.html",
+ "neon-animation-behavior.html",
+ "neon-animation-runner-behavior.html",
+ "neon-shared-element-animatable-behavior.html",
+ "neon-shared-element-animation-behavior.html",
+ "neon-animatable.html",
+ "neon-animations.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/neon-animation"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/neon-animation",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-meta": "PolymerElements/iron-meta#^1.0.0",
+ "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
+ "iron-selector": "PolymerElements/iron-selector#^1.0.0",
+ "web-animations-js": "web-animations/web-animations-js#^2.2.0"
+ },
+ "devDependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/index.html
new file mode 100644
index 00000000000..44993465fc4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/index.html
@@ -0,0 +1,166 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: card</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="../../../paper-styles/typography.html">
+ <link rel="import" href="x-card.html">
+ <link rel="import" href="x-cards-list.html">
+
+ <style is="custom-style">
+
+ body {
+ padding: 15px;
+ @apply(--layout-fullbleed);
+ @apply(--paper-font-common-base);
+ }
+
+ neon-animated-pages {
+ height: 100%;
+ }
+
+ .large {
+ width: 100%
+ }
+
+ .button {
+ text-align: center;
+ width: 120px;
+ height: 32px;
+ line-height: 32px;
+ border-radius: 2px;
+ font-size: 0.9em;
+ background-color: #fff;
+ color: #646464;
+ }
+
+ .button.blue {
+ background-color: #4285f4;
+ color: #fff;
+ }
+
+ .button.raised {
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+ }
+
+ .button.back {
+ position: fixed;
+ top: 30px;
+ left: 30px;
+ }
+
+ .card-contents {
+ @apply(--layout-vertical);
+ @apply(--layout-center-center);
+ @apply(--layout-fit);
+ }
+
+ .button-container {
+ @apply(--layout-flex);
+ @apply(--layout-horizontal);
+ @apply(--layout-around-justified);
+ }
+ </style>
+
+ </head>
+ <body>
+
+ <template is="dom-bind">
+ <neon-animated-pages id="pages" selected="0">
+ <x-cards-list id="list">
+ <div class="card-contents">
+ <h2>Choose a subject</h2>
+ <div class="button-container large">
+ <div class="blue raised button" on-click="_onPolymerClick">
+ POLYMER
+ </div>
+ <div class="blue raised button" on-click="_onAngularClick">
+ ANGULAR
+ </div>
+ </div>
+ </div>
+ </x-cards-list>
+
+ <x-card>
+ <div class="card-contents">
+ <div class="raised back button" on-click="_onBackClick">
+ BACK
+ </div>
+ <h2>Polymer</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ </div>
+ </x-card>
+
+ <x-card>
+ <div class="card-contents">
+ <div class="raised back button" on-click="_onBackClick">
+ BACK
+ </div>
+ <h2>Angular</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ </div>
+ </x-card>
+
+ </neon-animated-pages>
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onPolymerClick = function(event) {
+ this.$.list.sharedElements = {
+ 'ripple': event.target,
+ 'reverse-ripple': event.target
+ };
+ this.$.pages.selected = 1;
+ };
+
+ scope._onAngularClick = function(event) {
+ this.$.list.sharedElements = {
+ 'ripple': event.target,
+ 'reverse-ripple': event.target
+ };
+ this.$.pages.selected = 2;
+ };
+
+ scope._onBackClick = function(event) {
+ this.$.pages.selected = 0;
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-card.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-card.html
new file mode 100644
index 00000000000..92885d29c82
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-card.html
@@ -0,0 +1,94 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+
+<dom-module id="x-card">
+ <template>
+ <style>
+ :host {
+ display: block;
+ overflow: hidden;
+ }
+ #placeholder {
+ opacity: 0;
+ background-color: grey;
+ @apply(--layout-fit);
+ }
+ </style>
+
+ <div id="placeholder"></div>
+ <div id="container">
+ <content select="div"></content>
+ </div>
+
+ </template>
+</dom-module>
+
+<script>
+(function() {
+ Polymer({
+ is: 'x-card',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'ripple-animation',
+ id: 'ripple',
+ toPage: this
+ }, {
+ name: 'fade-out-animation',
+ node: this.$.placeholder,
+ timing: {
+ delay: 250
+ }
+ }, {
+ name: 'fade-in-animation',
+ node: this.$.container,
+ timing: {
+ delay: 50
+ }
+ }],
+
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.container,
+ timing: {
+ duration: 0
+ }
+ }, {
+ name: 'reverse-ripple-animation',
+ id: 'reverse-ripple',
+ fromPage: this
+ }]
+ };
+ }
+ },
+
+ sharedElements: {
+ value: function() {
+ return {
+ 'ripple': this.$.placeholder,
+ 'reverse-ripple': this.$.placeholder
+ };
+ }
+ }
+ }
+ });
+})();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-cards-list.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-cards-list.html
new file mode 100644
index 00000000000..b817698fb55
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/card/x-cards-list.html
@@ -0,0 +1,75 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+
+<dom-module id="x-cards-list">
+ <template>
+ <style>
+ :host {
+ display: block;
+ overflow: hidden;
+ }
+
+ #placeholder {
+ opacity: 0;
+ background-color: grey;
+ @apply(--layout-fit);
+ }
+ </style>
+
+ <div id="placeholder"></div>
+ <div id="container">
+ <content select="div"></content>
+ </div>
+
+ </template>
+</dom-module>
+
+<script>
+(function() {
+ Polymer({
+ is: 'x-cards-list',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'reverse-ripple-animation',
+ id: 'reverse-ripple',
+ toPage: this
+ }],
+
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.container,
+ timing: {
+ delay: 150,
+ duration: 0
+ }
+ }, {
+ name: 'ripple-animation',
+ id: 'ripple',
+ fromPage: this
+ }]
+ };
+ }
+ }
+ }
+ });
+})();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/declarative/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/declarative/index.html
new file mode 100644
index 00000000000..26ba53ff9b3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/declarative/index.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: declarative</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../../paper-styles/typography.html">
+ <link rel="import" href="../../../paper-styles/color.html">
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animatable.html">
+ <link rel="import" href="../../neon-animations.html">
+
+ <style is="custom-style">
+ body {
+ overflow: hidden;
+ @apply(--layout-fullbleed);
+ @apply(--layout-vertical);
+ }
+
+ .toolbar {
+ position: relative;
+
+ padding: 8px;
+
+ background-color: white;
+
+ z-index: 12;
+ }
+
+ neon-animated-pages {
+ @apply(--layout-flex);
+ }
+
+ neon-animatable {
+ color: white;
+ @apply(--layout-horizontal);
+ @apply(--layout-center-center);
+ @apply(--paper-font-display4);
+ }
+
+ neon-animatable:nth-child(1) {
+ background: var(--paper-red-500);
+ }
+
+ neon-animatable:nth-child(2) {
+ background: var(--paper-blue-500);
+ }
+
+ neon-animatable:nth-child(3) {
+ background: var(--paper-orange-500);
+ }
+
+ neon-animatable:nth-child(4) {
+ background: var(--paper-green-500);
+ }
+
+ neon-animatable:nth-child(5) {
+ background: var(--paper-purple-500);
+ }
+
+ </style>
+
+ </head>
+ <body>
+
+ <template is="dom-bind">
+
+ <div class="toolbar">
+ <button on-click="_onPrevClick">&#8678;</button>
+ <button on-click="_onNextClick">&#8680;</button>
+ <button on-click="_onUpClick">&#8679;</button>
+ <button on-click="_onDownClick">&#8681;</button>
+ </div>
+
+ <neon-animated-pages id="pages" selected="[[selected]]" entry-animation="[[entryAnimation]]" exit-animation="[[exitAnimation]]">
+ <neon-animatable>1</neon-animatable>
+ <neon-animatable>2</neon-animatable>
+ <neon-animatable>3</neon-animatable>
+ <neon-animatable>4</neon-animatable>
+ <neon-animatable>5</neon-animatable>
+ </neon-animated-pages>
+
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+ scope.selected = 0;
+
+ scope._onPrevClick = function() {
+ this.entryAnimation = 'slide-from-left-animation';
+ this.exitAnimation = 'slide-right-animation';
+ this.selected = this.selected === 0 ? 4 : (this.selected - 1);
+ }
+
+ scope._onNextClick = function() {
+ this.entryAnimation = 'slide-from-right-animation';
+ this.exitAnimation = 'slide-left-animation';
+ this.selected = this.selected === 4 ? 0 : (this.selected + 1);
+ }
+
+ scope._onUpClick = function() {
+ this.entryAnimation = 'slide-from-top-animation';
+ this.exitAnimation = 'slide-down-animation';
+ this.selected = this.selected === 4 ? 0 : (this.selected + 1);
+ }
+
+ scope._onDownClick = function() {
+ this.entryAnimation = 'slide-from-bottom-animation';
+ this.exitAnimation = 'slide-up-animation';
+ this.selected = this.selected === 0 ? 4 : (this.selected - 1);
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/index.html
new file mode 100644
index 00000000000..8b3875e7ec1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/index.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animation demo: basic</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="my-animatable.html">
+ <link rel="import" href="my-dialog.html">
+
+ </head>
+ <style>
+ my-animatable {
+ margin-top: 50px;
+ }
+ </style>
+ <body>
+
+ <template is="dom-bind">
+
+ <button on-click="_onCircleButtonClick">toggle circle</button>
+ <button on-click="_onDialogButtonClick">toggle dialog</button>
+
+ <div style="text-align: center">
+ <my-dialog>Hello World!</my-dialog>
+ </div>
+
+ <my-animatable></my-animatable>
+
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onCircleButtonClick = function(event) {
+ var node = document.querySelector('my-animatable');
+ if (node) {
+ node.animate();
+ }
+ };
+
+ scope._onDialogButtonClick = function(event) {
+ var node = document.querySelector('my-dialog');
+ if (node) {
+ if (node.opened) {
+ node.hide();
+ } else {
+ node.show();
+ }
+ }
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-animatable.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-animatable.html
new file mode 100644
index 00000000000..5063f74ba66
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-animatable.html
@@ -0,0 +1,68 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../neon-animation-runner-behavior.html">
+<link rel="import" href="../../animations/scale-down-animation.html">
+
+<dom-module id="my-animatable">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ border-radius: 50%;
+ width: 300px;
+ height: 300px;
+ background: orange;
+ }
+ </style>
+ <content></content>
+
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'my-animatable',
+
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ name: 'scale-down-animation',
+ node: this
+ }
+ }
+ }
+
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+
+ animate: function() {
+ this.playAnimation();
+ },
+
+ _onNeonAnimationFinish: function() {
+ console.log('animation finish!');
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-dialog.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-dialog.html
new file mode 100644
index 00000000000..bd3344c0ea7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/doc/my-dialog.html
@@ -0,0 +1,94 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../paper-styles/shadow.html">
+<link rel="import" href="../../neon-animation-runner-behavior.html">
+<link rel="import" href="../../animations/scale-up-animation.html">
+<link rel="import" href="../../animations/fade-out-animation.html">
+
+
+<dom-module id="my-dialog">
+ <template>
+ <style>
+ :host {
+ display: none;
+ padding: 16px;
+ background: white;
+ color: black;
+ margin: 0 auto;
+ z-index: 100;
+ position: absolute;
+ @apply(--shadow-elevation-2dp);
+ }
+ </style>
+ <content></content>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'my-dialog',
+
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+
+ opened: {
+ type: Boolean
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'scale-up-animation',
+ node: this
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this
+ }]
+ }
+ }
+ }
+
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onAnimationFinish'
+ },
+
+ _onAnimationFinish: function() {
+ if (!this.opened) {
+ this.style.display = '';
+ }
+ },
+
+ show: function() {
+ this.opened = true;
+ this.style.display = 'inline-block';
+ this.playAnimation('entry');
+ },
+
+ hide: function() {
+ this.opened = false;
+ this.playAnimation('exit');
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/animated-dropdown.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/animated-dropdown.html
new file mode 100644
index 00000000000..9a61530fb74
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/animated-dropdown.html
@@ -0,0 +1,90 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../paper-styles/shadow.html">
+<link rel="import" href="../../neon-animation-runner-behavior.html">
+
+<dom-module id="animated-dropdown">
+ <template>
+ <style>
+ :host {
+ display: none;
+ padding: 16px;
+ background: white;
+ color: black;
+
+ @apply(--shadow-elevation-2dp);
+ }
+ </style>
+ <content></content>
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'animated-dropdown',
+
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'scale-up-animation',
+ node: this,
+ transformOrigin: '0 0'
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this
+ }]
+ }
+ }
+ },
+
+ _showing: {
+ type: Boolean,
+ value: false
+ }
+
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onAnimationFinish'
+ },
+
+ _onAnimationFinish: function() {
+ if (this._showing) {
+ } else {
+ this.style.display = '';
+ }
+ },
+
+ show: function() {
+ this.style.display = 'inline-block';
+ this._showing = true;
+ this.playAnimation('entry');
+ },
+
+ hide: function() {
+ this._showing = false;
+ this.playAnimation('exit');
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/index.html
new file mode 100644
index 00000000000..b238474cbf4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/dropdown/index.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: dropdown</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="animated-dropdown.html">
+
+ </head>
+ <body>
+
+ <template is="dom-bind">
+
+ <button dropdown-id="dropdown" on-click="_onButtonClick">dropdown</button>
+ <br>
+ <animated-dropdown id="dropdown" on-click="_onDropdownClick">Hello world!</animated-dropdown>
+
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onButtonClick = function(event) {
+ var dropdown = document.querySelector('#' + event.target.getAttribute('dropdown-id'));
+ if (dropdown) {
+ dropdown.show();
+ }
+ };
+
+ scope._onDropdownClick = function(event) {
+ event.target.hide();
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/animated-grid.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/animated-grid.html
new file mode 100644
index 00000000000..a2689364169
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/animated-grid.html
@@ -0,0 +1,164 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../paper-styles/typography.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+<link rel="import" href="../shared-styles.html">
+
+<dom-module id="animated-grid">
+ <template>
+ <style include="shared-styles"></style>
+ <style>
+
+ :host {
+ display: block;
+ background: #000;
+ }
+
+ .tile {
+ display: inline-block;
+ float: left;
+ vertical-align: top;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+
+ @apply(--paper-font-title);
+ @apply(--layout-vertical);
+ @apply(--layout-center-center);
+ }
+
+ .tile:nth-of-type(1) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(4) {
+ width: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(5) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(8) {
+ width: calc(100% / 3);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(9) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: 0;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(10) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: calc(100% / 6);;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+ </style>
+
+ <template is="dom-repeat" items="[[config]]">
+ <div class$="[[_computeTileClass(item.color)]]">
+ <span>[[item.value]]</span>
+ </div>
+ </template>
+
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'animated-grid',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ config: {
+ type: Array,
+ value: function() {
+ return [
+ {value: 1, color: 'blue'},
+ {value: 2, color: 'red'},
+ {value: 3, color: 'blue'},
+ {value: 4, color: 'green'},
+ {value: 5, color: 'yellow'},
+ {value: 6, color: 'blue'},
+ {value: 7, color: 'red'},
+ {value: 8, color: 'green'},
+ {value: 9, color: 'yellow'},
+ {value: 10, color: 'red'}
+ ]
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'exit': [{
+ name: 'ripple-animation',
+ id: 'ripple',
+ fromPage: this
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }]
+ }
+ }
+ }
+
+ },
+
+ listeners: {
+ click: '_onClick'
+ },
+
+ _computeTileClass: function(color) {
+ return 'tile ' + color + '-300';
+ },
+
+ _onClick: function(event) {
+ var target = event.target;
+ while (target !== this && !target._templateInstance) {
+ target = target.parentNode;
+ }
+
+ // configure the page animation
+ this.sharedElements = {
+ 'hero': target,
+ 'ripple': target
+ };
+ this.animationConfig['exit'][0].gesture = {
+ x: event.x || event.pageX,
+ y: event.y || event.pageY
+ };
+
+ this.fire('tile-click', {
+ tile: target,
+ data: target._templateInstance.item
+ });
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/fullsize-page-with-card.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/fullsize-page-with-card.html
new file mode 100644
index 00000000000..63d35bbf688
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/fullsize-page-with-card.html
@@ -0,0 +1,122 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+<link rel="import" href="../../../paper-styles/color.html">
+<link rel="import" href="../shared-styles.html">
+
+<dom-module id="fullsize-page-with-card">
+ <template>
+ <style include="shared-styles"></style>
+ <style>
+
+ :host {
+ display: block;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100vh;
+ width: 100vw;
+ }
+
+ .card {
+ position: relative;
+ margin: 200px 100px 0;
+ height: 700px;
+ }
+
+ </style>
+
+ <div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
+ <div id="card" class$="[[_computeCardClass(color)]]"></div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'fullsize-page-with-card',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ color: {
+ type: String
+ },
+
+ sharedElements: {
+ type: Object,
+ value: function() {
+ return {
+ 'hero': this.$.card,
+ 'ripple': this.$.fixed
+ }
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'ripple-animation',
+ id: 'ripple',
+ toPage: this,
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this,
+ timing: {
+ delay: 150
+ }
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.fixed
+ }, {
+ name: 'transform-animation',
+ transformFrom: 'none',
+ transformTo: 'translate(0px,-200vh) scale(0.9,1)',
+ node: this.$.card
+ }]
+ }
+ }
+ }
+
+ },
+
+ _computeCardClass: function(color) {
+ var cls = 'card';
+ if (color) {
+ cls += ' ' + color + '-300';
+ }
+ return cls;
+ },
+
+ _computeFixedBackgroundClass: function(color) {
+ var cls = 'fixed';
+ if (color) {
+ cls += ' ' + color + '-100';
+ }
+ return cls;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/index.html
new file mode 100644
index 00000000000..b102dba40b5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/grid/index.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: grid</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="animated-grid.html">
+ <link rel="import" href="fullsize-page-with-card.html">
+
+ <style is="custom-style">
+ body {
+ overflow: hidden;
+ @apply(--layout-fullbleed);
+ }
+
+ neon-animated-pages {
+ height: 100%;
+ }
+ </style>
+
+ </head>
+ <body>
+
+ <template is="dom-bind">
+ <neon-animated-pages id="pages" selected="0">
+ <animated-grid on-tile-click="_onTileClick"></animated-grid>
+ <fullsize-page-with-card id="fullsize-card" on-click="_onFullsizeClick">
+ </fullsize-page-with-card>
+ </neon-animated-pages>
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onTileClick = function(event) {
+ this.$['fullsize-card'].color = event.detail.data.color;
+ this.$.pages.selected = 1;
+ };
+
+ scope._onFullsizeClick = function(event) {
+ this.$.pages.selected = 0;
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/index.html
new file mode 100644
index 00000000000..1e4e1204a8e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/index.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html lang="en">
+<head>
+ <title>neon-animated pages demo</title>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+</head>
+<style>
+ a {
+ display: block;
+ margin-bottom: 10px;
+ }
+</style>
+<body unresolved>
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Sample demos</h4>
+ <div class="horizontal-section">
+ <a href="doc/index.html">basic</a>
+ <a href="declarative/index.html">declarative</a>
+ <a href="dropdown/index.html">dropdown</a>
+ <a href="grid/index.html">grid</a>
+ <a href="list/index.html">list</a>
+ <a href="load/index.html">load</a>
+ <a href="tiles/index.html">tiles</a>
+ <a href="card/index.html">card</a>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/full-view.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/full-view.html
new file mode 100644
index 00000000000..565618c2182
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/full-view.html
@@ -0,0 +1,118 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../../paper-styles/shadow.html">
+<link rel="import" href="../../neon-animatable-behavior.html">
+
+<dom-module id="full-view">
+ <template>
+ <style>
+ :host {
+ @apply(--layout-vertical);
+ }
+
+ .main {
+ background: white;
+ @apply(--layout-flex);
+ @apply(--layout-scroll);
+ @apply(--shadow-elevation-8dp);
+ }
+
+ .image-container {
+ position: relative;
+ width: 100%;
+ padding-bottom: 100%;
+ }
+
+ .image {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ background: repeating-linear-gradient(
+ 45deg,
+ #f5f5f5,
+ #f5f5f5 8px,
+ #e0e0e0 8px,
+ #e0e0e0 16px
+ );
+ }
+ </style>
+ <paper-toolbar class="medium-tall">
+ <paper-icon-button id="button" icon="clear" on-click="_onClearButtonClick"></paper-icon-button>
+ </paper-toolbar>
+
+ <div id="main" class="main">
+ <div class="image-container">
+ <div class="image">
+ </div>
+ </div>
+ </div>
+
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'full-view',
+
+ behaviors: [
+ Polymer.NeonAnimatableBehavior
+ ],
+
+ properties: {
+
+ sharedElements: {
+ type: Object,
+ value: function() {
+ return {
+ 'hero': this.$.main
+ };
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'fade-in-animation',
+ node: this.$.button
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this
+ }],
+
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.button
+ }, {
+ name: 'scale-down-animation',
+ node: this.$.main,
+ transformOrigin: '50% 50%',
+ axis: 'y'
+ }]
+
+ }
+ }
+ }
+
+ },
+
+ _onClearButtonClick: function() {
+ this.fire('close');
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/index.html
new file mode 100644
index 00000000000..eabb02e5b6d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/index.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: list</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="list-demo.html">
+
+ </head>
+ <style is="custom-style">
+ body {
+ @apply(--layout-fullbleed);
+ }
+
+ list-demo {
+ @apply(--layout-fit);
+ }
+ </style>
+ <body>
+ <list-demo></list-demo>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-demo.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-demo.html
new file mode 100644
index 00000000000..45808c8cae3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-demo.html
@@ -0,0 +1,102 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../paper-toolbar/paper-toolbar.html">
+<link rel="import" href="../../neon-animated-pages.html">
+<link rel="import" href="../../neon-animations.html">
+<link rel="import" href="list-view.html">
+<link rel="import" href="full-view.html">
+
+<dom-module id="list-demo">
+ <template>
+ <style>
+ :host {
+ display: block;
+ }
+ neon-animated-pages {
+ height: 100%;
+ }
+ </style>
+ <neon-animated-pages id="pages" selected="0">
+ <list-view data="[[fileData]]" on-item-click="_onItemClick"></list-view>
+ <full-view on-close="_onClose"></full-view>
+ </neon-animated-pages>
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'list-demo',
+
+ properties: {
+
+ fileData: {
+ type: Array,
+ value: function() {
+ return [
+ {fileName: 'IMG_4130.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4131.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4132.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4133.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4134.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4135.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4136.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4137.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4138.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4139.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4140.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4141.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4142.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4143.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4144.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4145.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4146.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4147.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4148.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4149.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4150.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4151.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4152.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4153.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4154.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4155.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4156.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4157.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4158.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4159.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4160.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4161.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4162.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4163.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4164.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4165.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4166.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4167.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4168.jpg', modifiedDate: 'May 12 2015'},
+ {fileName: 'IMG_4169.jpg', modifiedDate: 'May 12 2015'}
+ ]
+ }
+ }
+ },
+
+ _onItemClick: function() {
+ this.$.pages.selected = 1;
+ },
+
+ _onClose: function() {
+ this.$.pages.selected = 0;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-view.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-view.html
new file mode 100644
index 00000000000..ddb05502caf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/list/list-view.html
@@ -0,0 +1,124 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-icons/iron-icons.html">
+<link rel="import" href="../../../iron-icon/iron-icon.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../../paper-icon-button/paper-icon-button.html">
+<link rel="import" href="../../../paper-item/paper-item.html">
+<link rel="import" href="../../../paper-item/paper-item-body.html">
+<link rel="import" href="../../../paper-styles/color.html">
+<link rel="import" href="../../neon-animatable-behavior.html">
+
+<dom-module id="list-view">
+ <template>
+ <style>
+ :host {
+ @apply(--layout-vertical);
+ }
+
+ .main {
+ @apply(--layout-flex);
+ @apply(--layout-scroll);
+ }
+
+ iron-icon {
+ color: var(--google-grey-500);
+ }
+ </style>
+ <paper-toolbar class="medium-tall">
+ <paper-icon-button id="button" icon="arrow-back"></paper-icon-button>
+ </paper-toolbar>
+
+ <div class="main">
+
+ <template is="dom-repeat" items="[[data]]">
+
+ <paper-item>
+ <paper-item-body two-line>
+ <div>[[item.fileName]]</div>
+ <div secondary>[[item.modifiedDate]]</div>
+ </paper-item-body>
+ <iron-icon icon="info"></iron-icon>
+ </paper-item>
+
+ </template>
+
+ </div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'list-view',
+
+ behaviors: [
+ Polymer.NeonAnimatableBehavior
+ ],
+
+ listeners: {
+ 'click': '_onClick'
+ },
+
+ properties: {
+
+ data: {
+ type: Array,
+ value: function() {
+ return [];
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'fade-in-animation',
+ node: this.$.button
+ }],
+
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.button
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }]
+ };
+ }
+ }
+
+ },
+
+ _onClick: function(event) {
+ var target = event.target;
+ while (target !== this && !target._templateInstance) {
+ target = target.parentNode;
+ }
+
+ // configure the page animation
+ this.sharedElements = {
+ 'hero': target,
+ };
+
+ this.fire('item-click', {
+ item: target,
+ });
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/animated-grid.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/animated-grid.html
new file mode 100644
index 00000000000..c1d52c1a5e0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/animated-grid.html
@@ -0,0 +1,146 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+<link rel="import" href="../../../paper-styles/typography.html">
+<link rel="import" href="../../../paper-styles/color.html">
+<link rel="import" href="../shared-styles.html">
+
+<dom-module id="animated-grid">
+ <template>
+ <style include="shared-styles"></style>
+ <style>
+ :host {
+ display: block;
+ background: #000;
+ }
+
+ .tile {
+ display: inline-block;
+ float: left;
+ vertical-align: top;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+
+ @apply(--paper-font-title);
+ @apply(--layout-vertical);
+ @apply(--layout-center-center);
+ }
+
+ .tile:nth-of-type(1) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(4) {
+ width: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(5) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(8) {
+ width: calc(100% / 3);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(9) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: 0;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(10) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: calc(100% / 6);;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+ </style>
+
+ <template is="dom-repeat" items="[[config]]">
+ <div class$="[[_computeTileClass(item.color)]]">
+ <span>[[item.value]]</span>
+ </div>
+ </template>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'animated-grid',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ config: {
+ type: Array,
+ value: function() {
+ return [
+ {value: 1, color: 'blue'},
+ {value: 2, color: 'red'},
+ {value: 3, color: 'blue'},
+ {value: 4, color: 'green'},
+ {value: 5, color: 'yellow'},
+ {value: 6, color: 'blue'},
+ {value: 7, color: 'red'},
+ {value: 8, color: 'green'},
+ {value: 9, color: 'yellow'},
+ {value: 10, color: 'red'}
+ ]
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'cascaded-animation',
+ animation: 'transform-animation',
+ transformFrom: 'translateY(100%)',
+ transformTo: 'none',
+ timing: {
+ delay: 50
+ }
+ }]
+ }
+ }
+ }
+
+ },
+
+ attached: function() {
+ this.async(function() {
+ var nodeList = Polymer.dom(this.root).querySelectorAll('.tile');
+ this.animationConfig['entry'][0].nodes = Array.prototype.slice.call(nodeList);
+ });
+ },
+
+ _computeTileClass: function(color) {
+ return 'tile ' + color + '-300';
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/full-page.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/full-page.html
new file mode 100644
index 00000000000..61a11bd7baa
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/full-page.html
@@ -0,0 +1,82 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-animatable-behavior.html">
+<link rel="import" href="../../neon-animation-runner-behavior.html">
+<link rel="import" href="../../../paper-styles/shadow.html">
+<link rel="import" href="animated-grid.html">
+
+<dom-module id="full-page">
+ <template>
+ <style>
+ :host {
+ background: black;
+ visibility: hidden;
+ @apply(--layout-vertical);
+ }
+
+ .toolbar {
+ background: #9c27b0;
+ height: 72px;
+ z-index: 1;
+ @apply(--shadow-elevation-2dp);
+ }
+
+ animated-grid {
+ height: calc(100% - 72px);
+ @apply(--layout-flex);
+ }
+ </style>
+
+ <div id="toolbar" class="toolbar"></div>
+ <animated-grid id="grid"></animated-grid>
+
+ </template>
+</dom-module>
+
+<script>
+
+Polymer({
+
+ is: 'full-page',
+
+ behaviors: [
+ Polymer.NeonAnimatableBehavior,
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'slide-from-top-animation',
+ node: this.$.toolbar
+ }, {
+ animatable: this.$.grid,
+ type: 'entry'
+ }]
+ };
+ }
+ }
+
+ },
+
+ show: function() {
+ this.style.visibility = 'visible';
+ this.playAnimation('entry');
+ }
+
+});
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/index.html
new file mode 100644
index 00000000000..54c8d68a5a9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/load/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: load</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="full-page.html">
+
+ <style is="custom-style">
+ body {
+ overflow: hidden;
+ @apply(--layout-fullbleed);
+ }
+ full-page {
+ @apply(--layout-fit);
+ }
+ </style>
+ </head>
+ <body>
+
+ <full-page></full-page>
+
+ <script>
+
+ document.addEventListener('WebComponentsReady', function() {
+ document.querySelector('full-page').show();
+ });
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/animated-grid.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/animated-grid.html
new file mode 100644
index 00000000000..f1244b442c5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/animated-grid.html
@@ -0,0 +1,167 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+<link rel="import" href="../../../paper-styles/typography.html">
+<link rel="import" href="../../../paper-styles/color.html">
+<link rel="import" href="../shared-styles.html">
+
+<dom-module id="animated-grid">
+ <template>
+ <style include="shared-styles"></style>
+ <style>
+
+ :host {
+ display: block;
+ background: #000;
+ }
+
+ .tile {
+ display: inline-block;
+ float: left;
+ vertical-align: top;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+
+ @apply(--paper-font-title);
+ @apply(--layout-vertical);
+ @apply(--layout-center-center);
+ }
+
+ .tile:nth-of-type(1) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(4) {
+ width: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(5) {
+ width: calc(100% / 3);
+ height: calc(100% / 3 * 2);
+ }
+
+ .tile:nth-of-type(8) {
+ width: calc(100% / 3);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(9) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: 0;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+
+ .tile:nth-of-type(10) {
+ position: absolute;
+ top: calc(100% / 3 * 2);
+ left: calc(100% / 6);;
+ width: calc(100% / 6);
+ height: calc(100% / 3);
+ }
+
+ </style>
+
+ <template is="dom-repeat" items="[[config]]">
+ <div class$="[[_computeTileClass(item.color)]]">
+ <span>[[item.value]]</span>
+ </div>
+ </template>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'animated-grid',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ config: {
+ type: Array,
+ value: function() {
+ return [
+ {value: 1, color: 'blue'},
+ {value: 2, color: 'red'},
+ {value: 3, color: 'blue'},
+ {value: 4, color: 'green'},
+ {value: 5, color: 'yellow'},
+ {value: 6, color: 'blue'},
+ {value: 7, color: 'red'},
+ {value: 8, color: 'green'},
+ {value: 9, color: 'yellow'},
+ {value: 10, color: 'red'}
+ ]
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'exit': [{
+ name: 'ripple-animation',
+ id: 'ripple',
+ fromPage: this
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }]
+ }
+ }
+ }
+
+ },
+
+ listeners: {
+ click: '_onClick'
+ },
+
+ _computeTileClass: function(color) {
+ return 'tile ' + color + '-300';
+ },
+
+ _onClick: function(event) {
+ var target = event.target;
+ while (target !== this && !target._templateInstance) {
+ target = target.parentNode;
+ }
+
+ // configure the page animation
+ this.sharedElements = {
+ 'hero': target,
+ 'ripple': target
+ };
+ this.animationConfig['exit'][0].gesture = {
+ x: event.x,
+ y: event.y
+ };
+
+ this.fire('tile-click', {
+ tile: target,
+ data: target._templateInstance.item
+ });
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/fullsize-page-with-card.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/fullsize-page-with-card.html
new file mode 100644
index 00000000000..83b8a9170cb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/fullsize-page-with-card.html
@@ -0,0 +1,120 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+<link rel="import" href="../shared-styles.html">
+
+<dom-module id="fullsize-page-with-card">
+ <template>
+ <style include="shared-styles"></style>
+ <style>
+
+ :host {
+ display: block;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100vh;
+ width: 100vw;
+ }
+
+ .card {
+ position: relative;
+ margin: 200px 100px 0;
+ height: 700px;
+ }
+
+ </style>
+
+ <div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
+ <div id="card" class$="[[_computeCardClass(color)]]"></div>
+
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'fullsize-page-with-card',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ color: {
+ type: String
+ },
+
+ sharedElements: {
+ type: Object,
+ value: function() {
+ return {
+ 'hero': this.$.card,
+ 'ripple': this.$.fixed
+ }
+ }
+ },
+
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'ripple-animation',
+ id: 'ripple',
+ toPage: this,
+ }, {
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this,
+ timing: {
+ delay: 150
+ }
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this.$.fixed
+ }, {
+ name: 'transform-animation',
+ transformFrom: 'none',
+ transformTo: 'translate(0px,-200vh) scale(0.9,1)',
+ node: this.$.card
+ }]
+ }
+ }
+ }
+
+ },
+
+ _computeCardClass: function(color) {
+ var cls = 'card';
+ if (color) {
+ cls += ' ' + color + '-300';
+ }
+ return cls;
+ },
+
+ _computeFixedBackgroundClass: function(color) {
+ var cls = 'fixed';
+ if (color) {
+ cls += ' ' + color + '-100';
+ }
+ return cls;
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/index.html
new file mode 100644
index 00000000000..591d63c6980
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/index.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: grid</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="reprojected-pages.html">
+ <link rel="import" href="animated-grid.html">
+ <link rel="import" href="fullsize-page-with-card.html">
+
+ <style is="custom-style">
+ body {
+ overflow: hidden;
+ @apply(--layout-fullbleed);
+ }
+ reprojected-pages {
+ height: 100%;
+ }
+ </style>
+ </head>
+ <body>
+ <template is="dom-bind">
+
+ <reprojected-pages id="pages" selected="0">
+ <animated-grid on-tile-click="_onTileClick"></animated-grid>
+ <fullsize-page-with-card id="fullsize-card" hero-id="hero" on-click="_onFullsizeClick">
+ </fullsize-page-with-card>
+ </reprojected-pages>
+
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onTileClick = function(event) {
+ this.$['fullsize-card'].color = event.detail.data.color;
+ this.$.pages.selected = 1;
+ };
+
+ scope._onFullsizeClick = function(event) {
+ this.$.pages.selected = 0;
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/reprojected-pages.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/reprojected-pages.html
new file mode 100644
index 00000000000..e71f2e055de
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/reprojection/reprojected-pages.html
@@ -0,0 +1,45 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../neon-animated-pages.html">
+
+<dom-module id="reprojected-pages">
+ <template>
+ <style>
+ neon-animated-pages {
+ height: 100%;
+ }
+ </style>
+ <neon-animated-pages selected="{{selected}}">
+ <content></content>
+ </neon-animated-pages>
+
+ </template>
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'reprojected-pages',
+
+ properties: {
+
+ selected: {
+ type: String,
+ notify: true
+ }
+
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/shared-styles.html
new file mode 100644
index 00000000000..4e48c8c4065
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/shared-styles.html
@@ -0,0 +1,47 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<dom-module id="shared-styles">
+ <template>
+ <style>
+ .red-100 {
+ background: var(--google-red-100);
+ }
+
+ .yellow-100 {
+ background: var(--google-yellow-100);
+ }
+
+ .blue-100 {
+ background: var(--google-blue-100);
+ }
+
+ .green-100 {
+ background: var(--google-green-100);
+ }
+
+ .red-300 {
+ background: var(--google-red-300);
+ }
+
+ .yellow-300 {
+ background: var(--google-yellow-300);
+ }
+
+ .blue-300 {
+ background: var(--google-blue-300);
+ }
+
+ .green-300 {
+ background: var(--google-green-300);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/circles-page.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/circles-page.html
new file mode 100644
index 00000000000..70a4a75210f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/circles-page.html
@@ -0,0 +1,107 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+
+<dom-module id="circles-page">
+ <template>
+ <style>
+ :host {
+ @apply(--layout-horizontal);
+ @apply(--layout-center-center);
+ }
+
+ .circle {
+ display: inline-block;
+ box-sizing: border-box;
+ width: 100px;
+ height: 100px;
+ margin: 16px;
+ border-radius: 50%;
+ background: var(--color-one);
+ }
+ </style>
+
+ <div>
+ <div class="circle"></div>
+ <div class="circle"></div>
+ <div class="circle"></div>
+ <div class="circle"></div>
+ </div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'circles-page',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ animationConfig: {
+ value: function() {
+ var circles = Polymer.dom(this.root).querySelectorAll('.circle');
+ var circlesArray = Array.prototype.slice.call(circles);
+ return {
+ 'entry': [{
+ name: 'cascaded-animation',
+ animation: 'scale-up-animation',
+ nodes: circlesArray
+ }],
+
+ 'exit': [{
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }, {
+ name: 'cascaded-animation',
+ animation: 'scale-down-animation'
+ }]
+ };
+ }
+ }
+ },
+
+ listeners: {
+ 'click': '_onClick'
+ },
+
+ _onClick: function(event) {
+ var target = event.target;
+ if (target.classList.contains('circle')) {
+ // configure the page animation
+ this.sharedElements = {
+ 'hero': target
+ };
+
+ var nodesToScale = [];
+ var circles = Polymer.dom(this.root).querySelectorAll('.circle');
+ for (var node, index = 0; node = circles[index]; index++) {
+ if (node !== event.target) {
+ nodesToScale.push(node);
+ }
+ }
+ this.animationConfig['exit'][1].nodes = nodesToScale;
+
+ this.fire('circle-click');
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/index.html
new file mode 100644
index 00000000000..f509f0b5e6c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/index.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>neon-animated-pages demo: tiles</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../neon-animated-pages.html">
+ <link rel="import" href="../../neon-animations.html">
+ <link rel="import" href="../../../paper-styles/color.html">
+ <link rel="import" href="circles-page.html">
+ <link rel="import" href="squares-page.html">
+
+ <style is="custom-style">
+ body {
+ overflow: hidden;
+ @apply(--layout-fullbleed);
+ }
+ neon-animated-pages {
+ height: 100%;
+ }
+
+ :root {
+ --color-one: var(--paper-cyan-300);
+ --color-two: var(--paper-orange-500);
+ }
+ </style>
+
+ </head>
+ <body>
+
+ <template is="dom-bind">
+
+ <neon-animated-pages id="pages" selected="0">
+ <circles-page on-circle-click="_onCircleClick"></circles-page>
+ <squares-page on-click="_onSquaresClick"></squares-page>
+ </neon-animated-pages>
+
+ </template>
+
+ <script>
+
+ var scope = document.querySelector('template[is="dom-bind"]');
+
+ scope._onCircleClick = function(event) {
+ this.$.pages.selected = 1;
+ };
+
+ scope._onSquaresClick = function(event) {
+ this.$.pages.selected = 0;
+ };
+
+ </script>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/squares-page.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/squares-page.html
new file mode 100644
index 00000000000..52fe7e18801
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/demo/tiles/squares-page.html
@@ -0,0 +1,100 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../../polymer/polymer.html">
+<link rel="import" href="../../neon-shared-element-animatable-behavior.html">
+
+<dom-module id="squares-page">
+ <template>
+ <style>
+ .header {
+ height: 40%;
+ background: var(--color-one);
+ }
+
+ .body {
+ text-align: center;
+ padding: 8px;
+ }
+
+ .square {
+ display: inline-block;
+ width: 150px;
+ height: 150px;
+ margin: 8px;
+ background: var(--color-two);
+ }
+ </style>
+
+ <div id="header" class="header"></div>
+
+ <div class="body">
+ <div class="square"></div>
+ <div class="square"></div>
+ <div class="square"></div>
+ <div class="square"></div>
+ </div>
+
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'squares-page',
+
+ behaviors: [
+ Polymer.NeonSharedElementAnimatableBehavior
+ ],
+
+ properties: {
+
+ sharedElements: {
+ value: function() {
+ return {
+ 'hero': this.$.header
+ }
+ }
+ },
+
+ animationConfig: {
+ value: function() {
+ var squares = Polymer.dom(this.root).querySelectorAll('.square');
+ var squaresArray = Array.prototype.slice.call(squares);
+ return {
+ 'entry': [{
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this
+ }, {
+ name: 'cascaded-animation',
+ animation: 'transform-animation',
+ transformFrom: 'translateY(100%)',
+ nodes: squaresArray
+ }],
+
+ 'exit': [{
+ name: 'slide-up-animation',
+ node: this.$.header
+ }, {
+ name: 'cascaded-animation',
+ animation: 'transform-animation',
+ transformTo: 'translateY(60vh)',
+ nodes: squaresArray
+ }]
+ };
+ }
+ }
+ }
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/guides/neon-animation.md b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/guides/neon-animation.md
new file mode 100644
index 00000000000..69727b864ff
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/guides/neon-animation.md
@@ -0,0 +1,314 @@
+---
+title: neon-animation
+summary: "A short guide to neon-animation and neon-animated-pages"
+tags: ['animation','core-animated-pages']
+elements: ['neon-animation','neon-animated-pages']
+updated: 2015-05-26
+---
+
+# neon-animation
+
+`neon-animation` is a suite of elements and behaviors to implement pluggable animated transitions for Polymer Elements using [Web Animations](https://w3c.github.io/web-animations/).
+
+*Warning: The API may change.*
+
+* [A basic animatable element](#basic)
+* [Animation configuration](#configuration)
+ * [Animation types](#configuration-types)
+ * [Configuration properties](#configuration-properties)
+ * [Using multiple animations](#configuration-multiple)
+ * [Running animations encapsulated in children nodes](#configuration-encapsulation)
+* [Page transitions](#page-transitions)
+ * [Shared element animations](#shared-element)
+ * [Declarative page transitions](#declarative-page)
+* [Included animations](#animations)
+* [Demos](#demos)
+
+<a name="basic"></a>
+## A basic animatable element
+
+Elements that can be animated should implement the `Polymer.NeonAnimatableBehavior` behavior, or `Polymer.NeonAnimationRunnerBehavior` if they're also responsible for running an animation.
+
+```js
+Polymer({
+ is: 'my-animatable',
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+ properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // provided by neon-animation/animations/scale-down-animation.html
+ name: 'scale-down-animation',
+ node: this
+ }
+ }
+ }
+ },
+ listeners: {
+ // this event is fired when the animation finishes
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+ animate: function() {
+ // run scale-down-animation
+ this.playAnimation();
+ },
+ _onNeonAnimationFinish: function() {
+ console.log('animation done!');
+ }
+});
+```
+
+[Live demo](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/doc/basic.html)
+
+<a name="configuration"></a>
+## Animation configuration
+
+<a name="configuration-types"></a>
+### Animation types
+
+An element might run different animations, for example it might do something different when it enters the view and when it exits from view. You can set the `animationConfig` property to a map from an animation type to configuration.
+
+```js
+Polymer({
+ is: 'my-dialog',
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+ properties: {
+ opened: {
+ type: Boolean
+ },
+ animationConfig: {
+ value: function() {
+ return {
+ 'entry': {
+ // provided by neon-animation/animations/scale-up-animation.html
+ name: 'scale-up-animation',
+ node: this
+ },
+ 'exit': {
+ // provided by neon-animation-animations/fade-out-animation.html
+ name: 'fade-out-animation',
+ node: this
+ }
+ }
+ }
+ }
+ },
+ listeners: {
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+ show: function() {
+ this.opened = true;
+ this.style.display = 'inline-block';
+ // run scale-up-animation
+ this.playAnimation('entry');
+ },
+ hide: function() {
+ this.opened = false;
+ // run fade-out-animation
+ this.playAnimation('exit');
+ },
+ _onNeonAnimationFinish: function() {
+ if (!this.opened) {
+ this.style.display = 'none';
+ }
+ }
+});
+```
+
+[Live demo](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/doc/types.html)
+
+You can also use the convenience properties `entryAnimation` and `exitAnimation` to set `entry` and `exit` animations:
+
+```js
+properties: {
+ entryAnimation: {
+ value: 'scale-up-animation'
+ },
+ exitAnimation: {
+ value: 'fade-out-animation'
+ }
+}
+```
+
+<a name="configuration-properties"></a>
+### Configuration properties
+
+You can pass additional parameters to configure an animation in the animation configuration object.
+All animations should accept the following properties:
+
+ * `name`: The name of an animation, ie. an element implementing `Polymer.NeonAnimationBehavior`.
+ * `node`: The target node to apply the animation to. Defaults to `this`.
+ * `timing`: Timing properties to use in this animation. They match the [Web Animations Animation Effect Timing interface](https://w3c.github.io/web-animations/#the-animationeffecttiming-interface). The
+ properties include the following:
+ * `duration`: The duration of the animation in milliseconds.
+ * `delay`: The delay before the start of the animation in milliseconds.
+ * `easing`: A timing function for the animation. Matches the CSS timing function values.
+
+Animations may define additional configuration properties and they are listed in their documentation.
+
+<a name="configuration-multiple"></a>
+### Using multiple animations
+
+Set the animation configuration to an array to combine animations, like this:
+
+```js
+animationConfig: {
+ value: function() {
+ return {
+ // fade-in-animation is run with a 50ms delay from slide-down-animation
+ 'entry': [{
+ name: 'slide-down-animation',
+ node: this
+ }, {
+ name: 'fade-in-animation',
+ node: this,
+ timing: {delay: 50}
+ }]
+ }
+ }
+}
+```
+
+<a name="configuration-encapsulation"></a>
+### Running animations encapsulated in children nodes
+
+You can include animations in the configuration that are encapsulated in a child element that implement `Polymer.NeonAnimatableBehavior` with the `animatable` property.
+
+```js
+animationConfig: {
+ value: function() {
+ return {
+ // run fade-in-animation on this, and the entry animation on this.$.myAnimatable
+ 'entry': [
+ {name: 'fade-in-animation', node: this},
+ {animatable: this.$.myAnimatable, type: 'entry'}
+ ]
+ }
+ }
+}
+```
+
+<a name="page-transitions"></a>
+## Page transitions
+
+*The artist formerly known as `<core-animated-pages>`*
+
+The `neon-animated-pages` element manages a set of pages to switch between, and runs animations between the page transitions. It implements the `Polymer.IronSelectableBehavior` behavior. Each child node should implement `Polymer.NeonAnimatableBehavior` and define the `entry` and `exit` animations. During a page transition, the `entry` animation is run on the new page and the `exit` animation is run on the old page.
+
+<a name="shared-element"></a>
+### Shared element animations
+
+Shared element animations work on multiple nodes. For example, a "hero" animation is used during a page transition to make two elements from separate pages appear to animate as a single element. Shared element animation configurations have an `id` property that identify they belong in the same animation. Elements containing shared elements also have a `sharedElements` property defines a map from `id` to element, the element involved with the animation.
+
+In the incoming page:
+
+```js
+properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // the incoming page defines the 'entry' animation
+ 'entry': {
+ name: 'hero-animation',
+ id: 'hero',
+ toPage: this
+ }
+ }
+ }
+ },
+ sharedElements: {
+ value: function() {
+ return {
+ 'hero': this.$.hero
+ }
+ }
+ }
+}
+```
+
+In the outgoing page:
+
+```js
+properties: {
+ animationConfig: {
+ value: function() {
+ return {
+ // the outgoing page defines the 'exit' animation
+ 'exit': {
+ name: 'hero-animation',
+ id: 'hero',
+ fromPage: this
+ }
+ }
+ }
+ },
+ sharedElements: {
+ value: function() {
+ return {
+ 'hero': this.$.otherHero
+ }
+ }
+ }
+}
+```
+
+<a name="declarative-page"></a>
+### Declarative page transitions
+
+For convenience, if you define the `entry-animation` and `exit-animation` attributes on `<neon-animated-pages>`, those animations will apply for all page transitions.
+
+For example:
+
+```js
+<neon-animated-pages id="pages" class="flex" selected="[[selected]]" entry-animation="slide-from-right-animation" exit-animation="slide-left-animation">
+ <neon-animatable>1</neon-animatable>
+ <neon-animatable>2</neon-animatable>
+ <neon-animatable>3</neon-animatable>
+ <neon-animatable>4</neon-animatable>
+ <neon-animatable>5</neon-animatable>
+</neon-animated-pages>
+```
+
+The new page will slide in from the right, and the old page slide away to the left.
+
+<a name="animations"></a>
+## Included animations
+
+Single element animations:
+
+ * `fade-in-animation` Animates opacity from `0` to `1`;
+ * `fade-out-animation` Animates opacity from `1` to `0`;
+ * `scale-down-animation` Animates transform from `scale(1)` to `scale(0)`;
+ * `scale-up-animation` Animates transform from `scale(0)` to `scale(1)`;
+ * `slide-down-animation` Animates transform from `none` to `translateY(100%)`;
+ * `slide-up-animation` Animates transform from `none` to `translateY(-100%)`;
+ * `slide-from-top-animation` Animates transform from `translateY(-100%)` to `none`;
+ * `slide-from-bottom-animation` Animates transform from `translateY(100%)` to `none`;
+ * `slide-left-animation` Animates transform from `none` to `translateX(-100%)`;
+ * `slide-right-animation` Animates transform from `none` to `translateX(100%)`;
+ * `slide-from-left-animation` Animates transform from `translateX(-100%)` to `none`;
+ * `slide-from-right-animation` Animates transform from `translateX(100%)` to `none`;
+ * `transform-animation` Animates a custom transform.
+
+Note that there is a restriction that only one transform animation can be applied on the same element at a time. Use the custom `transform-animation` to combine transform properties.
+
+Shared element animations
+
+ * `hero-animation` Animates an element such that it looks like it scales and transforms from another element.
+ * `ripple-animation` Animates an element to full screen such that it looks like it ripples from another element.
+
+Group animations
+ * `cascaded-animation` Applys an animation to an array of elements with a delay between each.
+
+<a name="demos"></a>
+## Demos
+
+ * [Grid to full screen](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/grid/index.html)
+ * [Animation on load](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/load/index.html)
+ * [List item to detail](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/list/index.html) (For narrow width)
+ * [Dots to squares](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/tiles/index.html)
+ * [Declarative](http://morethanreal.github.io/neon-animation-demo/bower_components/neon-animation/demo/declarative/index.html)
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/index.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/index.html
new file mode 100644
index 00000000000..6f5feedf455
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>neon-animation</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable-behavior.html
new file mode 100644
index 00000000000..dd58a6cfbac
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable-behavior.html
@@ -0,0 +1,150 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /**
+ * `Polymer.NeonAnimatableBehavior` is implemented by elements containing animations for use with
+ * elements implementing `Polymer.NeonAnimationRunnerBehavior`.
+ * @polymerBehavior
+ */
+ Polymer.NeonAnimatableBehavior = {
+
+ properties: {
+
+ /**
+ * Animation configuration. See README for more info.
+ */
+ animationConfig: {
+ type: Object
+ },
+
+ /**
+ * Convenience property for setting an 'entry' animation. Do not set `animationConfig.entry`
+ * manually if using this. The animated node is set to `this` if using this property.
+ */
+ entryAnimation: {
+ observer: '_entryAnimationChanged',
+ type: String
+ },
+
+ /**
+ * Convenience property for setting an 'exit' animation. Do not set `animationConfig.exit`
+ * manually if using this. The animated node is set to `this` if using this property.
+ */
+ exitAnimation: {
+ observer: '_exitAnimationChanged',
+ type: String
+ }
+
+ },
+
+ _entryAnimationChanged: function() {
+ this.animationConfig = this.animationConfig || {};
+ this.animationConfig['entry'] = [{
+ name: this.entryAnimation,
+ node: this
+ }];
+ },
+
+ _exitAnimationChanged: function() {
+ this.animationConfig = this.animationConfig || {};
+ this.animationConfig['exit'] = [{
+ name: this.exitAnimation,
+ node: this
+ }];
+ },
+
+ _copyProperties: function(config1, config2) {
+ // shallowly copy properties from config2 to config1
+ for (var property in config2) {
+ config1[property] = config2[property];
+ }
+ },
+
+ _cloneConfig: function(config) {
+ var clone = {
+ isClone: true
+ };
+ this._copyProperties(clone, config);
+ return clone;
+ },
+
+ _getAnimationConfigRecursive: function(type, map, allConfigs) {
+ if (!this.animationConfig) {
+ return;
+ }
+
+ if(this.animationConfig.value && typeof this.animationConfig.value === 'function') {
+ this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
+ return;
+ }
+
+ // type is optional
+ var thisConfig;
+ if (type) {
+ thisConfig = this.animationConfig[type];
+ } else {
+ thisConfig = this.animationConfig;
+ }
+
+ if (!Array.isArray(thisConfig)) {
+ thisConfig = [thisConfig];
+ }
+
+ // iterate animations and recurse to process configurations from child nodes
+ if (thisConfig) {
+ for (var config, index = 0; config = thisConfig[index]; index++) {
+ if (config.animatable) {
+ config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
+ } else {
+ if (config.id) {
+ var cachedConfig = map[config.id];
+ if (cachedConfig) {
+ // merge configurations with the same id, making a clone lazily
+ if (!cachedConfig.isClone) {
+ map[config.id] = this._cloneConfig(cachedConfig)
+ cachedConfig = map[config.id];
+ }
+ this._copyProperties(cachedConfig, config);
+ } else {
+ // put any configs with an id into a map
+ map[config.id] = config;
+ }
+ } else {
+ allConfigs.push(config);
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * An element implementing `Polymer.NeonAnimationRunnerBehavior` calls this method to configure
+ * an animation with an optional type. Elements implementing `Polymer.NeonAnimatableBehavior`
+ * should define the property `animationConfig`, which is either a configuration object
+ * or a map of animation type to array of configuration objects.
+ */
+ getAnimationConfig: function(type) {
+ var map = {};
+ var allConfigs = [];
+ this._getAnimationConfigRecursive(type, map, allConfigs);
+ // append the configurations saved in the map to the array
+ for (var key in map) {
+ allConfigs.push(map[key]);
+ }
+ return allConfigs;
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable.html
new file mode 100644
index 00000000000..82deb610b65
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animatable.html
@@ -0,0 +1,57 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
+<link rel="import" href="neon-animatable-behavior.html">
+
+<!--
+`<neon-animatable>` is a simple container element implementing `Polymer.NeonAnimatableBehavior`. This is a convenience element for use with `<neon-animated-pages>`.
+
+```
+<neon-animated-pages selected="0"
+ entry-animation="slide-from-right-animation"
+ exit-animation="slide-left-animation">
+ <neon-animatable>1</neon-animatable>
+ <neon-animatable>2</neon-animatable>
+</neon-animated-pages>
+```
+-->
+
+<dom-module id="neon-animatable">
+
+ <style>
+
+ :host {
+ display: block;
+ }
+
+ </style>
+
+ <template>
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'neon-animatable',
+
+ behaviors: [
+ Polymer.NeonAnimatableBehavior,
+ Polymer.IronResizableBehavior
+ ]
+
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animated-pages.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animated-pages.html
new file mode 100644
index 00000000000..4cc94c72b6e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animated-pages.html
@@ -0,0 +1,224 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
+<link rel="import" href="../iron-selector/iron-selectable.html">
+<link rel="import" href="neon-animation-runner-behavior.html">
+<link rel="import" href="animations/opaque-animation.html">
+
+<!--
+Material design: [Meaningful transitions](https://www.google.com/design/spec/animation/meaningful-transitions.html)
+
+`neon-animated-pages` manages a set of pages and runs an animation when switching between them. Its
+children pages should implement `Polymer.NeonAnimatableBehavior` and define `entry` and `exit`
+animations to be run when switching to or switching out of the page.
+
+@group Neon Elements
+@element neon-animated-pages
+@demo demo/index.html
+-->
+
+<dom-module id="neon-animated-pages">
+
+ <style>
+
+ :host {
+ display: block;
+ position: relative;
+ }
+
+ :host > ::content > * {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ }
+
+ :host > ::content > :not(.iron-selected):not(.neon-animating) {
+ display: none !important;
+ }
+
+ :host > ::content > .neon-animating {
+ pointer-events: none;
+ }
+
+ </style>
+
+ <template>
+ <content id="content"></content>
+ </template>
+
+</dom-module>
+
+<script>
+(function() {
+
+ Polymer({
+
+ is: 'neon-animated-pages',
+
+ behaviors: [
+ Polymer.IronResizableBehavior,
+ Polymer.IronSelectableBehavior,
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+
+ activateEvent: {
+ type: String,
+ value: ''
+ },
+
+ // if true, the initial page selection will also be animated according to its animation config.
+ animateInitialSelection: {
+ type: Boolean,
+ value: false
+ }
+
+ },
+
+ listeners: {
+ 'iron-select': '_onIronSelect',
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+
+ _onIronSelect: function(event) {
+ var selectedPage = event.detail.item;
+
+ // Only consider child elements.
+ if (this.items.indexOf(selectedPage) < 0) {
+ return;
+ }
+
+ var oldPage = this._valueToItem(this._prevSelected) || false;
+ this._prevSelected = this.selected;
+
+ // on initial load and if animateInitialSelection is negated, simply display selectedPage.
+ if (!oldPage && !this.animateInitialSelection) {
+ this._completeSelectedChanged();
+ return;
+ }
+
+ this.animationConfig = [];
+
+ // configure selectedPage animations.
+ if (this.entryAnimation) {
+ this.animationConfig.push({
+ name: this.entryAnimation,
+ node: selectedPage
+ });
+ } else {
+ if (selectedPage.getAnimationConfig) {
+ this.animationConfig.push({
+ animatable: selectedPage,
+ type: 'entry'
+ });
+ }
+ }
+
+ // configure oldPage animations iff exists.
+ if (oldPage) {
+
+ // cancel the currently running animation if one is ongoing.
+ if (oldPage.classList.contains('neon-animating')) {
+ this._squelchNextFinishEvent = true;
+ this.cancelAnimation();
+ this._completeSelectedChanged();
+ this._squelchNextFinishEvent = false;
+ }
+
+ // configure the animation.
+ if (this.exitAnimation) {
+ this.animationConfig.push({
+ name: this.exitAnimation,
+ node: oldPage
+ });
+ } else {
+ if (oldPage.getAnimationConfig) {
+ this.animationConfig.push({
+ animatable: oldPage,
+ type: 'exit'
+ });
+ }
+ }
+
+ // display the oldPage during the transition.
+ oldPage.classList.add('neon-animating');
+ }
+
+ // display the selectedPage during the transition.
+ selectedPage.classList.add('neon-animating');
+
+ // actually run the animations.
+ if (this.animationConfig.length >= 1) {
+
+ // on first load, ensure we run animations only after element is attached.
+ if (!this.isAttached) {
+ this.async(function () {
+ this.playAnimation(undefined, {
+ fromPage: null,
+ toPage: selectedPage
+ });
+ });
+
+ } else {
+ this.playAnimation(undefined, {
+ fromPage: oldPage,
+ toPage: selectedPage
+ });
+ }
+
+ } else {
+ this._completeSelectedChanged(oldPage, selectedPage);
+ }
+ },
+
+ /**
+ * @param {Object=} oldPage
+ * @param {Object=} selectedPage
+ */
+ _completeSelectedChanged: function(oldPage, selectedPage) {
+ if (selectedPage) {
+ selectedPage.classList.remove('neon-animating');
+ }
+ if (oldPage) {
+ oldPage.classList.remove('neon-animating');
+ }
+ if (!selectedPage || !oldPage) {
+ var nodes = Polymer.dom(this.$.content).getDistributedNodes();
+ for (var node, index = 0; node = nodes[index]; index++) {
+ node.classList && node.classList.remove('neon-animating');
+ }
+ }
+ this.async(this._notifyPageResize);
+ },
+
+ _onNeonAnimationFinish: function(event) {
+ if (this._squelchNextFinishEvent) {
+ this._squelchNextFinishEvent = false;
+ return;
+ }
+ this._completeSelectedChanged(event.detail.fromPage, event.detail.toPage);
+ },
+
+ _notifyPageResize: function() {
+ var selectedPage = this.selectedItem || this._valueToItem(this.selected);
+ this.resizerShouldNotify = function(element) {
+ return element == selectedPage;
+ }
+ this.notifyResize();
+ }
+
+ })
+
+})();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-behavior.html
new file mode 100644
index 00000000000..6939d3428a0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-behavior.html
@@ -0,0 +1,86 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-meta/iron-meta.html">
+
+<script>
+
+ /**
+ * Use `Polymer.NeonAnimationBehavior` to implement an animation.
+ * @polymerBehavior
+ */
+ Polymer.NeonAnimationBehavior = {
+
+ properties: {
+
+ /**
+ * Defines the animation timing.
+ */
+ animationTiming: {
+ type: Object,
+ value: function() {
+ return {
+ duration: 500,
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
+ fill: 'both'
+ }
+ }
+ }
+
+ },
+
+ /**
+ * Can be used to determine that elements implement this behavior.
+ */
+ isNeonAnimation: true,
+
+ /**
+ * Do any animation configuration here.
+ */
+ // configure: function(config) {
+ // },
+
+ /**
+ * Returns the animation timing by mixing in properties from `config` to the defaults defined
+ * by the animation.
+ */
+ timingFromConfig: function(config) {
+ if (config.timing) {
+ for (var property in config.timing) {
+ this.animationTiming[property] = config.timing[property];
+ }
+ }
+ return this.animationTiming;
+ },
+
+ /**
+ * Sets `transform` and `transformOrigin` properties along with the prefixed versions.
+ */
+ setPrefixedProperty: function(node, property, value) {
+ var map = {
+ 'transform': ['webkitTransform'],
+ 'transformOrigin': ['mozTransformOrigin', 'webkitTransformOrigin']
+ };
+ var prefixes = map[property];
+ for (var prefix, index = 0; prefix = prefixes[index]; index++) {
+ node.style[prefix] = value;
+ }
+ node.style[property] = value;
+ },
+
+ /**
+ * Called when the animation finishes.
+ */
+ complete: function() {}
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-runner-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-runner-behavior.html
new file mode 100644
index 00000000000..2b414e25778
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation-runner-behavior.html
@@ -0,0 +1,116 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-meta/iron-meta.html">
+<link rel="import" href="neon-animatable-behavior.html">
+
+<script>
+
+ /**
+ * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations.
+ *
+ * @polymerBehavior Polymer.NeonAnimationRunnerBehavior
+ */
+ Polymer.NeonAnimationRunnerBehaviorImpl = {
+
+ properties: {
+
+ /** @type {?Object} */
+ _player: {
+ type: Object
+ }
+
+ },
+
+ _configureAnimationEffects: function(allConfigs) {
+ var allAnimations = [];
+ if (allConfigs.length > 0) {
+ for (var config, index = 0; config = allConfigs[index]; index++) {
+ var animation = document.createElement(config.name);
+ // is this element actually a neon animation?
+ if (animation.isNeonAnimation) {
+ var effect = animation.configure(config);
+ if (effect) {
+ allAnimations.push({
+ animation: animation,
+ config: config,
+ effect: effect
+ });
+ }
+ } else {
+ console.warn(this.is + ':', config.name, 'not found!');
+ }
+ }
+ }
+ return allAnimations;
+ },
+
+ _runAnimationEffects: function(allEffects) {
+ return document.timeline.play(new GroupEffect(allEffects));
+ },
+
+ _completeAnimations: function(allAnimations) {
+ for (var animation, index = 0; animation = allAnimations[index]; index++) {
+ animation.animation.complete(animation.config);
+ }
+ },
+
+ /**
+ * Plays an animation with an optional `type`.
+ * @param {string=} type
+ * @param {!Object=} cookie
+ */
+ playAnimation: function(type, cookie) {
+ var allConfigs = this.getAnimationConfig(type);
+ if (!allConfigs) {
+ return;
+ }
+ try {
+ var allAnimations = this._configureAnimationEffects(allConfigs);
+ var allEffects = allAnimations.map(function(animation) {
+ return animation.effect;
+ });
+
+ if (allEffects.length > 0) {
+ this._player = this._runAnimationEffects(allEffects);
+ this._player.onfinish = function() {
+ this._completeAnimations(allAnimations);
+
+ if (this._player) {
+ this._player.cancel();
+ this._player = null;
+ }
+
+ this.fire('neon-animation-finish', cookie, {bubbles: false});
+ }.bind(this);
+ return;
+ }
+ } catch (e) {
+ console.warn('Couldnt play', '(', type, allConfigs, ').', e);
+ }
+ this.fire('neon-animation-finish', cookie, {bubbles: false});
+ },
+
+ /**
+ * Cancels the currently running animation.
+ */
+ cancelAnimation: function() {
+ if (this._player) {
+ this._player.cancel();
+ }
+ }
+ };
+
+ /** @polymerBehavior Polymer.NeonAnimationRunnerBehavior */
+ Polymer.NeonAnimationRunnerBehavior = [
+ Polymer.NeonAnimatableBehavior,
+ Polymer.NeonAnimationRunnerBehaviorImpl
+ ];
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation.html
new file mode 100644
index 00000000000..da645048597
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animation.html
@@ -0,0 +1,18 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="neon-animatable-behavior.html">
+<link rel="import" href="neon-animated-pages.html">
+<link rel="import" href="neon-animatable.html">
+<link rel="import" href="neon-animation-behavior.html">
+<link rel="import" href="neon-animation-runner-behavior.html">
+<link rel="import" href="neon-animations.html">
+<link rel="import" href="neon-shared-element-animatable-behavior.html">
+<link rel="import" href="neon-shared-element-animation-behavior.html">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animations.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animations.html
new file mode 100644
index 00000000000..67c4df4c76a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-animations.html
@@ -0,0 +1,29 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="animations/cascaded-animation.html">
+<link rel="import" href="animations/fade-in-animation.html">
+<link rel="import" href="animations/fade-out-animation.html">
+<link rel="import" href="animations/hero-animation.html">
+<link rel="import" href="animations/opaque-animation.html">
+<link rel="import" href="animations/ripple-animation.html">
+<link rel="import" href="animations/reverse-ripple-animation.html">
+<link rel="import" href="animations/scale-down-animation.html">
+<link rel="import" href="animations/scale-up-animation.html">
+<link rel="import" href="animations/slide-from-left-animation.html">
+<link rel="import" href="animations/slide-from-right-animation.html">
+<link rel="import" href="animations/slide-from-top-animation.html">
+<link rel="import" href="animations/slide-from-bottom-animation.html">
+<link rel="import" href="animations/slide-left-animation.html">
+<link rel="import" href="animations/slide-right-animation.html">
+<link rel="import" href="animations/slide-up-animation.html">
+<link rel="import" href="animations/slide-down-animation.html">
+<link rel="import" href="animations/transform-animation.html">
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animatable-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animatable-behavior.html
new file mode 100644
index 00000000000..e63173d368d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animatable-behavior.html
@@ -0,0 +1,43 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="neon-animatable-behavior.html">
+
+<script>
+
+ /**
+ * Use `Polymer.NeonSharedElementAnimatableBehavior` to implement elements containing shared element
+ * animations.
+ * @polymerBehavior Polymer.NeonSharedElementAnimatableBehavior
+ */
+ Polymer.NeonSharedElementAnimatableBehaviorImpl = {
+
+ properties: {
+
+ /**
+ * A map of shared element id to node.
+ */
+ sharedElements: {
+ type: Object,
+ value: {}
+ }
+
+ }
+
+ };
+
+ /** @polymerBehavior Polymer.NeonSharedElementAnimatableBehavior */
+ Polymer.NeonSharedElementAnimatableBehavior = [
+ Polymer.NeonAnimatableBehavior,
+ Polymer.NeonSharedElementAnimatableBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animation-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animation-behavior.html
new file mode 100644
index 00000000000..7787615b039
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/neon-shared-element-animation-behavior.html
@@ -0,0 +1,72 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="neon-animation-behavior.html">
+
+<script>
+
+ /**
+ * Use `Polymer.NeonSharedElementAnimationBehavior` to implement shared element animations.
+ * @polymerBehavior Polymer.NeonSharedElementAnimationBehavior
+ */
+ Polymer.NeonSharedElementAnimationBehaviorImpl = {
+
+ properties: {
+
+ /**
+ * Cached copy of shared elements.
+ */
+ sharedElements: {
+ type: Object
+ }
+
+ },
+
+ /**
+ * Finds shared elements based on `config`.
+ */
+ findSharedElements: function(config) {
+ var fromPage = config.fromPage;
+ var toPage = config.toPage;
+ if (!fromPage || !toPage) {
+ console.warn(this.is + ':', !fromPage ? 'fromPage' : 'toPage', 'is undefined!');
+ return null;
+ };
+
+ if (!fromPage.sharedElements || !toPage.sharedElements) {
+ console.warn(this.is + ':', 'sharedElements are undefined for', !fromPage.sharedElements ? fromPage : toPage);
+ return null;
+ };
+
+ var from = fromPage.sharedElements[config.id]
+ var to = toPage.sharedElements[config.id];
+
+ if (!from || !to) {
+ console.warn(this.is + ':', 'sharedElement with id', config.id, 'not found in', !from ? fromPage : toPage);
+ return null;
+ }
+
+ this.sharedElements = {
+ from: from,
+ to: to
+ };
+ return this.sharedElements;
+ }
+
+ };
+
+ /** @polymerBehavior Polymer.NeonSharedElementAnimationBehavior */
+ Polymer.NeonSharedElementAnimationBehavior = [
+ Polymer.NeonAnimationBehavior,
+ Polymer.NeonSharedElementAnimationBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.html b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/web-animations.html
index 7e3d8f1e498..c871854017a 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.html
+++ b/chromium/third_party/catapult/third_party/polymer/components/neon-animation/web-animations.html
@@ -1,5 +1,6 @@
<!--
-Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
@@ -7,6 +8,4 @@ Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
-<link rel="import" href="layout.html">
-
-<script src="polymer.js"></script>
+<script src="../web-animations-js/web-animations-next-lite.min.js"></script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.bower.json
new file mode 100644
index 00000000000..2b04bf9f8a9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.bower.json
@@ -0,0 +1,51 @@
+{
+ "name": "paper-behaviors",
+ "version": "1.0.11",
+ "description": "Common behaviors across the paper elements",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "main": [
+ "paper-button-behavior.html",
+ "paper-checked-element-behavior.html",
+ "paper-inky-focus-behavior.html"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "behavior"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-behaviors"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-behaviors",
+ "dependencies": {
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
+ "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
+ "polymer": "Polymer/polymer#^1.2.1"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-material": "PolymerElements/paper-material#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "_release": "1.0.11",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.11",
+ "commit": "e3c1ab0c72905b58fb4d9adc2921ea73b5c085a5"
+ },
+ "_source": "git://github.com/PolymerElements/paper-behaviors.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-behaviors"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.travis.yml
new file mode 100644
index 00000000000..f44cf504cff
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: Mni8srJPpo7GAk5wCLTiqqVqAJxxKMpGuxYxooqIAuc050n26KkHfDWLPY69taFY9WYjU3pzVEwrYX3HqSbib1CTlcfeATGs1+q2rXKZKmBAnKKPi12CEEXOcbMoVgzVQs7rzr8MQF9LR2TLtBuMQEoAimebA7uQcYGXcSWKJR4=
+ - secure: LYF3qBtJ6zZcf9dsSJ9t/My4Cne5ieI6RkHFj/0MBcy0vMbUazTH38vuy+FILYlrzbaxkVs36lPQFBXH83Ue3TxjdfjeNvK8YiuEcFjE5lQi2u7+x54eSV3myp2SIdtBLGE7rqmY0zj/Oeg91fV22OdfSHhJxuV/RxFFZIuZtHY=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/README.md
new file mode 100644
index 00000000000..969e7967c01
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/README.md
@@ -0,0 +1,44 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-button-behavior.html paper-checked-element-behavior.html paper-inky-focus-behavior.html paper-ripple-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/paper-behaviors.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-behaviors)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-behaviors)_
+
+
+<!-- No docs for Polymer.PaperButtonBehavior found. -->
+
+##Polymer.PaperCheckedElementBehavior
+
+Use `Polymer.PaperCheckedElementBehavior` to implement a custom element
+that has a `checked` property similar to `Polymer.IronCheckedElementBehavior`
+and is compatible with having a ripple effect.
+
+
+
+##Polymer.PaperInkyFocusBehavior
+
+`Polymer.PaperInkyFocusBehavior` implements a ripple when the element has keyboard focus.
+
+
+
+##Polymer.PaperRippleBehavior
+
+`Polymer.PaperRippleBehavior` dynamically implements a ripple
+when the element has focus via pointer or keyboard.
+
+NOTE: This behavior is intended to be used in conjunction with and after
+`Polymer.IronButtonState` and `Polymer.IronControlState`.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/bower.json
new file mode 100644
index 00000000000..5933ab1de9b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "paper-behaviors",
+ "version": "1.0.11",
+ "description": "Common behaviors across the paper elements",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "main": [
+ "paper-button-behavior.html",
+ "paper-checked-element-behavior.html",
+ "paper-inky-focus-behavior.html"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "behavior"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-behaviors"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-behaviors",
+ "dependencies": {
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
+ "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
+ "polymer": "Polymer/polymer#^1.2.1"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+ "paper-material": "PolymerElements/paper-material#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/index.html
new file mode 100644
index 00000000000..cc3b3fd3348
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/index.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-behaviors demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link href="paper-button.html" rel="import">
+ <link href="paper-radio-button.html" rel="import">
+
+ <style>
+
+ body {
+ font-family: sans-serif;
+ padding: 24px;
+ margin: 0;
+ }
+
+ </style>
+
+</head>
+<body unresolved>
+
+ <h3>Normal</h3>
+
+ <paper-button tabindex="0">Hello World</paper-button>
+
+ <h3>Toggles</h3>
+
+ <paper-button toggles tabindex="0">Hello World</paper-button>
+
+ <h3>Disabled</h3>
+
+ <paper-button disabled tabindex="0">Hello World</paper-button>
+
+ <h3>Radio button with focus state</h3>
+
+ <paper-radio-button tabindex="0" title="Radio button with focus state"></paper-radio-button>
+
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-button.html
new file mode 100644
index 00000000000..a520a0f9ec2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-button.html
@@ -0,0 +1,72 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../paper-material/paper-material.html">
+<link rel="import" href="../paper-button-behavior.html">
+
+<dom-module id="paper-button">
+
+ <style>
+
+ :host {
+ display: inline-block;
+ position: relative;
+ background-color: #4285F4;
+ color: #fff;
+ border-radius: 3px;
+ text-transform: uppercase;
+ outline: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ }
+
+ paper-material {
+ border-radius: inherit;
+ padding: 16px;
+ }
+
+ :host([disabled]) {
+ background-color: #888;
+ pointer-events: none;
+ }
+
+ :host([active]),
+ :host([pressed]) {
+ background-color: #3367D6;
+ box-shadow: inset 0 3px 5px rgba(0,0,0,.2);
+ }
+
+ </style>
+
+ <template>
+
+ <paper-material class="content" elevation="[[_elevation]]" animated>
+ <content></content>
+ </paper-material>
+
+ </template>
+
+ <script>
+
+ Polymer({
+ is: 'paper-button',
+
+ behaviors: [
+ Polymer.PaperButtonBehavior
+ ]
+ });
+
+ </script>
+
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-radio-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-radio-button.html
new file mode 100644
index 00000000000..b6644942846
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/demo/paper-radio-button.html
@@ -0,0 +1,119 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../paper-checked-element-behavior.html">
+
+<dom-module id="paper-radio-button">
+
+ <style>
+ :host {
+ display: inline-block;
+ white-space: nowrap;
+ }
+
+ :host(:focus) {
+ outline: none
+ }
+
+ #radioContainer {
+ display: inline-block;
+ position: relative;
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+ vertical-align: middle;
+ }
+
+ #offRadio {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ border: solid 2px;
+ border-color: black;
+ transition: border-color 0.28s;
+ }
+
+ #onRadio {
+ position: absolute;
+ top: 4px;
+ left: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: red;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ transition: -webkit-transform ease 0.28s;
+ transition: transform ease 0.28s;
+ }
+
+ :host([disabled]) {
+ opacity: 0.3;
+ pointer-events: none;
+ }
+
+ :host([pressed]) #offRadio,
+ :host([active]) #offRadio {
+ border-color: red;
+ }
+
+ :host([pressed]) #onRadio,
+ :host([active]) #onRadio {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+
+ #ink {
+ position: absolute;
+ top: -16px;
+ left: -16px;
+ width: 48px;
+ height: 48px;
+ }
+
+ </style>
+
+ <template>
+ <div id="radioContainer">
+ <div id="offRadio"></div>
+ <div id="onRadio"></div>
+ </div>
+ </template>
+
+ <script>
+
+ Polymer({
+
+ behaviors: [
+ Polymer.PaperCheckedElementBehavior
+ ],
+
+ hostAttributes: {
+ role: 'radio'
+ },
+
+ ready: function() {
+ this.toggles = true;
+ },
+
+ _createRipple: function() {
+ this._rippleContainer = this.$.radioContainer;
+ return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
+ }
+
+ });
+
+ </script>
+
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/index.html
new file mode 100644
index 00000000000..37184eaa0db
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/index.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page src="paper-button-behavior.html"></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-button-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-button-behavior.html
new file mode 100644
index 00000000000..21b999f5b4f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-button-behavior.html
@@ -0,0 +1,103 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-behaviors/iron-button-state.html">
+<link rel="import" href="paper-ripple-behavior.html">
+
+<script>
+
+ /** @polymerBehavior Polymer.PaperButtonBehavior */
+ Polymer.PaperButtonBehaviorImpl = {
+
+ properties: {
+
+ /**
+ * The z-depth of this element, from 0-5. Setting to 0 will remove the
+ * shadow, and each increasing number greater than 0 will be "deeper"
+ * than the last.
+ *
+ * @attribute elevation
+ * @type number
+ * @default 1
+ */
+ elevation: {
+ type: Number,
+ reflectToAttribute: true,
+ readOnly: true
+ }
+
+ },
+
+ observers: [
+ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)',
+ '_computeKeyboardClass(receivedFocusFromKeyboard)'
+ ],
+
+ hostAttributes: {
+ role: 'button',
+ tabindex: '0',
+ animated: true
+ },
+
+ _calculateElevation: function() {
+ var e = 1;
+ if (this.disabled) {
+ e = 0;
+ } else if (this.active || this.pressed) {
+ e = 4;
+ } else if (this.receivedFocusFromKeyboard) {
+ e = 3;
+ }
+ this._setElevation(e);
+ },
+
+ _computeKeyboardClass: function(receivedFocusFromKeyboard) {
+ this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
+ },
+
+ /**
+ * In addition to `IronButtonState` behavior, when space key goes down,
+ * create a ripple down effect.
+ *
+ * @param {!KeyboardEvent} event .
+ */
+ _spaceKeyDownHandler: function(event) {
+ Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
+ // Ensure that there is at most one ripple when the space key is held down.
+ if (this.hasRipple() && this.getRipple().ripples.length < 1) {
+ this._ripple.uiDownAction();
+ }
+ },
+
+ /**
+ * In addition to `IronButtonState` behavior, when space key goes up,
+ * create a ripple up effect.
+ *
+ * @param {!KeyboardEvent} event .
+ */
+ _spaceKeyUpHandler: function(event) {
+ Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
+ if (this.hasRipple()) {
+ this._ripple.uiUpAction();
+ }
+ }
+
+ };
+
+ /** @polymerBehavior */
+ Polymer.PaperButtonBehavior = [
+ Polymer.IronButtonState,
+ Polymer.IronControlState,
+ Polymer.PaperRippleBehavior,
+ Polymer.PaperButtonBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-checked-element-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-checked-element-behavior.html
new file mode 100644
index 00000000000..806392aa2cf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-checked-element-behavior.html
@@ -0,0 +1,61 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-checked-element-behavior/iron-checked-element-behavior.html">
+<link rel="import" href="paper-inky-focus-behavior.html">
+
+<script>
+
+ /**
+ * Use `Polymer.PaperCheckedElementBehavior` to implement a custom element
+ * that has a `checked` property similar to `Polymer.IronCheckedElementBehavior`
+ * and is compatible with having a ripple effect.
+ * @polymerBehavior Polymer.PaperCheckedElementBehavior
+ */
+ Polymer.PaperCheckedElementBehaviorImpl = {
+
+ /**
+ * Synchronizes the element's checked state with its ripple effect.
+ */
+ _checkedChanged: function() {
+ Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);
+ if (this.hasRipple()) {
+ if (this.checked) {
+ this._ripple.setAttribute('checked', '');
+ } else {
+ this._ripple.removeAttribute('checked');
+ }
+ }
+ },
+
+ /**
+ * Synchronizes the element's `active` and `checked` state.
+ */
+ _buttonStateChanged: function() {
+ Polymer.PaperRippleBehavior._buttonStateChanged.call(this);
+ if (this.disabled) {
+ return;
+ }
+ if (this.isAttached) {
+ this.checked = this.active;
+ }
+ }
+
+ };
+
+ /** @polymerBehavior Polymer.PaperCheckedElementBehavior */
+ Polymer.PaperCheckedElementBehavior = [
+ Polymer.PaperInkyFocusBehavior,
+ Polymer.IronCheckedElementBehavior,
+ Polymer.PaperCheckedElementBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-inky-focus-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-inky-focus-behavior.html
new file mode 100644
index 00000000000..76fffc116ba
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-inky-focus-behavior.html
@@ -0,0 +1,55 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-behaviors/iron-button-state.html">
+<link rel="import" href="paper-ripple-behavior.html">
+
+<script>
+
+ /**
+ * `Polymer.PaperInkyFocusBehavior` implements a ripple when the element has keyboard focus.
+ *
+ * @polymerBehavior Polymer.PaperInkyFocusBehavior
+ */
+ Polymer.PaperInkyFocusBehaviorImpl = {
+
+ observers: [
+ '_focusedChanged(receivedFocusFromKeyboard)'
+ ],
+
+ _focusedChanged: function(receivedFocusFromKeyboard) {
+ if (receivedFocusFromKeyboard) {
+ this.ensureRipple();
+ }
+ if (this.hasRipple()) {
+ this._ripple.holdDown = receivedFocusFromKeyboard;
+ }
+ },
+
+ _createRipple: function() {
+ var ripple = Polymer.PaperRippleBehavior._createRipple();
+ ripple.id = 'ink';
+ ripple.setAttribute('center', '');
+ ripple.classList.add('circle');
+ return ripple;
+ }
+
+ };
+
+ /** @polymerBehavior Polymer.PaperInkyFocusBehavior */
+ Polymer.PaperInkyFocusBehavior = [
+ Polymer.IronButtonState,
+ Polymer.IronControlState,
+ Polymer.PaperRippleBehavior,
+ Polymer.PaperInkyFocusBehaviorImpl
+ ];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-ripple-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-ripple-behavior.html
new file mode 100644
index 00000000000..1d63b75e89f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-behaviors/paper-ripple-behavior.html
@@ -0,0 +1,130 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-ripple/paper-ripple.html">
+
+<script>
+
+ /**
+ * `Polymer.PaperRippleBehavior` dynamically implements a ripple
+ * when the element has focus via pointer or keyboard.
+ *
+ * NOTE: This behavior is intended to be used in conjunction with and after
+ * `Polymer.IronButtonState` and `Polymer.IronControlState`.
+ *
+ * @polymerBehavior Polymer.PaperRippleBehavior
+ */
+ Polymer.PaperRippleBehavior = {
+
+ properties: {
+ /**
+ * If true, the element will not produce a ripple effect when interacted
+ * with via the pointer.
+ */
+ noink: {
+ type: Boolean,
+ observer: '_noinkChanged'
+ },
+
+ /**
+ * @type {Element|undefined}
+ */
+ _rippleContainer: {
+ type: Object,
+ }
+ },
+
+ /**
+ * Ensures a `<paper-ripple>` element is available when the element is
+ * focused.
+ */
+ _buttonStateChanged: function() {
+ if (this.focused) {
+ this.ensureRipple();
+ }
+ },
+
+ /**
+ * In addition to the functionality provided in `IronButtonState`, ensures
+ * a ripple effect is created when the element is in a `pressed` state.
+ */
+ _downHandler: function(event) {
+ Polymer.IronButtonStateImpl._downHandler.call(this, event);
+ if (this.pressed) {
+ this.ensureRipple(event);
+ }
+ },
+
+ /**
+ * Ensures this element contains a ripple effect. For startup efficiency
+ * the ripple effect is dynamically on demand when needed.
+ * @param {!Event=} optTriggeringEvent (optional) event that triggered the
+ * ripple.
+ */
+ ensureRipple: function(optTriggeringEvent) {
+ if (!this.hasRipple()) {
+ this._ripple = this._createRipple();
+ this._ripple.noink = this.noink;
+ var rippleContainer = this._rippleContainer || this.root;
+ if (rippleContainer) {
+ Polymer.dom(rippleContainer).appendChild(this._ripple);
+ }
+ if (optTriggeringEvent) {
+ // Check if the event happened inside of the ripple container
+ // Fall back to host instead of the root because distributed text
+ // nodes are not valid event targets
+ var domContainer = Polymer.dom(this._rippleContainer || this);
+ var target = Polymer.dom(optTriggeringEvent).rootTarget;
+ if (domContainer.deepContains( /** @type {Node} */(target))) {
+ this._ripple.uiDownAction(optTriggeringEvent);
+ }
+ }
+ }
+ },
+
+ /**
+ * Returns the `<paper-ripple>` element used by this element to create
+ * ripple effects. The element's ripple is created on demand, when
+ * necessary, and calling this method will force the
+ * ripple to be created.
+ */
+ getRipple: function() {
+ this.ensureRipple();
+ return this._ripple;
+ },
+
+ /**
+ * Returns true if this element currently contains a ripple effect.
+ * @return {boolean}
+ */
+ hasRipple: function() {
+ return Boolean(this._ripple);
+ },
+
+ /**
+ * Create the element's ripple effect via creating a `<paper-ripple>`.
+ * Override this method to customize the ripple element.
+ * @return {!PaperRippleElement} Returns a `<paper-ripple>` element.
+ */
+ _createRipple: function() {
+ return /** @type {!PaperRippleElement} */ (
+ document.createElement('paper-ripple'));
+ },
+
+ _noinkChanged: function(noink) {
+ if (this.hasRipple()) {
+ this._ripple.noink = noink;
+ }
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-button/.bower.json
new file mode 100644
index 00000000000..fae79a51e8b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/.bower.json
@@ -0,0 +1,50 @@
+{
+ "name": "paper-button",
+ "version": "1.0.12",
+ "description": "Material design button",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "button"
+ ],
+ "main": "paper-button.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-button.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-button",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-material": "PolymerElements/paper-material#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "_release": "1.0.12",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.12",
+ "commit": "96c3a2661c355223d0b41e1d34126f9c62d544dc"
+ },
+ "_source": "git://github.com/PolymerElements/paper-button.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-button"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-button/.travis.yml
new file mode 100644
index 00000000000..070e3e5403b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: geFs7Ipj7/9knSKT2FEYAB7b/zbmgWFXCgZm7cEcrG71EX/HB1do3spANGOlRly77xaZtNNF1OGYBHIP36DSyMEHRYj6TYtTrPIr2ySeHvoOv0nzYakXdscxBvfI5HJrNiFpld80KoGl8vKfroLNpVLallgumX3diydypolvW1I=
+ - secure: IILEhg3m49exN5hpxbPP1JA/q+s4v/QpOMbDiXVRV4Uz1XwOPGLCyrAB0ENjwzMCyeOah1Z2MyQSUiPisLheHKvZifhviNqizWN//8EDkg1gkU0R6egGdotD5mBb3UpCD0CNZ8+D0FYwOpdCWCruwr7N+zDUN+6r5H07KP/VeUU=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-button/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-button/README.md
new file mode 100644
index 00000000000..3bf90b5eaec
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/README.md
@@ -0,0 +1,94 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-button.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-button)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-button)_
+
+
+##&lt;paper-button&gt;
+
+Material design: [Buttons](https://www.google.com/design/spec/components/buttons.html)
+
+`paper-button` is a button. When the user touches the button, a ripple effect emanates
+from the point of contact. It may be flat or raised. A raised button is styled with a
+shadow.
+
+Example:
+
+```html
+<paper-button>Flat button</paper-button>
+<paper-button raised>Raised button</paper-button>
+<paper-button noink>No ripple effect</paper-button>
+<paper-button toggles>Toggle-able button</paper-button>
+```
+
+A button that has `toggles` true will remain `active` after being clicked (and
+will have an `active` attribute set). For more information, see the `Polymer.IronButtonState`
+behavior.
+
+You may use custom DOM in the button body to create a variety of buttons. For example, to
+create a button with an icon and some text:
+
+```html
+<paper-button>
+ <iron-icon icon="favorite"></iron-icon>
+ custom button content
+</paper-button>
+```
+
+To use `paper-button` as a link, wrap it in an anchor tag. Since `paper-button` will already
+receive focus, you may want to prevent the anchor tag from receiving focus as well by setting
+its tabindex to -1.
+
+```html
+<a href="https://www.polymer-project.org/" tabindex="-1">
+ <paper-button raised>Polymer Project</paper-button>
+</a>
+```
+
+### Styling
+
+Style the button with CSS as you would a normal DOM element.
+
+```css
+paper-button.fancy {
+ background: green;
+ color: yellow;
+}
+
+paper-button.fancy:hover {
+ background: lime;
+}
+
+paper-button[disabled],
+paper-button[toggles][active] {
+ background: red;
+}
+```
+
+By default, the ripple is the same color as the foreground at 25% opacity. You may
+customize the color using the `--paper-button-ink-color` custom property.
+
+The following custom properties and mixins are also available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-button-ink-color` | Background color of the ripple | `Based on the button's color` |
+| `--paper-button` | Mixin applied to the button | `{}` |
+| `--paper-button-disabled` | Mixin applied to the disabled button. Note that you can also use the `paper-button[disabled]` selector | `{}` |
+| `--paper-button-flat-keyboard-focus` | Mixin applied to a flat button after it's been focused using the keyboard | `{}` |
+| `--paper-button-raised-keyboard-focus` | Mixin applied to a raised button after it's been focused using the keyboard | `{}` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-button/bower.json
new file mode 100644
index 00000000000..71a919d013c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "paper-button",
+ "version": "1.0.12",
+ "description": "Material design button",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "button"
+ ],
+ "main": "paper-button.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-button.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-button",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-material": "PolymerElements/paper-material#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-button/demo/index.html
new file mode 100644
index 00000000000..c2130909f33
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/demo/index.html
@@ -0,0 +1,138 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-button demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../paper-button.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ .vertical-section-container {
+ max-width: 500px;
+ }
+ paper-button {
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Buttons can be flat, raised, toggleable, or disabled</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button>link</paper-button>
+ <paper-button raised>raised</paper-button>
+ <paper-button toggles raised>toggles</paper-button>
+ <paper-button disabled>disabled</paper-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can have icons</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button><iron-icon icon="check"></iron-icon>link</paper-button>
+ <paper-button raised><iron-icon icon="file-download"></iron-icon>raised</paper-button>
+ <paper-button toggles raised><iron-icon icon="favorite"></iron-icon>toggles</paper-button>
+ <paper-button disabled><iron-icon icon="block"></iron-icon>disabled</paper-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can hide the ripple effect using the <i>noink</i> attribute</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button noink>link</paper-button>
+ <paper-button raised noink>raised</paper-button>
+ <paper-button toggles raised noink>toggles</paper-button>
+ <paper-button disabled noink>disabled</paper-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can be styled using custom properties</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button class="custom pink">link</paper-button>
+ <paper-button raised class="custom indigo">raised</paper-button>
+ <paper-button toggles raised class="custom green">toggles</paper-button>
+ <paper-button disabled class="custom disabled">disabled</paper-button>
+
+ <style is="custom-style">
+ paper-button.custom {
+ --paper-button-ink-color: var(--paper-pink-a200);
+ /* These could also be individually defined for each of the
+ specific css classes, but we'll just do it once as an example */
+ --paper-button-flat-keyboard-focus: {
+ background-color: var(--paper-pink-a200);
+ color: white !important;
+ };
+ --paper-button-raised-keyboard-focus: {
+ background-color: var(--paper-pink-a200) !important;
+ color: white !important;
+ };
+ }
+ paper-button.custom:hover {
+ background-color: var(--paper-indigo-100);
+ }
+ paper-button.pink {
+ color: var(--paper-pink-a200);
+
+ }
+ paper-button.indigo {
+ background-color: var(--paper-indigo-500);
+ color: white;
+ --paper-button-raised-keyboard-focus: {
+ background-color: var(--paper-pink-a200) !important;
+ color: white !important;
+ };
+ }
+ paper-button.green {
+ background-color: var(--paper-green-500);
+ color: white;
+ }
+ paper-button.green[active] {
+ background-color: var(--paper-red-500);
+ }
+ paper-button.disabled {
+ color: white;
+ }
+ </style>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can be used as a link</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <a href="https://www.polymer-project.org/" tabindex="-1">
+ <paper-button raised>Polymer Project</paper-button>
+ </a>
+ <style>
+ a paper-button,
+ a:active paper-button,
+ a:visited paper-button {
+ color: #000;
+ }
+ </style>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-button/index.html
new file mode 100644
index 00000000000..487bb5c38a5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/index.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-button/paper-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-button/paper-button.html
new file mode 100644
index 00000000000..bf3b083b740
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-button/paper-button.html
@@ -0,0 +1,178 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-behaviors/paper-button-behavior.html">
+<link rel="import" href="../paper-material/paper-material.html">
+
+<!--
+Material design: [Buttons](https://www.google.com/design/spec/components/buttons.html)
+
+`paper-button` is a button. When the user touches the button, a ripple effect emanates
+from the point of contact. It may be flat or raised. A raised button is styled with a
+shadow.
+
+Example:
+
+ <paper-button>Flat button</paper-button>
+ <paper-button raised>Raised button</paper-button>
+ <paper-button noink>No ripple effect</paper-button>
+ <paper-button toggles>Toggle-able button</paper-button>
+
+A button that has `toggles` true will remain `active` after being clicked (and
+will have an `active` attribute set). For more information, see the `Polymer.IronButtonState`
+behavior.
+
+You may use custom DOM in the button body to create a variety of buttons. For example, to
+create a button with an icon and some text:
+
+ <paper-button>
+ <iron-icon icon="favorite"></iron-icon>
+ custom button content
+ </paper-button>
+
+To use `paper-button` as a link, wrap it in an anchor tag. Since `paper-button` will already
+receive focus, you may want to prevent the anchor tag from receiving focus as well by setting
+its tabindex to -1.
+
+ <a href="https://www.polymer-project.org/" tabindex="-1">
+ <paper-button raised>Polymer Project</paper-button>
+ </a>
+
+### Styling
+
+Style the button with CSS as you would a normal DOM element.
+
+ paper-button.fancy {
+ background: green;
+ color: yellow;
+ }
+
+ paper-button.fancy:hover {
+ background: lime;
+ }
+
+ paper-button[disabled],
+ paper-button[toggles][active] {
+ background: red;
+ }
+
+By default, the ripple is the same color as the foreground at 25% opacity. You may
+customize the color using the `--paper-button-ink-color` custom property.
+
+The following custom properties and mixins are also available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-button-ink-color` | Background color of the ripple | `Based on the button's color`
+`--paper-button` | Mixin applied to the button | `{}`
+`--paper-button-disabled` | Mixin applied to the disabled button. Note that you can also use the `paper-button[disabled]` selector | `{}`
+`--paper-button-flat-keyboard-focus` | Mixin applied to a flat button after it's been focused using the keyboard | `{}`
+`--paper-button-raised-keyboard-focus` | Mixin applied to a raised button after it's been focused using the keyboard | `{}`
+
+@demo demo/index.html
+-->
+
+<dom-module id="paper-button">
+ <template strip-whitespace>
+ <style include="paper-material">
+ :host {
+ @apply(--layout-inline);
+ @apply(--layout-center-center);
+ position: relative;
+ box-sizing: border-box;
+ min-width: 5.14em;
+ margin: 0 0.29em;
+ background: transparent;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-tap-highlight-color: transparent;
+ font: inherit;
+ text-transform: uppercase;
+ outline-width: 0;
+ border-radius: 3px;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ z-index: 0;
+ padding: 0.7em 0.57em;
+
+ @apply(--paper-font-common-base);
+ @apply(--paper-button);
+ }
+
+ :host([raised].keyboard-focus) {
+ font-weight: bold;
+ @apply(--paper-button-raised-keyboard-focus);
+ }
+
+ :host(:not([raised]).keyboard-focus) {
+ font-weight: bold;
+ @apply(--paper-button-flat-keyboard-focus);
+ }
+
+ :host([disabled]) {
+ background: #eaeaea;
+ color: #a8a8a8;
+ cursor: auto;
+ pointer-events: none;
+
+ @apply(--paper-button-disabled);
+ }
+
+ paper-ripple {
+ color: var(--paper-button-ink-color);
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-button',
+
+ behaviors: [
+ Polymer.PaperButtonBehavior
+ ],
+
+ properties: {
+ /**
+ * If true, the button should be styled with a shadow.
+ */
+ raised: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false,
+ observer: '_calculateElevation'
+ }
+ },
+
+ _calculateElevation: function() {
+ if (!this.raised) {
+ this._setElevation(0);
+ } else {
+ Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
+ }
+ }
+
+ /**
+ Fired when the animation finishes.
+ This is useful if you want to wait until
+ the ripple animation finishes to perform some action.
+
+ @event transitionend
+ Event param: {{node: Object}} detail Contains the animated node.
+ */
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-card/.travis.yml
new file mode 100755
index 00000000000..dd8f99e33b9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: KuASkT/4CBzdndyZ91e/plGIXpvostP2XOjiVc+Uwpfgu4ktzPdGxZS18NowS5sp0eXhQQRxtON28P4+xNcCULQ6gUe6HYErZUY9ijWEvYRdnt8HZyywZZpI4H1ZlXGFnCmsTvOI9azSaw56AwWnN7buVnEK0k7BHvnuofTs8qpcgZR3P7cMjoT/jcxu+S+nfO/hrsFBRwjw8vT1AitHp/tVTzLoiv26noLcPm3k8fQaAAVKWtioFlUV50fBCbCfDkbPwUMTlZiQxhVHbYxwNfPzgoJp+ETtJpS3VApXAClKWg4CvAinf3kVQI8cw6AG4hnaz9IRNnkwPUviQXrojb3QjZI14MRdTS+hjwGM7FypX3ZzKw2ttAGHLquJZKTX4G7Yh2LsWRvzzKPv4J/DIBKsGbxwgcHf71KSoPKY6pLqlAF74rcAb3MeahmeYT98gxmr1Bs9tKjR5/iw8knEqPa2K4KUTr2iv+qqkpoiQZOx5IM6niLv4IcAIlaYzJQTL/IuFSJ5/vAYk7B3GiBxtGfmh2C7Kc0xlNIwbYMqtI4vwOSGCUXPhnrxqvuD2ffGLgO+8jbGK37k3T4egbCc5ekA01I7faMK+hOrTyrIx6rwwvCuuoTPrqwCGE3en7oovzRBw3TzuD+HyixTYA6Q1AOTKH57qXPTInRh9YO220w=
+ - secure: xPkO7EnyvasJh1KedwftJzAx9kcxV0f+lmIvUIJyGCAvBhrdGrIuWDzTzYu9iZnTcRJKIN6FBd8pimUxs3LEY8QNl/eZ+iLqNstKCdzHKvkHhn9M4cBOyKo4+iI7z7mBmw1+qDBEC6hJ6Wr097ojF9IonAQqvXYXbbm5QLujThuY3tPviRUQuBWOSG8PVIcOtt+ExvjsRhqo7hS2hlxeSHcGiBNtWsCXdI+wFBPBCu0mXwZnOvpIrTapPyhm97NzDJmgb5/SPuZmiXAACjRPWQKAemHLyhBBvq4RFpDZQvQaNEiGeurF2pCwtQ1G3XfuWhlAE+hp0dSluOrRFPrqiLjtuk7sXrDTt8MzfA1lwksWr7o/05H37sk5Ay3Un25jmWz1ZYjn0Fzpgm73ycgljQqaeizl05Q0YVtNbv8asKFbZ4qAs/MXFcubw6z7LxjS7bEiSAT5P2SLQbKUI3hYsT1LbqZNAKTZw4zgPyS/kOq1MSTgILy3c5R4vSi3P8/dn72lqvmXveRH2EchQPwO+kwvPcQ1NWqwAUj1FNtvsc6ahBsJ9JQLl3Yo8/nIp/ssg0OtgqTOmm0f3RQ5Jzbg65iRguKqCpq1CKaXmIH2zlVUBW2NQpqc/bwulbYHMjR1dV+T3WbpRJ1X6g7WazsS1NZVzNB/qw+kTZ6SFA+8VHM=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-card/CONTRIBUTING.md
new file mode 100755
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-card/README.md
new file mode 100755
index 00000000000..94466db7745
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/README.md
@@ -0,0 +1,65 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-card.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-card.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-card)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-card)_
+
+
+##&lt;paper-card&gt;
+
+Material design: [Cards](https://www.google.com/design/spec/components/cards.html)
+
+`paper-card` is a container with a drop shadow.
+
+Example:
+
+```html
+<paper-card heading="Card Title">
+ <div class="card-content">Some content</div>
+ <div class="card-actions">
+ <paper-button>Some action</paper-button>
+ </div>
+</paper-card>
+```
+
+Example - top card image:
+
+```html
+<paper-card heading="Card Title" image="/path/to/image.png">
+ ...
+</paper-card>
+```
+
+### Accessibility
+
+By default, the `aria-label` will be set to the value of the `heading` attribute.
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-card-background-color` | The background color of the card | `--primary-background-color` |
+| `--paper-card-header-color` | The color of the header text | `#000` |
+| `--paper-card-header` | Mixin applied to the card header section | `{}` |
+| `--paper-card-header-text` | Mixin applied to the title in the card header section | `{}` |
+| `--paper-card-header-image` | Mixin applied to the image in the card header section | `{}` |
+| `--paper-card-header-image-text` | Mixin applied to the text overlapping the image in the card header section | `{}` |
+| `--paper-card-content` | Mixin applied to the card content section | `{}` |
+| `--paper-card-actions` | Mixin applied to the card action section | `{}` |
+| `--paper-card` | Mixin applied to the card | `{}` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-card/bower.json
new file mode 100755
index 00000000000..b17e3fa85c4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "paper-card",
+ "version": "1.1.1",
+ "description": "Material design piece of paper with unique related data",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "card"
+ ],
+ "main": "paper-card.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-card.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-card",
+ "ignore": [],
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-image": "PolymerElements/iron-image#^1.2.0",
+ "paper-material": "PolymerElements/paper-material#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.1.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-collapse": "PolymerElements/iron-collapse#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/cafe.png b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/cafe.png
new file mode 100644
index 00000000000..a3dc6a8a8ae
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/cafe.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/donuts.png b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/donuts.png
new file mode 100644
index 00000000000..5f668800d41
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/donuts.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/house.png b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/house.png
new file mode 100644
index 00000000000..a7f1c24e82b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/house.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/index.html
new file mode 100755
index 00000000000..c4dfbe99e4b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/index.html
@@ -0,0 +1,323 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html lang="en">
+<head>
+ <title>paper-card demo</title>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <link rel="import" href="../../iron-collapse/iron-collapse.html">
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../iron-icons/communication-icons.html">
+ <link rel="import" href="../../iron-icons/hardware-icons.html">
+ <link rel="import" href="../../iron-icons/social-icons.html">
+ <link rel="import" href="../../iron-flex-layout/iron-flex-layout.html">
+ <link rel="import" href="../../paper-button/paper-button.html">
+ <link rel="import" href="../../paper-checkbox/paper-checkbox.html">
+ <link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../paper-styles/typography.html">
+ <link rel="import" href="../paper-card.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ demo-snippet {
+ --demo-snippet-demo: {
+ background: var(--paper-grey-200);
+ padding: 8px;
+ };
+ --demo-snippet-code: {
+ max-height: 300px;
+ };
+ }
+
+ paper-card {
+ width: 100%;
+ }
+
+ .horizontal {
+ @apply(--layout-horizontal);
+ }
+
+ .justified {
+ @apply(--layout-justified);
+ }
+
+ .amber {
+ background: var(--paper-amber-900);
+ }
+
+ .lime {
+ background: var(--paper-lime-500);
+ }
+
+ .cyan {
+ background: var(--paper-cyan-500);
+ }
+
+ .dark {
+ background: var(--paper-blue-grey-500);
+ }
+ paper-card.dark, paper-card.amber, paper-card.lime, paper-card.cyan {
+ color: white;
+ --paper-card-header-color: white;
+ }
+
+ paper-checkbox {
+ display: block;
+ margin-bottom: 4px;
+ --paper-checkbox-label-color: white;
+ --paper-checkbox-unchecked-color: white;
+ }
+
+ paper-icon-button {
+ color: var(--paper-grey-600);
+ }
+
+ paper-icon-button.white {
+ color: white !important;
+ }
+ </style>
+
+</head>
+<body unresolved>
+ <body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>A paper-card with a simple heading, header image, body content, and actions</h3>
+ <demo-snippet>
+ <template>
+ <paper-card heading="Emmental" image="http://placehold.it/350x150/FFC107/000000">
+ <div class="card-content">
+ Emmentaler or Emmental is a yellow, medium-hard cheese that originated in the area around Emmental, Switzerland. It is one of the cheeses of Switzerland, and is sometimes known as Swiss cheese.
+ </div>
+ <div class="card-actions">
+ <paper-button>Share</paper-button>
+ <paper-button>Explore!</paper-button>
+ </div>
+ </paper-card>
+ </template>
+ </demo-snippet>
+
+ <h3>Paper-cards can contain advanced content</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .cafe-header { @apply(--paper-font-headline); }
+ .cafe-light { color: var(--paper-grey-600); }
+ .cafe-location {
+ float: right;
+ font-size: 15px;
+ vertical-align: middle;
+ }
+ .cafe-reserve { color: var(--google-blue-500); }
+ iron-icon.star {
+ --iron-icon-width: 16px;
+ --iron-icon-height: 16px;
+ color: var(--paper-amber-500);
+ }
+ iron-icon.star:last-of-type { color: var(--paper-grey-500); }
+ </style>
+ <paper-card image="./donuts.png">
+ <div class="card-content">
+ <div class="cafe-header">Cafe Basilico
+ <div class="cafe-location cafe-light">
+ <iron-icon icon="communication:location-on"></iron-icon>
+ <span>250ft</span>
+ </div>
+ </div>
+ <div class="cafe-rating">
+ <iron-icon class="star" icon="star"></iron-icon>
+ <iron-icon class="star" icon="star"></iron-icon>
+ <iron-icon class="star" icon="star"></iron-icon>
+ <iron-icon class="star" icon="star"></iron-icon>
+ <iron-icon class="star" icon="star"></iron-icon>
+ </div>
+ <p>$・Italian, Cafe</p>
+ <p class="cafe-light">Small plates, salads &amp; sandwiches in an intimate setting with 12 indoor seats plus patio seating.</p>
+ </div>
+ <div class="card-actions">
+ <p>Tonight's availability</p>
+ <div class="horizontal justified">
+ <paper-icon-button icon="icons:event"></paper-icon-button>
+ <paper-button>5:30PM</paper-button>
+ <paper-button>7:30PM</paper-button>
+ <paper-button>9:00PM</paper-button>
+ </div>
+ <paper-button class="cafe-reserve">Reserve</paper-button>
+ </div>
+ </paper-card>
+ </template>
+ </demo-snippet>
+
+ <h3>Paper-cards can have a horizontal image</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ paper-card.rate { @apply(--layout-horizontal); }
+ .rate-image {
+ width: 100px;
+ height: 170px;
+ background: url('./donuts.png');
+ background-size: cover;
+ }
+ .rate-content {
+ @apply(--layout-flex);
+ float: left;
+ }
+ .rate-header { @apply(--paper-font-headline); }
+ .rate-name { color: var(--paper-grey-600); margin: 10px 0; }
+ paper-icon-button.rate-icon {
+ --iron-icon-fill-color: white;
+ --iron-icon-stroke-color: var(--paper-grey-600);
+ }
+ </style>
+ <paper-card class="rate">
+ <div class="rate-content">
+ <div class="card-content">
+ <div class="rate-header">Rate this album</div>
+ <div class="rate-name">Mac Miller</div>
+ <div>Live from space</div>
+ </div>
+ <div class="card-actions">
+ <paper-icon-button class="rate-icon" icon="star"></paper-icon-button>
+ <paper-icon-button class="rate-icon" icon="star"></paper-icon-button>
+ <paper-icon-button class="rate-icon" icon="star"></paper-icon-button>
+ <paper-icon-button class="rate-icon" icon="star"></paper-icon-button>
+ <paper-icon-button class="rate-icon" icon="star"></paper-icon-button>
+ </div>
+ </div>
+ <div class="rate-image"></div>
+ </paper-card>
+ </template>
+ </demo-snippet>
+
+ <h3>Paper-cards can have expanded supporting text</h3>
+ <demo-snippet>
+ <template>
+ <paper-card heading="Top western road trips" image="./trip.png" class="white">
+ <div class="card-content">1,000 miles of wonder</div>
+ <div class="card-actions">
+ <paper-button>Share</paper-button>
+ <paper-button>Explore</paper-button>
+ <paper-icon-button
+ icon="hardware:keyboard-arrow-up"
+ title="more info"
+ onclick="_toggle()"
+ style="float:right;">
+ </paper-icon-button>
+ <iron-collapse id="more-info" style="width:100%;">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent enim ante, tempus eget volutpat ac, cursus ac ante. Nulla facilisi. Praesent sed lacinia ligula. Donec malesuada nisl eget quam iaculis, vel placerat justo cursus.
+ </iron-collapse>
+ <script>
+ function _toggle() {
+ var moreInfo = document.getElementById('more-info');
+ var iconButton = Polymer.dom(event).localTarget;
+ iconButton.icon = moreInfo.opened ? 'hardware:keyboard-arrow-up'
+ : 'hardware:keyboard-arrow-down';
+ moreInfo.toggle();
+ }
+ </script>
+ </div>
+ </paper-card>
+ </template>
+ </demo-snippet>
+
+ <h3>Paper-cards can be organized in different collections</h3>
+
+ <h3>Same layout, different content</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ paper-card.white {
+ --paper-card-header-color: #fff;
+ }
+ </style>
+ <paper-card heading="Pre-fab homes" image="./house.png" class="white" style="margin-bottom:8px;">
+ <div class="card-actions">
+ <paper-icon-button icon="favorite"></paper-icon-button>
+ <paper-icon-button icon="bookmark"></paper-icon-button>
+ <paper-icon-button icon="social:share"></paper-icon-button>
+ </div>
+ </paper-card>
+ <div class="horizontal">
+ <paper-card heading="Favorite trips" image="./trip.png" class="white" style="margin-right:4px;">
+ <div class="card-actions horizontal justified">
+ <paper-icon-button icon="favorite"></paper-icon-button>
+ <paper-icon-button icon="bookmark"></paper-icon-button>
+ <paper-icon-button icon="social:share"></paper-icon-button>
+ </div>
+ </paper-card>
+ <paper-card heading="Best airlines" image="./travel.png" class="white" style="margin-left:4px;">
+ <div class="card-actions horizontal justified">
+ <paper-icon-button icon="favorite"></paper-icon-button>
+ <paper-icon-button icon="bookmark"></paper-icon-button>
+ <paper-icon-button icon="social:share"></paper-icon-button>
+ </div>
+ </paper-card>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>Different layout and content</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ #notes {
+ @apply(--layout-vertical);
+ @apply(--layout-wrap);
+ height: 344px;
+ width: 384px;
+ }
+
+ #notes > paper-card {
+ box-sizing: border-box;
+ max-width: 184px;
+ margin: 4px;
+ flex: 0 0 auto;
+ }
+ </style>
+ <div id="notes">
+ <paper-card heading="Call Jennifer" class="cyan">
+ <div class="card-actions">
+ <paper-icon-button icon="communication:call" style="color:white;"></paper-icon-button>
+ <span>March 19, 2017</span>
+ </div>
+ </paper-card>
+ <paper-card class="dark">
+ <div class="card-content">
+ <p>Groceries:</p>
+ <paper-checkbox>almond milk</paper-checkbox>
+ <paper-checkbox>coconut water</paper-checkbox>
+ <paper-checkbox>cheese</paper-checkbox>
+ <paper-checkbox>green apples</paper-checkbox>
+ </div>
+ <div class="card-actions">
+ <paper-icon-button icon="communication:location-on" style="color:white"></paper-icon-button>
+ <span>Campbell</span>
+ </div>
+ </paper-card>
+ <paper-card heading="clean desk" class="lime"></paper-card>
+ <paper-card image="./donuts.png" class="amber">
+ <div class="card-content">New cafe opened on Valencia St.</div>
+ </paper-card>
+ <paper-card heading="Yuna tickets on sale 6/24" class="cyan">
+ </paper-card>
+ </div>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/travel.png b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/travel.png
new file mode 100644
index 00000000000..7d8e8215877
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/travel.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/trip.png b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/trip.png
new file mode 100644
index 00000000000..746d0b304d9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/demo/trip.png
Binary files differ
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-card/index.html
new file mode 100755
index 00000000000..fab428a1d1c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <title>paper-card</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+<iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-card/paper-card.html b/chromium/third_party/catapult/third_party/polymer/components/paper-card/paper-card.html
new file mode 100755
index 00000000000..20c462c4445
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-card/paper-card.html
@@ -0,0 +1,226 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../iron-image/iron-image.html">
+<link rel="import" href="../paper-material/paper-material.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<!--
+Material design: [Cards](https://www.google.com/design/spec/components/cards.html)
+
+`paper-card` is a container with a drop shadow.
+
+Example:
+
+ <paper-card heading="Card Title">
+ <div class="card-content">Some content</div>
+ <div class="card-actions">
+ <paper-button>Some action</paper-button>
+ </div>
+ </paper-card>
+
+Example - top card image:
+
+ <paper-card heading="Card Title" image="/path/to/image.png">
+ ...
+ </paper-card>
+
+### Accessibility
+
+By default, the `aria-label` will be set to the value of the `heading` attribute.
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-card-background-color` | The background color of the card | `--primary-background-color`
+`--paper-card-header-color` | The color of the header text | `#000`
+`--paper-card-header` | Mixin applied to the card header section | `{}`
+`--paper-card-header-text` | Mixin applied to the title in the card header section | `{}`
+`--paper-card-header-image` | Mixin applied to the image in the card header section | `{}`
+`--paper-card-header-image-text` | Mixin applied to the text overlapping the image in the card header section | `{}`
+`--paper-card-content` | Mixin applied to the card content section| `{}`
+`--paper-card-actions` | Mixin applied to the card action section | `{}`
+`--paper-card` | Mixin applied to the card | `{}`
+
+@group Paper Elements
+@element paper-card
+@demo demo/index.html
+-->
+
+<dom-module id="paper-card">
+ <template>
+ <style include="paper-material">
+ :host {
+ display: inline-block;
+ position: relative;
+ box-sizing: border-box;
+ background-color: var(--paper-card-background-color, --primary-background-color);
+ border-radius: 2px;
+
+ @apply(--paper-font-common-base);
+ @apply(--paper-card);
+ }
+
+ /* IE 10 support for HTML5 hidden attr */
+ [hidden] {
+ display: none !important;
+ }
+
+ .header {
+ position: relative;
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+ overflow: hidden;
+
+ @apply(--paper-card-header);
+ }
+
+ .header iron-image {
+ display: block;
+ width: 100%;
+ --iron-image-width: 100%;
+ pointer-events: none;
+
+ @apply(--paper-card-header-image);
+ }
+
+ .header .title-text {
+ padding: 16px;
+ font-size: 24px;
+ font-weight: 400;
+ color: var(--paper-card-header-color, #000);
+
+ @apply(--paper-card-header-text);
+ }
+
+ .header .title-text.over-image {
+ position: absolute;
+ bottom: 0px;
+
+ @apply(--paper-card-header-image-text);
+ }
+
+ :host ::content .card-content {
+ padding: 16px;
+ position:relative;
+
+ @apply(--paper-card-content);
+ }
+
+ :host ::content .card-actions {
+ border-top: 1px solid #e8e8e8;
+ padding: 5px 16px;
+ position:relative;
+
+ @apply(--paper-card-actions);
+ }
+ </style>
+
+ <div class="header">
+ <iron-image hidden$="[[!image]]" src="[[image]]" preload$="[[preloadImage]]" fade$="[[fadeImage]]"></iron-image>
+ <div hidden$="[[!heading]]" class$="[[_computeHeadingClass(image)]]">[[heading]]</div>
+ </div>
+
+ <content></content>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-card',
+
+ properties: {
+ /**
+ * The title of the card.
+ */
+ heading: {
+ type: String,
+ value: '',
+ observer: '_headingChanged'
+ },
+
+ /**
+ * The url of the title image of the card.
+ */
+ image: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * When `true`, any change to the image url property will cause the
+ * `placeholder` image to be shown until the image is fully rendered.
+ */
+ preloadImage: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * When `preloadImage` is true, setting `fadeImage` to true will cause the
+ * image to fade into place.
+ */
+ fadeImage: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The z-depth of the card, from 0-5.
+ */
+ elevation: {
+ type: Number,
+ value: 1,
+ reflectToAttribute: true
+ },
+
+ /**
+ * Set this to true to animate the card shadow when setting a new
+ * `z` value.
+ */
+ animatedShadow: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Read-only property used to pass down the `animatedShadow` value to
+ * the underlying paper-material style (since they have different names).
+ */
+ animated: {
+ type: Boolean,
+ reflectToAttribute: true,
+ readOnly: true,
+ computed: '_computeAnimated(animatedShadow)'
+ }
+ },
+
+ _headingChanged: function(heading) {
+ var label = this.getAttribute('aria-label');
+ this.setAttribute('aria-label', heading);
+ },
+
+ _computeHeadingClass: function(image) {
+ var cls = 'title-text';
+ if (image)
+ cls += ' over-image';
+ return cls;
+ },
+
+ _computeAnimated: function(animatedShadow) {
+ return animatedShadow;
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.bower.json
new file mode 100644
index 00000000000..1aa393b5604
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.bower.json
@@ -0,0 +1,49 @@
+{
+ "name": "paper-dialog-behavior",
+ "version": "1.2.7",
+ "description": "Implements a behavior used for material design dialogs",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "dialog",
+ "overlay",
+ "behavior"
+ ],
+ "main": "paper-dialog-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dialog-behavior"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dialog-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.1.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-listbox": "PolymerElements/paper-listbox#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.2.7",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.7",
+ "commit": "decc77ca55c0381cf01d7409ddf1eb966543e84e"
+ },
+ "_source": "git://github.com/PolymerElements/paper-dialog-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-dialog-behavior"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.travis.yml
new file mode 100644
index 00000000000..7319854afdb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: ZBrrZGA8OWY95x8yHSsKUNrQfowhRe/s/pMZhHgnoppnZ1+bDfpoms+ggOdvH0TgURAAdF+1Wq1mTCgNp0FYLJ3Oe34XseDIxiA3wXSQO/E2m4Cfj/w4fRvaSy8ikdz5urQJET33SjDKdggm1FmWmnt6vSVgW/mg8M7AW2KWDcE=
+ - secure: P5UKkTar39Q1k0VwtF5LhOphqNiW3r+DSnN1vRNA4oKZPrt6l3dJE1hpA9+1x1m6SryG856lLekPM6/fVZuC7nyDKFLz4vU/EWhiGdyWN1lHhE2MDh281TsCtzK56S0uJxdmlIpSiWTFWIrrEiiewN2b8dXy3FSPfy0Fo1sGn54=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/README.md
new file mode 100644
index 00000000000..ba8acc40913
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/README.md
@@ -0,0 +1,54 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-dialog-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-dialog-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-dialog-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-dialog-behavior)_
+
+
+##Polymer.PaperDialogBehavior
+
+Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to implement a Material Design
+dialog.
+
+For example, if `<paper-dialog-impl>` implements this behavior:
+
+```html
+<paper-dialog-impl>
+ <h2>Header</h2>
+ <div>Dialog body</div>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm>Accept</paper-button>
+ </div>
+</paper-dialog-impl>
+```
+
+`paper-dialog-shared-styles.html` provide styles for a header, content area, and an action area for buttons.
+Use the `<h2>` tag for the header and the `buttons` class for the action area. You can use the
+`paper-dialog-scrollable` element (in its own repository) if you need a scrolling content area.
+
+Use the `dialog-dismiss` and `dialog-confirm` attributes on interactive controls to close the
+dialog. If the user dismisses the dialog with `dialog-confirm`, the `closingReason` will update
+to include `confirmed: true`.
+
+### Accessibility
+
+This element has `role="dialog"` by default. Depending on the context, it may be more appropriate
+to override this attribute with `role="alertdialog"`.
+
+If `modal` is set, the element will set `aria-modal` and prevent the focus from exiting the element.
+It will also ensure that focus remains in the dialog.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/bower.json
new file mode 100644
index 00000000000..cbe17d39c00
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/bower.json
@@ -0,0 +1,40 @@
+{
+ "name": "paper-dialog-behavior",
+ "version": "1.2.7",
+ "description": "Implements a behavior used for material design dialogs",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "dialog",
+ "overlay",
+ "behavior"
+ ],
+ "main": "paper-dialog-behavior.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dialog-behavior"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dialog-behavior",
+ "ignore": [],
+ "dependencies": {
+ "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.1.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-listbox": "PolymerElements/paper-listbox#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/index.html
new file mode 100644
index 00000000000..193dddcc2e0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/index.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-dialog-behavior demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="simple-dialog.html">
+
+ <link rel="import" href="../../paper-button/paper-button.html">
+ <link rel="import" href="../../paper-dropdown-menu/paper-dropdown-menu.html">
+ <link rel="import" href="../../paper-item/paper-item.html">
+ <link rel="import" href="../../paper-listbox/paper-listbox.html">
+ <link rel="import" href="../../paper-dialog-scrollable/paper-dialog-scrollable.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles"></style>
+</head>
+<body unresolved class="centered">
+
+ <h3>An element with <code>PaperDialogBehavior</code> can be opened, closed, toggled. Use <code>h2</code> for the title</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button raised onclick="dialog.toggle()">dialog</paper-button>
+ <simple-dialog id="dialog">
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </simple-dialog>
+ </template>
+ </demo-snippet>
+
+ <h3>An element with <code>PaperDialogBehavior</code> can be modal. Use the attributes <code>dialog-dismiss</code> and <code>dialog-confirm</code> on the children to close it.</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button raised onclick="modalAlert.toggle()">modal alert</paper-button>
+ <simple-dialog id="modalAlert" modal role="alertdialog">
+ <h2>Alert</h2>
+ <paper-dropdown-menu label="Draft to discard">
+ <paper-listbox class="dropdown-content">
+ <paper-item>Draft 1</paper-item>
+ <paper-item>Draft 2</paper-item>
+ <paper-item>Draft 3</paper-item>
+ <paper-item>Draft 4</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+ <div class="buttons">
+ <paper-button onclick="modalDetails.toggle()">More details</paper-button>
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm autofocus>Discard</paper-button>
+ </div>
+ </simple-dialog>
+ <simple-dialog id="modalDetails" modal>
+ <h2>Details</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <div class="buttons">
+ <paper-button dialog-confirm autofocus>OK</paper-button>
+ </div>
+ </simple-dialog>
+ </template>
+ </demo-snippet>
+
+ <h3>Use <code>paper-dialog-scrollable</code> for scrolling content</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button raised onclick="scrolling.toggle()">scrolling</paper-button>
+ <simple-dialog id="scrolling">
+ <h2>Scrolling</h2>
+ <paper-dialog-scrollable>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog-scrollable>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm>OK</paper-button>
+ </div>
+ </simple-dialog>
+ </template>
+ </demo-snippet>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/simple-dialog.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/simple-dialog.html
new file mode 100644
index 00000000000..a204372393b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/demo/simple-dialog.html
@@ -0,0 +1,39 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../paper-dialog-behavior.html">
+<link rel="import" href="../paper-dialog-shared-styles.html">
+
+<dom-module id="simple-dialog">
+ <template>
+ <style include="paper-dialog-shared-styles"></style>
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+(function() {
+
+ Polymer({
+
+ is: 'simple-dialog',
+
+ behaviors: [
+ Polymer.PaperDialogBehavior
+ ]
+
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/hero.svg
new file mode 100755
index 00000000000..d47381685f8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/hero.svg
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <g>
+ <polygon points="76.7,98 79.2,98 74,91.1 74,94.4 "/>
+ <polygon points="74,81.4 74,84.7 84.1,98 86.6,98 "/>
+ <polygon points="74,71.7 74,75 91.5,98 94,98 "/>
+ <polygon points="74,62 74,65.3 98.9,98 101.4,98 "/>
+ <polygon points="94.3,79 92,79 92,76 74,52.3 74,55.6 106.2,98 108.7,98 "/>
+ <polygon points="92,69.6 92,66.3 74,42.6 74,45.9 "/>
+ <polygon points="101.7,79 99.2,79 113.6,98 116.1,98 "/>
+ <polygon points="92,59.9 92,56.6 74,32.9 74,36.2 "/>
+ <polygon points="109.1,79 106.5,79 121,98 123.5,98 "/>
+ <polygon points="92,50.2 92,47 92.1,47 77.7,28 75.2,28 "/>
+ <polygon points="116.4,79 113.9,79 128.4,98 130.9,98 "/>
+ <polygon points="97,47 99.5,47 85,28 82.5,28 "/>
+ <polygon points="123.8,79 121.3,79 135.7,98 138.2,98 "/>
+ <polygon points="104.4,47 106.9,47 92.4,28 89.9,28 "/>
+ <polygon points="131.2,79 128.7,79 143.1,98 145.6,98 "/>
+ <polygon points="132,70.4 132,73.7 150,97.4 150,94.1 "/>
+ <polygon points="111.7,47 114.2,47 99.8,28 97.3,28 "/>
+ <polygon points="132,60.7 132,64 150,87.7 150,84.3 "/>
+ <polygon points="119.1,47 121.6,47 107.2,28 104.7,28 "/>
+ <polygon points="132,51 132,54.3 150,77.9 150,74.6 "/>
+ <polygon points="114.6,28 112,28 126.5,47 129,47 "/>
+ <polygon points="121.9,28 119.4,28 150,68.2 150,64.9 "/>
+ <polygon points="129.3,28 126.8,28 150,58.5 150,55.2 "/>
+ <polygon points="136.7,28 134.2,28 150,48.8 150,45.5 "/>
+ <polygon points="144.1,28 141.5,28 150,39.1 150,35.8 "/>
+ <polygon points="150,29.4 150,28 148.9,28 "/>
+ </g>
+ <path d="M133,80H91V46h42V80z M93,78h38V48H93V78z"/>
+ <path d="M151,99H73V27h78V99z M75,97h74V29H75V97z"/>
+ <circle cx="74" cy="28" r="4"/>
+ <circle cx="150" cy="28" r="4"/>
+ <circle cx="150" cy="98" r="4"/>
+ <circle cx="74" cy="98" r="4"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/index.html
new file mode 100644
index 00000000000..af98b85acdc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-dialog-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-behavior.html
new file mode 100644
index 00000000000..6b45ddd1601
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-behavior.html
@@ -0,0 +1,140 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html">
+
+<script>
+
+/**
+Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to implement a Material Design
+dialog.
+
+For example, if `<paper-dialog-impl>` implements this behavior:
+
+ <paper-dialog-impl>
+ <h2>Header</h2>
+ <div>Dialog body</div>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm>Accept</paper-button>
+ </div>
+ </paper-dialog-impl>
+
+`paper-dialog-shared-styles.html` provide styles for a header, content area, and an action area for buttons.
+Use the `<h2>` tag for the header and the `buttons` class for the action area. You can use the
+`paper-dialog-scrollable` element (in its own repository) if you need a scrolling content area.
+
+Use the `dialog-dismiss` and `dialog-confirm` attributes on interactive controls to close the
+dialog. If the user dismisses the dialog with `dialog-confirm`, the `closingReason` will update
+to include `confirmed: true`.
+
+### Accessibility
+
+This element has `role="dialog"` by default. Depending on the context, it may be more appropriate
+to override this attribute with `role="alertdialog"`.
+
+If `modal` is set, the element will prevent the focus from exiting the element.
+It will also ensure that focus remains in the dialog.
+
+@hero hero.svg
+@demo demo/index.html
+@polymerBehavior Polymer.PaperDialogBehavior
+*/
+
+ Polymer.PaperDialogBehaviorImpl = {
+
+ hostAttributes: {
+ 'role': 'dialog',
+ 'tabindex': '-1'
+ },
+
+ properties: {
+
+ /**
+ * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-cancel-on-esc-key` and `with-backdrop`.
+ */
+ modal: {
+ type: Boolean,
+ value: false
+ }
+
+ },
+
+ observers: [
+ '_modalChanged(modal, _readied)'
+ ],
+
+ listeners: {
+ 'tap': '_onDialogClick'
+ },
+
+ ready: function () {
+ // Only now these properties can be read.
+ this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
+ this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
+ this.__prevWithBackdrop = this.withBackdrop;
+ },
+
+ _modalChanged: function(modal, readied) {
+ // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop.
+ // We need to wait for the element to be ready before we can read the
+ // properties values.
+ if (!readied) {
+ return;
+ }
+
+ if (modal) {
+ this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
+ this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
+ this.__prevWithBackdrop = this.withBackdrop;
+ this.noCancelOnOutsideClick = true;
+ this.noCancelOnEscKey = true;
+ this.withBackdrop = true;
+ } else {
+ // If the value was changed to false, let it false.
+ this.noCancelOnOutsideClick = this.noCancelOnOutsideClick &&
+ this.__prevNoCancelOnOutsideClick;
+ this.noCancelOnEscKey = this.noCancelOnEscKey &&
+ this.__prevNoCancelOnEscKey;
+ this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop;
+ }
+ },
+
+ _updateClosingReasonConfirmed: function(confirmed) {
+ this.closingReason = this.closingReason || {};
+ this.closingReason.confirmed = confirmed;
+ },
+
+ /**
+ * Will dismiss the dialog if user clicked on an element with dialog-dismiss
+ * or dialog-confirm attribute.
+ */
+ _onDialogClick: function(event) {
+ // Search for the element with dialog-confirm or dialog-dismiss,
+ // from the root target until this (excluded).
+ var path = Polymer.dom(event).path;
+ for (var i = 0; i < path.indexOf(this); i++) {
+ var target = path[i];
+ if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || target.hasAttribute('dialog-confirm'))) {
+ this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm'));
+ this.close();
+ event.stopPropagation();
+ break;
+ }
+ }
+ }
+
+ };
+
+ /** @polymerBehavior */
+ Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialogBehaviorImpl];
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-common.css b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-common.css
new file mode 100644
index 00000000000..560b0a56aa2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-common.css
@@ -0,0 +1,57 @@
+/*
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+*/
+
+:host {
+ display: block;
+ margin: 24px 40px;
+
+ background: var(--paper-dialog-background-color, --primary-background-color);
+ color: var(--paper-dialog-color, --primary-text-color);
+
+ @apply(--paper-font-body1);
+ @apply(--shadow-elevation-16dp);
+ @apply(--paper-dialog);
+}
+
+:host > ::content > * {
+ margin-top: 20px;
+ padding: 0 24px;
+}
+
+:host > ::content > .no-padding {
+ padding: 0;
+}
+
+:host > ::content > *:first-child {
+ margin-top: 24px;
+}
+
+:host > ::content > *:last-child {
+ margin-bottom: 24px;
+}
+
+:host > ::content h2 {
+ position: relative;
+ margin: 0;
+ @apply(--paper-font-title);
+
+ @apply(--paper-dialog-title);
+}
+
+:host > ::content .buttons {
+ position: relative;
+ padding: 8px 8px 8px 24px;
+ margin: 0;
+
+ color: var(--paper-dialog-button-color, --primary-color);
+
+ @apply(--layout-horizontal);
+ @apply(--layout-end-justified);
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-shared-styles.html
new file mode 100644
index 00000000000..35ea74bd7fb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog-behavior/paper-dialog-shared-styles.html
@@ -0,0 +1,83 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/typography.html">
+<link rel="import" href="../paper-styles/shadow.html">
+
+<!--
+### Styling
+
+The following custom properties and mixins are available for styling.
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-dialog-background-color` | Dialog background color | `--primary-background-color`
+`--paper-dialog-color` | Dialog foreground color | `--primary-text-color`
+`--paper-dialog` | Mixin applied to the dialog | `{}`
+`--paper-dialog-title` | Mixin applied to the title (`<h2>`) element | `{}`
+`--paper-dialog-button-color` | Button area foreground color | `--default-primary-color`
+-->
+
+<dom-module id="paper-dialog-shared-styles">
+ <template>
+ <style>
+ :host {
+ display: block;
+ margin: 24px 40px;
+
+ background: var(--paper-dialog-background-color, --primary-background-color);
+ color: var(--paper-dialog-color, --primary-text-color);
+
+ @apply(--paper-font-body1);
+ @apply(--shadow-elevation-16dp);
+ @apply(--paper-dialog);
+ }
+
+ :host > ::content > * {
+ margin-top: 20px;
+ padding: 0 24px;
+ }
+
+ :host > ::content > .no-padding {
+ padding: 0;
+ }
+
+ :host > ::content > *:first-child {
+ margin-top: 24px;
+ }
+
+ :host > ::content > *:last-child {
+ margin-bottom: 24px;
+ }
+
+ :host > ::content h2 {
+ position: relative;
+ margin: 0;
+ @apply(--paper-font-title);
+
+ @apply(--paper-dialog-title);
+ }
+
+ :host > ::content .buttons {
+ position: relative;
+ padding: 8px 8px 8px 24px;
+ margin: 0;
+
+ color: var(--paper-dialog-button-color, --primary-color);
+
+ @apply(--layout-horizontal);
+ @apply(--layout-end-justified);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.bower.json
new file mode 100644
index 00000000000..2882e47923c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.bower.json
@@ -0,0 +1,47 @@
+{
+ "name": "paper-dialog",
+ "description": "A Material Design dialog",
+ "version": "1.0.4",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "dialog",
+ "overlay"
+ ],
+ "main": "paper-dialog.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dialog"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dialog",
+ "ignore": [],
+ "dependencies": {
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0",
+ "paper-dialog-behavior": "PolymerElements/paper-dialog-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-menu": "PolymerElements/paper-menu#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.0.4",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.4",
+ "commit": "53b099bed06bbbab7cb0f82c8209328c1a82aee6"
+ },
+ "_source": "git://github.com/PolymerElements/paper-dialog.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-dialog"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.travis.yml
new file mode 100644
index 00000000000..eda70b02787
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: CiislAd2L7WGhu3ZFWeP/tq7aToNIKX//D4gUbafyI1vmFykDOTeZ22UzoFZ/SJ2pHUdoMGyjiYBr+MGS0G81+CEAgUC/8RI5HzWRg10KdEWB7qWQgWlxABdl0MV2T6RY2rv1gMss2b8sFL8FoBsR2ydqeKyGHhiuNG3/th7HBUdyLur4VnGlVHcQAHk8CgszBgL78RFU61+FbJR1RyJpjytAkJJP4X2DFdNx5XYh6nwDWKnRciZEHFzgj9c52eaQKBNOKwJjm/Gc2Mcyhq7inUM9di5qfRhP3EVn3aENC3WJoIyGu3wgzjD+r3Mp+PsEq6OLvm09g6ljbeMKfV9haQ0MPRQTmZiEjsiEXmxzL3qfYZhA/YoySyl/PyrXoAXFE19sbCBV9tCbbmR9vStIZOiFQLtUGAHUosWQOhR2Nym23q7B1sSlYAhaAaQlzkflhkb+h4QFCUW5IBjQEDl4CwG0n0dm7YO+Z+jZFoEz1kiper3D5T8mJxso69WQskG/kENqnrP1U9RMJbFQOQFYXauNBpc5ufbODTRivwHnNA+Gu2D5AbljGM8xcUNlzLJx+BWUU5QIt/ddfjynCdFyUazHNU/P2gH6R8e2ROVzupvBsdr2PyU5kQqdD8yTGPHkOimtlRY2Hsnp50NkNzDzuxIz+1SYjve7OOZXFWpRi4=
+ - secure: iEyYkfoa4Sp68fk1ttK0AEdoJ2i+3Ggx1cFcEuNtTjyrmSDVVb10E6LeTBWgWgxnK1EmV5MRY+5m3BzONDaPJMoChNa1ddqitPSqfK8SARjIUZ9DrliLwgsnfl/k/5EkKxzayH+xASYSqqMknpJC+irIs48oMZPB1zEVRK4FdhaCTPcWlDbdHtqwhDeRjXWmpY4uggRTyuql9PLwSU+P+e2S6UqBvXs5ldwHbC+361l8nDX4eB2AC/RmcSoawHoptd2+40+vJ2hs9+bcmQcD5rwGN3Y793q+F5L5ZTJu3v9KKU+9ABNT7yaIEk497dSA3lWa0I4MNT+pe5UcvJ6A1f5/pKLPZ8gYVdOx61Y9yHYW8c86k+QasGBTgwrzwIhk71iu+t9c6Jtt39mmZpewsfGpmUKoVTCBpO7YYlQwe1BCxQOLwdiudXE1wZKy2yLFSBHGa6wM1C9tLw6IW9Wb0ncUCSP/SIsXFlzBQKpOHBtJe0yGqw6yPf5/mxoVcsm5+F49Vh8nu7CTNVpZ9rcQcObLMAsy9qs7etiCHlzA5bAXtX0mmTob8+R5Cbjiir9LwR8ZltASivJg87taMldtXJDEDxNuHiSytxMTF56OxnWx82ek8aOaDY0WiIzUNEVufVh+sLTp47OHKOJXMRsLXu16TkaOkCVPsBkF2KVNwT4=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/README.md
new file mode 100644
index 00000000000..787cb7ee2bc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/README.md
@@ -0,0 +1,74 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-dialog.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-dialog.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-dialog)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-dialog)_
+
+
+##&lt;paper-dialog&gt;
+
+Material design: [Dialogs](https://www.google.com/design/spec/components/dialogs.html)
+
+`<paper-dialog>` is a dialog with Material Design styling and optional animations when it is
+opened or closed. It provides styles for a header, content area, and an action area for buttons.
+You can use the `<paper-dialog-scrollable>` element (in its own repository) if you need a scrolling
+content area. See `Polymer.PaperDialogBehavior` for specifics.
+
+For example, the following code implements a dialog with a header, scrolling content area and
+buttons.
+
+```html
+<paper-dialog>
+ <h2>Header</h2>
+ <paper-dialog-scrollable>
+ Lorem ipsum...
+ </paper-dialog-scrollable>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm>Accept</paper-button>
+ </div>
+</paper-dialog>
+```
+
+### Styling
+
+See the docs for `Polymer.PaperDialogBehavior` for the custom properties available for styling
+this element.
+
+### Animations
+
+Set the `entry-animation` and/or `exit-animation` attributes to add an animation when the dialog
+is opened or closed. See the documentation in
+[PolymerElements/neon-animation](https://github.com/PolymerElements/neon-animation) for more info.
+
+For example:
+
+```html
+<link rel="import" href="components/neon-animation/animations/scale-up-animation.html">
+<link rel="import" href="components/neon-animation/animations/fade-out-animation.html">
+
+<paper-dialog entry-animation="scale-up-animation"
+ exit-animation="fade-out-animation">
+ <h2>Header</h2>
+ <div>Dialog body</div>
+</paper-dialog>
+```
+
+### Accessibility
+
+See the docs for `Polymer.PaperDialogBehavior` for accessibility features implemented by this
+element.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/bower.json
new file mode 100644
index 00000000000..ab3be847f4c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/bower.json
@@ -0,0 +1,38 @@
+{
+ "name": "paper-dialog",
+ "description": "A Material Design dialog",
+ "version": "1.0.4",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "dialog",
+ "overlay"
+ ],
+ "main": "paper-dialog.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dialog"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dialog",
+ "ignore": [],
+ "dependencies": {
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0",
+ "paper-dialog-behavior": "PolymerElements/paper-dialog-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-menu": "PolymerElements/paper-menu#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/demo/index.html
new file mode 100644
index 00000000000..8b7549607ca
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/demo/index.html
@@ -0,0 +1,199 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-dialog demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../paper-dialog.html">
+ <link rel="import" href="../../paper-button/paper-button.html">
+ <link rel="import" href="../../paper-dialog-scrollable/paper-dialog-scrollable.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+ <link rel="import" href="../../neon-animation/neon-animations.html">
+ <link rel="import" href="../../paper-dropdown-menu/paper-dropdown-menu.html">
+ <link rel="import" href="../../paper-menu/paper-menu.html">
+ <link rel="import" href="../../paper-item/paper-item.html">
+
+ <link rel="stylesheet" href="../../paper-styles/demo.css">
+
+ <style is="custom-style">
+
+ section {
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ }
+
+ section > paper-button {
+ background-color: var(--google-grey-300);
+ padding: 5px;
+ }
+
+ section > paper-button:hover {
+ background-color: var(--paper-light-blue-200);
+ padding: 5px;
+ }
+
+ paper-dialog.colored {
+ border: 2px solid;
+ border-color: var(--paper-green-500);
+ background-color: var(--paper-light-green-50);
+ color: var(--paper-green-500);
+ }
+
+ paper-dialog.size-position {
+ position: fixed;
+ top: 16px;
+ right: 16px;
+ width: 300px;
+ height: 300px;
+ overflow: auto;
+ }
+ </style>
+
+</head>
+<body unresolved>
+
+ <section onclick="clickHandler(event)">
+ <h4>Dialog layouts</h4>
+
+ <paper-button data-dialog="dialog">plain dialog</paper-button>
+ <paper-button data-dialog="scrolling">scrolling dialog</paper-button>
+ <paper-button data-dialog="actions">dialog with actions</paper-button>
+ <paper-button data-dialog="modal">modal dialog</paper-button>
+ <paper-button data-dialog="dropdown">dialog with dropdown</paper-button>
+ <paper-button data-dialog="nested">dialog with nested dialog</paper-button>
+
+ <paper-dialog id="dialog">
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog>
+
+ <paper-dialog id="scrolling">
+ <h2>Scrolling</h2>
+ <paper-dialog-scrollable>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog-scrollable>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm autofocus>OK</paper-button>
+ </div>
+ </paper-dialog>
+
+ <paper-dialog id="actions">
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <div class="buttons">
+ <paper-button >More Info...</paper-button>
+ <paper-button dialog-dismiss>Decline</paper-button>
+ <paper-button dialog-confirm autofocus>Accept</paper-button>
+ </div>
+ </paper-dialog>
+
+ <paper-dialog id="modal" modal>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+ <div class="buttons">
+ <paper-button dialog-confirm autofocus>Tap me to close</paper-button>
+ </div>
+ </paper-dialog>
+
+ <paper-dialog id="dropdown">
+ <h2>Dialog Title</h2>
+ <paper-dropdown-menu label="Value">
+ <paper-menu class="dropdown-content">
+ <paper-item>1</paper-item>
+ <paper-item>2</paper-item>
+ <paper-item>3</paper-item>
+ <paper-item>4</paper-item>
+ <paper-item>5</paper-item>
+ <paper-item>6</paper-item>
+ <paper-item>7</paper-item>
+ <paper-item>8</paper-item>
+ <paper-item>9</paper-item>
+ <paper-item>10</paper-item>
+ </paper-menu>
+ </paper-dropdown-menu>
+ </paper-dialog>
+
+ <paper-dialog id="nested">
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ <div class="buttons">
+ <paper-button data-dialog="innerDialog">Open nested dialog</paper-button>
+ </div>
+ </paper-dialog>
+
+ <paper-dialog id="innerDialog">
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
+ </paper-dialog>
+
+ </section>
+
+ <section onclick="clickHandler(event)">
+ <h4>Custom styling</h4>
+ <paper-button data-dialog="colors">colors</paper-button>
+ <paper-button data-dialog="position">size &amp; position</paper-button>
+
+ <paper-dialog id="colors" class="colored">
+ <h2>Custom Colors</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog>
+
+ <paper-dialog id="position" class="size-position">
+ <h2>Custom Size &amp; Position</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog>
+ </section>
+
+ <section onclick="clickHandler(event)">
+ <h4>Transitions</h4>
+ <paper-button data-dialog="animated">transitions</paper-button>
+ <paper-dialog id="animated" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop>
+ <h2>Dialog Title</h2>
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </paper-dialog>
+ </section>
+
+ <script>
+ function clickHandler(e) {
+ var button = e.target;
+ while (!button.hasAttribute('data-dialog') && button !== document.body) {
+ button = button.parentElement;
+ }
+
+ if (!button.hasAttribute('data-dialog')) {
+ return;
+ }
+
+ var id = button.getAttribute('data-dialog');
+ var dialog = document.getElementById(id);
+ if (dialog) {
+ dialog.open();
+ }
+ }
+
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/hero.svg
new file mode 100755
index 00000000000..713329b8470
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/hero.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <g>
+ <polygon points="0,124 0,126 2,126 "/>
+ <polygon points="0,111.6 0,114.4 11.6,126 14.4,126 "/>
+ <polygon points="0,99.1 0,101.9 24.1,126 26.9,126 "/>
+ <polygon points="0,86.6 0,89.5 36.5,126 39.4,126 "/>
+ <polygon points="0,74.2 0,77 49,126 51.8,126 "/>
+ <polygon points="0,61.7 0,64.5 61.5,126 64.3,126 "/>
+ <polygon points="0,49.2 0,52.1 73.9,126 76.8,126 "/>
+ <polygon points="0,36.8 0,39.6 86.4,126 89.2,126 "/>
+ <polygon points="0,24.3 0,27.1 98.9,126 101.7,126 "/>
+ <polygon points="75.2,87 74,87 74,85.8 0,11.8 0,14.7 111.3,126 114.2,126 "/>
+ <polygon points="87.6,87 84.8,87 123.8,126 126.6,126 "/>
+ <polygon points="74,76.2 74,73.4 0.6,0 0,0 0,2.2 "/>
+ <polygon points="74,63.7 74,60.9 13.1,0 10.3,0 "/>
+ <polygon points="100.1,87 97.3,87 136.3,126 139.1,126 "/>
+ <polygon points="112.6,87 109.7,87 148.7,126 151.6,126 "/>
+ <polygon points="74,51.3 74,48.4 25.6,0 22.7,0 "/>
+ <polygon points="125,87 122.2,87 161.2,126 164,126 "/>
+ <polygon points="74.2,39 77,39 38,0 35.2,0 "/>
+ <polygon points="86.7,39 89.5,39 50.5,0 47.7,0 "/>
+ <polygon points="137.5,87 134.7,87 173.7,126 176.5,126 "/>
+ <polygon points="150,87 147.1,87 186.1,126 189,126 "/>
+ <polygon points="99.1,39 102,39 63,0 60.1,0 "/>
+ <polygon points="150,74.6 150,77.4 198.6,126 201.4,126 "/>
+ <polygon points="111.6,39 114.4,39 75.4,0 72.6,0 "/>
+ <polygon points="150,62.1 150,64.9 211.1,126 213.9,126 "/>
+ <polygon points="124.1,39 126.9,39 87.9,0 85.1,0 "/>
+ <polygon points="100.3,0 97.5,0 136.5,39 139.3,39 "/>
+ <polygon points="150,49.7 150,52.5 223.5,126 225,126 225,124.7 "/>
+ <polygon points="112.8,0 110,0 149,39 150,39 150,40 225,115 225,112.2 "/>
+ <polygon points="125.3,0 122.5,0 225,102.5 225,99.7 "/>
+ <polygon points="137.7,0 134.9,0 225,90.1 225,87.3 "/>
+ <polygon points="150.2,0 147.4,0 225,77.6 225,74.8 "/>
+ <polygon points="162.7,0 159.8,0 225,65.2 225,62.3 "/>
+ <polygon points="175.1,0 172.3,0 225,52.7 225,49.9 "/>
+ <polygon points="187.6,0 184.8,0 225,40.2 225,37.4 "/>
+ <polygon points="200.1,0 197.2,0 225,27.8 225,24.9 "/>
+ <polygon points="212.5,0 209.7,0 225,15.3 225,12.5 "/>
+ <polygon points="225,0 222.2,0 225,2.8 225,0 "/>
+ </g>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+ <path d="M151,88H73V38h78V88z M75,86h74V40H75V86z"/>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/index.html
new file mode 100644
index 00000000000..6304b8dc641
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-dialog</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/paper-dialog.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/paper-dialog.html
new file mode 100644
index 00000000000..ce3aab9f850
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dialog/paper-dialog.html
@@ -0,0 +1,122 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
+<link rel="import" href="../paper-dialog-behavior/paper-dialog-behavior.html">
+<link rel="import" href="../paper-dialog-behavior/paper-dialog-shared-styles.html">
+<!--
+Material design: [Dialogs](https://www.google.com/design/spec/components/dialogs.html)
+
+`<paper-dialog>` is a dialog with Material Design styling and optional animations when it is
+opened or closed. It provides styles for a header, content area, and an action area for buttons.
+You can use the `<paper-dialog-scrollable>` element (in its own repository) if you need a scrolling
+content area. See `Polymer.PaperDialogBehavior` for specifics.
+
+For example, the following code implements a dialog with a header, scrolling content area and
+buttons.
+
+ <paper-dialog>
+ <h2>Header</h2>
+ <paper-dialog-scrollable>
+ Lorem ipsum...
+ </paper-dialog-scrollable>
+ <div class="buttons">
+ <paper-button dialog-dismiss>Cancel</paper-button>
+ <paper-button dialog-confirm>Accept</paper-button>
+ </div>
+ </paper-dialog>
+
+### Styling
+
+See the docs for `Polymer.PaperDialogBehavior` for the custom properties available for styling
+this element.
+
+### Animations
+
+Set the `entry-animation` and/or `exit-animation` attributes to add an animation when the dialog
+is opened or closed. See the documentation in
+[PolymerElements/neon-animation](https://github.com/PolymerElements/neon-animation) for more info.
+
+For example:
+
+ <link rel="import" href="components/neon-animation/animations/scale-up-animation.html">
+ <link rel="import" href="components/neon-animation/animations/fade-out-animation.html">
+
+ <paper-dialog entry-animation="scale-up-animation"
+ exit-animation="fade-out-animation">
+ <h2>Header</h2>
+ <div>Dialog body</div>
+ </paper-dialog>
+
+### Accessibility
+
+See the docs for `Polymer.PaperDialogBehavior` for accessibility features implemented by this
+element.
+
+@group Paper Elements
+@element paper-dialog
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-dialog">
+ <template>
+ <style include="paper-dialog-shared-styles"></style>
+ <content></content>
+ </template>
+</dom-module>
+
+<script>
+
+(function() {
+
+ Polymer({
+
+ is: 'paper-dialog',
+
+ behaviors: [
+ Polymer.PaperDialogBehavior,
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ listeners: {
+ 'neon-animation-finish': '_onNeonAnimationFinish'
+ },
+
+ _renderOpened: function() {
+ this.cancelAnimation();
+ if (this.withBackdrop) {
+ this.backdropElement.open();
+ }
+ this.playAnimation('entry');
+ },
+
+ _renderClosed: function() {
+ this.cancelAnimation();
+ if (this.withBackdrop) {
+ this.backdropElement.close();
+ }
+ this.playAnimation('exit');
+ },
+
+ _onNeonAnimationFinish: function() {
+ if (this.opened) {
+ this._finishRenderOpened();
+ } else {
+ this._finishRenderClosed();
+ }
+ }
+
+ });
+
+})();
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.bower.json
new file mode 100644
index 00000000000..7a545934187
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.bower.json
@@ -0,0 +1,57 @@
+{
+ "name": "paper-dropdown-menu",
+ "version": "1.2.2",
+ "description": "An element that works similarly to a native browser select",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "dropdown",
+ "select"
+ ],
+ "main": "paper-dropdown-menu.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dropdown-menu.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dropdown-menu",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-iconset-svg": "polymerelements/iron-iconset-svg#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-input": "PolymerElements/paper-input#^1.0.9",
+ "paper-menu-button": "PolymerElements/paper-menu-button#^1.0.0",
+ "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-listbox": "PolymerElements/paper-listbox#^1.0.0",
+ "paper-tabs": "PolymerElements/paper-tabs#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "_release": "1.2.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.2",
+ "commit": "2e990c4b2a27529dead9d9ebcc5830f74379c63e"
+ },
+ "_source": "git://github.com/PolymerElements/paper-dropdown-menu.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-dropdown-menu"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.travis.yml
new file mode 100644
index 00000000000..bf7731c2517
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: Uv6d6W9yI2Lbj7gYh73LCGHpwvvdE1sdqdElVsTN4LSYW4msyLweDD4/Irbk5Nw5bavxkXraYkN655p5VU1SBucTRFMYYtpTDA7xBT/HvXVP3+OgkrN+joVStHcRJXHJCoVtq+YalZ07Q0dltw/brtSUCHhZkcNMxHd/p0NGD1FBSgXC1oXv+MSLjPsSKujz8WuXbfnGXkW682rZhS8Mp5x4Y31AAuGl64gNypAYTdWZ9bKLjeAx4ZY1poiw4Bs1z+V9tO3EeD6YQb/CVpxOH+67FQ2cX0ybLXumNuJQFIzki+EzFwXxuKrJsD4gu8B4kJKVWuAS9wuWkNgGdjR2HVe3/5+nMe7RiLL/wD6yGvcD2ZjP8S0RrxbOeZ03IzadH1NT0FWGf0J55VQgt4XjN0j9bVTYMfX5Xyg5bQ/E1qPzHbyteMAw6LF4Wmh2PyWzKHfz1uPGiZP/3BOKj8EbGMKPBci2181kbotPDENMT/5lk24e944tr7hKWWatNxCmkeb+lJomAxGwDYt2+I4mrpHFz/r4w9qgNr3DelhHTkBw2lNKzGAL5I177IJvsvGnZaCpGuRDWfq2xLGg2aTa9J1iyvil8gQP4CVxffWbqpPxvOax3V5nfbnAUpyYWvCtVSpOV5ndZA9FlBIn/pOsXqIjdiOTmmeJwFoddpCcZ1Y=
+ - secure: X0QrO1SQJs/ktfeJRfAzSTTAyLeMLu0NB5uj+hQCLPZ6QPacaOEaKmwx57CY2qsD9X34ijtXZHP8A3RWKXeQHt2H4CrQ/drWWzNjKMmaf42w8fzHNKkqlwsQV7Bh/g5qXnbzrkcsViOfDVkyPLIKumyG2NqZPrhjl8QDMGseiELB5oznBH/z8APY3lJVB1baT3Wxyzz7TdAYCpZGfdGjr/3bAx1qBNHJXeEMFJDYH4q2nKfqVhdNQx2VdB6nyxIoGKoDynPIGty2pVPOKrp6ctdJYFwtljbO1/AOh3uvkiZRB1dAwr8vE6xVBcUnpM8vseRhlipCSO6qcNTolF67DzlakjxNd8CUwnokJ1juxH9x4uUTAaUpaAHOFqL130Ogcqye6KJ4RavD9cs198dZE3Al9savUF8N2Q8Mpc04dc7AuMOglTTQqhIpLSdtFWsIptMUmhBS3hMgWfVAH7DEzR41SFwwXCN4ZvYC1ooCJK1+wL2po4kIHRaEHx+L6r+1+RKXQ+zBAG5VMtFtc0OoFtInTvyNqBcyHGkbxQaGdHN1FpBWo3wL5qcP37DtYbGe0iEtASk1w0MLlujQjHIY4smxVB/XmNRiOEkWHAtGxbBOu4NAHU5Qhxe22/w1fgPnO3YRoiNO4liJEYJNN1TpTYO3VolNq0IvdFKswj/p0vM=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/README.md
new file mode 100644
index 00000000000..fc59e19f963
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/README.md
@@ -0,0 +1,149 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-dropdown-menu-light.html paper-dropdown-menu.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-dropdown-menu.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-dropdown-menu)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-dropdown-menu)_
+
+
+##&lt;paper-dropdown-menu&gt;
+
+Material design: [Dropdown menus](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+`paper-dropdown-menu` is similar to a native browser select element.
+`paper-dropdown-menu` works with selectable content. The currently selected
+item is displayed in the control. If no item is selected, the `label` is
+displayed instead.
+
+Example:
+
+```html
+<paper-dropdown-menu label="Your favourite pastry">
+ <paper-listbox class="dropdown-content">
+ <paper-item>Croissant</paper-item>
+ <paper-item>Donut</paper-item>
+ <paper-item>Financier</paper-item>
+ <paper-item>Madeleine</paper-item>
+ </paper-listbox>
+</paper-dropdown-menu>
+```
+
+This example renders a dropdown menu with 4 options.
+
+The child element with the class `dropdown-content` is used as the dropdown
+menu. This can be a [`paper-listbox`](paper-listbox), or any other or
+element that acts like an [`iron-selector`](iron-selector).
+
+Specifically, the menu child must fire an
+[`iron-select`](iron-selector#event-iron-select) event when one of its
+children is selected, and an [`iron-deselect`](iron-selector#event-iron-deselect)
+event when a child is deselected. The selected or deselected item must
+be passed as the event's `detail.item` property.
+
+Applications can listen for the `iron-select` and `iron-deselect` events
+to react when options are selected and deselected.
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-dropdown-menu` | A mixin that is applied to the element host | `{}` |
+| `--paper-dropdown-menu-disabled` | A mixin that is applied to the element host when disabled | `{}` |
+| `--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple | `{}` |
+| `--paper-dropdown-menu-button` | A mixin that is applied to the internal menu button | `{}` |
+| `--paper-dropdown-menu-input` | A mixin that is applied to the internal paper input | `{}` |
+| `--paper-dropdown-menu-icon` | A mixin that is applied to the internal icon | `{}` |
+
+You can also use any of the `paper-input-container` and `paper-menu-button`
+style mixins and custom properties to style the internal input and menu button
+respectively.
+
+
+
+##&lt;paper-dropdown-menu-light&gt;
+
+Material design: [Dropdown menus](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+This is a faster, lighter version of `paper-dropdown-menu`, that does not
+use a `<paper-input>` internally. Use this element if you're concerned about
+the performance of this element, i.e., if you plan on using many dropdowns on
+the same page. Note that this element has a slightly different styling API
+than `paper-dropdown-menu`.
+
+`paper-dropdown-menu-light` is similar to a native browser select element.
+`paper-dropdown-menu-light` works with selectable content. The currently selected
+item is displayed in the control. If no item is selected, the `label` is
+displayed instead.
+
+Example:
+
+```html
+<paper-dropdown-menu-light label="Your favourite pastry">
+ <paper-listbox class="dropdown-content">
+ <paper-item>Croissant</paper-item>
+ <paper-item>Donut</paper-item>
+ <paper-item>Financier</paper-item>
+ <paper-item>Madeleine</paper-item>
+ </paper-listbox>
+</paper-dropdown-menu-light>
+```
+
+This example renders a dropdown menu with 4 options.
+
+The child element with the class `dropdown-content` is used as the dropdown
+menu. This can be a [`paper-listbox`](paper-listbox), or any other or
+element that acts like an [`iron-selector`](iron-selector).
+
+Specifically, the menu child must fire an
+[`iron-select`](iron-selector#event-iron-select) event when one of its
+children is selected, and an [`iron-deselect`](iron-selector#event-iron-deselect)
+event when a child is deselected. The selected or deselected item must
+be passed as the event's `detail.item` property.
+
+Applications can listen for the `iron-select` and `iron-deselect` events
+to react when options are selected and deselected.
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-dropdown-menu` | A mixin that is applied to the element host | `{}` |
+| `--paper-dropdown-menu-disabled` | A mixin that is applied to the element host when disabled | `{}` |
+| `--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple | `{}` |
+| `--paper-dropdown-menu-button` | A mixin that is applied to the internal menu button | `{}` |
+| `--paper-dropdown-menu-icon` | A mixin that is applied to the internal icon | `{}` |
+| `--paper-dropdown-menu-disabled-opacity` | The opacity of the dropdown when disabled | `0.33` |
+| `--paper-dropdown-menu-color` | The color of the input/label/underline when the dropdown is unfocused | `--primary-text-color` |
+| `--paper-dropdown-menu-focus-color` | The color of the label/underline when the dropdown is focused | `--primary-color` |
+| `--paper-dropdown-error-color` | The color of the label/underline when the dropdown is invalid | `--error-color` |
+| `--paper-dropdown-menu-label` | Mixin applied to the label | `{}` |
+| `--paper-dropdown-menu-input` | Mixin appled to the input | `{}` |
+
+Note that in this element, the underline is just the bottom border of the "input".
+To style it:
+
+```html
+<style is=custom-style>
+ paper-dropdown-menu-light.custom {
+ --paper-dropdown-menu-input: {
+ border-bottom: 2px dashed lavender;
+ };
+</style>
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/bower.json
new file mode 100644
index 00000000000..6a945cbeeb8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/bower.json
@@ -0,0 +1,48 @@
+{
+ "name": "paper-dropdown-menu",
+ "version": "1.2.2",
+ "description": "An element that works similarly to a native browser select",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "dropdown",
+ "select"
+ ],
+ "main": "paper-dropdown-menu.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-dropdown-menu.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-dropdown-menu",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-iconset-svg": "polymerelements/iron-iconset-svg#^1.0.0",
+ "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-input": "PolymerElements/paper-input#^1.0.9",
+ "paper-menu-button": "PolymerElements/paper-menu-button#^1.0.0",
+ "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-listbox": "PolymerElements/paper-listbox#^1.0.0",
+ "paper-tabs": "PolymerElements/paper-tabs#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/demo/index.html
new file mode 100644
index 00000000000..4bb258e6c92
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/demo/index.html
@@ -0,0 +1,295 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-dropdown-menu demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../paper-item/paper-item.html">
+ <link rel="import" href="../../paper-listbox/paper-listbox.html">
+ <link rel="import" href="../../paper-tabs/paper-tabs.html">
+ <link rel="import" href="../paper-dropdown-menu.html">
+ <link rel="import" href="../paper-dropdown-menu-light.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-tabs {
+ width: 400px;
+ }
+
+ .vertical-section-container {
+ max-width: 500px;
+ }
+
+ paper-dropdown-menu {
+ width: 200px;
+ margin-right: 20px;
+ }
+ </style>
+
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h4>This is a plain paper-dropdown-menu</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Dinosaurs">
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Dinosaurs (light)">
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+ <h4>You can pre-select a value using the <i>selected</i> attribute</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Dinosaurs">
+ <paper-listbox class="dropdown-content" selected="1">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Dinosaurs (light)">
+ <paper-listbox class="dropdown-content" selected="1">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+ <h4>You can change the direction in which the menu opens</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Upwards and to the left!" vertical-align="bottom" horizontal-align="left">
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Upwards and to the left! (light)" vertical-align="bottom" horizontal-align="left">
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+
+ <h4>A paper-dropdown-menu can be disabled</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Disabled dinosaurs" disabled>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Disabled dinosaurs (light)" disabled>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+ <!-- TODO(noms): enable this demo when the webcomponentsjs bug is fixed -->
+ <!-- <h4>Here is an example of a long, scrolling menu, using a <i>dom-repeat</i></h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <template is="dom-bind" id="Demo">
+ <paper-dropdown-menu label="Dinosaurs">
+ <paper-listbox class="dropdown-content">
+ <template is="dom-repeat" items='[[dinosaurs]]' as="dinosaur">
+ <paper-item>[[dinosaur]]</paper-item>
+ </template>
+ </paper-listbox>
+ </paper-dropdown-menu>
+ </template>
+ </template>
+ </demo-snippet> -->
+
+ <h4>A paper-dropdown-menu can contain any kind of content, such as tabs</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Menu tabs!?">
+ <paper-tabs class="dropdown-content">
+ <paper-tab>cheddar</paper-tab>
+ <paper-tab>stilton</paper-tab>
+ <paper-tab>emmental</paper-tab>
+ </paper-tabs>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Menu tabs!? (light)">
+ <paper-tabs class="dropdown-content">
+ <paper-tab>cheddar</paper-tab>
+ <paper-tab>stilton</paper-tab>
+ <paper-tab>emmental</paper-tab>
+ </paper-tabs>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+ <h4>You can remove the ripple and the animations</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-dropdown-menu label="Dinosaurs" noink no-animations>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light label="Dinosaurs (light)" noink no-animations>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+
+ <h4>You can style a paper-dropdown-menu using custom properties</h4>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-dropdown-menu.custom {
+ --paper-input-container-label: {
+ color: var(--paper-pink-500);
+ font-style: italic;
+ text-align: center;
+ font-weight: bold;
+ };
+ --paper-input-container-input: {
+ color: var(--paper-indigo-500);
+ font-style: normal;
+ font-family: serif;
+ text-transform: uppercase;
+ }
+ /* no underline */
+ --paper-input-container-underline: {
+ display: none;
+ };
+ }
+
+ paper-dropdown-menu-light.custom {
+ --paper-dropdown-menu-label: {
+ color: var(--paper-pink-500);
+ font-style: italic;
+ text-align: center;
+ font-weight: bold;
+ };
+ --paper-dropdown-menu-input: {
+ color: var(--paper-indigo-500);
+ font-style: normal;
+ font-family: serif;
+ text-transform: uppercase;
+ /* no underline */
+ border-bottom: none;
+ }
+ }
+ </style>
+ <paper-dropdown-menu class="custom" label="Custom" no-label-float>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+ <paper-dropdown-menu-light class="custom" label="Custom (light)" no-label-float>
+ <paper-listbox class="dropdown-content">
+ <paper-item>allosaurus</paper-item>
+ <paper-item>brontosaurus</paper-item>
+ <paper-item>carcharodontosaurus</paper-item>
+ <paper-item>diplodocus</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+ </template>
+ </demo-snippet>
+ </div>
+
+ <script>
+ // document.addEventListener('WebComponentsReady', function() {
+ // Demo.dinosaurs = [
+ // 'allosaurus',
+ // 'brontosaurus',
+ // 'carcharodontosaurus',
+ // 'diplodocus',
+ // 'ekrixinatosaurus',
+ // 'fukuiraptor',
+ // 'gallimimus',
+ // 'hadrosaurus',
+ // 'iguanodon',
+ // 'jainosaurus',
+ // 'kritosaurus',
+ // 'liaoceratops',
+ // 'megalosaurus',
+ // 'nemegtosaurus',
+ // 'ornithomimus',
+ // 'protoceratops',
+ // 'quetecsaurus',
+ // 'rajasaurus',
+ // 'stegosaurus',
+ // 'triceratops',
+ // 'utahraptor',
+ // 'vulcanodon',
+ // 'wannanosaurus',
+ // 'xenoceratops',
+ // 'yandusaurus',
+ // 'zephyrosaurus'
+ // ];
+ // });
+ </script>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/index.html
new file mode 100644
index 00000000000..b8053bfbf33
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>paper-dropdown-menu</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-icons.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-icons.html
new file mode 100644
index 00000000000..d8ca87c0a29
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-icons.html
@@ -0,0 +1,17 @@
+<!--
+@license
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
+
+<iron-iconset-svg name="paper-dropdown-menu" size="24">
+<svg><defs>
+<g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"></path></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-light.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-light.html
new file mode 100644
index 00000000000..383550952dd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-light.html
@@ -0,0 +1,576 @@
+<!--
+@license
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-button-state.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
+<link rel="import" href="../paper-menu-button/paper-menu-button.html">
+<link rel="import" href="../paper-behaviors/paper-ripple-behavior.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<link rel="import" href="paper-dropdown-menu-icons.html">
+<link rel="import" href="paper-dropdown-menu-shared-styles.html">
+
+<!--
+Material design: [Dropdown menus](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+This is a faster, lighter version of `paper-dropdown-menu`, that does not
+use a `<paper-input>` internally. Use this element if you're concerned about
+the performance of this element, i.e., if you plan on using many dropdowns on
+the same page. Note that this element has a slightly different styling API
+than `paper-dropdown-menu`.
+
+`paper-dropdown-menu-light` is similar to a native browser select element.
+`paper-dropdown-menu-light` works with selectable content. The currently selected
+item is displayed in the control. If no item is selected, the `label` is
+displayed instead.
+
+Example:
+
+ <paper-dropdown-menu-light label="Your favourite pastry">
+ <paper-listbox class="dropdown-content">
+ <paper-item>Croissant</paper-item>
+ <paper-item>Donut</paper-item>
+ <paper-item>Financier</paper-item>
+ <paper-item>Madeleine</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu-light>
+
+This example renders a dropdown menu with 4 options.
+
+The child element with the class `dropdown-content` is used as the dropdown
+menu. This can be a [`paper-listbox`](paper-listbox), or any other or
+element that acts like an [`iron-selector`](iron-selector).
+
+Specifically, the menu child must fire an
+[`iron-select`](iron-selector#event-iron-select) event when one of its
+children is selected, and an [`iron-deselect`](iron-selector#event-iron-deselect)
+event when a child is deselected. The selected or deselected item must
+be passed as the event's `detail.item` property.
+
+Applications can listen for the `iron-select` and `iron-deselect` events
+to react when options are selected and deselected.
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-dropdown-menu` | A mixin that is applied to the element host | `{}`
+`--paper-dropdown-menu-disabled` | A mixin that is applied to the element host when disabled | `{}`
+`--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple | `{}`
+`--paper-dropdown-menu-button` | A mixin that is applied to the internal menu button | `{}`
+`--paper-dropdown-menu-icon` | A mixin that is applied to the internal icon | `{}`
+`--paper-dropdown-menu-disabled-opacity` | The opacity of the dropdown when disabled | `0.33`
+`--paper-dropdown-menu-color` | The color of the input/label/underline when the dropdown is unfocused | `--primary-text-color`
+`--paper-dropdown-menu-focus-color` | The color of the label/underline when the dropdown is focused | `--primary-color`
+`--paper-dropdown-error-color` | The color of the label/underline when the dropdown is invalid | `--error-color`
+`--paper-dropdown-menu-label` | Mixin applied to the label | `{}`
+`--paper-dropdown-menu-input` | Mixin appled to the input | `{}`
+
+Note that in this element, the underline is just the bottom border of the "input".
+To style it:
+
+ <style is=custom-style>
+ paper-dropdown-menu-light.custom {
+ --paper-dropdown-menu-input: {
+ border-bottom: 2px dashed lavender;
+ };
+ </style>
+
+@group Paper Elements
+@element paper-dropdown-menu-light
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-dropdown-menu-light">
+ <template>
+ <style include="paper-dropdown-menu-shared-styles">
+ :host(:focus) {
+ outline: none;
+ }
+
+ /**
+ * All of these styles below are for styling the fake-input display
+ */
+ .dropdown-trigger {
+ box-sizing: border-box;
+ position: relative;
+ width: 100%;
+ padding: 16px 0 8px 0;
+ }
+
+ :host([disabled]) .dropdown-trigger {
+ pointer-events: none;
+ opacity: var(--paper-dropdown-menu-disabled-opacity, 0.33);
+ }
+
+ :host([no-label-float]) .dropdown-trigger {
+ padding-top: 8px; /* If there's no label, we need less space up top. */
+ }
+
+ #input {
+ @apply(--paper-font-subhead);
+ @apply(--paper-font-common-nowrap);
+ border-bottom: 1px solid var(--paper-dropdown-menu-color, --secondary-text-color);
+ color: var(--paper-dropdown-menu-color, --primary-text-color);
+ width: 200px; /* Default size of an <input> */
+ min-height: 24px;
+ box-sizing: border-box;
+ padding: 12px 20px 0 0; /* Right padding so that text doesn't overlap the icon */
+ outline: none;
+ @apply(--paper-dropdown-menu-input);
+ }
+
+ :host-context([dir="rtl"]) #input {
+ padding-right: 0px;
+ padding-left: 20px;
+ }
+
+ :host([disabled]) #input {
+ border-bottom: 1px dashed var(--paper-dropdown-menu-color, --secondary-text-color);
+ }
+
+ :host([invalid]) #input {
+ border-bottom: 2px solid var(--paper-dropdown-error-color, --error-color);
+ }
+
+ :host([no-label-float]) #input {
+ padding-top: 0; /* If there's no label, we need less space up top. */
+ }
+
+ label {
+ @apply(--paper-font-subhead);
+ @apply(--paper-font-common-nowrap);
+ display: block;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ /**
+ * The container has a 16px top padding, and there's 12px of padding
+ * between the input and the label (from the input's padding-top)
+ */
+ top: 28px;
+ box-sizing: border-box;
+ width: 100%;
+ padding-right: 20px; /* Right padding so that text doesn't overlap the icon */
+ text-align: left;
+ transition-duration: .2s;
+ transition-timing-function: cubic-bezier(.4,0,.2,1);
+ color: var(--paper-dropdown-menu-color, --secondary-text-color);
+ @apply(--paper-dropdown-menu-label);
+ }
+
+ :host-context([dir="rtl"]) label {
+ padding-right: 0px;
+ padding-left: 20px;
+ }
+
+ :host([no-label-float]) label {
+ top: 8px;
+ }
+
+ label.label-is-floating {
+ font-size: 12px;
+ top: 8px;
+ }
+
+ label.label-is-hidden {
+ display: none;
+ }
+
+ :host([focused]) label.label-is-floating {
+ color: var(--paper-dropdown-menu-focus-color, --primary-color);
+ }
+
+ :host([invalid]) label.label-is-floating {
+ color: var(--paper-dropdown-error-color, --error-color);
+ }
+
+ /**
+ * Sets up the focused underline. It's initially hidden, and becomes
+ * visible when it's focused.
+ */
+ label:after {
+ background-color: var(--paper-dropdown-menu-focus-color, --primary-color);
+ bottom: 7px; /* The container has an 8px bottom padding */
+ content: '';
+ height: 2px;
+ left: 45%;
+ position: absolute;
+ transition-duration: .2s;
+ transition-timing-function: cubic-bezier(.4,0,.2,1);
+ visibility: hidden;
+ width: 8px;
+ z-index: 10;
+ }
+
+ :host([invalid]) label:after {
+ background-color: var(--paper-dropdown-error-color, --error-color);
+ }
+
+ :host([no-label-float]) label:after {
+ bottom: 7px; /* The container has a 8px bottom padding */
+ }
+
+ :host([focused]:not([disabled])) label:after {
+ left: 0;
+ visibility: visible;
+ width: 100%;
+ }
+
+ iron-icon {
+ position: absolute;
+ right: 0px;
+ bottom: 8px; /* The container has an 8px bottom padding */
+ @apply(--paper-font-subhead);
+ margin-top: 12px;
+ color: var(--disabled-text-color);
+ @apply(--paper-dropdown-menu-icon);
+ }
+
+ :host-context([dir="rtl"]) iron-icon {
+ left: 0;
+ right: auto;
+ }
+
+ :host([no-label-float]) iron-icon {
+ margin-top: 0px;
+ }
+
+ .error {
+ display: inline-block;
+ visibility: hidden;
+ color: var(--paper-dropdown-error-color, --error-color);
+ @apply(--paper-font-caption);
+ position: absolute;
+ left:0;
+ right:0;
+ bottom: -12px;
+ }
+
+ :host([invalid]) .error {
+ visibility: visible;
+ }
+ </style>
+
+ <!-- this div fulfills an a11y requirement for combobox, do not remove -->
+ <div role="button"></div>
+ <paper-menu-button
+ id="menuButton"
+ vertical-align="[[verticalAlign]]"
+ horizontal-align="[[horizontalAlign]]"
+ vertical-offset="[[_computeMenuVerticalOffset(noLabelFloat)]]"
+ disabled="[[disabled]]"
+ no-animations="[[noAnimations]]"
+ on-iron-select="_onIronSelect"
+ on-iron-deselect="_onIronDeselect"
+ opened="{{opened}}">
+ <div class="dropdown-trigger">
+ <label hidden$="[[!label]]"
+ class$="[[_computeLabelClass(noLabelFloat,alwaysFloatLabel,hasContent)]]">[[label]]</label>
+ <div id="input" tabindex="-1">&nbsp;</div>
+ <iron-icon icon="paper-dropdown-menu:arrow-drop-down"></iron-icon>
+ <span class="error">[[errorMessage]]</span>
+ </div>
+ <content id="content" select=".dropdown-content"></content>
+ </paper-menu-button>
+ </template>
+
+ <script>
+ (function() {
+ 'use strict';
+
+ Polymer({
+ is: 'paper-dropdown-menu-light',
+
+ behaviors: [
+ Polymer.IronButtonState,
+ Polymer.IronControlState,
+ Polymer.PaperRippleBehavior,
+ Polymer.IronFormElementBehavior,
+ Polymer.IronValidatableBehavior
+ ],
+
+ properties: {
+ /**
+ * The derived "label" of the currently selected item. This value
+ * is the `label` property on the selected item if set, or else the
+ * trimmed text content of the selected item.
+ */
+ selectedItemLabel: {
+ type: String,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * The last selected item. An item is selected if the dropdown menu has
+ * a child with class `dropdown-content`, and that child triggers an
+ * `iron-select` event with the selected `item` in the `detail`.
+ *
+ * @type {?Object}
+ */
+ selectedItem: {
+ type: Object,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * The value for this element that will be used when submitting in
+ * a form. It is read only, and will always have the same value
+ * as `selectedItemLabel`.
+ */
+ value: {
+ type: String,
+ notify: true,
+ readOnly: true,
+ observer: '_valueChanged',
+ },
+
+ /**
+ * The label for the dropdown.
+ */
+ label: {
+ type: String
+ },
+
+ /**
+ * The placeholder for the dropdown.
+ */
+ placeholder: {
+ type: String
+ },
+
+ /**
+ * True if the dropdown is open. Otherwise, false.
+ */
+ opened: {
+ type: Boolean,
+ notify: true,
+ value: false,
+ observer: '_openedChanged'
+ },
+
+ /**
+ * Set to true to disable the floating label. Bind this to the
+ * `<paper-input-container>`'s `noLabelFloat` property.
+ */
+ noLabelFloat: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ /**
+ * Set to true to always float the label. Bind this to the
+ * `<paper-input-container>`'s `alwaysFloatLabel` property.
+ */
+ alwaysFloatLabel: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable animations when opening and closing the
+ * dropdown.
+ */
+ noAnimations: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * horizontally relative to the dropdown trigger.
+ */
+ horizontalAlign: {
+ type: String,
+ value: 'right'
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * vertically relative to the dropdown trigger.
+ */
+ verticalAlign: {
+ type: String,
+ value: 'top'
+ },
+
+ hasContent: {
+ type: Boolean,
+ readOnly: true
+ }
+ },
+
+ listeners: {
+ 'tap': '_onTap'
+ },
+
+ keyBindings: {
+ 'up down': 'open',
+ 'esc': 'close'
+ },
+
+ hostAttributes: {
+ tabindex: 0,
+ role: 'combobox',
+ 'aria-autocomplete': 'none',
+ 'aria-haspopup': 'true'
+ },
+
+ observers: [
+ '_selectedItemChanged(selectedItem)'
+ ],
+
+ attached: function() {
+ // NOTE(cdata): Due to timing, a preselected value in a `IronSelectable`
+ // child will cause an `iron-select` event to fire while the element is
+ // still in a `DocumentFragment`. This has the effect of causing
+ // handlers not to fire. So, we double check this value on attached:
+ var contentElement = this.contentElement;
+ if (contentElement && contentElement.selectedItem) {
+ this._setSelectedItem(contentElement.selectedItem);
+ }
+ },
+
+ /**
+ * The content element that is contained by the dropdown menu, if any.
+ */
+ get contentElement() {
+ return Polymer.dom(this.$.content).getDistributedNodes()[0];
+ },
+
+ /**
+ * Show the dropdown content.
+ */
+ open: function() {
+ this.$.menuButton.open();
+ },
+
+ /**
+ * Hide the dropdown content.
+ */
+ close: function() {
+ this.$.menuButton.close();
+ },
+
+ /**
+ * A handler that is called when `iron-select` is fired.
+ *
+ * @param {CustomEvent} event An `iron-select` event.
+ */
+ _onIronSelect: function(event) {
+ this._setSelectedItem(event.detail.item);
+ },
+
+ /**
+ * A handler that is called when `iron-deselect` is fired.
+ *
+ * @param {CustomEvent} event An `iron-deselect` event.
+ */
+ _onIronDeselect: function(event) {
+ this._setSelectedItem(null);
+ },
+
+ /**
+ * A handler that is called when the dropdown is tapped.
+ *
+ * @param {CustomEvent} event A tap event.
+ */
+ _onTap: function(event) {
+ if (Polymer.Gestures.findOriginalTarget(event) === this) {
+ this.open();
+ }
+ },
+
+ /**
+ * Compute the label for the dropdown given a selected item.
+ *
+ * @param {Element} selectedItem A selected Element item, with an
+ * optional `label` property.
+ */
+ _selectedItemChanged: function(selectedItem) {
+ var value = '';
+ if (!selectedItem) {
+ value = '';
+ } else {
+ value = selectedItem.label || selectedItem.textContent.trim();
+ }
+
+ this._setValue(value);
+ this._setSelectedItemLabel(value);
+ },
+
+ /**
+ * Compute the vertical offset of the menu based on the value of
+ * `noLabelFloat`.
+ *
+ * @param {boolean} noLabelFloat True if the label should not float
+ * above the input, otherwise false.
+ */
+ _computeMenuVerticalOffset: function(noLabelFloat) {
+ // NOTE(cdata): These numbers are somewhat magical because they are
+ // derived from the metrics of elements internal to `paper-input`'s
+ // template. The metrics will change depending on whether or not the
+ // input has a floating label.
+ return noLabelFloat ? -4 : 8;
+ },
+
+ /**
+ * Returns false if the element is required and does not have a selection,
+ * and true otherwise.
+ * @param {*=} _value Ignored.
+ * @return {boolean} true if `required` is false, or if `required` is true
+ * and the element has a valid selection.
+ */
+ _getValidity: function(_value) {
+ return this.disabled || !this.required || (this.required && !!this.value);
+ },
+
+ _openedChanged: function() {
+ var openState = this.opened ? 'true' : 'false';
+ var e = this.contentElement;
+ if (e) {
+ e.setAttribute('aria-expanded', openState);
+ }
+ },
+
+ _computeLabelClass: function(noLabelFloat, alwaysFloatLabel, hasContent) {
+ var cls = '';
+ if (noLabelFloat === true) {
+ return hasContent ? 'label-is-hidden' : '';
+ }
+
+ if (hasContent || alwaysFloatLabel === true) {
+ cls += ' label-is-floating';
+ }
+ return cls;
+ },
+
+ _valueChanged: function() {
+ // Only update if it's actually different.
+ if (this.$.input && this.$.input.textContent !== this.value) {
+ this.$.input.textContent = this.value;
+ }
+ this._setHasContent(!!this.value);
+ },
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-shared-styles.html
new file mode 100644
index 00000000000..e265a714f56
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu-shared-styles.html
@@ -0,0 +1,79 @@
+<!--
+@license
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<dom-module id="paper-dropdown-menu-shared-styles">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ position: relative;
+ text-align: left;
+ cursor: pointer;
+
+ /* NOTE(cdata): Both values are needed, since some phones require the
+ * value to be `transparent`.
+ */
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ -webkit-tap-highlight-color: transparent;
+
+ --paper-input-container-input: {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ box-sizing: border-box;
+ cursor: pointer;
+ };
+
+ @apply(--paper-dropdown-menu);
+ }
+
+ :host([disabled]) {
+ @apply(--paper-dropdown-menu-disabled);
+ }
+
+ :host([noink]) paper-ripple {
+ display: none;
+ }
+
+ :host([no-label-float]) paper-ripple {
+ top: 8px;
+ }
+
+ paper-ripple {
+ top: 12px;
+ left: 0px;
+ bottom: 8px;
+ right: 0px;
+
+ @apply(--paper-dropdown-menu-ripple);
+ }
+
+ paper-menu-button {
+ display: block;
+ padding: 0;
+
+ @apply(--paper-dropdown-menu-button);
+ }
+
+ paper-input {
+ @apply(--paper-dropdown-menu-input);
+ }
+
+ iron-icon {
+ color: var(--disabled-text-color);
+
+ @apply(--paper-dropdown-menu-icon);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu.html b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu.html
new file mode 100644
index 00000000000..d3c5c673d07
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-dropdown-menu/paper-dropdown-menu.html
@@ -0,0 +1,382 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-button-state.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
+<link rel="import" href="../paper-input/paper-input.html">
+<link rel="import" href="../paper-menu-button/paper-menu-button.html">
+<link rel="import" href="../paper-ripple/paper-ripple.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<link rel="import" href="paper-dropdown-menu-icons.html">
+<link rel="import" href="paper-dropdown-menu-shared-styles.html">
+
+<!--
+Material design: [Dropdown menus](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+`paper-dropdown-menu` is similar to a native browser select element.
+`paper-dropdown-menu` works with selectable content. The currently selected
+item is displayed in the control. If no item is selected, the `label` is
+displayed instead.
+
+Example:
+
+ <paper-dropdown-menu label="Your favourite pastry">
+ <paper-listbox class="dropdown-content">
+ <paper-item>Croissant</paper-item>
+ <paper-item>Donut</paper-item>
+ <paper-item>Financier</paper-item>
+ <paper-item>Madeleine</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+This example renders a dropdown menu with 4 options.
+
+The child element with the class `dropdown-content` is used as the dropdown
+menu. This can be a [`paper-listbox`](paper-listbox), or any other or
+element that acts like an [`iron-selector`](iron-selector).
+
+Specifically, the menu child must fire an
+[`iron-select`](iron-selector#event-iron-select) event when one of its
+children is selected, and an [`iron-deselect`](iron-selector#event-iron-deselect)
+event when a child is deselected. The selected or deselected item must
+be passed as the event's `detail.item` property.
+
+Applications can listen for the `iron-select` and `iron-deselect` events
+to react when options are selected and deselected.
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-dropdown-menu` | A mixin that is applied to the element host | `{}`
+`--paper-dropdown-menu-disabled` | A mixin that is applied to the element host when disabled | `{}`
+`--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple | `{}`
+`--paper-dropdown-menu-button` | A mixin that is applied to the internal menu button | `{}`
+`--paper-dropdown-menu-input` | A mixin that is applied to the internal paper input | `{}`
+`--paper-dropdown-menu-icon` | A mixin that is applied to the internal icon | `{}`
+
+You can also use any of the `paper-input-container` and `paper-menu-button`
+style mixins and custom properties to style the internal input and menu button
+respectively.
+
+@group Paper Elements
+@element paper-dropdown-menu
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-dropdown-menu">
+ <template>
+ <style include="paper-dropdown-menu-shared-styles"></style>
+
+ <!-- this div fulfills an a11y requirement for combobox, do not remove -->
+ <div role="button"></div>
+ <paper-menu-button
+ id="menuButton"
+ vertical-align="[[verticalAlign]]"
+ horizontal-align="[[horizontalAlign]]"
+ vertical-offset="[[_computeMenuVerticalOffset(noLabelFloat)]]"
+ disabled="[[disabled]]"
+ no-animations="[[noAnimations]]"
+ on-iron-select="_onIronSelect"
+ on-iron-deselect="_onIronDeselect"
+ opened="{{opened}}">
+ <div class="dropdown-trigger">
+ <paper-ripple></paper-ripple>
+ <!-- paper-input has type="text" for a11y, do not remove -->
+ <paper-input
+ type="text"
+ invalid="[[invalid]]"
+ readonly
+ disabled="[[disabled]]"
+ value="[[selectedItemLabel]]"
+ placeholder="[[placeholder]]"
+ error-message="[[errorMessage]]"
+ always-float-label="[[alwaysFloatLabel]]"
+ no-label-float="[[noLabelFloat]]"
+ label="[[label]]">
+ <iron-icon icon="paper-dropdown-menu:arrow-drop-down" suffix></iron-icon>
+ </paper-input>
+ </div>
+ <content id="content" select=".dropdown-content"></content>
+ </paper-menu-button>
+ </template>
+
+ <script>
+ (function() {
+ 'use strict';
+
+ Polymer({
+ is: 'paper-dropdown-menu',
+
+ behaviors: [
+ Polymer.IronButtonState,
+ Polymer.IronControlState,
+ Polymer.IronFormElementBehavior,
+ Polymer.IronValidatableBehavior
+ ],
+
+ properties: {
+ /**
+ * The derived "label" of the currently selected item. This value
+ * is the `label` property on the selected item if set, or else the
+ * trimmed text content of the selected item.
+ */
+ selectedItemLabel: {
+ type: String,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * The last selected item. An item is selected if the dropdown menu has
+ * a child with class `dropdown-content`, and that child triggers an
+ * `iron-select` event with the selected `item` in the `detail`.
+ *
+ * @type {?Object}
+ */
+ selectedItem: {
+ type: Object,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * The value for this element that will be used when submitting in
+ * a form. It is read only, and will always have the same value
+ * as `selectedItemLabel`.
+ */
+ value: {
+ type: String,
+ notify: true,
+ readOnly: true
+ },
+
+ /**
+ * The label for the dropdown.
+ */
+ label: {
+ type: String
+ },
+
+ /**
+ * The placeholder for the dropdown.
+ */
+ placeholder: {
+ type: String
+ },
+
+ /**
+ * The error message to display when invalid.
+ */
+ errorMessage: {
+ type: String
+ },
+
+ /**
+ * True if the dropdown is open. Otherwise, false.
+ */
+ opened: {
+ type: Boolean,
+ notify: true,
+ value: false,
+ observer: '_openedChanged'
+ },
+
+ /**
+ * Set to true to disable the floating label. Bind this to the
+ * `<paper-input-container>`'s `noLabelFloat` property.
+ */
+ noLabelFloat: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ /**
+ * Set to true to always float the label. Bind this to the
+ * `<paper-input-container>`'s `alwaysFloatLabel` property.
+ */
+ alwaysFloatLabel: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable animations when opening and closing the
+ * dropdown.
+ */
+ noAnimations: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * horizontally relative to the dropdown trigger.
+ */
+ horizontalAlign: {
+ type: String,
+ value: 'right'
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * vertically relative to the dropdown trigger.
+ */
+ verticalAlign: {
+ type: String,
+ value: 'top'
+ }
+ },
+
+ listeners: {
+ 'tap': '_onTap'
+ },
+
+ keyBindings: {
+ 'up down': 'open',
+ 'esc': 'close'
+ },
+
+ hostAttributes: {
+ role: 'combobox',
+ 'aria-autocomplete': 'none',
+ 'aria-haspopup': 'true'
+ },
+
+ observers: [
+ '_selectedItemChanged(selectedItem)'
+ ],
+
+ attached: function() {
+ // NOTE(cdata): Due to timing, a preselected value in a `IronSelectable`
+ // child will cause an `iron-select` event to fire while the element is
+ // still in a `DocumentFragment`. This has the effect of causing
+ // handlers not to fire. So, we double check this value on attached:
+ var contentElement = this.contentElement;
+ if (contentElement && contentElement.selectedItem) {
+ this._setSelectedItem(contentElement.selectedItem);
+ }
+ },
+
+ /**
+ * The content element that is contained by the dropdown menu, if any.
+ */
+ get contentElement() {
+ return Polymer.dom(this.$.content).getDistributedNodes()[0];
+ },
+
+ /**
+ * Show the dropdown content.
+ */
+ open: function() {
+ this.$.menuButton.open();
+ },
+
+ /**
+ * Hide the dropdown content.
+ */
+ close: function() {
+ this.$.menuButton.close();
+ },
+
+ /**
+ * A handler that is called when `iron-select` is fired.
+ *
+ * @param {CustomEvent} event An `iron-select` event.
+ */
+ _onIronSelect: function(event) {
+ this._setSelectedItem(event.detail.item);
+ },
+
+ /**
+ * A handler that is called when `iron-deselect` is fired.
+ *
+ * @param {CustomEvent} event An `iron-deselect` event.
+ */
+ _onIronDeselect: function(event) {
+ this._setSelectedItem(null);
+ },
+
+ /**
+ * A handler that is called when the dropdown is tapped.
+ *
+ * @param {CustomEvent} event A tap event.
+ */
+ _onTap: function(event) {
+ if (Polymer.Gestures.findOriginalTarget(event) === this) {
+ this.open();
+ }
+ },
+
+ /**
+ * Compute the label for the dropdown given a selected item.
+ *
+ * @param {Element} selectedItem A selected Element item, with an
+ * optional `label` property.
+ */
+ _selectedItemChanged: function(selectedItem) {
+ var value = '';
+ if (!selectedItem) {
+ value = '';
+ } else {
+ value = selectedItem.label || selectedItem.textContent.trim();
+ }
+
+ this._setValue(value);
+ this._setSelectedItemLabel(value);
+ },
+
+ /**
+ * Compute the vertical offset of the menu based on the value of
+ * `noLabelFloat`.
+ *
+ * @param {boolean} noLabelFloat True if the label should not float
+ * above the input, otherwise false.
+ */
+ _computeMenuVerticalOffset: function(noLabelFloat) {
+ // NOTE(cdata): These numbers are somewhat magical because they are
+ // derived from the metrics of elements internal to `paper-input`'s
+ // template. The metrics will change depending on whether or not the
+ // input has a floating label.
+ return noLabelFloat ? -4 : 8;
+ },
+
+ /**
+ * Returns false if the element is required and does not have a selection,
+ * and true otherwise.
+ * @param {*=} _value Ignored.
+ * @return {boolean} true if `required` is false, or if `required` is true
+ * and the element has a valid selection.
+ */
+ _getValidity: function(_value) {
+ return this.disabled || !this.required || (this.required && !!this.value);
+ },
+
+ _openedChanged: function() {
+ var openState = this.opened ? 'true' : 'false';
+ var e = this.contentElement;
+ if (e) {
+ e.setAttribute('aria-expanded', openState);
+ }
+ }
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/README.md
new file mode 100644
index 00000000000..3637258acf6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/README.md
@@ -0,0 +1,4 @@
+paper-fab
+===================
+
+See the [component page](https://www.polymer-project.org/0.5/docs/elements/paper-fab.html) for more information.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/bower.json
new file mode 100644
index 00000000000..ec35f259cee
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/bower.json
@@ -0,0 +1,16 @@
+{
+ "name": "paper-fab",
+ "private": true,
+ "dependencies": {
+ "polymer": "Polymer/polymer#^0.5",
+ "core-icon": "Polymer/core-icon#^0.5",
+ "core-icons": "Polymer/core-icons#^0.5",
+ "paper-button": "Polymer/paper-button#^0.5",
+ "paper-ripple": "Polymer/paper-ripple#^0.5",
+ "paper-shadow": "Polymer/paper-shadow#^0.5"
+ },
+ "devDependencies": {
+ "web-component-tester": "Polymer/web-component-tester#^1.1.4"
+ },
+ "version": "0.5.6"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/demo.html b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/demo.html
new file mode 100644
index 00000000000..f6b9261366f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/demo.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<!--
+Copyright 2013 The Polymer Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-fab</title>
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+
+ <link href="../font-roboto/roboto.html" rel="import">
+ <link href="../core-icons/core-icons.html" rel="import">
+ <link href="paper-fab.html" rel="import">
+
+ <style shim-shadowdom>
+
+ body {
+ font-family: RobotoDraft, 'Helvetica Neue', Helvetica, Arial;
+ font-size: 14px;
+ margin: 0;
+ padding: 24px;
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ -webkit-touch-callout: none;
+ }
+
+ section {
+ padding: 20px 0;
+ }
+
+ section > div {
+ padding: 14px;
+ font-size: 16px;
+ }
+
+ paper-fab {
+ color: #fff;
+ margin-right:2em;
+ }
+
+ paper-fab.blue {
+ background: #5677fc;
+ }
+
+ paper-fab.green {
+ background: #259b24;
+ }
+
+ paper-fab.yellow {
+ background: #ffeb3b;
+ }
+
+ </style>
+
+</head>
+<body unresolved>
+
+ <section>
+
+ <div>Regular</div>
+
+ <paper-fab icon="arrow-forward" title="arrow-forward"></paper-fab>
+ <paper-fab icon="create" class="blue" title="create"></paper-fab>
+
+ </section>
+
+ <section>
+
+ <div>Mini</div>
+
+ <paper-fab mini icon="done" class="green" title="done"></paper-fab>
+ <paper-fab mini icon="reply" class="yellow" title="reply"></paper-fab>
+
+ </section>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/index.html
new file mode 100644
index 00000000000..294215a738b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/index.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+ <link rel="import" href="../core-component-page/core-component-page.html">
+
+</head>
+<body unresolved>
+
+ <core-component-page></core-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/metadata.html b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/metadata.html
new file mode 100644
index 00000000000..bfb9d6eee94
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/metadata.html
@@ -0,0 +1,36 @@
+<!--
+ @license
+ Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<x-meta id="paper-fab" label="Floating Action Button" group="Paper">
+
+ <template>
+ <paper-fab icon="av:play-arrow"></paper-fab>
+ </template>
+
+ <template id="imports">
+ <link rel="import" href="../core-icons/core-icons.html">
+ <link rel="import" href="../core-icons/av-icons.html">
+ <link rel="import" href="paper-fab.html">
+ </template>
+
+</x-meta>
+
+<x-meta id="paper-fab-right-aligned" label="Floating Action Button Panel" group="Paper">
+
+ <template>
+ <div layout horizontal>
+ <paper-fab icon="check"></paper-fab>
+ </div>
+ </template>
+
+ <template id="imports">
+ <link rel="import" href="../core-icons/core-icons.html">
+ <link rel="import" href="paper-fab.html">
+ </template>
+</x-meta>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-fab/paper-fab.html b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/paper-fab.html
new file mode 100644
index 00000000000..c71a5bb7f46
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-fab/paper-fab.html
@@ -0,0 +1,180 @@
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<!--
+@group Paper Elements
+
+Material Design: <a href="http://www.google.com/design/spec/components/buttons.html">Button</a>
+
+`paper-fab` is a floating action button. It contains an image placed in the center and
+comes in two sizes: regular size and a smaller size by applying the attribute `mini`. When
+the user touches the button, a ripple effect emanates from the center of the button.
+
+You may import `core-icons` to use with this element, or provide an URL to a custom icon.
+See `core-iconset` for more information about how to use a custom icon set.
+
+Example:
+
+ <link href="path/to/core-icons/core-icons.html" rel="import">
+
+ <paper-fab icon="add"></paper-fab>
+ <paper-fab mini icon="favorite"></paper-fab>
+ <paper-fab src="star.png"></paper-fab>
+
+Styling
+-------
+
+Style the button with CSS as you would a normal DOM element. If you are using the icons
+provided by `core-icons`, the icon will inherit the foreground color of the button.
+
+ /* make a blue "cloud" button */
+ <paper-fab icon="cloud" style="color: blue;"></paper-fab>
+
+By default, the ripple is the same color as the foreground at 25% opacity. You may
+customize the color using this selector:
+
+ /* make #my-button use a blue ripple instead of foreground color */
+ #my-button::shadow #ripple {
+ color: blue;
+ }
+
+The opacity of the ripple is not customizable via CSS.
+
+Accessibility
+-------------
+
+The button is accessible by default if you use the `icon` property. By default, the
+`aria-label` attribute will be set to the `icon` property. If you use a custom icon,
+you should ensure that the `aria-label` attribute is set.
+
+ <paper-fab src="star.png" aria-label="star"></paper-fab>
+
+@element paper-fab
+@extends paper-button-base
+@status unstable
+-->
+
+<link href="../polymer/polymer.html" rel="import">
+<link href="../core-icon/core-icon.html" rel="import">
+<link href="../paper-button/paper-button-base.html" rel="import">
+<link href="../paper-ripple/paper-ripple.html" rel="import">
+<link href="../paper-shadow/paper-shadow.html" rel="import">
+
+<polymer-element name="paper-fab" extends="paper-button-base" attributes="src icon mini" role="button">
+
+ <template>
+
+ <style>
+ :host {
+ display: inline-block;
+ position: relative;
+ outline: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ z-index: 0;
+
+ box-sizing: border-box;
+ width: 56px;
+ height: 56px;
+ background: #d23f31;
+ color: #fff;
+ border-radius: 50%;
+ padding: 16px;
+ }
+
+ :host([mini]) {
+ width: 40px;
+ height: 40px;
+ padding: 8px;
+ }
+
+ :host([disabled]) {
+ color: #c9c9c9;
+ pointer-events: none;
+ cursor: auto;
+ }
+
+ #ripple {
+ pointer-events: none;
+ z-index: -1;
+ }
+
+ #shadow {
+ border-radius: inherit;
+ pointer-events: none;
+ }
+
+ #icon {
+ display: block;
+ pointer-events: none;
+ }
+ </style>
+
+ <template if="{{raised}}">
+ <paper-shadow id="shadow" fit animated></paper-shadow>
+ </template>
+
+ <!-- to position to ripple behind the icon -->
+ <core-icon relative id="icon" src="{{src}}" icon="{{icon}}"></core-icon>
+
+ </template>
+
+ <script>
+ Polymer({
+
+ publish: {
+
+ /**
+ * The URL of an image for the icon. If the src property is specified,
+ * the icon property should not be.
+ *
+ * @attribute src
+ * @type string
+ * @default ''
+ */
+ src: '',
+
+ /**
+ * Specifies the icon name or index in the set of icons available in
+ * the icon's icon set. If the icon property is specified,
+ * the src property should not be.
+ *
+ * @attribute icon
+ * @type string
+ * @default ''
+ */
+ icon: '',
+
+ /**
+ * Set this to true to style this is a "mini" FAB.
+ *
+ * @attribute mini
+ * @type boolean
+ * @default false
+ */
+ mini: false,
+
+ raised: true,
+ recenteringTouch: true,
+ fill: false
+
+ },
+
+ iconChanged: function(oldIcon) {
+ var label = this.getAttribute('aria-label');
+ if (!label || label === oldIcon) {
+ this.setAttribute('aria-label', this.icon);
+ }
+ }
+
+ });
+
+ </script>
+</polymer-element>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.bower.json
new file mode 100644
index 00000000000..abf5a6ac5ee
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.bower.json
@@ -0,0 +1,50 @@
+{
+ "name": "paper-icon-button",
+ "private": true,
+ "version": "1.1.2",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "A material design icon button",
+ "main": [
+ "paper-icon-button.html",
+ "paper-icon-button-light.html"
+ ],
+ "author": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "button",
+ "icon",
+ "control"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-icon-button.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/paper-icon-button",
+ "_release": "1.1.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.2",
+ "commit": "0a6c65f73765d6f6ae6cfe90ddc9905a2cf45f20"
+ },
+ "_source": "git://github.com/PolymerElements/paper-icon-button.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-icon-button"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.travis.yml
new file mode 100644
index 00000000000..82fb60bde23
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: A+iEL5FUMQWkkaOduE26bo0jW49LYKxDwWGZOty9H9fCDpBNQSADOhIvLzScGtjE7Rr3jVmowVsDN0XfVSRpJneEIvj7+tHAXUFoVey8vDVklOmhlR25IH2OczEmCkOS+sAKRiSF54aptdPeJhmpbMH0FyZfuX+jJfhdonJ+YQg=
+ - secure: Ps1Hy0fzmYRYF/ur2Myg7ol43HpzpooCoDvqzpMbIBWkXjXcN0KlPoNc6lEFlhjSpjddMFavdajKYIO0j9adAjZA7HYlf+BglhxV45lz13o04+QlNbDSADNyAlKJLrIvFacn9DE3VXlvBwBu83m+ndHUN/uMyHyZo0VE1/ad9Iw=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/README.md
new file mode 100644
index 00000000000..b48be667741
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/README.md
@@ -0,0 +1,81 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-icon-button-light.html paper-icon-button.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-icon-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-icon-button)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-icon-button)_
+
+
+##&lt;paper-icon-button&gt;
+
+Material design: [Icon toggles](https://www.google.com/design/spec/components/buttons.html#buttons-toggle-buttons)
+
+`paper-icon-button` is a button with an image placed at the center. When the user touches
+the button, a ripple effect emanates from the center of the button.
+
+`paper-icon-button` includes a default icon set. Use `icon` to specify which icon
+from the icon set to use.
+
+```html
+<paper-icon-button icon="menu"></paper-icon-button>
+```
+
+See [`iron-iconset`](iron-iconset) for more information about
+how to use a custom icon set.
+
+Example:
+
+```html
+<link href="path/to/iron-icons/iron-icons.html" rel="import">
+
+<paper-icon-button icon="favorite"></paper-icon-button>
+<paper-icon-button src="star.png"></paper-icon-button>
+```
+
+To use `paper-icon-button` as a link, wrap it in an anchor tag. Since `paper-icon-button`
+will already receive focus, you may want to prevent the anchor tag from receiving focus
+as well by setting its tabindex to -1.
+
+```html
+<a href="https://www.polymer-project.org" tabindex="-1">
+ <paper-icon-button icon="polymer"></paper-icon-button>
+</a>
+```
+
+### Styling
+
+Style the button with CSS as you would a normal DOM element. If you are using the icons
+provided by `iron-icons`, they will inherit the foreground color of the button.
+
+```html
+/* make a red "favorite" button */
+<paper-icon-button icon="favorite" style="color: red;"></paper-icon-button>
+```
+
+By default, the ripple is the same color as the foreground at 25% opacity. You may
+customize the color using the `--paper-icon-button-ink-color` custom property.
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-icon-button-disabled-text` | The color of the disabled button | `--disabled-text-color` |
+| `--paper-icon-button-ink-color` | Selected/focus ripple color | `--primary-text-color` |
+| `--paper-icon-button` | Mixin for a button | `{}` |
+| `--paper-icon-button-disabled` | Mixin for a disabled button | `{}` |
+| `--paper-icon-button-hover` | Mixin for button on hover | `{}` |
+
+
+
+<!-- No docs for <paper-icon-button-light> found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/bower.json
new file mode 100644
index 00000000000..ab58e4c2beb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/bower.json
@@ -0,0 +1,40 @@
+{
+ "name": "paper-icon-button",
+ "private": true,
+ "version": "1.1.2",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "A material design icon button",
+ "main": [
+ "paper-icon-button.html",
+ "paper-icon-button-light.html"
+ ],
+ "author": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "button",
+ "icon",
+ "control"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-icon-button.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/index.html
new file mode 100644
index 00000000000..98d496f82bc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/index.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>paper-icon-button demo</title>
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../paper-icon-button.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-icon-button {
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+ </style>
+ </head>
+ <body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Buttons can use iron-icons or external images, and can be disabled</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-icon-button icon="favorite" title="heart"></paper-icon-button>
+ <paper-icon-button src="https://assets-cdn.github.com/images/modules/logos_page/Octocat.png" alt="octocat" title="octocat"></paper-icon-button>
+ <paper-icon-button disabled icon="reply" title="reply"></paper-icon-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can hide the ripple effect using the <i>noink</i> attribute</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-icon-button noink icon="find-in-page" title="find"></paper-icon-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can be styled using regular CSS and custom properties</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-icon-button.pink {
+ color: var(--paper-pink-500);
+ --paper-icon-button-ink-color: var(--paper-indigo-500);
+ }
+ paper-icon-button.pink:hover {
+ background-color: var(--paper-pink-500);
+ color: white;
+ }
+ paper-icon-button.blue {
+ --paper-icon-button-ink-color: var(--paper-orange-500);
+ background-color: var(--paper-light-blue-500);
+ color: white;
+ border-radius: 3px;
+ padding: 2px;
+ }
+ </style>
+ <paper-icon-button icon="favorite" title="heart" class="pink"></paper-icon-button>
+ <paper-icon-button icon="flight-takeoff" title="take off" class="blue"></paper-icon-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can be resized</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-icon-button.giant {
+ width: 100px;
+ height: 100px;
+ }
+ </style>
+ <paper-icon-button icon="alarm-on" title="wake up" class="giant"></paper-icon-button>
+ </template>
+ </demo-snippet>
+
+ <h3>Buttons can be used as a link</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <a href="https://www.polymer-project.org" tabindex="-1">
+ <paper-icon-button icon="polymer"></paper-icon-button>
+ </a>
+ <style>
+ a paper-icon-button,
+ a:active paper-icon-button,
+ a:visited paper-icon-button {
+ color: #000000;
+ }
+ </style>
+ </template>
+ </demo-snippet>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/paper-icon-button-light.html b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/paper-icon-button-light.html
new file mode 100644
index 00000000000..6bae8e372a6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/demo/paper-icon-button-light.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+ <title>paper-icon-button-light demo</title>
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../paper-icon-button-light.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles"></style>
+ </head>
+ <body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>paper-icon-button-light can contain iron-icons or external images and can be disabled</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ button[is=paper-icon-button-light] {
+ width: 40px;
+ height: 40px;
+ padding: 8px;
+ margin: 10px;
+ }
+
+ button[is=paper-icon-button-light] > img {
+ width: 24px;
+ height: 24px;
+ }
+ </style>
+
+ <button is="paper-icon-button-light" title="heart">
+ <iron-icon icon="favorite"></iron-icon>
+ </button>
+ <button is="paper-icon-button-light" title="octocat">
+ <img src="https://assets-cdn.github.com/images/modules/logos_page/Octocat.png" alt="octocat">
+ </button>
+ <button is="paper-icon-button-light" title="reply" disabled>
+ <iron-icon icon="reply"></iron-icon>
+ </button>
+ </template>
+ </demo-snippet>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/index.html
new file mode 100644
index 00000000000..78f963c7e89
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/index.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button-light.html b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button-light.html
new file mode 100644
index 00000000000..c1c6c4e3c5b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button-light.html
@@ -0,0 +1,91 @@
+<!--
+@license
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-behaviors/paper-ripple-behavior.html">
+
+<!--
+@group Paper Elements
+@element paper-icon-button-light
+@demo demo/paper-icon-button-light.html
+-->
+<dom-module id="paper-icon-button-light">
+ <template strip-whitespace>
+ <style>
+ :host {
+ vertical-align: middle;
+ color: inherit;
+ outline: none;
+ width: 24px;
+ height: 24px;
+ background: none;
+ margin: 0;
+ border: none;
+ padding: 0;
+
+ position: relative;
+ cursor: pointer;
+
+ /* NOTE: Both values are needed, since some phones require the value to be `transparent`. */
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-tap-highlight-color: transparent;
+ }
+
+ :host([disabled]) {
+ color: #9b9b9b;
+ pointer-events: none;
+ cursor: auto;
+ }
+
+ paper-ripple {
+ opacity: 0.6;
+ color: currentColor;
+ }
+ </style>
+ <content></content>
+ </template>
+ <script>
+ Polymer({
+ is: 'paper-icon-button-light',
+ extends: 'button',
+
+ behaviors: [
+ Polymer.PaperRippleBehavior
+ ],
+
+ listeners: {
+ 'down': '_rippleDown',
+ 'up': '_rippleUp',
+ 'focus': '_rippleDown',
+ 'blur': '_rippleUp',
+ },
+
+ _rippleDown: function() {
+ this.getRipple().downAction();
+ },
+
+ _rippleUp: function() {
+ this.getRipple().upAction();
+ },
+
+ /**
+ * @param {...*} var_args
+ */
+ ensureRipple: function(var_args) {
+ var lastRipple = this._ripple;
+ Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
+ if (this._ripple && this._ripple !== lastRipple) {
+ this._ripple.center = true;
+ this._ripple.classList.add('circle');
+ }
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button.html
new file mode 100644
index 00000000000..b69330fbb07
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-icon-button/paper-icon-button.html
@@ -0,0 +1,176 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-icon/iron-icon.html">
+<link rel="import" href="../paper-behaviors/paper-inky-focus-behavior.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<!--
+Material design: [Icon toggles](https://www.google.com/design/spec/components/buttons.html#buttons-toggle-buttons)
+
+`paper-icon-button` is a button with an image placed at the center. When the user touches
+the button, a ripple effect emanates from the center of the button.
+
+`paper-icon-button` includes a default icon set. Use `icon` to specify which icon
+from the icon set to use.
+
+ <paper-icon-button icon="menu"></paper-icon-button>
+
+See [`iron-iconset`](iron-iconset) for more information about
+how to use a custom icon set.
+
+Example:
+
+ <link href="path/to/iron-icons/iron-icons.html" rel="import">
+
+ <paper-icon-button icon="favorite"></paper-icon-button>
+ <paper-icon-button src="star.png"></paper-icon-button>
+
+To use `paper-icon-button` as a link, wrap it in an anchor tag. Since `paper-icon-button`
+will already receive focus, you may want to prevent the anchor tag from receiving focus
+as well by setting its tabindex to -1.
+
+ <a href="https://www.polymer-project.org" tabindex="-1">
+ <paper-icon-button icon="polymer"></paper-icon-button>
+ </a>
+
+### Styling
+
+Style the button with CSS as you would a normal DOM element. If you are using the icons
+provided by `iron-icons`, they will inherit the foreground color of the button.
+
+ /* make a red "favorite" button */
+ <paper-icon-button icon="favorite" style="color: red;"></paper-icon-button>
+
+By default, the ripple is the same color as the foreground at 25% opacity. You may
+customize the color using the `--paper-icon-button-ink-color` custom property.
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-icon-button-disabled-text` | The color of the disabled button | `--disabled-text-color`
+`--paper-icon-button-ink-color` | Selected/focus ripple color | `--primary-text-color`
+`--paper-icon-button` | Mixin for a button | `{}`
+`--paper-icon-button-disabled` | Mixin for a disabled button | `{}`
+`--paper-icon-button-hover` | Mixin for button on hover | `{}`
+
+@group Paper Elements
+@element paper-icon-button
+@demo demo/index.html
+-->
+
+<dom-module id="paper-icon-button">
+ <template strip-whitespace>
+ <style>
+ :host {
+ display: inline-block;
+ position: relative;
+ padding: 8px;
+ outline: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ z-index: 0;
+ line-height: 1;
+
+ width: 40px;
+ height: 40px;
+
+ /* NOTE: Both values are needed, since some phones require the value to be `transparent`. */
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-tap-highlight-color: transparent;
+
+ /* Because of polymer/2558, this style has lower specificity than * */
+ box-sizing: border-box !important;
+
+ @apply(--paper-icon-button);
+ }
+
+ :host #ink {
+ color: var(--paper-icon-button-ink-color, --primary-text-color);
+ opacity: 0.6;
+ }
+
+ :host([disabled]) {
+ color: var(--paper-icon-button-disabled-text, --disabled-text-color);
+ pointer-events: none;
+ cursor: auto;
+
+ @apply(--paper-icon-button-disabled);
+ }
+
+ :host(:hover) {
+ @apply(--paper-icon-button-hover);
+ }
+
+ iron-icon {
+ --iron-icon-width: 100%;
+ --iron-icon-height: 100%;
+ }
+ </style>
+
+ <iron-icon id="icon" src="[[src]]" icon="[[icon]]" alt$="[[alt]]"></iron-icon>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-icon-button',
+
+ hostAttributes: {
+ role: 'button',
+ tabindex: '0'
+ },
+
+ behaviors: [
+ Polymer.PaperInkyFocusBehavior
+ ],
+
+ properties: {
+ /**
+ * The URL of an image for the icon. If the src property is specified,
+ * the icon property should not be.
+ */
+ src: {
+ type: String
+ },
+
+ /**
+ * Specifies the icon name or index in the set of icons available in
+ * the icon's icon set. If the icon property is specified,
+ * the src property should not be.
+ */
+ icon: {
+ type: String
+ },
+
+ /**
+ * Specifies the alternate text for the button, for accessibility.
+ */
+ alt: {
+ type: String,
+ observer: "_altChanged"
+ }
+ },
+
+ _altChanged: function(newValue, oldValue) {
+ var label = this.getAttribute('aria-label');
+
+ // Don't stomp over a user-set aria-label.
+ if (!label || oldValue == label) {
+ this.setAttribute('aria-label', newValue);
+ }
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-input/.bower.json
new file mode 100644
index 00000000000..4e060b99175
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/.bower.json
@@ -0,0 +1,60 @@
+{
+ "name": "paper-input",
+ "version": "1.1.14",
+ "description": "Material design text fields",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input"
+ ],
+ "main": [
+ "paper-input.html",
+ "paper-textarea.html",
+ "paper-input-behavior.html",
+ "paper-input-container.html",
+ "paper-input-error.html",
+ "paper-input-addon-behavior.html",
+ "paper-input-char-counter.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-input.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-input",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0",
+ "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#^1.0.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "iron-input": "PolymerElements/iron-input#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.1.4",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.1.14",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.14",
+ "commit": "6f43713e93e1f3f21593b7f231f53bc19289fc42"
+ },
+ "_source": "git://github.com/PolymerElements/paper-input.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-input"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-input/.travis.yml
new file mode 100644
index 00000000000..2212dafd547
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: TcDqx+YdNCa/DRQjdKt9dgYCPgXtPl2EZ7Nnv6bRvbcmUjW2eSr7Zwb+e0fO8wgwms/RqFaVx+u5jo7D1lnC4Ybcg1HKiMOvCyzY36MjF9oB/VKSEUC+p4tMVQfw1IZ/RmK3dD+WEWaoT/EKmNfctz7v5kR+yk2lZo44D9I7rrc=
+ - secure: nh65tvhnhOrK05qKvDJKMV7Jm9yiCoG1wFkP3ZnqOHix9Ny+KmcTa41Bl6NXQdvYaMTFtzS7lMZX5cqIziyKyGWHVN30LzGMHJNz12fhcMi3nJ84trhQGcu/9qR9yDv16q9ouGlcz1VxnDOHaRAHnIKjLIbhN3aJtMtZBbnWihA=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-input/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-input/README.md
new file mode 100644
index 00000000000..0561f76ec68
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/README.md
@@ -0,0 +1,254 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-input-addon-behavior.html paper-input-behavior.html paper-input-char-counter.html paper-input-container.html paper-input-error.html paper-input.html paper-textarea.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-input.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-input)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-input)_
+
+
+##&lt;paper-input&gt;
+
+Material design: [Text fields](https://www.google.com/design/spec/components/text-fields.html)
+
+`<paper-input>` is a single-line text field with Material Design styling.
+
+```html
+<paper-input label="Input label"></paper-input>
+```
+
+It may include an optional error message or character counter.
+
+```html
+<paper-input error-message="Invalid input!" label="Input label"></paper-input>
+<paper-input char-counter label="Input label"></paper-input>
+```
+
+It can also include custom prefix or suffix elements, which are displayed
+before or after the text input itself. In order for an element to be
+considered as a prefix, it must have the `prefix` attribute (and similarly
+for `suffix`).
+
+```html
+<paper-input label="total">
+ <div prefix>$</div>
+ <paper-icon-button suffix icon="clear"></paper-icon-button>
+</paper-input>
+```
+
+A `paper-input` can use the native `type=search` or `type=file` features.
+However, since we can't control the native styling of the input (search icon,
+file button, date placeholder, etc.), in these cases the label will be
+automatically floated. The `placeholder` attribute can still be used for
+additional informational text.
+
+```html
+<paper-input label="search!" type="search"
+ placeholder="search for cats" autosave="test" results="5">
+</paper-input>
+```
+
+See `Polymer.PaperInputBehavior` for more API docs.
+
+### Focus
+
+To focus a paper-input, you can call the native `focus()` method as long as the
+paper input has a tab index.
+
+### Styling
+
+See `Polymer.PaperInputContainer` for a list of custom properties used to
+style this element.
+
+
+
+##&lt;paper-input-char-counter&gt;
+
+`<paper-input-char-counter>` is a character counter for use with `<paper-input-container>`. It
+shows the number of characters entered in the input and the max length if it is specified.
+
+```html
+<paper-input-container>
+ <input is="iron-input" maxlength="20">
+ <paper-input-char-counter></paper-input-char-counter>
+</paper-input-container>
+```
+
+### Styling
+
+The following mixin is available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-input-char-counter` | Mixin applied to the element | `{}` |
+
+
+
+##&lt;paper-input-container&gt;
+
+`<paper-input-container>` is a container for a `<label>`, an `<input is="iron-input">` or
+`<iron-autogrow-textarea>` and optional add-on elements such as an error message or character
+counter, used to implement Material Design text fields.
+
+For example:
+
+```html
+<paper-input-container>
+ <label>Your name</label>
+ <input is="iron-input">
+</paper-input-container>
+```
+
+Do not wrap `<paper-input-container>` around elements that already include it, such as `<paper-input>`.
+Doing so may cause events to bounce infintely between the container and its contained element.
+
+### Listening for input changes
+
+By default, it listens for changes on the `bind-value` attribute on its children nodes and perform
+tasks such as auto-validating and label styling when the `bind-value` changes. You can configure
+the attribute it listens to with the `attr-for-value` attribute.
+
+### Using a custom input element
+
+You can use a custom input element in a `<paper-input-container>`, for example to implement a
+compound input field like a social security number input. The custom input element should have the
+`paper-input-input` class, have a `notify:true` value property and optionally implements
+`Polymer.IronValidatableBehavior` if it is validatable.
+
+```html
+<paper-input-container attr-for-value="ssn-value">
+ <label>Social security number</label>
+ <ssn-input class="paper-input-input"></ssn-input>
+</paper-input-container>
+```
+
+If you're using a `<paper-input-container>` imperatively, it's important to make sure
+that you attach its children (the `iron-input` and the optional `label`) before you
+attach the `<paper-input-container>` itself, so that it can be set up correctly.
+
+### Validation
+
+If the `auto-validate` attribute is set, the input container will validate the input and update
+the container styling when the input value changes.
+
+### Add-ons
+
+Add-ons are child elements of a `<paper-input-container>` with the `add-on` attribute and
+implements the `Polymer.PaperInputAddonBehavior` behavior. They are notified when the input value
+or validity changes, and may implement functionality such as error messages or character counters.
+They appear at the bottom of the input.
+
+### Prefixes and suffixes
+
+These are child elements of a `<paper-input-container>` with the `prefix`
+or `suffix` attribute, and are displayed inline with the input, before or after.
+
+```html
+<paper-input-container>
+ <div prefix>$</div>
+ <label>Total</label>
+ <input is="iron-input">
+ <paper-icon-button suffix icon="clear"></paper-icon-button>
+</paper-input-container>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-input-container-color` | Label and underline color when the input is not focused | `--secondary-text-color` |
+| `--paper-input-container-focus-color` | Label and underline color when the input is focused | `--primary-color` |
+| `--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--error-color` |
+| `--paper-input-container-input-color` | Input foreground color | `--primary-text-color` |
+| `--paper-input-container` | Mixin applied to the container | `{}` |
+| `--paper-input-container-disabled` | Mixin applied to the container when it's disabled | `{}` |
+| `--paper-input-container-label` | Mixin applied to the label | `{}` |
+| `--paper-input-container-label-focus` | Mixin applied to the label when the input is focused | `{}` |
+| `--paper-input-container-label-floating` | Mixin applied to the label when floating | `{}` |
+| `--paper-input-container-input` | Mixin applied to the input | `{}` |
+| `--paper-input-container-underline` | Mixin applied to the underline | `{}` |
+| `--paper-input-container-underline-focus` | Mixin applied to the underline when the input is focused | `{}` |
+| `--paper-input-container-underline-disabled` | Mixin applied to the underline when the input is disabled | `{}` |
+| `--paper-input-prefix` | Mixin applied to the input prefix | `{}` |
+| `--paper-input-suffix` | Mixin applied to the input suffix | `{}` |
+
+This element is `display:block` by default, but you can set the `inline` attribute to make it
+`display:inline-block`.
+
+
+
+##&lt;paper-input-error&gt;
+
+`<paper-input-error>` is an error message for use with `<paper-input-container>`. The error is
+displayed when the `<paper-input-container>` is `invalid`.
+
+```html
+<paper-input-container>
+ <input is="iron-input" pattern="[0-9]*">
+ <paper-input-error>Only numbers are allowed!</paper-input-error>
+</paper-input-container>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-input-container-invalid-color` | The foreground color of the error | `--error-color` |
+| `--paper-input-error` | Mixin applied to the error | `{}` |
+
+
+
+##&lt;paper-textarea&gt;
+
+`<paper-textarea>` is a multi-line text field with Material Design styling.
+
+```html
+<paper-textarea label="Textarea label"></paper-textarea>
+```
+
+See `Polymer.PaperInputBehavior` for more API docs.
+
+### Validation
+
+Currently only `required` and `maxlength` validation is supported.
+
+### Styling
+
+See `Polymer.PaperInputContainer` for a list of custom properties used to
+style this element.
+
+
+
+##Polymer.PaperInputAddonBehavior
+
+Use `Polymer.PaperInputAddonBehavior` to implement an add-on for `<paper-input-container>`. A
+add-on appears below the input, and may display information based on the input value and
+validity such as a character counter or an error message.
+
+
+
+##Polymer.PaperInputBehavior
+
+Use `Polymer.PaperInputBehavior` to implement inputs with `<paper-input-container>`. This
+behavior is implemented by `<paper-input>`. It exposes a number of properties from
+`<paper-input-container>` and `<input is="iron-input">` and they should be bound in your
+template.
+
+The input element can be accessed by the `inputElement` property if you need to access
+properties or methods that are not exposed.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/all-imports.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/all-imports.html
new file mode 100644
index 00000000000..0f457718644
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/all-imports.html
@@ -0,0 +1,12 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="paper-input.html">
+<link rel="import" href="paper-textarea.html">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-input/bower.json
new file mode 100644
index 00000000000..15be02fc355
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/bower.json
@@ -0,0 +1,51 @@
+{
+ "name": "paper-input",
+ "version": "1.1.14",
+ "description": "Material design text fields",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "input"
+ ],
+ "main": [
+ "paper-input.html",
+ "paper-textarea.html",
+ "paper-input-behavior.html",
+ "paper-input-container.html",
+ "paper-input-error.html",
+ "paper-input-addon-behavior.html",
+ "paper-input-char-counter.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-input.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-input",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.2.0",
+ "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#^1.0.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0",
+ "iron-input": "PolymerElements/iron-input#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.1.4",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/index.html
new file mode 100644
index 00000000000..f84799de75d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/index.html
@@ -0,0 +1,155 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-input demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-icon/iron-icon.html">
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../iron-input/iron-input.html">
+ <link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../paper-input-container.html">
+ <link rel="import" href="../paper-input-error.html">
+ <link rel="import" href="../paper-input.html">
+ <link rel="import" href="../paper-textarea.html">
+ <link rel="import" href="ssn-input.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-input {
+ display: block;
+ }
+
+ demo-snippet.horizontal {
+ --demo-snippet-demo: {
+ @apply(--layout-horizontal);
+ @apply(--layout-justified);
+ @apply(--layout-wrap);
+ }
+ }
+ demo-snippet.horizontal paper-input {
+ display: inline-block;
+ }
+
+ button {
+ width: 70px;
+ }
+
+ #inputForValidation {
+ display: inline-block;
+ width: calc(100% - 75px);
+ }
+
+ .vertical-section-container {
+ max-width: 600px;
+ }
+
+ paper-icon-button {
+ color: var(--paper-red-300);
+ --paper-icon-button-ink-color: var(--paper-red-a100);
+ width: 23px; /* 15px + 2*4px for padding */
+ height: 23px;
+ padding: 0px 4px;
+ }
+
+ iron-icon {
+ padding-right: 5px;
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Inputs can have different types, and be disabled</h3>
+ <demo-snippet>
+ <template>
+ <paper-input label="text input"></paper-input>
+ <paper-textarea label="autoresizing textarea input"></paper-textarea>
+ <paper-input label="password input" type="password"></paper-input>
+ <paper-input label="disabled input" disabled></paper-input>
+ </template>
+ </demo-snippet>
+
+ <h3>Inputs can have character counters</h3>
+ <demo-snippet>
+ <template>
+ <paper-input label="simple character counter" char-counter></paper-input>
+ <paper-input label="input with at most 10 characters" char-counter maxlength="10"></paper-input>
+ </template>
+ </demo-snippet>
+
+ <h3>The label can have different floating states</h3>
+ <demo-snippet>
+ <template>
+ <paper-input label="this label floats after typing"></paper-input>
+ <paper-input label="this label is always floating" always-float-label></paper-input>
+ <paper-input label="this label never floats" no-label-float></paper-input>
+ <paper-input label="this label is always floating" always-float-label placeholder="placeholder text"></paper-input>
+ </template>
+ </demo-snippet>
+
+ <h3>Inputs can validate automatically or on demand, and can have custom error messages</h3>
+ <demo-snippet>
+ <template>
+ <paper-input label="this input requires some text" required auto-validate error-message="needs some text!"></paper-input>
+ <paper-input label="this input requires letters only" auto-validate pattern="[a-zA-Z]*" error-message="letters only!"></paper-input>
+ <paper-input label="this input will only let you type letters" auto-validate allowed-pattern="[a-zA-Z]"></paper-input>
+ <paper-input id="inputForValidation" required label="this input is manually validated" pattern="[a-zA-Z]*" error-message="letters only!"></paper-input>
+ <button onclick="validate()">Validate!</button>
+ </template>
+ </demo-snippet>
+
+ <h3>Inputs can have prefixes and suffixes</h3>
+ <demo-snippet class="horizontal">
+ <template>
+ <paper-input label="total" type="number">
+ <div prefix>$</div>
+ </paper-input>
+ <paper-input label="username" id="inputWithButton">
+ <iron-icon icon="mail" prefix></iron-icon>
+ <div suffix>@email.com</div>
+ <paper-icon-button suffix onclick="clearInput()"
+ icon="clear" alt="clear" title="clear">
+ </paper-icon-button>
+ </paper-input>
+ </template>
+ </demo-snippet>
+
+ <h3>Inputs can have custom logic</h3>
+ <demo-snippet>
+ <template>
+ <paper-input-container always-float-label auto-validate attr-for-value="value">
+ <label>Social Security Number</label>
+ <ssn-input class="paper-input-input"></ssn-input>
+ <paper-input-error>SSN invalid!</paper-input-error>
+ </paper-input-container>
+ </template>
+ </demo-snippet>
+ </div>
+
+ <script>
+ function validate() {
+ document.getElementById('inputForValidation').validate();
+ }
+
+ function clearInput() {
+ document.getElementById('inputWithButton').value = '';
+ }
+ </script>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-input.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-input.html
new file mode 100644
index 00000000000..c7ab51dd61c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-input.html
@@ -0,0 +1,96 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../iron-input/iron-input.html">
+<link rel="import" href="../../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="ssn-validator.html">
+
+<dom-module id="ssn-input">
+ <template>
+
+ <style>
+ :host {
+ display: inline-block;
+ }
+
+ :host([hidden]) {
+ display: none !important;
+ }
+
+ input[is="iron-input"] {
+ font: inherit;
+ outline: none;
+ box-shadow: none;
+ border: none;
+ width: auto;
+ text-align: center;
+ }
+
+ .container {
+ @apply(--layout-horizontal);
+ }
+ </style>
+
+ <ssn-validator></ssn-validator>
+
+ <div class="container">
+
+ <input is="iron-input" maxlength="3" bind-value="{{_ssn1}}" size="3" aria-label="First 3 digits of social security number">
+ -
+ <input is="iron-input" maxlength="2" bind-value="{{_ssn2}}" size="2" aria-label="Middle 2 digits of social security number">
+ -
+ <input is="iron-input" maxlength="4" bind-value="{{_ssn3}}" size="4" aria-label="Last 4 digits of social security number">
+
+ </div>
+
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'ssn-input',
+
+ behaviors: [
+ Polymer.IronValidatableBehavior
+ ],
+
+ properties: {
+ value: {
+ notify: true,
+ type: String
+ },
+
+ _ssn1: {
+ type: String
+ },
+
+ _ssn2: {
+ type: String
+ },
+
+ _ssn3: {
+ type: String
+ },
+
+ validator: {
+ type: String,
+ value: 'ssn-validator'
+ }
+ },
+
+ observers: [
+ '_computeValue(_ssn1,_ssn2,_ssn3)'
+ ],
+
+ _computeValue: function(ssn1, ssn2, ssn3) {
+ this.value = ssn1.trim() + '-' + ssn2.trim() + '-' + ssn3.trim();
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-validator.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-validator.html
new file mode 100644
index 00000000000..e45365b51b2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/demo/ssn-validator.html
@@ -0,0 +1,27 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../iron-validator-behavior/iron-validator-behavior.html">
+
+<script>
+ Polymer({
+ is: 'ssn-validator',
+
+ behaviors: [
+ Polymer.IronValidatorBehavior
+ ],
+
+ validate: function(value) {
+ // this regex validates incomplete ssn's (by design)
+ return !value || value.match(/^[0-9]{0,3}-[0-9]{0,2}-[0-9]{0,4}$/);
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-input/hero.svg
new file mode 100755
index 00000000000..146ffeac67c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/hero.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <rect x="49" y="53" width="2" height="18"/>
+ <path d="M188,78H37V44h151V78z M39,76h147V46H39V76z"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/index.html
new file mode 100644
index 00000000000..e6c9fadcee5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <title>paper-input</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page src="all-imports.html"></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-addon-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-addon-behavior.html
new file mode 100644
index 00000000000..41081c71361
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-addon-behavior.html
@@ -0,0 +1,47 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /**
+ * Use `Polymer.PaperInputAddonBehavior` to implement an add-on for `<paper-input-container>`. A
+ * add-on appears below the input, and may display information based on the input value and
+ * validity such as a character counter or an error message.
+ * @polymerBehavior
+ */
+ Polymer.PaperInputAddonBehavior = {
+
+ hostAttributes: {
+ 'add-on': ''
+ },
+
+ attached: function() {
+ this.fire('addon-attached');
+ },
+
+ /**
+ * The function called by `<paper-input-container>` when the input value or validity changes.
+ * @param {{
+ * inputElement: (Element|undefined),
+ * value: (string|undefined),
+ * invalid: boolean
+ * }} state -
+ * inputElement: The input element.
+ * value: The input value.
+ * invalid: True if the input value is invalid.
+ */
+ update: function(state) {
+ }
+
+ };
+
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-behavior.html
new file mode 100644
index 00000000000..9bb10019aac
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-behavior.html
@@ -0,0 +1,541 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+
+<script>
+
+ // Generate unique, monotonically increasing IDs for labels (needed by
+ // aria-labelledby) and add-ons.
+ Polymer.PaperInputHelper = {};
+ Polymer.PaperInputHelper.NextLabelID = 1;
+ Polymer.PaperInputHelper.NextAddonID = 1;
+
+ /**
+ * Use `Polymer.PaperInputBehavior` to implement inputs with `<paper-input-container>`. This
+ * behavior is implemented by `<paper-input>`. It exposes a number of properties from
+ * `<paper-input-container>` and `<input is="iron-input">` and they should be bound in your
+ * template.
+ *
+ * The input element can be accessed by the `inputElement` property if you need to access
+ * properties or methods that are not exposed.
+ * @polymerBehavior Polymer.PaperInputBehavior
+ */
+ Polymer.PaperInputBehaviorImpl = {
+
+ properties: {
+ /**
+ * Fired when the input changes due to user interaction.
+ *
+ * @event change
+ */
+
+ /**
+ * The label for this input. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * `<label>`'s content and `hidden` property, e.g.
+ * `<label hidden$="[[!label]]">[[label]]</label>` in your `template`
+ */
+ label: {
+ type: String
+ },
+
+ /**
+ * The value for this input. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<input is="iron-input">`'s `bindValue`
+ * property, or the value property of your input that is `notify:true`.
+ */
+ value: {
+ notify: true,
+ type: String
+ },
+
+ /**
+ * Set to true to disable this input. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * both the `<paper-input-container>`'s and the input's `disabled` property.
+ */
+ disabled: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Returns true if the value is invalid. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to both the
+ * `<paper-input-container>`'s and the input's `invalid` property.
+ *
+ * If `autoValidate` is true, the `invalid` attribute is managed automatically,
+ * which can clobber attempts to manage it manually.
+ */
+ invalid: {
+ type: Boolean,
+ value: false,
+ notify: true
+ },
+
+ /**
+ * Set to true to prevent the user from entering invalid input. If you're
+ * using PaperInputBehavior to implement your own paper-input-like element,
+ * bind this to `<input is="iron-input">`'s `preventInvalidInput` property.
+ */
+ preventInvalidInput: {
+ type: Boolean
+ },
+
+ /**
+ * Set this to specify the pattern allowed by `preventInvalidInput`. If
+ * you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `allowedPattern`
+ * property.
+ */
+ allowedPattern: {
+ type: String
+ },
+
+ /**
+ * The type of the input. The supported types are `text`, `number` and `password`.
+ * If you're using PaperInputBehavior to implement your own paper-input-like element,
+ * bind this to the `<input is="iron-input">`'s `type` property.
+ */
+ type: {
+ type: String
+ },
+
+ /**
+ * The datalist of the input (if any). This should match the id of an existing `<datalist>`.
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `list` property.
+ */
+ list: {
+ type: String
+ },
+
+ /**
+ * A pattern to validate the `input` with. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<input is="iron-input">`'s `pattern` property.
+ */
+ pattern: {
+ type: String
+ },
+
+ /**
+ * Set to true to mark the input as required. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<input is="iron-input">`'s `required` property.
+ */
+ required: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The error message to display when the input is invalid. If you're using
+ * PaperInputBehavior to implement your own paper-input-like element,
+ * bind this to the `<paper-input-error>`'s content, if using.
+ */
+ errorMessage: {
+ type: String
+ },
+
+ /**
+ * Set to true to show a character counter.
+ */
+ charCounter: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable the floating label. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<paper-input-container>`'s `noLabelFloat` property.
+ */
+ noLabelFloat: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to always float the label. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<paper-input-container>`'s `alwaysFloatLabel` property.
+ */
+ alwaysFloatLabel: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to auto-validate the input value. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<paper-input-container>`'s `autoValidate` property.
+ */
+ autoValidate: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Name of the validator to use. If you're using PaperInputBehavior to
+ * implement your own paper-input-like element, bind this to
+ * the `<input is="iron-input">`'s `validator` property.
+ */
+ validator: {
+ type: String
+ },
+
+ // HTMLInputElement attributes for binding if needed
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `autocomplete` property.
+ */
+ autocomplete: {
+ type: String,
+ value: 'off'
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `autofocus` property.
+ */
+ autofocus: {
+ type: Boolean
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `inputmode` property.
+ */
+ inputmode: {
+ type: String
+ },
+
+ /**
+ * The minimum length of the input value.
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `minlength` property.
+ */
+ minlength: {
+ type: Number
+ },
+
+ /**
+ * The maximum length of the input value.
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `maxlength` property.
+ */
+ maxlength: {
+ type: Number
+ },
+
+ /**
+ * The minimum (numeric or date-time) input value.
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `min` property.
+ */
+ min: {
+ type: String
+ },
+
+ /**
+ * The maximum (numeric or date-time) input value.
+ * Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `max` property.
+ */
+ max: {
+ type: String
+ },
+
+ /**
+ * Limits the numeric or date-time increments.
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `step` property.
+ */
+ step: {
+ type: String
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `name` property.
+ */
+ name: {
+ type: String
+ },
+
+ /**
+ * A placeholder string in addition to the label. If this is set, the label will always float.
+ */
+ placeholder: {
+ type: String,
+ // need to set a default so _computeAlwaysFloatLabel is run
+ value: ''
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `readonly` property.
+ */
+ readonly: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `size` property.
+ */
+ size: {
+ type: Number
+ },
+
+ // Nonstandard attributes for binding if needed
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `autocapitalize` property.
+ */
+ autocapitalize: {
+ type: String,
+ value: 'none'
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `autocorrect` property.
+ */
+ autocorrect: {
+ type: String,
+ value: 'off'
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `autosave` property,
+ * used with type=search.
+ */
+ autosave: {
+ type: String
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `results` property,
+ * used with type=search.
+ */
+ results: {
+ type: Number
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the `<input is="iron-input">`'s `accept` property,
+ * used with type=file.
+ */
+ accept: {
+ type: String
+ },
+
+ /**
+ * If you're using PaperInputBehavior to implement your own paper-input-like
+ * element, bind this to the`<input is="iron-input">`'s `multiple` property,
+ * used with type=file.
+ */
+ multiple: {
+ type: Boolean
+ },
+
+ _ariaDescribedBy: {
+ type: String,
+ value: ''
+ },
+
+ _ariaLabelledBy: {
+ type: String,
+ value: ''
+ }
+
+ },
+
+ listeners: {
+ 'addon-attached': '_onAddonAttached',
+ },
+
+ keyBindings: {
+ 'shift+tab:keydown': '_onShiftTabDown'
+ },
+
+ hostAttributes: {
+ tabindex: 0
+ },
+
+ /**
+ * Returns a reference to the input element.
+ */
+ get inputElement() {
+ return this.$.input;
+ },
+
+ /**
+ * Returns a reference to the focusable element.
+ */
+ get _focusableElement() {
+ return this.inputElement;
+ },
+
+ registered: function() {
+ // These types have some default placeholder text; overlapping
+ // the label on top of it looks terrible. Auto-float the label in this case.
+ this._typesThatHaveText = ["date", "datetime", "datetime-local", "month",
+ "time", "week", "file"];
+ },
+
+ attached: function() {
+ this._updateAriaLabelledBy();
+
+ if (this.inputElement &&
+ this._typesThatHaveText.indexOf(this.inputElement.type) !== -1) {
+ this.alwaysFloatLabel = true;
+ }
+ },
+
+ _appendStringWithSpace: function(str, more) {
+ if (str) {
+ str = str + ' ' + more;
+ } else {
+ str = more;
+ }
+ return str;
+ },
+
+ _onAddonAttached: function(event) {
+ var target = event.path ? event.path[0] : event.target;
+ if (target.id) {
+ this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, target.id);
+ } else {
+ var id = 'paper-input-add-on-' + Polymer.PaperInputHelper.NextAddonID++;
+ target.id = id;
+ this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, id);
+ }
+ },
+
+ /**
+ * Validates the input element and sets an error style if needed.
+ *
+ * @return {boolean}
+ */
+ validate: function() {
+ return this.inputElement.validate();
+ },
+
+ /**
+ * Forward focus to inputElement. Overriden from IronControlState.
+ */
+ _focusBlurHandler: function(event) {
+ Polymer.IronControlState._focusBlurHandler.call(this, event);
+
+ // Forward the focus to the nested input.
+ if (this.focused && !this._shiftTabPressed)
+ this._focusableElement.focus();
+ },
+
+ /**
+ * Handler that is called when a shift+tab keypress is detected by the menu.
+ *
+ * @param {CustomEvent} event A key combination event.
+ */
+ _onShiftTabDown: function(event) {
+ var oldTabIndex = this.getAttribute('tabindex');
+ this._shiftTabPressed = true;
+ this.setAttribute('tabindex', '-1');
+ this.async(function() {
+ this.setAttribute('tabindex', oldTabIndex);
+ this._shiftTabPressed = false;
+ }, 1);
+ },
+
+ /**
+ * If `autoValidate` is true, then validates the element.
+ */
+ _handleAutoValidate: function() {
+ if (this.autoValidate)
+ this.validate();
+ },
+
+ /**
+ * Restores the cursor to its original position after updating the value.
+ * @param {string} newValue The value that should be saved.
+ */
+ updateValueAndPreserveCaret: function(newValue) {
+ // Not all elements might have selection, and even if they have the
+ // right properties, accessing them might throw an exception (like for
+ // <input type=number>)
+ try {
+ var start = this.inputElement.selectionStart;
+ this.value = newValue;
+
+ // The cursor automatically jumps to the end after re-setting the value,
+ // so restore it to its original position.
+ this.inputElement.selectionStart = start;
+ this.inputElement.selectionEnd = start;
+ } catch (e) {
+ // Just set the value and give up on the caret.
+ this.value = newValue;
+ }
+ },
+
+ _computeAlwaysFloatLabel: function(alwaysFloatLabel, placeholder) {
+ return placeholder || alwaysFloatLabel;
+ },
+
+ _updateAriaLabelledBy: function() {
+ var label = Polymer.dom(this.root).querySelector('label');
+ if (!label) {
+ this._ariaLabelledBy = '';
+ return;
+ }
+ var labelledBy;
+ if (label.id) {
+ labelledBy = label.id;
+ } else {
+ labelledBy = 'paper-input-label-' + Polymer.PaperInputHelper.NextLabelID++;
+ label.id = labelledBy;
+ }
+ this._ariaLabelledBy = labelledBy;
+ },
+
+ _onChange:function(event) {
+ // In the Shadow DOM, the `change` event is not leaked into the
+ // ancestor tree, so we must do this manually.
+ // See https://w3c.github.io/webcomponents/spec/shadow/#events-that-are-not-leaked-into-ancestor-trees.
+ if (this.shadowRoot) {
+ this.fire(event.type, {sourceEvent: event}, {
+ node: this,
+ bubbles: event.bubbles,
+ cancelable: event.cancelable
+ });
+ }
+ }
+ }
+
+ /** @polymerBehavior */
+ Polymer.PaperInputBehavior = [
+ Polymer.IronControlState,
+ Polymer.IronA11yKeysBehavior,
+ Polymer.PaperInputBehaviorImpl
+ ];
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-char-counter.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-char-counter.html
new file mode 100644
index 00000000000..1a09a06d0ee
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-char-counter.html
@@ -0,0 +1,99 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-styles/typography.html">
+<link rel="import" href="paper-input-addon-behavior.html">
+
+<!--
+`<paper-input-char-counter>` is a character counter for use with `<paper-input-container>`. It
+shows the number of characters entered in the input and the max length if it is specified.
+
+ <paper-input-container>
+ <input is="iron-input" maxlength="20">
+ <paper-input-char-counter></paper-input-char-counter>
+ </paper-input-container>
+
+### Styling
+
+The following mixin is available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-input-char-counter` | Mixin applied to the element | `{}`
+-->
+
+<dom-module id="paper-input-char-counter">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ float: right;
+
+ @apply(--paper-font-caption);
+ @apply(--paper-input-char-counter);
+ }
+
+ :host([hidden]) {
+ display: none !important;
+ }
+
+ :host-context([dir="rtl"]) {
+ float: left;
+ }
+ </style>
+
+ <span>[[_charCounterStr]]</span>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-input-char-counter',
+
+ behaviors: [
+ Polymer.PaperInputAddonBehavior
+ ],
+
+ properties: {
+ _charCounterStr: {
+ type: String,
+ value: '0'
+ }
+ },
+
+ /**
+ * This overrides the update function in PaperInputAddonBehavior.
+ * @param {{
+ * inputElement: (Element|undefined),
+ * value: (string|undefined),
+ * invalid: boolean
+ * }} state -
+ * inputElement: The input element.
+ * value: The input value.
+ * invalid: True if the input value is invalid.
+ */
+ update: function(state) {
+ if (!state.inputElement) {
+ return;
+ }
+
+ state.value = state.value || '';
+
+ var counter = state.value.toString().length.toString();
+
+ if (state.inputElement.hasAttribute('maxlength')) {
+ counter += '/' + state.inputElement.getAttribute('maxlength');
+ }
+
+ this._charCounterStr = counter;
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-container.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-container.html
new file mode 100644
index 00000000000..815a0a36ad1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-container.html
@@ -0,0 +1,621 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/typography.html">
+
+<!--
+`<paper-input-container>` is a container for a `<label>`, an `<input is="iron-input">` or
+`<iron-autogrow-textarea>` and optional add-on elements such as an error message or character
+counter, used to implement Material Design text fields.
+
+For example:
+
+ <paper-input-container>
+ <label>Your name</label>
+ <input is="iron-input">
+ </paper-input-container>
+
+Do not wrap `<paper-input-container>` around elements that already include it, such as `<paper-input>`.
+Doing so may cause events to bounce infintely between the container and its contained element.
+
+### Listening for input changes
+
+By default, it listens for changes on the `bind-value` attribute on its children nodes and perform
+tasks such as auto-validating and label styling when the `bind-value` changes. You can configure
+the attribute it listens to with the `attr-for-value` attribute.
+
+### Using a custom input element
+
+You can use a custom input element in a `<paper-input-container>`, for example to implement a
+compound input field like a social security number input. The custom input element should have the
+`paper-input-input` class, have a `notify:true` value property and optionally implements
+`Polymer.IronValidatableBehavior` if it is validatable.
+
+ <paper-input-container attr-for-value="ssn-value">
+ <label>Social security number</label>
+ <ssn-input class="paper-input-input"></ssn-input>
+ </paper-input-container>
+
+
+If you're using a `<paper-input-container>` imperatively, it's important to make sure
+that you attach its children (the `iron-input` and the optional `label`) before you
+attach the `<paper-input-container>` itself, so that it can be set up correctly.
+
+### Validation
+
+If the `auto-validate` attribute is set, the input container will validate the input and update
+the container styling when the input value changes.
+
+### Add-ons
+
+Add-ons are child elements of a `<paper-input-container>` with the `add-on` attribute and
+implements the `Polymer.PaperInputAddonBehavior` behavior. They are notified when the input value
+or validity changes, and may implement functionality such as error messages or character counters.
+They appear at the bottom of the input.
+
+### Prefixes and suffixes
+These are child elements of a `<paper-input-container>` with the `prefix`
+or `suffix` attribute, and are displayed inline with the input, before or after.
+
+ <paper-input-container>
+ <div prefix>$</div>
+ <label>Total</label>
+ <input is="iron-input">
+ <paper-icon-button suffix icon="clear"></paper-icon-button>
+ </paper-input-container>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-input-container-color` | Label and underline color when the input is not focused | `--secondary-text-color`
+`--paper-input-container-focus-color` | Label and underline color when the input is focused | `--primary-color`
+`--paper-input-container-invalid-color` | Label and underline color when the input is is invalid | `--error-color`
+`--paper-input-container-input-color` | Input foreground color | `--primary-text-color`
+`--paper-input-container` | Mixin applied to the container | `{}`
+`--paper-input-container-disabled` | Mixin applied to the container when it's disabled | `{}`
+`--paper-input-container-label` | Mixin applied to the label | `{}`
+`--paper-input-container-label-focus` | Mixin applied to the label when the input is focused | `{}`
+`--paper-input-container-label-floating` | Mixin applied to the label when floating | `{}`
+`--paper-input-container-input` | Mixin applied to the input | `{}`
+`--paper-input-container-underline` | Mixin applied to the underline | `{}`
+`--paper-input-container-underline-focus` | Mixin applied to the underline when the input is focused | `{}`
+`--paper-input-container-underline-disabled` | Mixin applied to the underline when the input is disabled | `{}`
+`--paper-input-prefix` | Mixin applied to the input prefix | `{}`
+`--paper-input-suffix` | Mixin applied to the input suffix | `{}`
+
+This element is `display:block` by default, but you can set the `inline` attribute to make it
+`display:inline-block`.
+-->
+
+<dom-module id="paper-input-container">
+ <template>
+ <style>
+ :host {
+ display: block;
+ padding: 8px 0;
+
+ @apply(--paper-input-container);
+ }
+
+ :host([inline]) {
+ display: inline-block;
+ }
+
+ :host([disabled]) {
+ pointer-events: none;
+ opacity: 0.33;
+
+ @apply(--paper-input-container-disabled);
+ }
+
+ :host([hidden]) {
+ display: none !important;
+ }
+
+ .floated-label-placeholder {
+ @apply(--paper-font-caption);
+ }
+
+ .underline {
+ position: relative;
+ }
+
+ .focused-line {
+ @apply(--layout-fit);
+
+ background: var(--paper-input-container-focus-color, --primary-color);
+ height: 2px;
+
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+ -webkit-transform: scale3d(0,1,1);
+ transform: scale3d(0,1,1);
+
+ @apply(--paper-input-container-underline-focus);
+ }
+
+ .underline.is-highlighted .focused-line {
+ -webkit-transform: none;
+ transform: none;
+ -webkit-transition: -webkit-transform 0.25s;
+ transition: transform 0.25s;
+
+ @apply(--paper-transition-easing);
+ }
+
+ .underline.is-invalid .focused-line {
+ background: var(--paper-input-container-invalid-color, --error-color);
+ -webkit-transform: none;
+ transform: none;
+ -webkit-transition: -webkit-transform 0.25s;
+ transition: transform 0.25s;
+
+ @apply(--paper-transition-easing);
+ }
+
+ .unfocused-line {
+ @apply(--layout-fit);
+
+ background: var(--paper-input-container-color, --secondary-text-color);
+ height: 1px;
+
+ @apply(--paper-input-container-underline);
+ }
+
+ :host([disabled]) .unfocused-line {
+ border-bottom: 1px dashed;
+ border-color: var(--paper-input-container-color, --secondary-text-color);
+ background: transparent;
+
+ @apply(--paper-input-container-underline-disabled);
+ }
+
+ .label-and-input-container {
+ @apply(--layout-flex-auto);
+ @apply(--layout-relative);
+
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .input-content {
+ @apply(--layout-horizontal);
+ @apply(--layout-center);
+
+ position: relative;
+ }
+
+ .input-content ::content label,
+ .input-content ::content .paper-input-label {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ width: 100%;
+ font: inherit;
+ color: var(--paper-input-container-color, --secondary-text-color);
+ -webkit-transition: -webkit-transform 0.25s, width 0.25s;
+ transition: transform 0.25s, width 0.25s;
+ -webkit-transform-origin: left top;
+ transform-origin: left top;
+
+ @apply(--paper-font-common-nowrap);
+ @apply(--paper-font-subhead);
+ @apply(--paper-input-container-label);
+ @apply(--paper-transition-easing);
+ }
+
+ .input-content.label-is-floating ::content label,
+ .input-content.label-is-floating ::content .paper-input-label {
+ -webkit-transform: translateY(-75%) scale(0.75);
+ transform: translateY(-75%) scale(0.75);
+
+ /* Since we scale to 75/100 of the size, we actually have 100/75 of the
+ original space now available */
+ width: 133%;
+
+ @apply(--paper-input-container-label-floating);
+ }
+
+ :host-context([dir="rtl"]) .input-content.label-is-floating ::content label,
+ :host-context([dir="rtl"]) .input-content.label-is-floating ::content .paper-input-label {
+ /* TODO(noms): Figure out why leaving the width at 133% before the animation
+ * actually makes
+ * it wider on the right side, not left side, as you would expect in RTL */
+ width: 100%;
+ -webkit-transform-origin: right top;
+ transform-origin: right top;
+ }
+
+ .input-content.label-is-highlighted ::content label,
+ .input-content.label-is-highlighted ::content .paper-input-label {
+ color: var(--paper-input-container-focus-color, --primary-color);
+
+ @apply(--paper-input-container-label-focus);
+ }
+
+ .input-content.is-invalid ::content label,
+ .input-content.is-invalid ::content .paper-input-label {
+ color: var(--paper-input-container-invalid-color, --error-color);
+ }
+
+ .input-content.label-is-hidden ::content label,
+ .input-content.label-is-hidden ::content .paper-input-label {
+ visibility: hidden;
+ }
+
+ .input-content ::content input,
+ .input-content ::content textarea,
+ .input-content ::content iron-autogrow-textarea,
+ .input-content ::content .paper-input-input {
+ position: relative; /* to make a stacking context */
+ outline: none;
+ box-shadow: none;
+ padding: 0;
+ width: 100%;
+ max-width: 100%;
+ background: transparent;
+ border: none;
+ color: var(--paper-input-container-input-color, --primary-text-color);
+ -webkit-appearance: none;
+ text-align: inherit;
+
+ @apply(--paper-font-subhead);
+ @apply(--paper-input-container-input);
+ }
+
+ ::content [prefix] {
+ @apply(--paper-font-subhead);
+
+ @apply(--paper-input-prefix);
+ @apply(--layout-flex-none);
+ }
+
+ ::content [suffix] {
+ @apply(--paper-font-subhead);
+
+ @apply(--paper-input-suffix);
+ @apply(--layout-flex-none);
+ }
+
+ /* Firefox sets a min-width on the input, which can cause layout issues */
+ .input-content ::content input {
+ min-width: 0;
+ }
+
+ .input-content ::content textarea {
+ resize: none;
+ }
+
+ .add-on-content {
+ position: relative;
+ }
+
+ .add-on-content.is-invalid ::content * {
+ color: var(--paper-input-container-invalid-color, --error-color);
+ }
+
+ .add-on-content.is-highlighted ::content * {
+ color: var(--paper-input-container-focus-color, --primary-color);
+ }
+ </style>
+
+ <template is="dom-if" if="[[!noLabelFloat]]">
+ <div class="floated-label-placeholder" aria-hidden="true">&nbsp;</div>
+ </template>
+
+ <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]">
+ <content select="[prefix]" id="prefix"></content>
+
+ <div class="label-and-input-container" id="labelAndInputContainer">
+ <content select=":not([add-on]):not([prefix]):not([suffix])"></content>
+ </div>
+
+ <content select="[suffix]"></content>
+ </div>
+
+ <div class$="[[_computeUnderlineClass(focused,invalid)]]">
+ <div class="unfocused-line"></div>
+ <div class="focused-line"></div>
+ </div>
+
+ <div class$="[[_computeAddOnContentClass(focused,invalid)]]">
+ <content id="addOnContent" select="[add-on]"></content>
+ </div>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-input-container',
+
+ properties: {
+ /**
+ * Set to true to disable the floating label. The label disappears when the input value is
+ * not null.
+ */
+ noLabelFloat: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to always float the floating label.
+ */
+ alwaysFloatLabel: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The attribute to listen for value changes on.
+ */
+ attrForValue: {
+ type: String,
+ value: 'bind-value'
+ },
+
+ /**
+ * Set to true to auto-validate the input value when it changes.
+ */
+ autoValidate: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * True if the input is invalid. This property is set automatically when the input value
+ * changes if auto-validating, or when the `iron-input-validate` event is heard from a child.
+ */
+ invalid: {
+ observer: '_invalidChanged',
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * True if the input has focus.
+ */
+ focused: {
+ readOnly: true,
+ type: Boolean,
+ value: false,
+ notify: true
+ },
+
+ _addons: {
+ type: Array
+ // do not set a default value here intentionally - it will be initialized lazily when a
+ // distributed child is attached, which may occur before configuration for this element
+ // in polyfill.
+ },
+
+ _inputHasContent: {
+ type: Boolean,
+ value: false
+ },
+
+ _inputSelector: {
+ type: String,
+ value: 'input,textarea,.paper-input-input'
+ },
+
+ _boundOnFocus: {
+ type: Function,
+ value: function() {
+ return this._onFocus.bind(this);
+ }
+ },
+
+ _boundOnBlur: {
+ type: Function,
+ value: function() {
+ return this._onBlur.bind(this);
+ }
+ },
+
+ _boundOnInput: {
+ type: Function,
+ value: function() {
+ return this._onInput.bind(this);
+ }
+ },
+
+ _boundValueChanged: {
+ type: Function,
+ value: function() {
+ return this._onValueChanged.bind(this);
+ }
+ }
+ },
+
+ listeners: {
+ 'addon-attached': '_onAddonAttached',
+ 'iron-input-validate': '_onIronInputValidate'
+ },
+
+ get _valueChangedEvent() {
+ return this.attrForValue + '-changed';
+ },
+
+ get _propertyForValue() {
+ return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
+ },
+
+ get _inputElement() {
+ return Polymer.dom(this).querySelector(this._inputSelector);
+ },
+
+ get _inputElementValue() {
+ return this._inputElement[this._propertyForValue] || this._inputElement.value;
+ },
+
+ ready: function() {
+ if (!this._addons) {
+ this._addons = [];
+ }
+ this.addEventListener('focus', this._boundOnFocus, true);
+ this.addEventListener('blur', this._boundOnBlur, true);
+ },
+
+ attached: function() {
+ if (this.attrForValue) {
+ this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
+ } else {
+ this.addEventListener('input', this._onInput);
+ }
+
+ // Only validate when attached if the input already has a value.
+ if (this._inputElementValue != '') {
+ this._handleValueAndAutoValidate(this._inputElement);
+ } else {
+ this._handleValue(this._inputElement);
+ }
+ },
+
+ _onAddonAttached: function(event) {
+ if (!this._addons) {
+ this._addons = [];
+ }
+ var target = event.target;
+ if (this._addons.indexOf(target) === -1) {
+ this._addons.push(target);
+ if (this.isAttached) {
+ this._handleValue(this._inputElement);
+ }
+ }
+ },
+
+ _onFocus: function() {
+ this._setFocused(true);
+ },
+
+ _onBlur: function() {
+ this._setFocused(false);
+ this._handleValueAndAutoValidate(this._inputElement);
+ },
+
+ _onInput: function(event) {
+ this._handleValueAndAutoValidate(event.target);
+ },
+
+ _onValueChanged: function(event) {
+ this._handleValueAndAutoValidate(event.target);
+ },
+
+ _handleValue: function(inputElement) {
+ var value = this._inputElementValue;
+
+ // type="number" hack needed because this.value is empty until it's valid
+ if (value || value === 0 || (inputElement.type === 'number' && !inputElement.checkValidity())) {
+ this._inputHasContent = true;
+ } else {
+ this._inputHasContent = false;
+ }
+
+ this.updateAddons({
+ inputElement: inputElement,
+ value: value,
+ invalid: this.invalid
+ });
+ },
+
+ _handleValueAndAutoValidate: function(inputElement) {
+ if (this.autoValidate) {
+ var valid;
+ if (inputElement.validate) {
+ valid = inputElement.validate(this._inputElementValue);
+ } else {
+ valid = inputElement.checkValidity();
+ }
+ this.invalid = !valid;
+ }
+
+ // Call this last to notify the add-ons.
+ this._handleValue(inputElement);
+ },
+
+ _onIronInputValidate: function(event) {
+ this.invalid = this._inputElement.invalid;
+ },
+
+ _invalidChanged: function() {
+ if (this._addons) {
+ this.updateAddons({invalid: this.invalid});
+ }
+ },
+
+ /**
+ * Call this to update the state of add-ons.
+ * @param {Object} state Add-on state.
+ */
+ updateAddons: function(state) {
+ for (var addon, index = 0; addon = this._addons[index]; index++) {
+ addon.update(state);
+ }
+ },
+
+ _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
+ var cls = 'input-content';
+ if (!noLabelFloat) {
+ var label = this.querySelector('label');
+
+ if (alwaysFloatLabel || _inputHasContent) {
+ cls += ' label-is-floating';
+ // If the label is floating, ignore any offsets that may have been
+ // applied from a prefix element.
+ this.$.labelAndInputContainer.style.position = 'static';
+
+ if (invalid) {
+ cls += ' is-invalid';
+ } else if (focused) {
+ cls += " label-is-highlighted";
+ }
+ } else {
+ // When the label is not floating, it should overlap the input element.
+ if (label) {
+ this.$.labelAndInputContainer.style.position = 'relative';
+ }
+ }
+ } else {
+ if (_inputHasContent) {
+ cls += ' label-is-hidden';
+ }
+ }
+ return cls;
+ },
+
+ _computeUnderlineClass: function(focused, invalid) {
+ var cls = 'underline';
+ if (invalid) {
+ cls += ' is-invalid';
+ } else if (focused) {
+ cls += ' is-highlighted'
+ }
+ return cls;
+ },
+
+ _computeAddOnContentClass: function(focused, invalid) {
+ var cls = 'add-on-content';
+ if (invalid) {
+ cls += ' is-invalid';
+ } else if (focused) {
+ cls += ' is-highlighted'
+ }
+ return cls;
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-error.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-error.html
new file mode 100644
index 00000000000..645f1e722b0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input-error.html
@@ -0,0 +1,94 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/typography.html">
+<link rel="import" href="paper-input-addon-behavior.html">
+
+<!--
+`<paper-input-error>` is an error message for use with `<paper-input-container>`. The error is
+displayed when the `<paper-input-container>` is `invalid`.
+
+ <paper-input-container>
+ <input is="iron-input" pattern="[0-9]*">
+ <paper-input-error>Only numbers are allowed!</paper-input-error>
+ </paper-input-container>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-input-container-invalid-color` | The foreground color of the error | `--error-color`
+`--paper-input-error` | Mixin applied to the error | `{}`
+-->
+
+<dom-module id="paper-input-error">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ visibility: hidden;
+
+ color: var(--paper-input-container-invalid-color, --error-color);
+
+ @apply(--paper-font-caption);
+ @apply(--paper-input-error);
+ position: absolute;
+ left:0;
+ right:0;
+ }
+
+ :host([invalid]) {
+ visibility: visible;
+ };
+ </style>
+
+ <content></content>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-input-error',
+
+ behaviors: [
+ Polymer.PaperInputAddonBehavior
+ ],
+
+ properties: {
+ /**
+ * True if the error is showing.
+ */
+ invalid: {
+ readOnly: true,
+ reflectToAttribute: true,
+ type: Boolean
+ }
+ },
+
+ /**
+ * This overrides the update function in PaperInputAddonBehavior.
+ * @param {{
+ * inputElement: (Element|undefined),
+ * value: (string|undefined),
+ * invalid: boolean
+ * }} state -
+ * inputElement: The input element.
+ * value: The input value.
+ * invalid: True if the input value is invalid.
+ */
+ update: function(state) {
+ this._setInvalid(state.invalid);
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input.html
new file mode 100644
index 00000000000..075cfa68b45
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-input.html
@@ -0,0 +1,162 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+<link rel="import" href="../iron-input/iron-input.html">
+<link rel="import" href="paper-input-behavior.html">
+<link rel="import" href="paper-input-char-counter.html">
+<link rel="import" href="paper-input-container.html">
+<link rel="import" href="paper-input-error.html">
+
+<!--
+Material design: [Text fields](https://www.google.com/design/spec/components/text-fields.html)
+
+`<paper-input>` is a single-line text field with Material Design styling.
+
+ <paper-input label="Input label"></paper-input>
+
+It may include an optional error message or character counter.
+
+ <paper-input error-message="Invalid input!" label="Input label"></paper-input>
+ <paper-input char-counter label="Input label"></paper-input>
+
+It can also include custom prefix or suffix elements, which are displayed
+before or after the text input itself. In order for an element to be
+considered as a prefix, it must have the `prefix` attribute (and similarly
+for `suffix`).
+
+ <paper-input label="total">
+ <div prefix>$</div>
+ <paper-icon-button suffix icon="clear"></paper-icon-button>
+ </paper-input>
+
+A `paper-input` can use the native `type=search` or `type=file` features.
+However, since we can't control the native styling of the input (search icon,
+file button, date placeholder, etc.), in these cases the label will be
+automatically floated. The `placeholder` attribute can still be used for
+additional informational text.
+
+ <paper-input label="search!" type="search"
+ placeholder="search for cats" autosave="test" results="5">
+ </paper-input>
+
+See `Polymer.PaperInputBehavior` for more API docs.
+
+### Focus
+
+To focus a paper-input, you can call the native `focus()` method as long as the
+paper input has a tab index.
+
+### Styling
+
+See `Polymer.PaperInputContainer` for a list of custom properties used to
+style this element.
+
+
+@group Paper Elements
+@element paper-input
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-input">
+ <template>
+ <style>
+ :host {
+ display: block;
+ }
+
+ :host([hidden]) {
+ display: none !important;
+ }
+
+ input::-webkit-input-placeholder {
+ color: var(--paper-input-container-color, --secondary-text-color);
+ }
+
+ input:-moz-placeholder {
+ color: var(--paper-input-container-color, --secondary-text-color);
+ }
+
+ input::-moz-placeholder {
+ color: var(--paper-input-container-color, --secondary-text-color);
+ }
+
+ input:-ms-input-placeholder {
+ color: var(--paper-input-container-color, --secondary-text-color);
+ }
+ </style>
+
+ <paper-input-container no-label-float="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[autoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
+
+ <content select="[prefix]"></content>
+
+ <label hidden$="[[!label]]" aria-hidden="true">[[label]]</label>
+
+ <input is="iron-input" id="input"
+ aria-labelledby$="[[_ariaLabelledBy]]"
+ aria-describedby$="[[_ariaDescribedBy]]"
+ disabled$="[[disabled]]"
+ title$="[[title]]"
+ bind-value="{{value}}"
+ invalid="{{invalid}}"
+ prevent-invalid-input="[[preventInvalidInput]]"
+ allowed-pattern="[[allowedPattern]]"
+ validator="[[validator]]"
+ type$="[[type]]"
+ pattern$="[[pattern]]"
+ required$="[[required]]"
+ autocomplete$="[[autocomplete]]"
+ autofocus$="[[autofocus]]"
+ inputmode$="[[inputmode]]"
+ minlength$="[[minlength]]"
+ maxlength$="[[maxlength]]"
+ min$="[[min]]"
+ max$="[[max]]"
+ step$="[[step]]"
+ name$="[[name]]"
+ placeholder$="[[placeholder]]"
+ readonly$="[[readonly]]"
+ list$="[[list]]"
+ size$="[[size]]"
+ autocapitalize$="[[autocapitalize]]"
+ autocorrect$="[[autocorrect]]"
+ on-change="_onChange"
+ tabindex$="[[tabindex]]"
+ autosave$="[[autosave]]"
+ results$="[[results]]"
+ accept$="[[accept]]"
+ multiple$="[[multiple]]">
+
+ <content select="[suffix]"></content>
+
+ <template is="dom-if" if="[[errorMessage]]">
+ <paper-input-error>[[errorMessage]]</paper-input-error>
+ </template>
+
+ <template is="dom-if" if="[[charCounter]]">
+ <paper-input-char-counter></paper-input-char-counter>
+ </template>
+
+ </paper-input-container>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-input',
+
+ behaviors: [
+ Polymer.IronFormElementBehavior,
+ Polymer.PaperInputBehavior
+ ]
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-textarea.html b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-textarea.html
new file mode 100644
index 00000000000..064efec83dc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-input/paper-textarea.html
@@ -0,0 +1,138 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-autogrow-textarea/iron-autogrow-textarea.html">
+<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+<link rel="import" href="paper-input-behavior.html">
+<link rel="import" href="paper-input-char-counter.html">
+<link rel="import" href="paper-input-container.html">
+<link rel="import" href="paper-input-error.html">
+
+<!--
+`<paper-textarea>` is a multi-line text field with Material Design styling.
+
+ <paper-textarea label="Textarea label"></paper-textarea>
+
+See `Polymer.PaperInputBehavior` for more API docs.
+
+### Validation
+
+Currently only `required` and `maxlength` validation is supported.
+
+### Styling
+
+See `Polymer.PaperInputContainer` for a list of custom properties used to
+style this element.
+-->
+
+<dom-module id="paper-textarea">
+ <template>
+ <style>
+ :host {
+ display: block;
+ }
+
+ :host([hidden]) {
+ display: none !important;
+ }
+ </style>
+
+ <paper-input-container no-label-float$="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[autoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
+
+ <label hidden$="[[!label]]" aria-hidden="true">[[label]]</label>
+
+ <iron-autogrow-textarea id="input" class="paper-input-input"
+ bind-value="{{value}}"
+ disabled$="[[disabled]]"
+ autocomplete$="[[autocomplete]]"
+ autofocus$="[[autofocus]]"
+ inputmode$="[[inputmode]]"
+ name$="[[name]]"
+ placeholder$="[[placeholder]]"
+ readonly$="[[readonly]]"
+ required$="[[required]]"
+ maxlength$="[[maxlength]]"
+ autocapitalize$="[[autocapitalize]]"
+ rows$="[[rows]]"
+ max-rows$="[[maxRows]]"
+ on-change="_onChange"></iron-autogrow-textarea>
+
+ <template is="dom-if" if="[[errorMessage]]">
+ <paper-input-error>[[errorMessage]]</paper-input-error>
+ </template>
+
+ <template is="dom-if" if="[[charCounter]]">
+ <paper-input-char-counter></paper-input-char-counter>
+ </template>
+
+ </paper-input-container>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-textarea',
+
+ behaviors: [
+ Polymer.PaperInputBehavior,
+ Polymer.IronFormElementBehavior
+ ],
+
+ properties: {
+ _ariaLabelledBy: {
+ observer: '_ariaLabelledByChanged',
+ type: String
+ },
+
+ _ariaDescribedBy: {
+ observer: '_ariaDescribedByChanged',
+ type: String
+ },
+
+ /**
+ * The initial number of rows.
+ *
+ * @attribute rows
+ * @type number
+ * @default 1
+ */
+ rows: {
+ type: Number,
+ value: 1
+ },
+
+ /**
+ * The maximum number of rows this element can grow to until it
+ * scrolls. 0 means no maximum.
+ *
+ * @attribute maxRows
+ * @type number
+ * @default 0
+ */
+ maxRows: {
+ type: Number,
+ value: 0
+ }
+ },
+
+ _ariaLabelledByChanged: function(ariaLabelledBy) {
+ this.$.input.textarea.setAttribute('aria-labelledby', ariaLabelledBy);
+ },
+
+ _ariaDescribedByChanged: function(ariaDescribedBy) {
+ this.$.input.textarea.setAttribute('aria-describedby', ariaDescribedBy);
+ },
+
+ get _focusableElement() {
+ return this.$.input.textarea;
+ },
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-item/.bower.json
new file mode 100644
index 00000000000..91f23cd9745
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/.bower.json
@@ -0,0 +1,52 @@
+{
+ "name": "paper-item",
+ "version": "1.2.1",
+ "description": "A material-design styled list item",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "item"
+ ],
+ "main": [
+ "paper-item.html",
+ "paper-icon-item.html",
+ "paper-item-body.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-item"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-item",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-behaviors": "polymerelements/iron-behaviors#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
+ },
+ "_release": "1.2.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.1",
+ "commit": "1eab91333b318ae19e315866575b2dddd38e6abc"
+ },
+ "_source": "git://github.com/PolymerElements/paper-item.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-item"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-item/.travis.yml
new file mode 100644
index 00000000000..c4d7b1805f6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: NCk3KK+wbaXMzp8XAY6FeL+TSdI0AlPI3/tl0OpsUIaU2EiCjQuzf/UpyzCW5XZMEVFF4q/eDjrPkqJodHfpngj36mpkfmfqj9DrgDmYsV9BDvsTd8KmLsA6H8D6p7Qer+r1JMMB8PvX44vdhQ6GhZD1HFNYK1Ekpt0TkYwWKNw=
+ - secure: TGgUEQe6FJS+GuYk94d//8YQmDLUu0ekMvPSIs8TQ2QkdBK4SL+2bSXZt44BbDEOwc9P4NCPSUx/RMiCAqsc5OGRJImzb/zqPNIDTeKG6q72HPBBBD3Sk0CrEpTQbOK/Flaa/B7RYR0U1kuljSmRS7lPG19nnY8gOHnIAgwIyk0=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-item/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-item/README.md
new file mode 100644
index 00000000000..18deb629f49
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/README.md
@@ -0,0 +1,163 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-icon-item.html paper-item-behavior.html paper-item-body.html paper-item.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-item.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-item)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-item)_
+
+
+##&lt;paper-item&gt;
+
+Material design: [Lists](https://www.google.com/design/spec/components/lists.html)
+
+`<paper-item>` is an interactive list item. By default, it is a horizontal flexbox.
+
+```html
+<paper-item>Item</paper-item>
+```
+
+Use this element with `<paper-item-body>` to make Material Design styled two-line and three-line
+items.
+
+```html
+<paper-item>
+ <paper-item-body two-line>
+ <div>Show your status</div>
+ <div secondary>Your status is visible to everyone</div>
+ </paper-item-body>
+ <iron-icon icon="warning"></iron-icon>
+</paper-item>
+```
+
+To use `paper-item` as a link, wrap it in an anchor tag. Since `paper-item` will
+already receive focus, you may want to prevent the anchor tag from receiving
+focus as well by setting its tabindex to -1.
+
+```html
+<a href="https://www.polymer-project.org/" tabindex="-1">
+ <paper-item raised>Polymer Project</paper-item>
+</a>
+```
+
+If you are concerned about performance and want to use `paper-item` in a `paper-listbox`
+with many items, you can just use a native `button` with the `paper-item` class
+applied (provided you have correctly included the shared styles):
+
+```html
+<style is="custom-style" include="paper-item-shared-styles"></style>
+
+<paper-listbox>
+ <button class="paper-item" role="option">Inbox</button>
+ <button class="paper-item" role="option">Starred</button>
+ <button class="paper-item" role="option">Sent mail</button>
+</paper-listbox>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-min-height` | Minimum height of the item | `48px` |
+| `--paper-item` | Mixin applied to the item | `{}` |
+| `--paper-item-selected-weight` | The font weight of a selected item | `bold` |
+| `--paper-item-selected` | Mixin applied to selected paper-items | `{}` |
+| `--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color` |
+| `--paper-item-disabled` | Mixin applied to disabled paper-items | `{}` |
+| `--paper-item-focused` | Mixin applied to focused paper-items | `{}` |
+| `--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}` |
+
+### Accessibility
+
+This element has `role="listitem"` by default. Depending on usage, it may be more appropriate to set
+`role="menuitem"`, `role="menuitemcheckbox"` or `role="menuitemradio"`.
+
+```html
+<paper-item role="menuitemcheckbox">
+ <paper-item-body>
+ Show your status
+ </paper-item-body>
+ <paper-checkbox></paper-checkbox>
+</paper-item>
+```
+
+
+
+##&lt;paper-icon-item&gt;
+
+`<paper-icon-item>` is a convenience element to make an item with icon. It is an interactive list
+item with a fixed-width icon area, according to Material Design. This is useful if the icons are of
+varying widths, but you want the item bodies to line up. Use this like a `<paper-item>`. The child
+node with the attribute `item-icon` is placed in the icon area.
+
+```html
+<paper-icon-item>
+ <iron-icon icon="favorite" item-icon></iron-icon>
+ Favorite
+</paper-icon-item>
+<paper-icon-item>
+ <div class="avatar" item-icon></div>
+ Avatar
+</paper-icon-item>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-icon-width` | Width of the icon area | `56px` |
+| `--paper-item-icon` | Mixin applied to the icon area | `{}` |
+| `--paper-icon-item` | Mixin applied to the item | `{}` |
+| `--paper-item-selected-weight` | The font weight of a selected item | `bold` |
+| `--paper-item-selected` | Mixin applied to selected paper-items | `{}` |
+| `--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color` |
+| `--paper-item-disabled` | Mixin applied to disabled paper-items | `{}` |
+| `--paper-item-focused` | Mixin applied to focused paper-items | `{}` |
+| `--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}` |
+
+
+
+##&lt;paper-item-body&gt;
+
+Use `<paper-item-body>` in a `<paper-item>` or `<paper-icon-item>` to make two- or
+three- line items. It is a flex item that is a vertical flexbox.
+
+```html
+<paper-item>
+ <paper-item-body two-line>
+ <div>Show your status</div>
+ <div secondary>Your status is visible to everyone</div>
+ </paper-item-body>
+</paper-item>
+```
+
+The child elements with the `secondary` attribute is given secondary text styling.
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-item-body-two-line-min-height` | Minimum height of a two-line item | `72px` |
+| `--paper-item-body-three-line-min-height` | Minimum height of a three-line item | `88px` |
+| `--paper-item-body-secondary-color` | Foreground color for the `secondary` area | `--secondary-text-color` |
+| `--paper-item-body-secondary` | Mixin applied to the `secondary` area | `{}` |
+
+
+
+<!-- No docs for Polymer.PaperItemBehavior found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/all-imports.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/all-imports.html
new file mode 100644
index 00000000000..4b1583fe410
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/all-imports.html
@@ -0,0 +1,13 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="paper-item.html">
+<link rel="import" href="paper-item-body.html">
+<link rel="import" href="paper-icon-item.html">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-item/bower.json
new file mode 100644
index 00000000000..9028ed7fd58
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/bower.json
@@ -0,0 +1,43 @@
+{
+ "name": "paper-item",
+ "version": "1.2.1",
+ "description": "A material-design styled list item",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "item"
+ ],
+ "main": [
+ "paper-item.html",
+ "paper-icon-item.html",
+ "paper-item-body.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-item"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-item",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-behaviors": "polymerelements/iron-behaviors#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/demo/index.html
new file mode 100644
index 00000000000..bc95e7f9c0b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/demo/index.html
@@ -0,0 +1,191 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-item demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-icon/iron-icon.html">
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../iron-icons/communication-icons.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+ <link rel="import" href="../paper-icon-item.html">
+ <link rel="import" href="../paper-item.html">
+ <link rel="import" href="../paper-item-body.html">
+ <link rel="import" href="../../paper-styles/color.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ div[role="listbox"] {
+ border: 1px solid #e5e5e5;
+ }
+ .avatar {
+ display: inline-block;
+ box-sizing: border-box;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ background: var(--paper-amber-500);
+ }
+
+ .blue {
+ background-color: var(--paper-light-blue-300);
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Paper-items are simple list elements, ideally used in a paper-listbox or
+ an element with <i>role="listbox"</i></h3>
+ <demo-snippet>
+ <template>
+ <div role="listbox">
+ <paper-item>Inbox</paper-item>
+ <paper-item>Starred</paper-item>
+ <paper-item>Sent mail</paper-item>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>They can be styled using custom properties</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ paper-item.fancy {
+ --paper-item-focused: {
+ background: var(--paper-amber-500);
+ font-weight: bold;
+ };
+ --paper-item-focused-before: {
+ opacity: 0;
+ };
+ }
+ </style>
+ <div role="listbox">
+ <paper-item class="fancy">Inbox</paper-item>
+ <paper-item class="fancy">Starred</paper-item>
+ <paper-item class="fancy">Sent mail</paper-item>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>To add a leading element, use a paper-icon-item with an <i>item-icon</i> attribute. This
+ leading image can be an iron-icon, or any other regular element.</h3>
+ <demo-snippet>
+ <template>
+ <div role="listbox">
+ <paper-icon-item>
+ <iron-icon icon="inbox" item-icon></iron-icon>
+ Inbox
+ </paper-icon-item>
+ <paper-icon-item>
+ <iron-icon icon="star" item-icon></iron-icon>
+ Starred
+ </paper-icon-item>
+ <paper-icon-item>
+ <div class="avatar blue" item-icon></div>
+ Alphonso Engelking
+ </paper-icon-item>
+ <paper-icon-item>
+ <div class="avatar" item-icon></div>
+ Angela Decker
+ </paper-icon-item>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>For two-line items, use a paper-icon-body inside a paper-item or paper-icon-item</h3>
+ <demo-snippet>
+ <template>
+ <div role="listbox">
+ <paper-item>
+ <paper-item-body two-line>
+ <div>Profile Photo</div>
+ <div secondary>Change your Google+ profile photo</div>
+ </paper-item-body>
+ </paper-item>
+ <paper-icon-item>
+ <iron-icon icon="communication:phone" item-icon>
+ </iron-icon>
+ <paper-item-body two-line>
+ <div>(650) 555-1234</div>
+ <div secondary>Mobile</div>
+ </paper-item-body>
+ </paper-icon-item>
+ <paper-icon-item>
+ <div class="avatar blue" item-icon></div>
+ <paper-item-body two-line>
+ <div>Alphonso Engelking</div>
+ <div secondary>Change photo</div>
+ </paper-item-body>
+ </paper-icon-item>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>Complex layouts are usually a combination of all these elements</h3>
+ <demo-snippet>
+ <template>
+ <div role="listbox">
+ <paper-icon-item>
+ <div class="avatar blue" item-icon></div>
+ <paper-item-body two-line>
+ <div>Photos</div>
+ <div secondary>Jan 9, 2014</div>
+ </paper-item-body>
+ <paper-icon-button icon="star" alt="favourite this!">
+ </paper-icon-button>
+ </paper-icon-item>
+ <paper-icon-item>
+ <div class="avatar" item-icon></div>
+ <paper-item-body two-line>
+ <div>Recipes</div>
+ <div secondary>Jan 17, 2014</div>
+ </paper-item-body>
+ <paper-icon-button icon="star" alt="favourite this!">
+ </paper-icon-button>
+ </paper-icon-item>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>Paper-items can be used as links</h3>
+ <demo-snippet>
+ <template>
+ <style is="custom-style">
+ .paper-item-link {
+ color: inherit;
+ text-decoration: none;
+ }
+ </style>
+ <div role="listbox">
+ <a class="paper-item-link" href="#inbox" tabindex="-1">
+ <paper-item>Inbox</paper-item>
+ </a>
+ <a class="paper-item-link" href="#starred" tabindex="-1">
+ <paper-item>Starred</paper-item>
+ </a>
+ <a class="paper-item-link" href="#sent" tabindex="-1">
+ <paper-item>Sent mail</paper-item>
+ </a>
+ </div>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/index.html
new file mode 100644
index 00000000000..b409ed121cd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/index.html
@@ -0,0 +1,30 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-item</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page src="all-imports.html"></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-icon-item.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-icon-item.html
new file mode 100644
index 00000000000..e8f6d0795ed
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-icon-item.html
@@ -0,0 +1,86 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/typography.html">
+<link rel="import" href="paper-item-behavior.html">
+<link rel="import" href="paper-item-shared-styles.html">
+
+<!--
+`<paper-icon-item>` is a convenience element to make an item with icon. It is an interactive list
+item with a fixed-width icon area, according to Material Design. This is useful if the icons are of
+varying widths, but you want the item bodies to line up. Use this like a `<paper-item>`. The child
+node with the attribute `item-icon` is placed in the icon area.
+
+ <paper-icon-item>
+ <iron-icon icon="favorite" item-icon></iron-icon>
+ Favorite
+ </paper-icon-item>
+ <paper-icon-item>
+ <div class="avatar" item-icon></div>
+ Avatar
+ </paper-icon-item>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+------------------------------|------------------------------------------------|----------
+`--paper-item-icon-width` | Width of the icon area | `56px`
+`--paper-item-icon` | Mixin applied to the icon area | `{}`
+`--paper-icon-item` | Mixin applied to the item | `{}`
+`--paper-item-selected-weight`| The font weight of a selected item | `bold`
+`--paper-item-selected` | Mixin applied to selected paper-items | `{}`
+`--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color`
+`--paper-item-disabled` | Mixin applied to disabled paper-items | `{}`
+`--paper-item-focused` | Mixin applied to focused paper-items | `{}`
+`--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}`
+-->
+
+<dom-module id="paper-icon-item">
+ <template>
+ <style include="paper-item-shared-styles"></style>
+ <style>
+ :host {
+ @apply(--layout-horizontal);
+ @apply(--layout-center);
+ @apply(--paper-font-subhead);
+
+ @apply(--paper-item);
+ @apply(--paper-icon-item);
+ }
+
+ .content-icon {
+ @apply(--layout-horizontal);
+ @apply(--layout-center);
+
+ width: var(--paper-item-icon-width, 56px);
+ @apply(--paper-item-icon);
+ }
+ </style>
+
+ <div id="contentIcon" class="content-icon">
+ <content select="[item-icon]"></content>
+ </div>
+ <content></content>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-icon-item',
+
+ behaviors: [
+ Polymer.PaperItemBehavior
+ ]
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-behavior.html
new file mode 100644
index 00000000000..f97b262b737
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-behavior.html
@@ -0,0 +1,36 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-behaviors/iron-button-state.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+
+<!--
+`PaperItemBehavior` is a convenience behavior shared by <paper-item> and
+<paper-icon-item> that manages the shared control states and attributes of
+the items.
+-->
+
+<script>
+ /** @polymerBehavior Polymer.PaperItemBehavior */
+ Polymer.PaperItemBehaviorImpl = {
+ hostAttributes: {
+ role: 'option',
+ tabindex: '0'
+ }
+ };
+
+ /** @polymerBehavior */
+ Polymer.PaperItemBehavior = [
+ Polymer.IronButtonState,
+ Polymer.IronControlState,
+ Polymer.PaperItemBehaviorImpl
+ ];
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-body.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-body.html
new file mode 100644
index 00000000000..5c46cd891c7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-body.html
@@ -0,0 +1,83 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/typography.html">
+
+<!--
+Use `<paper-item-body>` in a `<paper-item>` or `<paper-icon-item>` to make two- or
+three- line items. It is a flex item that is a vertical flexbox.
+
+ <paper-item>
+ <paper-item-body two-line>
+ <div>Show your status</div>
+ <div secondary>Your status is visible to everyone</div>
+ </paper-item-body>
+ </paper-item>
+
+The child elements with the `secondary` attribute is given secondary text styling.
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-item-body-two-line-min-height` | Minimum height of a two-line item | `72px`
+`--paper-item-body-three-line-min-height` | Minimum height of a three-line item | `88px`
+`--paper-item-body-secondary-color` | Foreground color for the `secondary` area | `--secondary-text-color`
+`--paper-item-body-secondary` | Mixin applied to the `secondary` area | `{}`
+
+-->
+
+<dom-module id="paper-item-body">
+ <template>
+ <style>
+ :host {
+ overflow: hidden; /* needed for text-overflow: ellipsis to work on ff */
+ @apply(--layout-vertical);
+ @apply(--layout-center-justified);
+ @apply(--layout-flex);
+ }
+
+ :host([two-line]) {
+ min-height: var(--paper-item-body-two-line-min-height, 72px);
+ }
+
+ :host([three-line]) {
+ min-height: var(--paper-item-body-three-line-min-height, 88px);
+ }
+
+ :host > ::content > * {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ :host > ::content [secondary] {
+ @apply(--paper-font-body1);
+
+ color: var(--paper-item-body-secondary-color, --secondary-text-color);
+
+ @apply(--paper-item-body-secondary);
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-item-body'
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-shared-styles.html
new file mode 100644
index 00000000000..868d415350a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item-shared-styles.html
@@ -0,0 +1,70 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/typography.html">
+
+<dom-module id="paper-item-shared-styles">
+ <template>
+ <style>
+ :host, .paper-item {
+ display: block;
+ position: relative;
+ min-height: var(--paper-item-min-height, 48px);
+ padding: 0px 16px;
+ }
+
+ .paper-item {
+ @apply(--paper-font-subhead);
+ border:none;
+ outline: none;
+ background: white;
+ width: 100%;
+ text-align: left;
+ }
+
+ :host([hidden]), .paper-item[hidden] {
+ display: none !important;
+ }
+
+ :host(.iron-selected), .paper-item.iron-selected {
+ font-weight: var(--paper-item-selected-weight, bold);
+
+ @apply(--paper-item-selected);
+ }
+
+ :host([disabled]), .paper-item[disabled] {
+ color: var(--paper-item-disabled-color, --disabled-text-color);
+
+ @apply(--paper-item-disabled);
+ }
+
+ :host(:focus), .paper-item:focus {
+ position: relative;
+ outline: 0;
+
+ @apply(--paper-item-focused);
+ }
+
+ :host(:focus):before, .paper-item:focus:before {
+ @apply(--layout-fit);
+
+ background: currentColor;
+ content: '';
+ opacity: var(--dark-divider-opacity);
+ pointer-events: none;
+
+ @apply(--paper-item-focused-before);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item.html b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item.html
new file mode 100644
index 00000000000..60b4692d7cb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-item/paper-item.html
@@ -0,0 +1,111 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="paper-item-behavior.html">
+<link rel="import" href="paper-item-shared-styles.html">
+
+<!--
+Material design: [Lists](https://www.google.com/design/spec/components/lists.html)
+
+`<paper-item>` is an interactive list item. By default, it is a horizontal flexbox.
+
+ <paper-item>Item</paper-item>
+
+Use this element with `<paper-item-body>` to make Material Design styled two-line and three-line
+items.
+
+ <paper-item>
+ <paper-item-body two-line>
+ <div>Show your status</div>
+ <div secondary>Your status is visible to everyone</div>
+ </paper-item-body>
+ <iron-icon icon="warning"></iron-icon>
+ </paper-item>
+
+To use `paper-item` as a link, wrap it in an anchor tag. Since `paper-item` will
+already receive focus, you may want to prevent the anchor tag from receiving
+focus as well by setting its tabindex to -1.
+
+ <a href="https://www.polymer-project.org/" tabindex="-1">
+ <paper-item raised>Polymer Project</paper-item>
+ </a>
+
+If you are concerned about performance and want to use `paper-item` in a `paper-listbox`
+with many items, you can just use a native `button` with the `paper-item` class
+applied (provided you have correctly included the shared styles):
+
+ <style is="custom-style" include="paper-item-shared-styles"></style>
+
+ <paper-listbox>
+ <button class="paper-item" role="option">Inbox</button>
+ <button class="paper-item" role="option">Starred</button>
+ <button class="paper-item" role="option">Sent mail</button>
+ </paper-listbox>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+------------------------------|----------------------------------------------|----------
+`--paper-item-min-height` | Minimum height of the item | `48px`
+`--paper-item` | Mixin applied to the item | `{}`
+`--paper-item-selected-weight`| The font weight of a selected item | `bold`
+`--paper-item-selected` | Mixin applied to selected paper-items | `{}`
+`--paper-item-disabled-color` | The color for disabled paper-items | `--disabled-text-color`
+`--paper-item-disabled` | Mixin applied to disabled paper-items | `{}`
+`--paper-item-focused` | Mixin applied to focused paper-items | `{}`
+`--paper-item-focused-before` | Mixin applied to :before focused paper-items | `{}`
+
+### Accessibility
+
+This element has `role="listitem"` by default. Depending on usage, it may be more appropriate to set
+`role="menuitem"`, `role="menuitemcheckbox"` or `role="menuitemradio"`.
+
+ <paper-item role="menuitemcheckbox">
+ <paper-item-body>
+ Show your status
+ </paper-item-body>
+ <paper-checkbox></paper-checkbox>
+ </paper-item>
+
+@group Paper Elements
+@element paper-item
+@demo demo/index.html
+-->
+
+<dom-module id="paper-item">
+ <template>
+ <style include="paper-item-shared-styles"></style>
+ <style>
+ :host {
+ @apply(--layout-horizontal);
+ @apply(--layout-center);
+ @apply(--paper-font-subhead);
+
+ @apply(--paper-item);
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-item',
+
+ behaviors: [
+ Polymer.PaperItemBehavior
+ ]
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/README.md
new file mode 100644
index 00000000000..95f0106e558
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/README.md
@@ -0,0 +1,5 @@
+# paper-listbox
+
+![Build status](https://api.travis-ci.org/PolymerElements/paper-listbox.svg?branch=master)
+
+`<paper-listbox>` implements an accessible listbox control with Material Design styling.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/bower.json
new file mode 100644
index 00000000000..66a09108b19
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/bower.json
@@ -0,0 +1,38 @@
+{
+ "name": "paper-listbox",
+ "version": "1.1.2",
+ "description": "Implements an accessible material design listbox",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "listbox"
+ ],
+ "main": [
+ "paper-listbox.html",
+ "paper-sublistbox.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-listbox"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-listbox",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-collapse": "PolymerElements/iron-collapse#^1.0.0",
+ "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "Polymer/web-component-tester#^3.4.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/demo/index.html
new file mode 100644
index 00000000000..c79e63e775e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/demo/index.html
@@ -0,0 +1,93 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-listbox demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-item/paper-item.html">
+ <link rel="import" href="../../iron-collapse/iron-collapse.html">
+ <link rel="import" href="../paper-listbox.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+
+ <style is="custom-style">
+ .horizontal-section {
+ padding: 0 !important;
+ }
+
+ .avatar {
+ display: inline-block;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ overflow: hidden;
+ background: #ccc;
+ }
+
+ paper-item {
+ --paper-item: {
+ cursor: pointer;
+ };
+ }
+
+ .sublist {
+ padding-left: 20px;
+ padding-right: 20px;
+
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Standard</h4>
+ <div class="horizontal-section">
+ <paper-listbox>
+ <paper-item>Inbox</paper-item>
+ <paper-item>Starred</paper-item>
+ <paper-item>Sent mail</paper-item>
+ <paper-item>Drafts</paper-item>
+ </paper-listbox>
+ </div>
+ </div>
+
+ <div>
+ <h4>Pre-selected</h4>
+ <div class="horizontal-section">
+ <paper-listbox selected="0">
+ <paper-item>Inbox</paper-item>
+ <paper-item disabled>Starred</paper-item>
+ <paper-item>Sent mail</paper-item>
+ <paper-item>Drafts</paper-item>
+ </paper-listbox>
+ </div>
+ </div>
+
+ <div>
+ <h4>Multi-select</h4>
+ <div class="horizontal-section">
+ <paper-listbox multi>
+ <paper-item>Bold</paper-item>
+ <paper-item>Italic</paper-item>
+ <paper-item>Underline</paper-item>
+ <paper-item>Strikethrough</paper-item>
+ </paper-listbox>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/hero.svg
new file mode 100755
index 00000000000..91af1f60ea1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/hero.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <g>
+ <circle cx="86.5" cy="39" r="4"/>
+ <path d="M138,44c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,37.3,100,36,98,36v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V44z"/>
+ <circle cx="86.5" cy="63" r="4"/>
+ <path d="M138,68c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,61.3,100,60,98,60v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V68z"/>
+ <circle cx="86.5" cy="88" r="4"/>
+ <path d="M138,93c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,86.3,100,85,98,85v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V93z"/>
+ <path d="M151,102H73V24h78V102z M75,100h74V26H75V100z"/>
+ </g>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/index.html
new file mode 100644
index 00000000000..b9dad4bd9d3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-listbox</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/paper-listbox.html b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/paper-listbox.html
new file mode 100644
index 00000000000..15d6cf0ea9d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-listbox/paper-listbox.html
@@ -0,0 +1,96 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-menu-behavior/iron-menu-behavior.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+
+<!--
+Material design: [Menus](https://www.google.com/design/spec/components/menus.html)
+
+`<paper-listbox>` implements an accessible listbox control with Material Design styling. The focused item
+is highlighted, and the selected item has bolded text.
+
+ <paper-listbox>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-listbox>
+
+An initial selection can be specified with the `selected` attribute.
+
+ <paper-listbox selected="0">
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-listbox>
+
+Make a multi-select listbox with the `multi` attribute. Items in a multi-select listbox can be deselected,
+and multiple item can be selected.
+
+ <paper-listbox multi>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-listbox>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-listbox-background-color` | Menu background color | `--primary-background-color`
+`--paper-listbox-color` | Menu foreground color | `--primary-text-color`
+`--paper-listbox` | Mixin applied to the listbox | `{}`
+
+### Accessibility
+
+`<paper-listbox>` has `role="listbox"` by default. A multi-select listbox will also have
+`aria-multiselectable` set. It implements key bindings to navigate through the listbox with the up and
+down arrow keys, esc to exit the listbox, and enter to activate a listbox item. Typing the first letter
+of a listbox item will also focus it.
+
+@group Paper Elements
+@element paper-listbox
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-listbox">
+ <template>
+ <style>
+ :host {
+ display: block;
+ padding: 8px 0;
+
+ background: var(--paper-listbox-background-color, --primary-background-color);
+ color: var(--paper-listbox-color, --primary-text-color);
+
+ @apply(--paper-listbox);
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+ <script>
+ (function() {
+ Polymer({
+ is: 'paper-listbox',
+
+ behaviors: [
+ Polymer.IronMenuBehavior
+ ],
+
+ hostAttributes: {
+ role: 'listbox'
+ }
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-material/.bower.json
new file mode 100644
index 00000000000..76995ae72fa
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/.bower.json
@@ -0,0 +1,44 @@
+{
+ "name": "paper-material",
+ "version": "1.0.6",
+ "description": "A material design container that looks like a lifted sheet of paper",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "container"
+ ],
+ "main": "paper-material.html",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-material"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-material",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0"
+ },
+ "_release": "1.0.6",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.6",
+ "commit": "6aef0896fcbc25f9f5bd1dd55f7679e6ab7f92ad"
+ },
+ "_source": "git://github.com/PolymerElements/paper-material.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-material"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-material/.travis.yml
new file mode 100644
index 00000000000..1834edcaecc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: PEaqY+YpV0ZhnQbJlNQbmfIFLqy7UvvCtii0sPoGKT5/P7ulMqMOPQV9l/zLAtYi14HEz63FKLqDrpnGaVe7Cz7jtt2WRWrWqTBdarqwSHs73Z2XqztD1+2wW6vgz/lfK00B8UplAk28B7d5dbWzwUF6Kg02zOfQMsawMpulFjo=
+ - secure: f/3XYrYjM8aXLe9kqM/MjHQ6IEsDRuoxDqM+l2JiR3v2Nw7lP6ZyXSNvKm8bN+VNU7ubSzAmRbUGnRU7e61BhnGzuLXjOqxYeJLWZaqoSm9TDz3re3rd7wB2ddAhRokeSSPO2KeAgr6C02P9M3Au1DiO1G66fuWVH62WtzW4+qY=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-material/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-material/README.md
new file mode 100644
index 00000000000..6a74b5e1e0e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/README.md
@@ -0,0 +1,35 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-material.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/paper-material.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-material)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-material)_
+
+
+##&lt;paper-material&gt;
+
+Material design: [Cards](https://www.google.com/design/spec/components/cards.html)
+
+`paper-material` is a container that renders two shadows on top of each other to
+create the effect of a lifted piece of paper.
+
+Example:
+
+```html
+<paper-material elevation="1">
+ ... content ...
+</paper-material>
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-material/bower.json
new file mode 100644
index 00000000000..40895d2d4c6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "paper-material",
+ "version": "1.0.6",
+ "description": "A material design container that looks like a lifted sheet of paper",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "paper",
+ "container"
+ ],
+ "main": "paper-material.html",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-material"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-material",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-material/demo/index.html
new file mode 100644
index 00000000000..c0b6d394154
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/demo/index.html
@@ -0,0 +1,84 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+ <title>paper-material demo</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../paper-material.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-material {
+ display: inline-block;
+ background: white;
+ box-sizing: border-box;
+ margin: 8px;
+ padding: 16px;
+ border-radius: 2px;
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Paper-materials can have different elevations</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-material elevation="0">0</paper-material>
+ <paper-material elevation="1">1</paper-material>
+ <paper-material elevation="2">2</paper-material>
+ <paper-material elevation="3">3</paper-material>
+ <paper-material elevation="4">4</paper-material>
+ <paper-material elevation="5">5</paper-material>
+ </template>
+ </demo-snippet>
+
+ <h3>Changes in elevation can be animated</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style>
+ #a1, #a2 { cursor: pointer; }
+ </style>
+ Tap each of these boxes!
+ <div>
+ <paper-material elevation="0" animated id="a1">animated</paper-material>
+ <paper-material elevation="3" id="a2">not animated</paper-material>
+ </div>
+ <script>
+ document.addEventListener('WebComponentsReady', function() {
+ a1.addEventListener('click', _onTap);
+ a2.addEventListener('click', _onTap);
+ });
+ function _onTap(e) {
+ var target = e.target;
+ if (!target.down) {
+ target.elevation += 1;
+ if (target.elevation === 5) {
+ target.down = true;
+ }
+ } else {
+ target.elevation -= 1;
+ if (target.elevation === 0) {
+ target.down = false;
+ }
+ }
+ };
+ </script>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-material/index.html
new file mode 100644
index 00000000000..7209e6d0952
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-material</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material-shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material-shared-styles.html
new file mode 100644
index 00000000000..b795f4f47fb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material-shared-styles.html
@@ -0,0 +1,42 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../paper-styles/shadow.html">
+
+<dom-module id="paper-material-shared-styles">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: relative;
+ }
+
+ :host([elevation="1"]) {
+ @apply(--shadow-elevation-2dp);
+ }
+
+ :host([elevation="2"]) {
+ @apply(--shadow-elevation-4dp);
+ }
+
+ :host([elevation="3"]) {
+ @apply(--shadow-elevation-6dp);
+ }
+
+ :host([elevation="4"]) {
+ @apply(--shadow-elevation-8dp);
+ }
+
+ :host([elevation="5"]) {
+ @apply(--shadow-elevation-16dp);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material.html b/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material.html
new file mode 100644
index 00000000000..e754d4ea336
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-material/paper-material.html
@@ -0,0 +1,78 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-styles/shadow.html">
+<link rel="import" href="paper-material-shared-styles.html">
+
+<!--
+Material design: [Cards](https://www.google.com/design/spec/components/cards.html)
+
+`paper-material` is a container that renders two shadows on top of each other to
+create the effect of a lifted piece of paper.
+
+Example:
+
+ <paper-material elevation="1">
+ ... content ...
+ </paper-material>
+
+@group Paper Elements
+@demo demo/index.html
+-->
+
+<dom-module id="paper-material">
+ <template>
+ <style include="paper-material-shared-styles"></style>
+ <style>
+ :host([animated]) {
+ @apply(--shadow-transition);
+ }
+ </style>
+
+ <content></content>
+ </template>
+</dom-module>
+<script>
+ Polymer({
+ is: 'paper-material',
+
+ properties: {
+ /**
+ * The z-depth of this element, from 0-5. Setting to 0 will remove the
+ * shadow, and each increasing number greater than 0 will be "deeper"
+ * than the last.
+ *
+ * @attribute elevation
+ * @type number
+ * @default 1
+ */
+ elevation: {
+ type: Number,
+ reflectToAttribute: true,
+ value: 1
+ },
+
+ /**
+ * Set this to true to animate the shadow when setting a new
+ * `elevation` value.
+ *
+ * @attribute animated
+ * @type boolean
+ * @default false
+ */
+ animated: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false
+ }
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.bower.json
new file mode 100644
index 00000000000..e6142fff525
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.bower.json
@@ -0,0 +1,55 @@
+{
+ "name": "paper-menu-button",
+ "version": "1.1.1",
+ "description": "A material design element that composes a trigger and a dropdown menu",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "menu",
+ "button"
+ ],
+ "main": "paper-menu-button.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-menu-button.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-menu-button",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-dropdown": "PolymerElements/iron-dropdown#^1.0.0",
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "iron-image": "PolymerElements/iron-image#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-menu": "PolymerElements/paper-menu#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "_release": "1.1.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.1",
+ "commit": "2d4d1cbdcfe260878e972e42d73ca5a3b7248cb9"
+ },
+ "_source": "git://github.com/PolymerElements/paper-menu-button.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-menu-button"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.travis.yml
new file mode 100644
index 00000000000..2b43e04fc85
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: KylA/s+GkWGDpW9vcaBDrcr9M4xsE7HVyH36I5p7UBvQUiqPMFR/+GbFx7UoYR1OPNMf2hgHD4nd5G8hfnKjFuRl8NKe63Dnwt+83tKO9MKWrOAPq1/fMG/ZS1vRNP8Jqkp3iOsRUdatWsrs9LA5Pa6tM2OefQXs5ZF0F8s+de8Wv3+QwoGSjfJmTTC8j9tvrzEI6eOX66PAFGWUnySwV66tph+LRT/B/Y2HDcA0KbQucbyxCMnKU100xGJwK3+ZuPTEnqEqPv7R/9Z1Ggh+wXO/MduN+7OO6ZbF9//jrQNSY4QMKcz5zziYa0ugXH7F7HZijq3qxuLST0edPknozGi4xR7Vn00Zu8yHkIKYqswHrXM97qwoZZkBkwD8LEoZTkEIvk/uts68WVTiFaXV2FufBjl48E1BpjvMX1fW0hKTyFKXURXiJBphwNepyHFHpxSF29TKW1FBXy9ITiSMmKrdmqnnPliunDU44NK23tiuY90ZLKPLcOHBzLU7yzqVu67flbWxoWCCkP8gEkT6qRWHzRiZOiw0eHvXkmE1Gs+z1q/JuDg8Aaa40lm9oKC+dY8AfmQDhfXgfd89RbsF+AsJk7kp6wOVGCgmanrAeFSQcdU3qHB0ZQspS5kD1Y6mxl/R9a0iQnhtcHyLTadG8bfvc3EzP+2nYrP326Kir60=
+ - secure: HBHAEcnTe6APHH/ZHmN4fd1sid/RCsgUsn7abA3hRxU6PM4Jo0C4nZhet60Q8joQyxiA415FSETvJVhdY7zHUcmxd0KklEAZjKX08v5vroAGJt0OUmxpZ/scoAcC09JfnZeVFO8Df/kx1WWP+q2LydrZhasPP8ifM+BBdD2wE/ShM6Jz7E5yQHgQ+pUf5yShfOzoYy0+tYtBpm9bxxj1i9qjPEfUiOxAWmSpefJ94dcIh2mCFpakBhPRh/l6FQip0+NPT00YEpk5/fDh+I2Apg8whWm02WiqGsXUpZZZaiGn8oAO5XckrKJGm0xuGYrI3cM1zRvsieaA424WwXNCSkXt6M8s0zQTqj+wlFQMOpEoIgD8dKW0gkIEt09ChKgmhs82FKE3OuI+Nz5z9DRRrtfoOckPi0bjVsOmXNDX0x569dpNOoJB21opfj6Nyl3Ln7/9q1J4LStt/VeuHzUUhBI33GTSlqW6qg0E0difa/bOc8dhSuXQ3Y8uunAXPk1Do7sWUhszF7k/wOjZ/oMsvvl8CiNZCJn0dbvrANOACNW8qBLoAlw2eHwA0wGTuN3VCZohYnHkeioYfkAFzPZX6QR4+NdpOorGBhxuOm0R7rR2q3SIrd+6Wd+T6A4+NLL8e+A57pc2lHKhtSwOOE7DdQpzrVyfN5NOaixlScqcbAw=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/README.md
new file mode 100644
index 00000000000..4e45429b62b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/README.md
@@ -0,0 +1,69 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-menu-button-animations.html paper-menu-button.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-menu-button.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-menu-button)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-menu-button)_
+
+
+##&lt;paper-menu-button&gt;
+
+Material design: [Dropdown buttons](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+`paper-menu-button` allows one to compose a designated "trigger" element with
+another element that represents "content", to create a dropdown menu that
+displays the "content" when the "trigger" is clicked.
+
+The child element with the class `dropdown-trigger` will be used as the
+"trigger" element. The child element with the class `dropdown-content` will be
+used as the "content" element.
+
+The `paper-menu-button` is sensitive to its content's `iron-select` events. If
+the "content" element triggers an `iron-select` event, the `paper-menu-button`
+will close automatically.
+
+Example:
+
+```html
+<paper-menu-button>
+ <paper-icon-button icon="menu" class="dropdown-trigger"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <paper-item>Share</paper-item>
+ <paper-item>Settings</paper-item>
+ <paper-item>Help</paper-item>
+ </paper-menu>
+</paper-menu-button>
+```
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-menu-button-dropdown-background` | Background color of the paper-menu-button dropdown | `--primary-background-color` |
+| `--paper-menu-button` | Mixin applied to the paper-menu-button | `{}` |
+| `--paper-menu-button-disabled` | Mixin applied to the paper-menu-button when disabled | `{}` |
+| `--paper-menu-button-dropdown` | Mixin applied to the paper-menu-button dropdown | `{}` |
+| `--paper-menu-button-content` | Mixin applied to the paper-menu-button content | `{}` |
+
+
+
+<!-- No docs for <paper-menu-grow-height-animation> found. -->
+
+<!-- No docs for <paper-menu-grow-width-animation> found. -->
+
+<!-- No docs for <paper-menu-shrink-height-animation> found. -->
+
+<!-- No docs for <paper-menu-shrink-width-animation> found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/bower.json
new file mode 100644
index 00000000000..58a0a5c734e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/bower.json
@@ -0,0 +1,46 @@
+{
+ "name": "paper-menu-button",
+ "version": "1.1.1",
+ "description": "A material design element that composes a trigger and a dropdown menu",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "web-component",
+ "polymer",
+ "menu",
+ "button"
+ ],
+ "main": "paper-menu-button.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-menu-button.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-menu-button",
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-dropdown": "PolymerElements/iron-dropdown#^1.0.0",
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-icon": "PolymerElements/iron-icon#^1.0.0",
+ "iron-icons": "PolymerElements/iron-icons#^1.0.0",
+ "iron-image": "PolymerElements/iron-image#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "paper-menu": "PolymerElements/paper-menu#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/demo/index.html
new file mode 100644
index 00000000000..e439951450b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/demo/index.html
@@ -0,0 +1,203 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-menu-button</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../iron-icon/iron-icon.html">
+ <link rel="import" href="../../iron-image/iron-image.html">
+ <link rel="import" href="../../paper-menu/paper-menu.html">
+ <link rel="import" href="../../paper-item/paper-item.html">
+ <link rel="import" href="../../paper-button/paper-button.html">
+ <link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+
+ <link rel="import" href="../paper-menu-button.html">
+
+ <style is="custom-style">
+ paper-button {
+ display: block;
+ background: #4285f4;
+ color: #fff;
+ }
+
+ paper-menu {
+ display: block;
+ }
+
+ paper-menu-button {
+ margin: auto;
+ }
+
+ iron-image {
+ padding: 1em;
+ }
+
+ .item {
+ max-width: 300px;
+ }
+
+ .horizontal-section {
+ text-align: center;
+ }
+ </style>
+
+</head>
+<body unresolved>
+
+
+ <template id="Demo" is="dom-bind">
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Paper Icon Button + Paper Menu</h4>
+ <div class="horizontal-section">
+ <paper-menu-button>
+ <paper-icon-button icon="menu" class="dropdown-trigger" alt="menu"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <template is="dom-repeat" items="[[letters]]" as="letter">
+ <paper-item>[[letter]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Paper Menu with multi selection</h4>
+ <div class="horizontal-section">
+ <paper-menu-button ignore-select>
+ <paper-icon-button icon="menu" class="dropdown-trigger" alt="multi select"></paper-icon-button>
+ <paper-menu class="dropdown-content" multi>
+ <template is="dom-repeat" items="[[letters]]" as="letter">
+ <paper-item>[[letter]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Disabled</h4>
+ <div class="horizontal-section">
+ <paper-menu-button disabled>
+ <paper-icon-button icon="menu" class="dropdown-trigger" alt="menu"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <template is="dom-repeat" items="[[letters]]" as="letter">
+ <paper-item>[[letter]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Alternate Alignment</h4>
+ <div class="horizontal-section">
+ <paper-menu-button vertical-align="bottom" horizontal-align="right">
+ <paper-icon-button icon="menu" class="dropdown-trigger" alt="bottom align"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <template is="dom-repeat" items="[[letters]]" as="letter">
+ <paper-item>[[letter]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Alternate Button</h4>
+ <div class="horizontal-section">
+ <paper-menu-button>
+ <paper-button class="dropdown-trigger" raised>
+ <iron-icon icon="check"></iron-icon>
+ <span>Dinosaurs</span>
+ </paper-button>
+ <paper-menu class="dropdown-content">
+ <template is="dom-repeat" items="[[dinosaurs]]" as="dinosaur">
+ <paper-item>[[dinosaur]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Alternate Content</h4>
+ <div class="horizontal-section">
+ <paper-menu-button vertical-align="bottom">
+ <paper-icon-button class="dropdown-trigger" icon="polymer" alt="polymer"></paper-icon-button>
+ <iron-image class="dropdown-content" src="../../iron-image/demo/polymer.svg"></iron-image>
+ </paper-menu-button>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ <script>
+ Demo.letters = [
+ 'alpha',
+ 'beta',
+ 'gamma',
+ 'delta',
+ 'epsilon'
+ ];
+ Demo.dinosaurs = [
+ 'allosaurus',
+ 'brontosaurus',
+ 'carcharodontosaurus',
+ 'diplodocus',
+ 'ekrixinatosaurus',
+ 'fukuiraptor',
+ 'gallimimus',
+ 'hadrosaurus',
+ 'iguanodon',
+ 'jainosaurus',
+ 'kritosaurus',
+ 'liaoceratops',
+ 'megalosaurus',
+ 'nemegtosaurus',
+ 'ornithomimus',
+ 'protoceratops',
+ 'quetecsaurus',
+ 'rajasaurus',
+ 'stegosaurus',
+ 'triceratops',
+ 'utahraptor',
+ 'vulcanodon',
+ 'wannanosaurus',
+ 'xenoceratops',
+ 'yandusaurus',
+ 'zephyrosaurus'
+ ];
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/hero.svg
new file mode 100755
index 00000000000..31c411c969c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/hero.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <circle cx="109" cy="45" r="4"/>
+ <path d="M165,50c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5
+ c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5c-2.8,0-4.1-2.4-5.3-4.5
+ c-1.2-2.2-2-3.5-3.5-3.5v-2c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5
+ c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5s4.1,2.4,5.3,4.5
+ c1.2,2.2,2,3.5,3.5,3.5V50z"/>
+ <circle cx="109" cy="63" r="4"/>
+ <path d="M165,68c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5
+ c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5c-2.8,0-4.1-2.4-5.3-4.5
+ c-1.2-2.2-2-3.5-3.5-3.5v-2c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5
+ c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5s4.1,2.4,5.3,4.5
+ c1.2,2.2,2,3.5,3.5,3.5V68z"/>
+ <circle cx="109" cy="81" r="4"/>
+ <path d="M165,86c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5
+ c-2.8,0-4.1-2.4-5.3-4.5c-1.2-2.2-2-3.5-3.5-3.5c-1.5,0-2.3,1.3-3.5,3.5c-1.2,2.1-2.5,4.5-5.3,4.5c-2.8,0-4.1-2.4-5.3-4.5
+ c-1.2-2.2-2-3.5-3.5-3.5v-2c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5
+ c2.8,0,4.1,2.4,5.3,4.5c1.2,2.2,2,3.5,3.5,3.5c1.5,0,2.3-1.3,3.5-3.5c1.2-2.1,2.5-4.5,5.3-4.5s4.1,2.4,5.3,4.5
+ c1.2,2.2,2,3.5,3.5,3.5V86z"/>
+ <path d="M176,98H94V28h82V98z M96,96h78V30H96V96z"/>
+ <circle cx="65" cy="61" r="8"/>
+ <path d="M82,78H48V44h34V78z M50,76h30V46H50V76z"/>
+ <rect x="81" y="58" width="14" height="2"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/index.html
new file mode 100644
index 00000000000..040b19528b3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
+The complete set of authors may be found at http://polymer.github.io/AUTHORS
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
+-->
+<html>
+<head>
+
+ <title>paper-menu-button</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button-animations.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button-animations.html
new file mode 100644
index 00000000000..b1339f29307
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button-animations.html
@@ -0,0 +1,109 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../neon-animation/web-animations.html">
+<link rel="import" href="../neon-animation/neon-animation-behavior.html">
+<script>
+ Polymer({
+ is: 'paper-menu-grow-height-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ var rect = node.getBoundingClientRect();
+ var height = rect.height;
+
+ this._effect = new KeyframeEffect(node, [{
+ height: (height / 2) + 'px'
+ }, {
+ height: height + 'px'
+ }], this.timingFromConfig(config));
+
+ return this._effect;
+ }
+ });
+
+ Polymer({
+ is: 'paper-menu-grow-width-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ var rect = node.getBoundingClientRect();
+ var width = rect.width;
+
+ this._effect = new KeyframeEffect(node, [{
+ width: (width / 2) + 'px'
+ }, {
+ width: width + 'px'
+ }], this.timingFromConfig(config));
+
+ return this._effect;
+ }
+ });
+
+ Polymer({
+ is: 'paper-menu-shrink-width-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ var rect = node.getBoundingClientRect();
+ var width = rect.width;
+
+ this._effect = new KeyframeEffect(node, [{
+ width: width + 'px'
+ }, {
+ width: width - (width / 20) + 'px'
+ }], this.timingFromConfig(config));
+
+ return this._effect;
+ }
+ });
+
+ Polymer({
+ is: 'paper-menu-shrink-height-animation',
+
+ behaviors: [
+ Polymer.NeonAnimationBehavior
+ ],
+
+ configure: function(config) {
+ var node = config.node;
+ var rect = node.getBoundingClientRect();
+ var height = rect.height;
+ var top = rect.top;
+
+ this.setPrefixedProperty(node, 'transformOrigin', '0 0');
+
+ this._effect = new KeyframeEffect(node, [{
+ height: height + 'px',
+ transform: 'translateY(0)'
+ }, {
+ height: height / 2 + 'px',
+ transform: 'translateY(-20px)'
+ }], this.timingFromConfig(config));
+
+ return this._effect;
+ }
+ });
+</script>
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button.html
new file mode 100644
index 00000000000..77e29c6fb29
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu-button/paper-menu-button.html
@@ -0,0 +1,407 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-dropdown/iron-dropdown.html">
+<link rel="import" href="../neon-animation/animations/fade-in-animation.html">
+<link rel="import" href="../neon-animation/animations/fade-out-animation.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/shadow.html">
+<link rel="import" href="paper-menu-button-animations.html">
+
+<!--
+Material design: [Dropdown buttons](https://www.google.com/design/spec/components/buttons.html#buttons-dropdown-buttons)
+
+`paper-menu-button` allows one to compose a designated "trigger" element with
+another element that represents "content", to create a dropdown menu that
+displays the "content" when the "trigger" is clicked.
+
+The child element with the class `dropdown-trigger` will be used as the
+"trigger" element. The child element with the class `dropdown-content` will be
+used as the "content" element.
+
+The `paper-menu-button` is sensitive to its content's `iron-select` events. If
+the "content" element triggers an `iron-select` event, the `paper-menu-button`
+will close automatically.
+
+Example:
+
+ <paper-menu-button>
+ <paper-icon-button icon="menu" class="dropdown-trigger"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <paper-item>Share</paper-item>
+ <paper-item>Settings</paper-item>
+ <paper-item>Help</paper-item>
+ </paper-menu>
+ </paper-menu-button>
+
+### Styling
+
+The following custom properties and mixins are also available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-menu-button-dropdown-background` | Background color of the paper-menu-button dropdown | `--primary-background-color`
+`--paper-menu-button` | Mixin applied to the paper-menu-button | `{}`
+`--paper-menu-button-disabled` | Mixin applied to the paper-menu-button when disabled | `{}`
+`--paper-menu-button-dropdown` | Mixin applied to the paper-menu-button dropdown | `{}`
+`--paper-menu-button-content` | Mixin applied to the paper-menu-button content | `{}`
+
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-menu-button">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ position: relative;
+ padding: 8px;
+ outline: none;
+
+ @apply(--paper-menu-button);
+ }
+
+ :host([disabled]) {
+ cursor: auto;
+ color: var(--disabled-text-color);
+
+ @apply(--paper-menu-button-disabled);
+ }
+
+ iron-dropdown {
+ @apply(--paper-menu-button-dropdown);
+ }
+
+ .dropdown-content {
+ @apply(--shadow-elevation-2dp);
+
+ position: relative;
+ border-radius: 2px;
+ background-color: var(--paper-menu-button-dropdown-background, --primary-background-color);
+
+ @apply(--paper-menu-button-content);
+ }
+
+ :host([vertical-align="top"]) .dropdown-content {
+ margin-bottom: 20px;
+ margin-top: -10px;
+ top: 10px;
+ }
+
+ :host([vertical-align="bottom"]) .dropdown-content {
+ bottom: 10px;
+ margin-bottom: -10px;
+ margin-top: 20px;
+ }
+ </style>
+
+ <div id="trigger" on-tap="toggle">
+ <content select=".dropdown-trigger"></content>
+ </div>
+
+ <iron-dropdown
+ id="dropdown"
+ opened="{{opened}}"
+ horizontal-align="[[horizontalAlign]]"
+ vertical-align="[[verticalAlign]]"
+ horizontal-offset="[[horizontalOffset]]"
+ vertical-offset="[[verticalOffset]]"
+ open-animation-config="[[openAnimationConfig]]"
+ close-animation-config="[[closeAnimationConfig]]"
+ no-animations="[[noAnimations]]"
+ focus-target="[[_dropdownContent]]"
+ restore-focus-on-close
+ on-iron-overlay-canceled="__onIronOverlayCanceled">
+ <div class="dropdown-content">
+ <content id="content" select=".dropdown-content"></content>
+ </div>
+ </iron-dropdown>
+ </template>
+
+ <script>
+ (function() {
+ 'use strict';
+
+ var PaperMenuButton = Polymer({
+ is: 'paper-menu-button',
+
+ /**
+ * Fired when the dropdown opens.
+ *
+ * @event paper-dropdown-open
+ */
+
+ /**
+ * Fired when the dropdown closes.
+ *
+ * @event paper-dropdown-close
+ */
+
+ behaviors: [
+ Polymer.IronA11yKeysBehavior,
+ Polymer.IronControlState
+ ],
+
+ properties: {
+ /**
+ * True if the content is currently displayed.
+ */
+ opened: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ observer: '_openedChanged'
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * horizontally relative to the dropdown trigger.
+ */
+ horizontalAlign: {
+ type: String,
+ value: 'left',
+ reflectToAttribute: true
+ },
+
+ /**
+ * The orientation against which to align the menu dropdown
+ * vertically relative to the dropdown trigger.
+ */
+ verticalAlign: {
+ type: String,
+ value: 'top',
+ reflectToAttribute: true
+ },
+
+ /**
+ * A pixel value that will be added to the position calculated for the
+ * given `horizontalAlign`. Use a negative value to offset to the
+ * left, or a positive value to offset to the right.
+ */
+ horizontalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * A pixel value that will be added to the position calculated for the
+ * given `verticalAlign`. Use a negative value to offset towards the
+ * top, or a positive value to offset towards the bottom.
+ */
+ verticalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * Set to true to disable animations when opening and closing the
+ * dropdown.
+ */
+ noAnimations: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Set to true to disable automatically closing the dropdown after
+ * a selection has been made.
+ */
+ ignoreSelect: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * An animation config. If provided, this will be used to animate the
+ * opening of the dropdown.
+ */
+ openAnimationConfig: {
+ type: Object,
+ value: function() {
+ return [{
+ name: 'fade-in-animation',
+ timing: {
+ delay: 100,
+ duration: 200
+ }
+ }, {
+ name: 'paper-menu-grow-width-animation',
+ timing: {
+ delay: 100,
+ duration: 150,
+ easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
+ }
+ }, {
+ name: 'paper-menu-grow-height-animation',
+ timing: {
+ delay: 100,
+ duration: 275,
+ easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
+ }
+ }];
+ }
+ },
+
+ /**
+ * An animation config. If provided, this will be used to animate the
+ * closing of the dropdown.
+ */
+ closeAnimationConfig: {
+ type: Object,
+ value: function() {
+ return [{
+ name: 'fade-out-animation',
+ timing: {
+ duration: 150
+ }
+ }, {
+ name: 'paper-menu-shrink-width-animation',
+ timing: {
+ delay: 100,
+ duration: 50,
+ easing: PaperMenuButton.ANIMATION_CUBIC_BEZIER
+ }
+ }, {
+ name: 'paper-menu-shrink-height-animation',
+ timing: {
+ duration: 200,
+ easing: 'ease-in'
+ }
+ }];
+ }
+ },
+
+ /**
+ * This is the element intended to be bound as the focus target
+ * for the `iron-dropdown` contained by `paper-menu-button`.
+ */
+ _dropdownContent: {
+ type: Object
+ }
+ },
+
+ hostAttributes: {
+ role: 'group',
+ 'aria-haspopup': 'true'
+ },
+
+ listeners: {
+ 'iron-select': '_onIronSelect'
+ },
+
+ /**
+ * The content element that is contained by the menu button, if any.
+ */
+ get contentElement() {
+ return Polymer.dom(this.$.content).getDistributedNodes()[0];
+ },
+
+ /**
+ * Toggles the drowpdown content between opened and closed.
+ */
+ toggle: function() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ },
+
+ /**
+ * Make the dropdown content appear as an overlay positioned relative
+ * to the dropdown trigger.
+ */
+ open: function() {
+ if (this.disabled) {
+ return;
+ }
+
+ this.$.dropdown.open();
+ },
+
+ /**
+ * Hide the dropdown content.
+ */
+ close: function() {
+ this.$.dropdown.close();
+ },
+
+ /**
+ * When an `iron-select` event is received, the dropdown should
+ * automatically close on the assumption that a value has been chosen.
+ *
+ * @param {CustomEvent} event A CustomEvent instance with type
+ * set to `"iron-select"`.
+ */
+ _onIronSelect: function(event) {
+ if (!this.ignoreSelect) {
+ this.close();
+ }
+ },
+
+ /**
+ * When the dropdown opens, the `paper-menu-button` fires `paper-open`.
+ * When the dropdown closes, the `paper-menu-button` fires `paper-close`.
+ *
+ * @param {boolean} opened True if the dropdown is opened, otherwise false.
+ * @param {boolean} oldOpened The previous value of `opened`.
+ */
+ _openedChanged: function(opened, oldOpened) {
+ if (opened) {
+ // TODO(cdata): Update this when we can measure changes in distributed
+ // children in an idiomatic way.
+ // We poke this property in case the element has changed. This will
+ // cause the focus target for the `iron-dropdown` to be updated as
+ // necessary:
+ this._dropdownContent = this.contentElement;
+ this.fire('paper-dropdown-open');
+ } else if (oldOpened != null) {
+ this.fire('paper-dropdown-close');
+ }
+ },
+
+ /**
+ * If the dropdown is open when disabled becomes true, close the
+ * dropdown.
+ *
+ * @param {boolean} disabled True if disabled, otherwise false.
+ */
+ _disabledChanged: function(disabled) {
+ Polymer.IronControlState._disabledChanged.apply(this, arguments);
+ if (disabled && this.opened) {
+ this.close();
+ }
+ },
+
+ __onIronOverlayCanceled: function(event) {
+ var uiEvent = event.detail;
+ var target = Polymer.dom(uiEvent).rootTarget;
+ var trigger = this.$.trigger;
+ var path = Polymer.dom(uiEvent).path;
+
+ if (path.indexOf(trigger) > -1) {
+ event.preventDefault();
+ }
+ }
+ });
+
+ PaperMenuButton.ANIMATION_CUBIC_BEZIER = 'cubic-bezier(.3,.95,.5,1)';
+ PaperMenuButton.MAX_ANIMATION_TIME_MS = 400;
+
+ Polymer.PaperMenuButton = PaperMenuButton;
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.bower.json
new file mode 100644
index 00000000000..2feb07eddb1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.bower.json
@@ -0,0 +1,48 @@
+{
+ "name": "paper-menu",
+ "version": "1.2.2",
+ "description": "Implements an accessible material design menu",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "menu"
+ ],
+ "main": [
+ "paper-menu.html",
+ "paper-submenu.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-menu"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-menu",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-collapse": "PolymerElements/iron-collapse#^1.0.0",
+ "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "_release": "1.2.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.2",
+ "commit": "f31a1dbc5b594a84c8c01eca0f23f9bcb8f6ba76"
+ },
+ "_source": "git://github.com/PolymerElements/paper-menu.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-menu"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.travis.yml
new file mode 100644
index 00000000000..429eafc46bf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: Mh0qP0wSbfQ00LpaW8ObBU6CBLqgUgIM/Qvuog7dw7atnZ3a2I7UqLXCJHkH0a66r0bF2PyuS6a8qz/croSr1rQQ0G+1HgNczm7nuQO8cw2ZLXZglpaldYfUzKBw9ip+XGA1zgFQ1+O3uWisy+4pQrsGhRsB1RSmXBcKJsSUjZw=
+ - secure: QhEW2jW0Uj3dp4xJOYVfP/MUV2UeZW48811cDZRSwWQ/43vrZU/4VCSTFJdODZ4A9nXAhOeKtT+S1BWoH4VslGLCfmrF1dbTxHZEdg2WAt8OkV9XpMNMBYtGomlUs9asnU/Q1294DWolAGG8wwnReibg0r6H3VQCmD4vIE6oEmQ=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/CONTRIBUTING.md
new file mode 100644
index 00000000000..7b101415652
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/CONTRIBUTING.md
@@ -0,0 +1,72 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [http://jsbin.com/cagaye](http://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/README.md
new file mode 100644
index 00000000000..9dbd2b2c125
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/README.md
@@ -0,0 +1,113 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-menu.html paper-submenu.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build Status](https://travis-ci.org/PolymerElements/paper-menu.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-menu)
+
+_[Demo and API Docs](https://elements.polymer-project.org/elements/paper-menu)_
+
+
+##&lt;paper-menu&gt;
+
+Material design: [Menus](https://www.google.com/design/spec/components/menus.html)
+
+`<paper-menu>` implements an accessible menu control with Material Design styling. The focused item
+is highlighted, and the selected item has bolded text.
+
+```html
+<paper-menu>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+</paper-menu>
+```
+
+An initial selection can be specified with the `selected` attribute.
+
+```html
+<paper-menu selected="0">
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+</paper-menu>
+```
+
+Make a multi-select menu with the `multi` attribute. Items in a multi-select menu can be deselected,
+and multiple items can be selected.
+
+```html
+<paper-menu multi>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+</paper-menu>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-menu-background-color` | Menu background color | `--primary-background-color` |
+| `--paper-menu-color` | Menu foreground color | `--primary-text-color` |
+| `--paper-menu-disabled-color` | Foreground color for a disabled item | `--disabled-text-color` |
+| `--paper-menu` | Mixin applied to the menu | `{}` |
+| `--paper-menu-selected-item` | Mixin applied to the selected item | `{}` |
+| `--paper-menu-focused-item` | Mixin applied to the focused item | `{}` |
+| `--paper-menu-focused-item-after` | Mixin applied to the ::after pseudo-element for the focused item | `{}` |
+
+### Accessibility
+
+`<paper-menu>` has `role="menu"` by default. A multi-select menu will also have
+`aria-multiselectable` set. It implements key bindings to navigate through the menu with the up and
+down arrow keys, esc to exit the menu, and enter to activate a menu item. Typing the first letter
+of a menu item will also focus it.
+
+
+
+##&lt;paper-submenu&gt;
+
+`<paper-submenu>` is a nested menu inside of a parent `<paper-menu>`. It
+consists of a trigger that expands or collapses another `<paper-menu>`:
+
+```html
+<paper-menu>
+ <paper-submenu>
+ <paper-item class="menu-trigger">Topics</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Topic 1</paper-item>
+ <paper-item>Topic 2</paper-item>
+ <paper-item>Topic 3</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu>
+ <paper-item class="menu-trigger">Faves</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Fave 1</paper-item>
+ <paper-item>Fave 2</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu disabled>
+ <paper-item class="menu-trigger">Unavailable</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Disabled 1</paper-item>
+ <paper-item>Disabled 2</paper-item>
+ </paper-menu>
+ </paper-submenu>
+</paper-menu>
+```
+
+Just like in `<paper-menu>`, the focused item is highlighted, and the selected
+item has bolded text. Please see the `<paper-menu>` docs for which attributes
+(such as `multi` and `selected`), and styling options are available for the
+`menu-content` menu.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/bower.json
new file mode 100644
index 00000000000..661403112ff
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/bower.json
@@ -0,0 +1,39 @@
+{
+ "name": "paper-menu",
+ "version": "1.2.2",
+ "description": "Implements an accessible material design menu",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "menu"
+ ],
+ "main": [
+ "paper-menu.html",
+ "paper-submenu.html"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-menu"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-menu",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+ "iron-collapse": "PolymerElements/iron-collapse#^1.0.0",
+ "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-item": "PolymerElements/paper-item#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/demo/index.html
new file mode 100644
index 00000000000..a7cd2c945fb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/demo/index.html
@@ -0,0 +1,150 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <title>paper-menu demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../paper-item/paper-item.html">
+ <link rel="import" href="../../iron-collapse/iron-collapse.html">
+ <link rel="import" href="../paper-menu.html">
+ <link rel="import" href="../paper-submenu.html">
+ <link rel="import" href="../../paper-styles/demo-pages.html">
+
+ <style is="custom-style">
+ .horizontal-section {
+ padding: 0 !important;
+ }
+
+ .avatar {
+ display: inline-block;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ overflow: hidden;
+ background: #ccc;
+ }
+
+ paper-item {
+ --paper-item: {
+ cursor: pointer;
+ };
+ }
+
+ .sublist paper-item {
+ padding-left: 30px;
+ }
+
+ .sublist2 paper-item {
+ padding-left: 50px;
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Standard</h4>
+ <div class="horizontal-section">
+ <paper-menu>
+ <paper-item>Inbox</paper-item>
+ <paper-item>Starred</paper-item>
+ <paper-item>Sent mail</paper-item>
+ <paper-item>Drafts</paper-item>
+ </paper-menu>
+ </div>
+ </div>
+
+ <div>
+ <h4>Pre-selected</h4>
+ <div class="horizontal-section">
+ <paper-menu selected="0">
+ <paper-item>Inbox</paper-item>
+ <paper-item disabled>Starred</paper-item>
+ <paper-item>Sent mail</paper-item>
+ <paper-item>Drafts</paper-item>
+ </paper-menu>
+ </div>
+ </div>
+
+ <div>
+ <h4>Multi-select</h4>
+ <div class="horizontal-section">
+ <paper-menu multi>
+ <paper-item>Bold</paper-item>
+ <paper-item>Italic</paper-item>
+ <paper-item>Underline</paper-item>
+ <paper-item>Strikethrough</paper-item>
+ </paper-menu>
+ </div>
+ </div>
+
+ <div>
+ <h4>Sub-menu</h4>
+ <div class="horizontal-section">
+ <paper-menu attr-for-item-title="label" multi>
+ <paper-submenu label="paper-menu">
+ <paper-item class="menu-trigger">paper-menu</paper-item>
+ <paper-menu class="menu-content sublist" multi>
+ <paper-submenu label="Properties">
+ <paper-item class="menu-trigger">Properties</paper-item>
+ <paper-menu class="menu-content sublist2">
+ <paper-item>focusedItem</paper-item>
+ <paper-item>attrForItemTitle</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu label="Methods">
+ <paper-item class="menu-trigger">Methods</paper-item>
+ <paper-menu class="menu-content sublist2">
+ <paper-item>select(value)</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ </paper-menu>
+ </paper-submenu>
+
+ <paper-submenu label="paper-submenu">
+ <paper-item class="menu-trigger">paper-submenu</paper-item>
+ <paper-menu class="menu-content sublist">
+ <paper-submenu label="Properties">
+ <paper-item class="menu-trigger">Properties</paper-item>
+ <paper-menu class="menu-content sublist2">
+ <paper-item>opened</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu label="Methods">
+ <paper-item class="menu-trigger">Methods</paper-item>
+ <paper-menu class="menu-content sublist2">
+ <paper-item>open()</paper-item>
+ <paper-item>close()</paper-item>
+ <paper-item>toggle()</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ </paper-menu>
+ </paper-submenu>
+
+ <paper-submenu label="Unavailable" disabled>
+ <paper-item class="menu-trigger">Unavailable</paper-item>
+ <paper-menu class="menu-content sublist">
+ <paper-item>Unavailable 1</paper-item>
+ <paper-item>Unavailable 2</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ </paper-menu>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/hero.svg
new file mode 100755
index 00000000000..91af1f60ea1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/hero.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <g>
+ <circle cx="86.5" cy="39" r="4"/>
+ <path d="M138,44c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,37.3,100,36,98,36v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V44z"/>
+ <circle cx="86.5" cy="63" r="4"/>
+ <path d="M138,68c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,61.3,100,60,98,60v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V68z"/>
+ <circle cx="86.5" cy="88" r="4"/>
+ <path d="M138,93c-2,0-3.6-2.4-4.6-4.6c-1.1-2.1-1.7-3.4-3-3.4s-2,1.3-3,3.4c-1.1,2.1-2.2,4.6-4.9,4.6c-2.6,0-3.8-2.4-4.9-4.6
+ c-1.1-2.1-1.8-3.4-3.1-3.4c-1.3,0-2,1.3-3.1,3.4c-1.1,2.1-2.3,4.6-4.9,4.6c-2.6,0-4.1-2.4-5.1-4.6C100.3,86.3,100,85,98,85v-2
+ c3,0,4.1,2.4,5.1,4.6c1.1,2.1,1.9,3.4,3.2,3.4c1.3,0,2.1-1.3,3.2-3.4c1.1-2.1,2.3-4.6,4.9-4.6c2.6,0,3.8,2.4,4.9,4.6
+ c1.1,2.1,1.8,3.4,3.1,3.4c1.3,0,2-1.3,3.1-3.4c1.1-2.1,2.3-4.6,4.9-4.6s3.6,2.4,4.6,4.6c1.1,2.1,1.9,3.4,2.9,3.4V93z"/>
+ <path d="M151,102H73V24h78V102z M75,100h74V26H75V100z"/>
+ </g>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/index.html
new file mode 100644
index 00000000000..fc8841148b2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-menu</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu-shared-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu-shared-styles.html
new file mode 100644
index 00000000000..840bc7382ae
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu-shared-styles.html
@@ -0,0 +1,47 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<dom-module id="paper-menu-shared-styles">
+ <template>
+ <style>
+ /* need a wrapper element to make this higher specificity than the :host rule in paper-item */
+ .selectable-content > ::content > .iron-selected {
+ font-weight: bold;
+
+ @apply(--paper-menu-selected-item);
+ }
+
+ .selectable-content > ::content > [disabled] {
+ color: var(--paper-menu-disabled-color, --disabled-text-color);
+ }
+
+ .selectable-content > ::content > *:focus {
+ position: relative;
+ outline: 0;
+
+ @apply(--paper-menu-focused-item);
+ }
+
+ .selectable-content > ::content > *:focus:after {
+ @apply(--layout-fit);
+ background: currentColor;
+ opacity: var(--dark-divider-opacity);
+ content: '';
+ pointer-events: none;
+
+ @apply(--paper-menu-focused-item-after);
+ }
+
+ .selectable-content > ::content > *[colored]:focus:after {
+ opacity: 0.26;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu.html
new file mode 100644
index 00000000000..10e562b4085
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-menu.html
@@ -0,0 +1,102 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../iron-menu-behavior/iron-menu-behavior.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="paper-menu-shared-styles.html">
+
+<!--
+Material design: [Menus](https://www.google.com/design/spec/components/menus.html)
+
+`<paper-menu>` implements an accessible menu control with Material Design styling. The focused item
+is highlighted, and the selected item has bolded text.
+
+ <paper-menu>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-menu>
+
+An initial selection can be specified with the `selected` attribute.
+
+ <paper-menu selected="0">
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-menu>
+
+Make a multi-select menu with the `multi` attribute. Items in a multi-select menu can be deselected,
+and multiple items can be selected.
+
+ <paper-menu multi>
+ <paper-item>Item 1</paper-item>
+ <paper-item>Item 2</paper-item>
+ </paper-menu>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-menu-background-color` | Menu background color | `--primary-background-color`
+`--paper-menu-color` | Menu foreground color | `--primary-text-color`
+`--paper-menu-disabled-color` | Foreground color for a disabled item | `--disabled-text-color`
+`--paper-menu` | Mixin applied to the menu | `{}`
+`--paper-menu-selected-item` | Mixin applied to the selected item | `{}`
+`--paper-menu-focused-item` | Mixin applied to the focused item | `{}`
+`--paper-menu-focused-item-after` | Mixin applied to the ::after pseudo-element for the focused item | `{}`
+
+### Accessibility
+
+`<paper-menu>` has `role="menu"` by default. A multi-select menu will also have
+`aria-multiselectable` set. It implements key bindings to navigate through the menu with the up and
+down arrow keys, esc to exit the menu, and enter to activate a menu item. Typing the first letter
+of a menu item will also focus it.
+
+@group Paper Elements
+@element paper-menu
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-menu">
+ <template>
+ <style include="paper-menu-shared-styles"></style>
+ <style>
+ :host {
+ display: block;
+ padding: 8px 0;
+
+ background: var(--paper-menu-background-color, --primary-background-color);
+ color: var(--paper-menu-color, --primary-text-color);
+
+ @apply(--paper-menu);
+ }
+ </style>
+
+ <div class="selectable-content">
+ <content></content>
+ </div>
+ </template>
+
+ <script>
+ (function() {
+ Polymer({
+ is: 'paper-menu',
+
+ behaviors: [
+ Polymer.IronMenuBehavior
+ ]
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-submenu.html b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-submenu.html
new file mode 100644
index 00000000000..e1c1d111cdb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-menu/paper-submenu.html
@@ -0,0 +1,231 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-menu-behavior/iron-menu-behavior.html">
+<link rel="import" href="../iron-behaviors/iron-control-state.html">
+<link rel="import" href="../iron-collapse/iron-collapse.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/default-theme.html">
+<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="paper-menu-shared-styles.html">
+
+<!--
+`<paper-submenu>` is a nested menu inside of a parent `<paper-menu>`. It
+consists of a trigger that expands or collapses another `<paper-menu>`:
+
+ <paper-menu>
+ <paper-submenu>
+ <paper-item class="menu-trigger">Topics</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Topic 1</paper-item>
+ <paper-item>Topic 2</paper-item>
+ <paper-item>Topic 3</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu>
+ <paper-item class="menu-trigger">Faves</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Fave 1</paper-item>
+ <paper-item>Fave 2</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ <paper-submenu disabled>
+ <paper-item class="menu-trigger">Unavailable</paper-item>
+ <paper-menu class="menu-content">
+ <paper-item>Disabled 1</paper-item>
+ <paper-item>Disabled 2</paper-item>
+ </paper-menu>
+ </paper-submenu>
+ </paper-menu>
+
+Just like in `<paper-menu>`, the focused item is highlighted, and the selected
+item has bolded text. Please see the `<paper-menu>` docs for which attributes
+(such as `multi` and `selected`), and styling options are available for the
+`menu-content` menu.
+
+@group Paper Elements
+@element paper-submenu
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-submenu">
+ <template>
+ <style include="paper-menu-shared-styles"></style>
+
+ <div class="selectable-content" on-tap="_onTap">
+ <content id="trigger" select=".menu-trigger"></content>
+ </div>
+ <iron-collapse id="collapse" opened="{{opened}}">
+ <content id="content" select=".menu-content"></content>
+ </iron-collapse>
+ </template>
+
+ <script>
+
+ (function() {
+
+ Polymer({
+
+ is: 'paper-submenu',
+
+ properties: {
+ /**
+ * Fired when the submenu is opened.
+ *
+ * @event paper-submenu-open
+ */
+
+ /**
+ * Fired when the submenu is closed.
+ *
+ * @event paper-submenu-close
+ */
+
+ /**
+ * Set opened to true to show the collapse element and to false to hide it.
+ *
+ * @attribute opened
+ */
+ opened: {
+ type: Boolean,
+ value: false,
+ notify: true,
+ observer: '_openedChanged'
+ }
+ },
+
+ behaviors: [
+ Polymer.IronControlState
+ ],
+
+ listeners: {
+ 'focus': '_onFocus'
+ },
+
+ get __parent() {
+ return Polymer.dom(this).parentNode;
+ },
+
+ get __trigger() {
+ return Polymer.dom(this.$.trigger).getDistributedNodes()[0];
+ },
+
+ get __content() {
+ return Polymer.dom(this.$.content).getDistributedNodes()[0];
+ },
+
+ attached: function() {
+ this.listen(this.__parent, 'iron-activate', '_onParentIronActivate');
+ },
+
+ dettached: function() {
+ this.unlisten(this.__parent, 'iron-activate', '_onParentIronActivate');
+ },
+
+ /**
+ * Expand the submenu content.
+ */
+ open: function() {
+ if (!this.disabled && !this._active) {
+ this.$.collapse.show();
+ this._active = true;
+ this.__trigger && this.__trigger.classList.add('iron-selected');
+ this.__content && this.__content.focus();
+ }
+ },
+
+ /**
+ * Collapse the submenu content.
+ */
+ close: function() {
+ if (this._active) {
+ this.$.collapse.hide();
+ this._active = false;
+ this.__trigger && this.__trigger.classList.remove('iron-selected');
+ }
+ },
+
+ /**
+ * Toggle the submenu.
+ */
+ toggle: function() {
+ if (this._active) {
+ this.close();
+ } else {
+ this.open();
+ }
+ },
+
+ /**
+ * A handler that is called when the trigger is tapped.
+ */
+ _onTap: function(e) {
+ if (!this.disabled) {
+ this.toggle();
+ }
+ },
+
+ /**
+ * Toggles the submenu content when the trigger is tapped.
+ */
+ _openedChanged: function(opened, oldOpened) {
+ if (opened) {
+ this.fire('paper-submenu-open');
+ } else if (oldOpened != null) {
+ this.fire('paper-submenu-close');
+ }
+ },
+
+ /**
+ * A handler that is called when `iron-activate` is fired.
+ *
+ * @param {CustomEvent} event An `iron-activate` event.
+ */
+ _onParentIronActivate: function(event) {
+ var parent = this.__parent;
+ if (Polymer.dom(event).localTarget === parent) {
+ // The activated item can either be this submenu, in which case it
+ // should be expanded, or any of the other sibling submenus, in which
+ // case this submenu should be collapsed.
+ if (event.detail.item !== this && !parent.multi) {
+ this.close();
+ }
+ }
+ },
+
+ /**
+ * If the dropdown is open when disabled becomes true, close the
+ * dropdown.
+ *
+ * @param {boolean} disabled True if disabled, otherwise false.
+ */
+ _disabledChanged: function(disabled) {
+ Polymer.IronControlState._disabledChanged.apply(this, arguments);
+ if (disabled && this._active) {
+ this.close();
+ }
+ },
+
+ /**
+ * Handler that is called when the menu receives focus.
+ *
+ * @param {FocusEvent} event A focus event.
+ */
+ _onFocus: function(event) {
+ this.__trigger && this.__trigger.focus();
+ }
+
+ });
+
+ })();
+</script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.bower.json
new file mode 100644
index 00000000000..d76d4cd97d3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "paper-progress",
+ "version": "1.0.9",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "A material design progress bar",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "progress"
+ ],
+ "main": "paper-progress.html",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-progress.git"
+ },
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-range-behavior": "PolymerElements/iron-range-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/paper-progress",
+ "_release": "1.0.9",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.9",
+ "commit": "389e717d2e600bb44c6cb1537ee12b203b55fca1"
+ },
+ "_source": "git://github.com/PolymerElements/paper-progress.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-progress"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.travis.yml
new file mode 100644
index 00000000000..cfc1bd93516
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: fmp2kJysxTcVsouaQfEkPCJYPzbsuGCeq5RqvttDaYdue92n5912OR/WI476PPGpX2owvxq97saVX9CqXweVtgrmdhONsrGy31eULpW0vUonuhbjkKU87E0aAmHu478uuJnc4hU7oN7wuNEtqWmpFG+oqMqHKwUyAWLk+V4XY0nseuFYQLX52qfglD+CqipQsoe84nIM0JxQxpDw1njYZbKQzZVttyLQVv13Ahh+5v75EqqwggoD2mgU1xQIH1GarbnZpmE9BL4ETbaJwJ7Fon/Pxsrs1Zs9hEStJCwo5aTiyPJibRQBCk9Cj+PJY3TkqfE3zIwhbW1/aSCIuUg5egsh6Of6clqrDE2wWPyIURUBFcE3UXsqBEXh56K9WQh+KNIgJYoQ/tzhD2VlgQhM89geTKZc6ysSTWcukv9tw9h9gaG2gD1e+uRQ/rMyt6vlh2DNI/J8oAv1WifZwuUKRkwm7SUBP55sukFryJIQEXEMqjT0WVbjTWP+2VNiHFPo7wGdVZ8X7y4bwA7lmnlC4AnNd8L6BE0tStZUBAKv3LhzRvd+DrRvaiSPdFhGBbAiMzytKGgxfD7nhMntV7GREjfQCB/hch5anePK7Cuw58kF8PiZX9aVk8Se3VP0+rdUkzVgWTW5THhdpw2nnuIyK5QDtL4/L3l/oJhl9Jbmak4=
+ - secure: WzzECDnm17AwL4VDbMJD0E1cdi11p2YLahJRPi/+GZ9BFNIV3I2WZFc5l0WEiGDMB4igx5DdXHzDFk7HF2z2qRpf2skhWDTd/Ie5+exZlY9/D/tED8dJepGtV40UTuWr+vHsDJeNkXteYNpNU7ZHfNbXl14/x25ccaLYSX5yRNLBRMn9KToRNBhXA0YH/Q9AnWNKGFWb0YBfjSRywSvVuVRQr/tL43JUCTEEwjdGHVTUlvWPE5XHDs6yqjJlTI70GVvQb5WPZdQJugiolG9Z66ZRWEEuawJgzTCdlaKwBQX0UAXLdfUsQKwrcxvLnDibMHVG6hNOBw4Un73YL0klD7nKoPlhCiDHtPWoNUCvpNGxPWozw2KC50YX4MZSFKAWCkIA4/oiIhMvSUOWcrOpfHZNpJNNBCFHvv6JS5PwEiNlqM2BjqfS4Vy/03Fy0h6CyNX8o5wDAjZvJKCyZQHGy4tFWNPpyZ6SbwsnzH+bjqXSDURI6hCUNiujlIRzUT95H8rIega1mWT8sffvb4qK72iXAqf7hoQbi1Ldhjq/b0iO0PRdpjX5vusLN797KxPNrxDZc9LoaIgVMAFD5AJmwF/DilvwsW6sI4o5cpAw58/g1wpB7iX0YFWXNzXv/hZh2o4gW81Y2afM//gIgCFSitRO10bOqw+pEcGCnLrz/BQ=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/README.md
new file mode 100644
index 00000000000..2f452a94f95
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/README.md
@@ -0,0 +1,94 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-progress.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-progress.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-progress)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-progress)_
+
+
+##&lt;paper-progress&gt;
+
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+The progress bars are for situations where the percentage completed can be
+determined. They give users a quick sense of how much longer an operation
+will take.
+
+Example:
+
+```html
+<paper-progress value="10"></paper-progress>
+```
+
+There is also a secondary progress which is useful for displaying intermediate
+progress, such as the buffer level during a streaming playback progress bar.
+
+Example:
+
+```html
+<paper-progress value="10" secondary-progress="30"></paper-progress>
+```
+
+### Styling progress bar:
+
+To change the active progress bar color:
+
+```css
+paper-progress {
+ --paper-progress-active-color: #e91e63;
+}
+```
+
+To change the secondary progress bar color:
+
+```css
+paper-progress {
+ --paper-progress-secondary-color: #f8bbd0;
+}
+```
+
+To change the progress bar background color:
+
+```css
+paper-progress {
+ --paper-progress-container-color: #64ffda;
+}
+```
+
+Add the class `transiting` to a paper-progress to animate the progress bar when
+the value changed. You can also customize the transition:
+
+```css
+paper-progress {
+ --paper-progress-transition-duration: 0.08s;
+ --paper-progress-transition-timing-function: ease;
+ --paper-progress-transition-transition-delay: 0s;
+}
+```
+
+The following mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-progress-container-color` | Mixin applied to container | `--google-grey-300` |
+| `--paper-progress-transition-duration` | Duration of the transition | `0.008s` |
+| `--paper-progress-transition-timing-function` | The timing function for the transition | `ease` |
+| `--paper-progress-transition-delay` | delay for the transition | `0s` |
+| `--paper-progress-active-color` | The color of the active bar | `--google-green-500` |
+| `--paper-progress-secondary-color` | The color of the secondary bar | `--google-green-100` |
+| `--paper-progress-disabled-active-color` | The color of the active bar if disabled | `--google-grey-500` |
+| `--paper-progress-disabled-secondary-color` | The color of the secondary bar if disabled | `--google-grey-300` |
+| `--paper-progress-height` | The height of the progress bar | `4px` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/bower.json
new file mode 100644
index 00000000000..69a5c5ef224
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/bower.json
@@ -0,0 +1,32 @@
+{
+ "name": "paper-progress",
+ "version": "1.0.9",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "A material design progress bar",
+ "authors": "The Polymer Authors",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "progress"
+ ],
+ "main": "paper-progress.html",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-progress.git"
+ },
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "iron-range-behavior": "PolymerElements/iron-range-behavior#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/demo/index.html
new file mode 100644
index 00000000000..88f4b76897b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/demo/index.html
@@ -0,0 +1,122 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html>
+<head>
+ <title>paper-progress demo</title>
+
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../paper-progress.html">
+ <link rel="import" href="../../paper-button/paper-button.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-progress {
+ display: block;
+ width: 100%;
+ margin: 20px 0;
+ }
+ paper-button {
+ display: inline-block;
+ padding: 5px;
+ }
+ </style>
+
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>paper-progress can be imperatively controlled</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <p>Once started, loops 5 times before stopping.
+ <!-- View the source code to see the contents of startProgress() -->
+ <paper-button raised onclick="startProgress();" id="start">Start</paper-button>
+ </p>
+ <paper-progress id="progress"></paper-progress>
+ </template>
+ </demo-snippet>
+
+ <h3>paper-progress can be indeterminate</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-progress indeterminate></paper-progress>
+ <paper-progress indeterminate value="800" min="100" max="1000"></paper-progress>
+ </template>
+ </demo-snippet>
+
+ <h3>It can be styled using custom properties</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-progress.blue {
+ --paper-progress-active-color: var(--paper-light-blue-500);
+ --paper-progress-secondary-color: var(--paper-light-blue-100);
+ }
+
+ paper-progress.red {
+ --paper-progress-active-color: var(--paper-red-500);
+ --paper-progress-secondary-color: var(--paper-red-100);
+ }
+
+ paper-progress.green {
+ --paper-progress-active-color: var(--paper-light-green-500);
+ --paper-progress-secondary-color: var(--paper-light-green-100);
+ }
+ </style>
+ <paper-progress value="800" min="100" max="1000" class="red"></paper-progress>
+ <paper-progress value="60" class="green"></paper-progress>
+ <paper-progress value="40" secondary-progress="80" class="blue"></paper-progress>
+ </template>
+ </demo-snippet>
+ </div>
+
+ <script>
+ var progress, button, animationFrame;
+ var repeat, maxRepeat = 5, animating = false;
+
+ function nextProgress() {
+ animating = true;
+ if (progress.value < progress.max) {
+ progress.value += (progress.step || 1);
+ } else {
+ if (++repeat >= maxRepeat) {
+ animating = false;
+ button.disabled = false;
+ return;
+ }
+ progress.value = progress.min;
+ }
+ var animationFrame = requestAnimationFrame(nextProgress);
+ }
+
+ function startProgress() {
+ repeat = 0;
+ progress.value = progress.min;
+ button.disabled = true;
+ if (!animating) {
+ nextProgress();
+ }
+ }
+
+ window.addEventListener('WebComponentsReady', function() {
+ progress = document.querySelector('paper-progress');
+ button = document.querySelector('paper-button');
+ });
+
+ </script>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/hero.svg
new file mode 100755
index 00000000000..dc422a4912a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/hero.svg
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <rect x="57" y="59" width="20" height="2"/>
+ <rect x="38" y="59" width="11" height="2"/>
+ <rect x="84" y="59" width="40" height="2"/>
+ <rect x="133" y="59" width="54" height="2"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/index.html
new file mode 100644
index 00000000000..225e3dd93df
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <title>paper-progress</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-progress/paper-progress.html b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/paper-progress.html
new file mode 100644
index 00000000000..77b1eecd016
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-progress/paper-progress.html
@@ -0,0 +1,341 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../iron-range-behavior/iron-range-behavior.html">
+<link rel="import" href="../paper-styles/color.html">
+
+<!--
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+The progress bars are for situations where the percentage completed can be
+determined. They give users a quick sense of how much longer an operation
+will take.
+
+Example:
+
+ <paper-progress value="10"></paper-progress>
+
+There is also a secondary progress which is useful for displaying intermediate
+progress, such as the buffer level during a streaming playback progress bar.
+
+Example:
+
+ <paper-progress value="10" secondary-progress="30"></paper-progress>
+
+### Styling progress bar:
+
+To change the active progress bar color:
+
+ paper-progress {
+ --paper-progress-active-color: #e91e63;
+ }
+
+To change the secondary progress bar color:
+
+ paper-progress {
+ --paper-progress-secondary-color: #f8bbd0;
+ }
+
+To change the progress bar background color:
+
+ paper-progress {
+ --paper-progress-container-color: #64ffda;
+ }
+
+Add the class `transiting` to a paper-progress to animate the progress bar when
+the value changed. You can also customize the transition:
+
+ paper-progress {
+ --paper-progress-transition-duration: 0.08s;
+ --paper-progress-transition-timing-function: ease;
+ --paper-progress-transition-transition-delay: 0s;
+ }
+
+The following mixins are available for styling:
+
+Custom property | Description | Default
+----------------------------------------------|---------------------------------------------|--------------
+`--paper-progress-container-color` | Mixin applied to container | `--google-grey-300`
+`--paper-progress-transition-duration` | Duration of the transition | `0.008s`
+`--paper-progress-transition-timing-function` | The timing function for the transition | `ease`
+`--paper-progress-transition-delay` | delay for the transition | `0s`
+`--paper-progress-active-color` | The color of the active bar | `--google-green-500`
+`--paper-progress-secondary-color` | The color of the secondary bar | `--google-green-100`
+`--paper-progress-disabled-active-color` | The color of the active bar if disabled | `--google-grey-500`
+`--paper-progress-disabled-secondary-color` | The color of the secondary bar if disabled | `--google-grey-300`
+`--paper-progress-height` | The height of the progress bar | `4px`
+
+@group Paper Elements
+@element paper-progress
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-progress">
+ <template>
+ <style>
+ :host {
+ display: block;
+ width: 200px;
+ position: relative;
+ overflow: hidden;
+ }
+
+ #progressContainer {
+ position: relative;
+ }
+
+ #progressContainer,
+ /* the stripe for the indeterminate animation*/
+ .indeterminate::after {
+ height: var(--paper-progress-height, 4px);
+ }
+
+ #primaryProgress,
+ #secondaryProgress,
+ .indeterminate::after {
+ @apply(--layout-fit);
+ }
+
+ #progressContainer,
+ .indeterminate::after {
+ background: var(--paper-progress-container-color, --google-grey-300);
+ }
+
+ :host(.transiting) #primaryProgress,
+ :host(.transiting) #secondaryProgress {
+ -webkit-transition-property: -webkit-transform;
+ transition-property: transform;
+
+ /* Duration */
+ -webkit-transition-duration: var(--paper-progress-transition-duration, 0.08s);
+ transition-duration: var(--paper-progress-transition-duration, 0.08s);
+
+ /* Timing function */
+ -webkit-transition-timing-function: var(--paper-progress-transition-timing-function, ease);
+ transition-timing-function: var(--paper-progress-transition-timing-function, ease);
+
+ /* Delay */
+ -webkit-transition-delay: var(--paper-progress-transition-delay, 0s);
+ transition-delay: var(--paper-progress-transition-delay, 0s);
+ }
+
+ #primaryProgress,
+ #secondaryProgress {
+ @apply(--layout-fit);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ will-change: transform;
+ }
+
+ #primaryProgress {
+ background: var(--paper-progress-active-color, --google-green-500);
+ }
+
+ #secondaryProgress {
+ background: var(--paper-progress-secondary-color, --google-green-100);
+ }
+
+ :host([disabled]) #primaryProgress {
+ background: var(--paper-progress-disabled-active-color, --google-grey-500);
+ }
+
+ :host([disabled]) #secondaryProgress {
+ background: var(--paper-progress-disabled-secondary-color, --google-grey-300);
+ }
+
+ :host(:not([disabled])) #primaryProgress.indeterminate {
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ -webkit-animation: indeterminate-bar 2s linear infinite;
+ animation: indeterminate-bar 2s linear infinite;
+ }
+
+ :host(:not([disabled])) #primaryProgress.indeterminate::after {
+ content: "";
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+
+ -webkit-animation: indeterminate-splitter 2s linear infinite;
+ animation: indeterminate-splitter 2s linear infinite;
+ }
+
+ @-webkit-keyframes indeterminate-bar {
+ 0% {
+ -webkit-transform: scaleX(1) translateX(-100%);
+ }
+ 50% {
+ -webkit-transform: scaleX(1) translateX(0%);
+ }
+ 75% {
+ -webkit-transform: scaleX(1) translateX(0%);
+ -webkit-animation-timing-function: cubic-bezier(.28,.62,.37,.91);
+ }
+ 100% {
+ -webkit-transform: scaleX(0) translateX(0%);
+ }
+ }
+
+ @-webkit-keyframes indeterminate-splitter {
+ 0% {
+ -webkit-transform: scaleX(.75) translateX(-125%);
+ }
+ 30% {
+ -webkit-transform: scaleX(.75) translateX(-125%);
+ -webkit-animation-timing-function: cubic-bezier(.42,0,.6,.8);
+ }
+ 90% {
+ -webkit-transform: scaleX(.75) translateX(125%);
+ }
+ 100% {
+ -webkit-transform: scaleX(.75) translateX(125%);
+ }
+ }
+
+ @keyframes indeterminate-bar {
+ 0% {
+ transform: scaleX(1) translateX(-100%);
+ }
+ 50% {
+ transform: scaleX(1) translateX(0%);
+ }
+ 75% {
+ transform: scaleX(1) translateX(0%);
+ animation-timing-function: cubic-bezier(.28,.62,.37,.91);
+ }
+ 100% {
+ transform: scaleX(0) translateX(0%);
+ }
+ }
+
+ @keyframes indeterminate-splitter {
+ 0% {
+ transform: scaleX(.75) translateX(-125%);
+ }
+ 30% {
+ transform: scaleX(.75) translateX(-125%);
+ animation-timing-function: cubic-bezier(.42,0,.6,.8);
+ }
+ 90% {
+ transform: scaleX(.75) translateX(125%);
+ }
+ 100% {
+ transform: scaleX(.75) translateX(125%);
+ }
+ }
+ </style>
+
+ <div id="progressContainer">
+ <div id="secondaryProgress" hidden$="[[_hideSecondaryProgress(secondaryRatio)]]"></div>
+ <div id="primaryProgress"></div>
+ </div>
+ </template>
+</dom-module>
+
+<script>
+ Polymer({
+ is: 'paper-progress',
+
+ behaviors: [
+ Polymer.IronRangeBehavior
+ ],
+
+ properties: {
+ /**
+ * The number that represents the current secondary progress.
+ */
+ secondaryProgress: {
+ type: Number,
+ value: 0
+ },
+
+ /**
+ * The secondary ratio
+ */
+ secondaryRatio: {
+ type: Number,
+ value: 0,
+ readOnly: true
+ },
+
+ /**
+ * Use an indeterminate progress indicator.
+ */
+ indeterminate: {
+ type: Boolean,
+ value: false,
+ observer: '_toggleIndeterminate'
+ },
+
+ /**
+ * True if the progress is disabled.
+ */
+ disabled: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ observer: '_disabledChanged'
+ }
+ },
+
+ observers: [
+ '_progressChanged(secondaryProgress, value, min, max)'
+ ],
+
+ hostAttributes: {
+ role: 'progressbar'
+ },
+
+ _toggleIndeterminate: function(indeterminate) {
+ // If we use attribute/class binding, the animation sometimes doesn't translate properly
+ // on Safari 7.1. So instead, we toggle the class here in the update method.
+ this.toggleClass('indeterminate', indeterminate, this.$.primaryProgress);
+ },
+
+ _transformProgress: function(progress, ratio) {
+ var transform = 'scaleX(' + (ratio / 100) + ')';
+ progress.style.transform = progress.style.webkitTransform = transform;
+ },
+
+ _mainRatioChanged: function(ratio) {
+ this._transformProgress(this.$.primaryProgress, ratio);
+ },
+
+ _progressChanged: function(secondaryProgress, value, min, max) {
+ secondaryProgress = this._clampValue(secondaryProgress);
+ value = this._clampValue(value);
+
+ var secondaryRatio = this._calcRatio(secondaryProgress) * 100;
+ var mainRatio = this._calcRatio(value) * 100;
+
+ this._setSecondaryRatio(secondaryRatio);
+ this._transformProgress(this.$.secondaryProgress, secondaryRatio);
+ this._transformProgress(this.$.primaryProgress, mainRatio);
+
+ this.secondaryProgress = secondaryProgress;
+
+ this.setAttribute('aria-valuenow', value);
+ this.setAttribute('aria-valuemin', min);
+ this.setAttribute('aria-valuemax', max);
+ },
+
+ _disabledChanged: function(disabled) {
+ this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
+ },
+
+ _hideSecondaryProgress: function(secondaryRatio) {
+ return secondaryRatio === 0;
+ }
+ });
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.bower.json
new file mode 100644
index 00000000000..fc0feff6497
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.bower.json
@@ -0,0 +1,45 @@
+{
+ "name": "paper-ripple",
+ "version": "1.0.8",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Adds a material design ripple to any container",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "ripple"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-ripple.git"
+ },
+ "main": "paper-ripple.html",
+ "dependencies": {
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.1.5",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "iron-icons": "polymerelements/iron-icons#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/paper-ripple",
+ "_release": "1.0.8",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.0.8",
+ "commit": "eb1c01cac162b7ce7e78760d5c0df61c9a5c2974"
+ },
+ "_source": "git://github.com/PolymerElements/paper-ripple.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-ripple"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.travis.yml
new file mode 100644
index 00000000000..c4c91b4e018
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: YrC5bTrJwlszZQWfnRwDbLaZNLf+KnWXTAfzvul7eij21W3/v+E0wp9pFTLQj/G3bZWgOEZSsoXxASNcNu1JUmJRyLXpJgTps25IlS/VJTRHoK7jUjt5pJG1CbcgTixQblyOVtPqT6j0V23V0d3mhQ3H2xFBbcl87iYO1w+6nmQ=
+ - secure: NZv74uwtibMbmarEOWRUNkEwjz/2akWEIe2JDxglag2JUECWrcAKJIQUqYsO0KNUIg09xJEqWLWED4fN73p3z27Jl/z99ssVMvPQt8duoxwZ6UwcjVWUQNjgXKN6JDZCf+3hJsmU51Lp6mpzj0Y5m8nCjhh7/bBnJahH+VRm7bA=
+node_js: stable
+addons:
+ firefox: '46.0'
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/README.md
new file mode 100644
index 00000000000..359b131959a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/README.md
@@ -0,0 +1,90 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-ripple.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-ripple.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-ripple)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-ripple)_
+
+
+##&lt;paper-ripple&gt;
+
+Material design: [Surface reaction](https://www.google.com/design/spec/animation/responsive-interaction.html#responsive-interaction-surface-reaction)
+
+`paper-ripple` provides a visual effect that other paper elements can
+use to simulate a rippling effect emanating from the point of contact. The
+effect can be visualized as a concentric circle with motion.
+
+Example:
+
+```html
+<div style="position:relative">
+ <paper-ripple></paper-ripple>
+</div>
+```
+
+Note, it's important that the parent container of the ripple be relative position, otherwise
+the ripple will emanate outside of the desired container.
+
+`paper-ripple` listens to "mousedown" and "mouseup" events so it would display ripple
+effect when touches on it. You can also defeat the default behavior and
+manually route the down and up actions to the ripple element. Note that it is
+important if you call `downAction()` you will have to make sure to call
+`upAction()` so that `paper-ripple` would end the animation loop.
+
+Example:
+
+```html
+<paper-ripple id="ripple" style="pointer-events: none;"></paper-ripple>
+...
+downAction: function(e) {
+ this.$.ripple.downAction({detail: {x: e.x, y: e.y}});
+},
+upAction: function(e) {
+ this.$.ripple.upAction();
+}
+```
+
+Styling ripple effect:
+
+ Use CSS color property to style the ripple:
+
+```css
+paper-ripple {
+ color: #4285f4;
+}
+```
+
+ Note that CSS color property is inherited so it is not required to set it on
+ the `paper-ripple` element directly.
+
+By default, the ripple is centered on the point of contact. Apply the `recenters`
+attribute to have the ripple grow toward the center of its container.
+
+```html
+<paper-ripple recenters></paper-ripple>
+```
+
+You can also center the ripple inside its container from the start.
+
+```html
+<paper-ripple center></paper-ripple>
+```
+
+Apply `circle` class to make the rippling effect within a circle.
+
+```html
+<paper-ripple class="circle"></paper-ripple>
+```
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/bower.json
new file mode 100644
index 00000000000..1fce5584770
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "paper-ripple",
+ "version": "1.0.8",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Adds a material design ripple to any container",
+ "private": true,
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "ripple"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-ripple.git"
+ },
+ "main": "paper-ripple.html",
+ "dependencies": {
+ "iron-a11y-keys-behavior": "polymerelements/iron-a11y-keys-behavior#^1.1.5",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "iron-icon": "polymerelements/iron-icon#^1.0.0",
+ "iron-icons": "polymerelements/iron-icons#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-styles": "polymerelements/paper-styles#^1.0.0",
+ "test-fixture": "polymerelements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/demo/index.html
new file mode 100644
index 00000000000..e12cde5c080
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/demo/index.html
@@ -0,0 +1,415 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html>
+<head>
+ <title>paper-ripple demo</title>
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../paper-ripple.html">
+ <link rel="import" href="../../paper-styles/typography.html">
+ <link rel="import" href="../../iron-icon/iron-icon.html">
+
+ <style>
+
+ body {
+ background-color: #f9f9f9;
+ font-family: RobotoDraft, 'Helvetica Neue', Helvetica, Arial;
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ -webkit-touch-callout: none;
+ }
+
+ section {
+ padding: 30px 25px;
+ }
+
+ section > * {
+ margin: 10px
+ }
+
+ /* Button */
+ .button {
+ display: inline-block;
+ position: relative;
+ width: 120px;
+ height: 32px;
+ line-height: 32px;
+ border-radius: 2px;
+ font-size: 0.9em;
+ background-color: #fff;
+ color: #646464;
+ }
+
+ .button > paper-ripple {
+ border-radius: 2px;
+ overflow: hidden;
+ }
+
+ .button.narrow {
+ width: 60px;
+ }
+
+ .button.grey {
+ background-color: #eee;
+ }
+
+ .button.blue {
+ background-color: #4285f4;
+ color: #fff;
+ }
+
+ .button.green {
+ background-color: #0f9d58;
+ color: #fff;
+ }
+
+ .button.raised {
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ transition-delay: 0.2s;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+ }
+
+ .button.raised:active {
+ box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
+ transition-delay: 0s;
+ }
+
+ /* Icon Button */
+ .icon-button {
+ position: relative;
+ display: inline-block;
+ width: 56px;
+ height: 56px;
+ }
+
+ .icon-button > iron-icon {
+ margin: 16px;
+ transition: -webkit-transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ }
+
+ .icon-button:hover > iron-icon {
+ -webkit-transform: scale(1.2);
+ transform: scale(1.2);
+ }
+
+ .icon-button > paper-ripple {
+ overflow: hidden;
+ color: #646464;
+ }
+
+ .icon-button.red > iron-icon::shadow path {
+ fill: #db4437;
+ }
+
+ .icon-button.red > paper-ripple {
+ color: #db4437;
+ }
+
+ .icon-button.blue > iron-icon::shadow path {
+ fill: #4285f4;
+ }
+
+ .icon-button.blue > paper-ripple {
+ color: #4285f4;
+ }
+
+ /* FAB */
+ .fab {
+ position: relative;
+ display: inline-block;
+ width: 56px;
+ height: 56px;
+ border-radius: 50%;
+ color: #fff;
+ overflow: hidden;
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ transition-delay: 0.2s;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+ }
+
+ .fab.red {
+ background-color: #d23f31;
+ }
+
+ .fab.blue {
+ background-color: #4285f4;
+ }
+
+ .fab.green {
+ background-color: #0f9d58;
+ }
+
+ .fab:active {
+ box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
+ transition-delay: 0s;
+ }
+
+ .fab > iron-icon {
+ margin: 16px;
+ }
+
+ .fab > iron-icon::shadow path {
+ fill: #fff;
+ }
+
+ /* Menu */
+ .menu {
+ display: inline-block;
+ width: 180px;
+ background-color: #fff;
+ box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
+ }
+
+ .item {
+ position: relative;
+ height: 48px;
+ line-height: 48px;
+ color: #646464;
+ font-size: 0.9em;
+ }
+
+ .menu.blue > .item {
+ color: #4285f4;
+ }
+
+ /* Card, Dialog */
+ .card, .dialog {
+ position: relative;
+ display: inline-block;
+ width: 300px;
+ height: 240px;
+ vertical-align: top;
+ background-color: #fff;
+ box-shadow: 0 12px 15px 0 rgba(0, 0, 0, 0.24);
+ }
+
+ .dialog {
+ box-sizing: border-box;
+ padding: 16px;
+ }
+
+ .dialog > .content {
+ height: 170px;
+ font-size: 0.9em;
+ }
+
+ .dialog > .content > .title {
+ font-size: 1.3em;
+ }
+
+ .dialog > .button {
+ width: 90px;
+ float: right;
+ }
+
+ .card.image {
+ background: url(http://lorempixel.com/300/240/nature/);
+ color: #fff;
+ }
+
+ /* Misc */
+ .center {
+ text-align: center;
+ }
+
+ .label {
+ padding: 0 16px;
+ }
+
+ .label-blue {
+ color: #4285f4;
+ }
+
+ .label-red {
+ color: #d23f31;
+ }
+
+ </style>
+
+</head>
+<body>
+
+ <section>
+
+ <div class="button raised">
+ <div class="center" fit tabindex="1">SUBMIT</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button raised" noink>
+ <div class="center" fit tabindex="1">NO INK</div>
+ <paper-ripple noink></paper-ripple>
+ </div>
+
+ <div class="button raised grey">
+ <div class="center" fit tabindex="1">CANCEL</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button raised blue">
+ <div class="center" fit tabindex="1">COMPOSE</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button raised green">
+ <div class="center" fit tabindex="1">OK</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ </section>
+
+ <section>
+
+ <div class="button raised grey narrow">
+ <div class="center" fit tabindex="1">+1</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button raised grey narrow label-blue">
+ <div class="center" fit tabindex="1">+1</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button raised grey narrow label-red">
+ <div class="center" fit tabindex="1">+1</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ </section>
+
+ <section>
+
+ <div class="icon-button">
+ <iron-icon icon="menu" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ <div class="icon-button">
+ <iron-icon icon="more-vert" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ <div class="icon-button red">
+ <iron-icon icon="delete" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ <div class="icon-button blue">
+ <iron-icon icon="account-box" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ </section>
+
+ <section>
+
+ <div class="fab red">
+ <iron-icon icon="add" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ <div class="fab blue">
+ <iron-icon icon="mail" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ <div class="fab green">
+ <iron-icon icon="create" tabindex="1"></iron-icon>
+ <paper-ripple class="circle" recenters></paper-ripple>
+ </div>
+
+ </section>
+
+ <section>
+
+ <div class="menu">
+
+ <div class="item">
+ <div class="label" fit tabindex="1">Mark as unread</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Mark as important</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Add to Tasks</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Create event</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ </div>
+
+ <div class="menu blue">
+
+ <div class="item">
+ <div class="label" fit tabindex="1">Import</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Export</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Print</div>
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="item">
+ <div class="label" fit tabindex="1">Restore contacts</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ </div>
+
+ </section>
+
+ <section>
+
+ <div class="dialog">
+
+ <div class="content">
+ <div class="title">Permission</div><br>
+ <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</div>
+ </div>
+
+ <div class="button label-blue">
+ <div class="center" fit tabindex="1">ACCEPT</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ <div class="button">
+ <div class="center" fit tabindex="1">DECLINE</div>
+ <paper-ripple></paper-ripple>
+ </div>
+
+ </div>
+
+ <div class="card" tabindex="1">
+ <paper-ripple recenters></paper-ripple>
+ </div>
+
+ <div class="card image" tabindex="1">
+ <paper-ripple recenters></paper-ripple>
+ </div>
+
+ </section>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/hero.svg
new file mode 100755
index 00000000000..f8a872f1e63
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/hero.svg
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <path d="M175,81H49V45h126V81z M51,79h122V47H51V79z"/>
+ <g>
+ <defs>
+ <rect id="SVGID_5_" x="50" y="46" width="124" height="34"/>
+ </defs>
+ <clipPath id="SVGID_2_">
+ <use xlink:href="#SVGID_5_" overflow="visible"/>
+ </clipPath>
+ <circle opacity="0.5" clip-path="url(#SVGID_2_)" cx="84.4" cy="62.7" r="41.9"/>
+ <circle opacity="0.6" clip-path="url(#SVGID_2_)" cx="84.4" cy="62.7" r="26.3"/>
+ <circle opacity="0.6" clip-path="url(#SVGID_2_)" cx="66.4" cy="62.7" r="26.3"/>
+ </g>
+ <circle cx="50" cy="80" r="4"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/index.html
new file mode 100644
index 00000000000..e552b0bb955
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/index.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>paper-ripple</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/paper-ripple.html b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/paper-ripple.html
new file mode 100644
index 00000000000..c0d74e6e916
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-ripple/paper-ripple.html
@@ -0,0 +1,758 @@
+<!--
+@license
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+
+<!--
+Material design: [Surface reaction](https://www.google.com/design/spec/animation/responsive-interaction.html#responsive-interaction-surface-reaction)
+
+`paper-ripple` provides a visual effect that other paper elements can
+use to simulate a rippling effect emanating from the point of contact. The
+effect can be visualized as a concentric circle with motion.
+
+Example:
+
+ <div style="position:relative">
+ <paper-ripple></paper-ripple>
+ </div>
+
+Note, it's important that the parent container of the ripple be relative position, otherwise
+the ripple will emanate outside of the desired container.
+
+`paper-ripple` listens to "mousedown" and "mouseup" events so it would display ripple
+effect when touches on it. You can also defeat the default behavior and
+manually route the down and up actions to the ripple element. Note that it is
+important if you call `downAction()` you will have to make sure to call
+`upAction()` so that `paper-ripple` would end the animation loop.
+
+Example:
+
+ <paper-ripple id="ripple" style="pointer-events: none;"></paper-ripple>
+ ...
+ downAction: function(e) {
+ this.$.ripple.downAction({detail: {x: e.x, y: e.y}});
+ },
+ upAction: function(e) {
+ this.$.ripple.upAction();
+ }
+
+Styling ripple effect:
+
+ Use CSS color property to style the ripple:
+
+ paper-ripple {
+ color: #4285f4;
+ }
+
+ Note that CSS color property is inherited so it is not required to set it on
+ the `paper-ripple` element directly.
+
+By default, the ripple is centered on the point of contact. Apply the `recenters`
+attribute to have the ripple grow toward the center of its container.
+
+ <paper-ripple recenters></paper-ripple>
+
+You can also center the ripple inside its container from the start.
+
+ <paper-ripple center></paper-ripple>
+
+Apply `circle` class to make the rippling effect within a circle.
+
+ <paper-ripple class="circle"></paper-ripple>
+
+@group Paper Elements
+@element paper-ripple
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-ripple">
+
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: absolute;
+ border-radius: inherit;
+ overflow: hidden;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+
+ /* See PolymerElements/paper-behaviors/issues/34. On non-Chrome browsers,
+ * creating a node (with a position:absolute) in the middle of an event
+ * handler "interrupts" that event handler (which happens when the
+ * ripple is created on demand) */
+ pointer-events: none;
+ }
+
+ :host([animating]) {
+ /* This resolves a rendering issue in Chrome (as of 40) where the
+ ripple is not properly clipped by its parent (which may have
+ rounded corners). See: http://jsbin.com/temexa/4
+
+ Note: We only apply this style conditionally. Otherwise, the browser
+ will create a new compositing layer for every ripple element on the
+ page, and that would be bad. */
+ -webkit-transform: translate(0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ #background,
+ #waves,
+ .wave-container,
+ .wave {
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ #background,
+ .wave {
+ opacity: 0;
+ }
+
+ #waves,
+ .wave {
+ overflow: hidden;
+ }
+
+ .wave-container,
+ .wave {
+ border-radius: 50%;
+ }
+
+ :host(.circle) #background,
+ :host(.circle) #waves {
+ border-radius: 50%;
+ }
+
+ :host(.circle) .wave-container {
+ overflow: hidden;
+ }
+ </style>
+
+ <div id="background"></div>
+ <div id="waves"></div>
+ </template>
+</dom-module>
+<script>
+ (function() {
+ var Utility = {
+ distance: function(x1, y1, x2, y2) {
+ var xDelta = (x1 - x2);
+ var yDelta = (y1 - y2);
+
+ return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
+ },
+
+ now: window.performance && window.performance.now ?
+ window.performance.now.bind(window.performance) : Date.now
+ };
+
+ /**
+ * @param {HTMLElement} element
+ * @constructor
+ */
+ function ElementMetrics(element) {
+ this.element = element;
+ this.width = this.boundingRect.width;
+ this.height = this.boundingRect.height;
+
+ this.size = Math.max(this.width, this.height);
+ }
+
+ ElementMetrics.prototype = {
+ get boundingRect () {
+ return this.element.getBoundingClientRect();
+ },
+
+ furthestCornerDistanceFrom: function(x, y) {
+ var topLeft = Utility.distance(x, y, 0, 0);
+ var topRight = Utility.distance(x, y, this.width, 0);
+ var bottomLeft = Utility.distance(x, y, 0, this.height);
+ var bottomRight = Utility.distance(x, y, this.width, this.height);
+
+ return Math.max(topLeft, topRight, bottomLeft, bottomRight);
+ }
+ };
+
+ /**
+ * @param {HTMLElement} element
+ * @constructor
+ */
+ function Ripple(element) {
+ this.element = element;
+ this.color = window.getComputedStyle(element).color;
+
+ this.wave = document.createElement('div');
+ this.waveContainer = document.createElement('div');
+ this.wave.style.backgroundColor = this.color;
+ this.wave.classList.add('wave');
+ this.waveContainer.classList.add('wave-container');
+ Polymer.dom(this.waveContainer).appendChild(this.wave);
+
+ this.resetInteractionState();
+ }
+
+ Ripple.MAX_RADIUS = 300;
+
+ Ripple.prototype = {
+ get recenters() {
+ return this.element.recenters;
+ },
+
+ get center() {
+ return this.element.center;
+ },
+
+ get mouseDownElapsed() {
+ var elapsed;
+
+ if (!this.mouseDownStart) {
+ return 0;
+ }
+
+ elapsed = Utility.now() - this.mouseDownStart;
+
+ if (this.mouseUpStart) {
+ elapsed -= this.mouseUpElapsed;
+ }
+
+ return elapsed;
+ },
+
+ get mouseUpElapsed() {
+ return this.mouseUpStart ?
+ Utility.now () - this.mouseUpStart : 0;
+ },
+
+ get mouseDownElapsedSeconds() {
+ return this.mouseDownElapsed / 1000;
+ },
+
+ get mouseUpElapsedSeconds() {
+ return this.mouseUpElapsed / 1000;
+ },
+
+ get mouseInteractionSeconds() {
+ return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
+ },
+
+ get initialOpacity() {
+ return this.element.initialOpacity;
+ },
+
+ get opacityDecayVelocity() {
+ return this.element.opacityDecayVelocity;
+ },
+
+ get radius() {
+ var width2 = this.containerMetrics.width * this.containerMetrics.width;
+ var height2 = this.containerMetrics.height * this.containerMetrics.height;
+ var waveRadius = Math.min(
+ Math.sqrt(width2 + height2),
+ Ripple.MAX_RADIUS
+ ) * 1.1 + 5;
+
+ var duration = 1.1 - 0.2 * (waveRadius / Ripple.MAX_RADIUS);
+ var timeNow = this.mouseInteractionSeconds / duration;
+ var size = waveRadius * (1 - Math.pow(80, -timeNow));
+
+ return Math.abs(size);
+ },
+
+ get opacity() {
+ if (!this.mouseUpStart) {
+ return this.initialOpacity;
+ }
+
+ return Math.max(
+ 0,
+ this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity
+ );
+ },
+
+ get outerOpacity() {
+ // Linear increase in background opacity, capped at the opacity
+ // of the wavefront (waveOpacity).
+ var outerOpacity = this.mouseUpElapsedSeconds * 0.3;
+ var waveOpacity = this.opacity;
+
+ return Math.max(
+ 0,
+ Math.min(outerOpacity, waveOpacity)
+ );
+ },
+
+ get isOpacityFullyDecayed() {
+ return this.opacity < 0.01 &&
+ this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
+ },
+
+ get isRestingAtMaxRadius() {
+ return this.opacity >= this.initialOpacity &&
+ this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
+ },
+
+ get isAnimationComplete() {
+ return this.mouseUpStart ?
+ this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
+ },
+
+ get translationFraction() {
+ return Math.min(
+ 1,
+ this.radius / this.containerMetrics.size * 2 / Math.sqrt(2)
+ );
+ },
+
+ get xNow() {
+ if (this.xEnd) {
+ return this.xStart + this.translationFraction * (this.xEnd - this.xStart);
+ }
+
+ return this.xStart;
+ },
+
+ get yNow() {
+ if (this.yEnd) {
+ return this.yStart + this.translationFraction * (this.yEnd - this.yStart);
+ }
+
+ return this.yStart;
+ },
+
+ get isMouseDown() {
+ return this.mouseDownStart && !this.mouseUpStart;
+ },
+
+ resetInteractionState: function() {
+ this.maxRadius = 0;
+ this.mouseDownStart = 0;
+ this.mouseUpStart = 0;
+
+ this.xStart = 0;
+ this.yStart = 0;
+ this.xEnd = 0;
+ this.yEnd = 0;
+ this.slideDistance = 0;
+
+ this.containerMetrics = new ElementMetrics(this.element);
+ },
+
+ draw: function() {
+ var scale;
+ var translateString;
+ var dx;
+ var dy;
+
+ this.wave.style.opacity = this.opacity;
+
+ scale = this.radius / (this.containerMetrics.size / 2);
+ dx = this.xNow - (this.containerMetrics.width / 2);
+ dy = this.yNow - (this.containerMetrics.height / 2);
+
+
+ // 2d transform for safari because of border-radius and overflow:hidden clipping bug.
+ // https://bugs.webkit.org/show_bug.cgi?id=98538
+ this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
+ this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
+ this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
+ this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
+ },
+
+ /** @param {Event=} event */
+ downAction: function(event) {
+ var xCenter = this.containerMetrics.width / 2;
+ var yCenter = this.containerMetrics.height / 2;
+
+ this.resetInteractionState();
+ this.mouseDownStart = Utility.now();
+
+ if (this.center) {
+ this.xStart = xCenter;
+ this.yStart = yCenter;
+ this.slideDistance = Utility.distance(
+ this.xStart, this.yStart, this.xEnd, this.yEnd
+ );
+ } else {
+ this.xStart = event ?
+ event.detail.x - this.containerMetrics.boundingRect.left :
+ this.containerMetrics.width / 2;
+ this.yStart = event ?
+ event.detail.y - this.containerMetrics.boundingRect.top :
+ this.containerMetrics.height / 2;
+ }
+
+ if (this.recenters) {
+ this.xEnd = xCenter;
+ this.yEnd = yCenter;
+ this.slideDistance = Utility.distance(
+ this.xStart, this.yStart, this.xEnd, this.yEnd
+ );
+ }
+
+ this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(
+ this.xStart,
+ this.yStart
+ );
+
+ this.waveContainer.style.top =
+ (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px';
+ this.waveContainer.style.left =
+ (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
+
+ this.waveContainer.style.width = this.containerMetrics.size + 'px';
+ this.waveContainer.style.height = this.containerMetrics.size + 'px';
+ },
+
+ /** @param {Event=} event */
+ upAction: function(event) {
+ if (!this.isMouseDown) {
+ return;
+ }
+
+ this.mouseUpStart = Utility.now();
+ },
+
+ remove: function() {
+ Polymer.dom(this.waveContainer.parentNode).removeChild(
+ this.waveContainer
+ );
+ }
+ };
+
+ Polymer({
+ is: 'paper-ripple',
+
+ behaviors: [
+ Polymer.IronA11yKeysBehavior
+ ],
+
+ properties: {
+ /**
+ * The initial opacity set on the wave.
+ *
+ * @attribute initialOpacity
+ * @type number
+ * @default 0.25
+ */
+ initialOpacity: {
+ type: Number,
+ value: 0.25
+ },
+
+ /**
+ * How fast (opacity per second) the wave fades out.
+ *
+ * @attribute opacityDecayVelocity
+ * @type number
+ * @default 0.8
+ */
+ opacityDecayVelocity: {
+ type: Number,
+ value: 0.8
+ },
+
+ /**
+ * If true, ripples will exhibit a gravitational pull towards
+ * the center of their container as they fade away.
+ *
+ * @attribute recenters
+ * @type boolean
+ * @default false
+ */
+ recenters: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * If true, ripples will center inside its container
+ *
+ * @attribute recenters
+ * @type boolean
+ * @default false
+ */
+ center: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * A list of the visual ripples.
+ *
+ * @attribute ripples
+ * @type Array
+ * @default []
+ */
+ ripples: {
+ type: Array,
+ value: function() {
+ return [];
+ }
+ },
+
+ /**
+ * True when there are visible ripples animating within the
+ * element.
+ */
+ animating: {
+ type: Boolean,
+ readOnly: true,
+ reflectToAttribute: true,
+ value: false
+ },
+
+ /**
+ * If true, the ripple will remain in the "down" state until `holdDown`
+ * is set to false again.
+ */
+ holdDown: {
+ type: Boolean,
+ value: false,
+ observer: '_holdDownChanged'
+ },
+
+ /**
+ * If true, the ripple will not generate a ripple effect
+ * via pointer interaction.
+ * Calling ripple's imperative api like `simulatedRipple` will
+ * still generate the ripple effect.
+ */
+ noink: {
+ type: Boolean,
+ value: false
+ },
+
+ _animating: {
+ type: Boolean
+ },
+
+ _boundAnimate: {
+ type: Function,
+ value: function() {
+ return this.animate.bind(this);
+ }
+ }
+ },
+
+ get target () {
+ return this.keyEventTarget;
+ },
+
+ keyBindings: {
+ 'enter:keydown': '_onEnterKeydown',
+ 'space:keydown': '_onSpaceKeydown',
+ 'space:keyup': '_onSpaceKeyup'
+ },
+
+ attached: function() {
+ // Set up a11yKeysBehavior to listen to key events on the target,
+ // so that space and enter activate the ripple even if the target doesn't
+ // handle key events. The key handlers deal with `noink` themselves.
+ if (this.parentNode.nodeType == 11) { // DOCUMENT_FRAGMENT_NODE
+ this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
+ } else {
+ this.keyEventTarget = this.parentNode;
+ }
+ var keyEventTarget = /** @type {!EventTarget} */ (this.keyEventTarget);
+ this.listen(keyEventTarget, 'up', 'uiUpAction');
+ this.listen(keyEventTarget, 'down', 'uiDownAction');
+ },
+
+ detached: function() {
+ this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
+ this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
+ this.keyEventTarget = null;
+ },
+
+ get shouldKeepAnimating () {
+ for (var index = 0; index < this.ripples.length; ++index) {
+ if (!this.ripples[index].isAnimationComplete) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ simulatedRipple: function() {
+ this.downAction(null);
+
+ // Please see polymer/polymer#1305
+ this.async(function() {
+ this.upAction();
+ }, 1);
+ },
+
+ /**
+ * Provokes a ripple down effect via a UI event,
+ * respecting the `noink` property.
+ * @param {Event=} event
+ */
+ uiDownAction: function(event) {
+ if (!this.noink) {
+ this.downAction(event);
+ }
+ },
+
+ /**
+ * Provokes a ripple down effect via a UI event,
+ * *not* respecting the `noink` property.
+ * @param {Event=} event
+ */
+ downAction: function(event) {
+ if (this.holdDown && this.ripples.length > 0) {
+ return;
+ }
+
+ var ripple = this.addRipple();
+
+ ripple.downAction(event);
+
+ if (!this._animating) {
+ this._animating = true;
+ this.animate();
+ }
+ },
+
+ /**
+ * Provokes a ripple up effect via a UI event,
+ * respecting the `noink` property.
+ * @param {Event=} event
+ */
+ uiUpAction: function(event) {
+ if (!this.noink) {
+ this.upAction(event);
+ }
+ },
+
+ /**
+ * Provokes a ripple up effect via a UI event,
+ * *not* respecting the `noink` property.
+ * @param {Event=} event
+ */
+ upAction: function(event) {
+ if (this.holdDown) {
+ return;
+ }
+
+ this.ripples.forEach(function(ripple) {
+ ripple.upAction(event);
+ });
+
+ this._animating = true;
+ this.animate();
+ },
+
+ onAnimationComplete: function() {
+ this._animating = false;
+ this.$.background.style.backgroundColor = null;
+ this.fire('transitionend');
+ },
+
+ addRipple: function() {
+ var ripple = new Ripple(this);
+
+ Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
+ this.$.background.style.backgroundColor = ripple.color;
+ this.ripples.push(ripple);
+
+ this._setAnimating(true);
+
+ return ripple;
+ },
+
+ removeRipple: function(ripple) {
+ var rippleIndex = this.ripples.indexOf(ripple);
+
+ if (rippleIndex < 0) {
+ return;
+ }
+
+ this.ripples.splice(rippleIndex, 1);
+
+ ripple.remove();
+
+ if (!this.ripples.length) {
+ this._setAnimating(false);
+ }
+ },
+
+ animate: function() {
+ if (!this._animating) {
+ return;
+ }
+ var index;
+ var ripple;
+
+ for (index = 0; index < this.ripples.length; ++index) {
+ ripple = this.ripples[index];
+
+ ripple.draw();
+
+ this.$.background.style.opacity = ripple.outerOpacity;
+
+ if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
+ this.removeRipple(ripple);
+ }
+ }
+
+ if (!this.shouldKeepAnimating && this.ripples.length === 0) {
+ this.onAnimationComplete();
+ } else {
+ window.requestAnimationFrame(this._boundAnimate);
+ }
+ },
+
+ _onEnterKeydown: function() {
+ this.uiDownAction();
+ this.async(this.uiUpAction, 1);
+ },
+
+ _onSpaceKeydown: function() {
+ this.uiDownAction();
+ },
+
+ _onSpaceKeyup: function() {
+ this.uiUpAction();
+ },
+
+ // note: holdDown does not respect noink since it can be a focus based
+ // effect.
+ _holdDownChanged: function(newVal, oldVal) {
+ if (oldVal === undefined) {
+ return;
+ }
+ if (newVal) {
+ this.downAction();
+ } else {
+ this.upAction();
+ }
+ }
+
+ /**
+ Fired when the animation finishes.
+ This is useful if you want to wait until
+ the ripple animation finishes to perform some action.
+
+ @event transitionend
+ @param {{node: Object}} detail Contains the animated node.
+ */
+ });
+ })();
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.bower.json
new file mode 100644
index 00000000000..38dad0d72a4
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.bower.json
@@ -0,0 +1,47 @@
+{
+ "name": "paper-spinner",
+ "version": "1.2.0",
+ "description": "A material design spinner",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "spinner",
+ "loading"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-spinner"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-spinner",
+ "ignore": [],
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": [
+ "paper-spinner.html",
+ "paper-spinner-lite.html"
+ ],
+ "_release": "1.2.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.0",
+ "commit": "66dc50a940aa9a3a067137defe1712aa85de6f35"
+ },
+ "_source": "git://github.com/PolymerElements/paper-spinner.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-spinner"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.travis.yml
new file mode 100644
index 00000000000..2f5e400e2b3
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: dpHtK5BMl68o/D6cQO9VsQWBPVuTrFPC56NT6kBLbiQtmxG2E2FD8dN4cHuEWafZopwYSsLLmEIIK77FMaonTSmzos5EixIQyqGxWTyNTpthg0Jenzc+6vZEs3h+3LDodFjdZSu8FgKyxU8SFLLGjAsSy8aegUNBszy7/SY8FAM=
+ - secure: EASvFsWb/njjh3DOLD5Oz3nw4QPl4aIhDAIhU2qelb2UCp8Q/KGniU7VjNoQ7OSN05jh2ooz8Pu3cAhLmrWumJn2atXEXvRPKtT/+1Ciy3xFcvgmqM0RHB+7qSSOUwgvPW9bwdzVxxMjAW7Oqb7w3nVn9/mEv2sMPNSv7iEbiUI=
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
+dist: trusty
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/README.md
new file mode 100644
index 00000000000..ad57a2fca3d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/README.md
@@ -0,0 +1,93 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-spinner-behavior.html paper-spinner-lite.html paper-spinner.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-spinner.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-spinner)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-spinner)_
+
+
+##&lt;paper-spinner&gt;
+
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+Element providing a multiple color material design circular spinner.
+
+```html
+<paper-spinner active></paper-spinner>
+```
+
+The default spinner cycles between four layers of colors; by default they are
+blue, red, yellow and green. It can be customized to cycle between four different
+colors. Use <paper-spinner-lite> for single color spinners.
+
+### Accessibility
+
+Alt attribute should be set to provide adequate context for accessibility. If not provided,
+it defaults to 'loading'.
+Empty alt can be provided to mark the element as decorative if alternative content is provided
+in another form (e.g. a text block following the spinner).
+
+```html
+<paper-spinner alt="Loading contacts list" active></paper-spinner>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-spinner-layer-1-color` | Color of the first spinner rotation | `--google-blue-500` |
+| `--paper-spinner-layer-2-color` | Color of the second spinner rotation | `--google-red-500` |
+| `--paper-spinner-layer-3-color` | Color of the third spinner rotation | `--google-yellow-500` |
+| `--paper-spinner-layer-4-color` | Color of the fourth spinner rotation | `--google-green-500` |
+| `--paper-spinner-stroke-width` | The width of the spinner stroke | 3px |
+
+
+
+##&lt;paper-spinner-lite&gt;
+
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+Element providing a single color material design circular spinner.
+
+```html
+<paper-spinner-lite active></paper-spinner-lite>
+```
+
+The default spinner is blue. It can be customized to be a different color.
+
+### Accessibility
+
+Alt attribute should be set to provide adequate context for accessibility. If not provided,
+it defaults to 'loading'.
+Empty alt can be provided to mark the element as decorative if alternative content is provided
+in another form (e.g. a text block following the spinner).
+
+```html
+<paper-spinner-lite alt="Loading contacts list" active></paper-spinner-lite>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-spinner-color` | Color of the spinner | `--google-blue-500` |
+| `--paper-spinner-stroke-width` | The width of the spinner stroke | 3px |
+
+
+
+<!-- No docs for Polymer.PaperSpinnerBehavior found. -->
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/bower.json
new file mode 100644
index 00000000000..7f8f09a9d6f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/bower.json
@@ -0,0 +1,38 @@
+{
+ "name": "paper-spinner",
+ "version": "1.2.0",
+ "description": "A material design spinner",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "spinner",
+ "loading"
+ ],
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-spinner"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-spinner",
+ "ignore": [],
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "main": [
+ "paper-spinner.html",
+ "paper-spinner-lite.html"
+ ]
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/demo/index.html
new file mode 100644
index 00000000000..d4c56f945e0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/demo/index.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html lang="en">
+ <head>
+ <title>paper-spinner demo</title>
+
+ <meta charset="UTF-8">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../paper-spinner-lite.html">
+ <link rel="import" href="../paper-spinner.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ .vertical-section-container {
+ max-width: 550px;
+ }
+
+ paper-spinner, paper-spinner-lite {
+ margin-right: 24px;
+ }
+ </style>
+ </head>
+ <body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Spinners can be deactivated or activated</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-spinner></paper-spinner>
+ <paper-spinner active></paper-spinner>
+
+ <paper-spinner-lite></paper-spinner-lite>
+ <paper-spinner-lite active></paper-spinner-lite>
+
+ <button onclick="toggle(event)">Toggle</button>
+ </template>
+ </demo-snippet>
+
+ <h3>Spinners can be styled using custom properties</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-spinner.multi {
+ --paper-spinner-layer-1-color: var(--paper-purple-500);
+ --paper-spinner-layer-2-color: var(--paper-cyan-500);
+ --paper-spinner-layer-3-color: var(--paper-blue-grey-500);
+ --paper-spinner-layer-4-color: var(--paper-amber-500);
+ }
+ paper-spinner-lite.orange {
+ --paper-spinner-color: var(--google-yellow-500);
+ }
+ paper-spinner-lite.green {
+ --paper-spinner-color: var(--google-green-500);
+ }
+ paper-spinner-lite.thin {
+ --paper-spinner-stroke-width: 1px;
+ }
+ paper-spinner-lite.thick {
+ --paper-spinner-stroke-width: 6px;
+ }
+ </style>
+
+ <paper-spinner class="multi" active></paper-spinner>
+
+ <paper-spinner-lite class="orange" active></paper-spinner-lite>
+ <paper-spinner-lite class="green" active></paper-spinner-lite>
+
+ <paper-spinner-lite class="thin" active></paper-spinner-lite>
+ <paper-spinner-lite class="thick" active></paper-spinner-lite>
+ </template>
+ </demo-snippet>
+ </div>
+
+ <script>
+ function toggle(event) {
+ var spinners = event.target.parentElement.querySelectorAll('paper-spinner, paper-spinner-lite');
+ Array.prototype.forEach.call(spinners, function(spinner) {
+ spinner.active = !spinner.active;
+ });
+ };
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/hero.svg
new file mode 100755
index 00000000000..034b1f11add
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/hero.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <g>
+ <path d="M112.1,92.3c-13.4,0-25.1-9.1-28.4-22l1.9-0.5c3.1,12.1,13.9,20.5,26.4,20.5c15,0,27.3-12.2,27.3-27.3
+ s-12.2-27.3-27.3-27.3c-8.1,0-15.8,3.6-21,9.8l-1.5-1.3c5.6-6.7,13.8-10.6,22.5-10.6c16.1,0,29.3,13.1,29.3,29.3
+ S128.2,92.3,112.1,92.3z"/>
+ <path d="M112.7,87.3c-6.6,0-12.7-2.5-17.3-7.2c-4.6-4.6-7.2-10.8-7.2-17.3c0-6.6,2.5-12.7,7.2-17.3c7.9-7.9,20.2-9.5,29.8-3.8
+ l-1,1.7c-8.8-5.3-20.1-3.8-27.4,3.5c-4.2,4.2-6.6,9.9-6.6,15.9s2.3,11.7,6.6,15.9s9.9,6.6,15.9,6.6c6,0,11.7-2.3,15.9-6.6
+ c4.7-4.7,7.1-11.3,6.5-18l2-0.2c0.7,7.3-1.9,14.4-7.1,19.6C125.4,84.7,119.2,87.3,112.7,87.3z"/>
+ <path d="M112.5,43.5C101.8,43.5,93,52.3,93,63s8.7,19.5,19.5,19.5S132,73.7,132,63S123.2,43.5,112.5,43.5z M119,64h-6v6h-2v-6h-6
+ v-2h6v-6h2v6h6V64z"/>
+ </g>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/index.html
new file mode 100644
index 00000000000..9874334610e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-spinner</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+ </head>
+ <body>
+
+ <iron-component-page></iron-component-page>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-behavior.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-behavior.html
new file mode 100644
index 00000000000..ce3594b0200
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-behavior.html
@@ -0,0 +1,87 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+
+ /** @polymerBehavior */
+ Polymer.PaperSpinnerBehavior = {
+
+ listeners: {
+ 'animationend': '__reset',
+ 'webkitAnimationEnd': '__reset'
+ },
+
+ properties: {
+ /**
+ * Displays the spinner.
+ */
+ active: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ observer: '__activeChanged'
+ },
+
+ /**
+ * Alternative text content for accessibility support.
+ * If alt is present, it will add an aria-label whose content matches alt when active.
+ * If alt is not present, it will default to 'loading' as the alt value.
+ */
+ alt: {
+ type: String,
+ value: 'loading',
+ observer: '__altChanged'
+ },
+
+ __coolingDown: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ __computeContainerClasses: function(active, coolingDown) {
+ return [
+ active || coolingDown ? 'active' : '',
+ coolingDown ? 'cooldown' : ''
+ ].join(' ');
+ },
+
+ __activeChanged: function(active, old) {
+ this.__setAriaHidden(!active);
+ this.__coolingDown = !active && old;
+ },
+
+ __altChanged: function(alt) {
+ // user-provided `aria-label` takes precedence over prototype default
+ if (alt === this.getPropertyInfo('alt').value) {
+ this.alt = this.getAttribute('aria-label') || alt;
+ } else {
+ this.__setAriaHidden(alt==='');
+ this.setAttribute('aria-label', alt);
+ }
+ },
+
+ __setAriaHidden: function(hidden) {
+ var attr = 'aria-hidden';
+ if (hidden) {
+ this.setAttribute(attr, 'true');
+ } else {
+ this.removeAttribute(attr);
+ }
+ },
+
+ __reset: function() {
+ this.active = false;
+ this.__coolingDown = false;
+ }
+ };
+</script>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-lite.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-lite.html
new file mode 100644
index 00000000000..5d123a756e0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-lite.html
@@ -0,0 +1,71 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="paper-spinner-behavior.html">
+<link rel="import" href="paper-spinner-styles.html">
+
+<!--
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+Element providing a single color material design circular spinner.
+
+ <paper-spinner-lite active></paper-spinner-lite>
+
+The default spinner is blue. It can be customized to be a different color.
+
+### Accessibility
+
+Alt attribute should be set to provide adequate context for accessibility. If not provided,
+it defaults to 'loading'.
+Empty alt can be provided to mark the element as decorative if alternative content is provided
+in another form (e.g. a text block following the spinner).
+
+ <paper-spinner-lite alt="Loading contacts list" active></paper-spinner-lite>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-spinner-color` | Color of the spinner | `--google-blue-500`
+`--paper-spinner-stroke-width` | The width of the spinner stroke | 3px
+
+@group Paper Elements
+@element paper-spinner-lite
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-spinner-lite">
+ <template strip-whitespace>
+ <style include="paper-spinner-styles"></style>
+
+ <div id="spinnerContainer" class-name="[[__computeContainerClasses(active, __coolingDown)]]">
+ <div class="spinner-layer">
+ <div class="circle-clipper left"></div>
+ <div class="circle-clipper right"></div>
+ </div>
+ </div>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-spinner-lite',
+
+ behaviors: [
+ Polymer.PaperSpinnerBehavior
+ ]
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-styles.html
new file mode 100644
index 00000000000..08329293755
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner-styles.html
@@ -0,0 +1,341 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<dom-module id="paper-spinner-styles">
+ <template>
+ <style>
+ /*
+ /**************************/
+ /* STYLES FOR THE SPINNER */
+ /**************************/
+
+ /*
+ * Constants:
+ * ARCSIZE = 270 degrees (amount of circle the arc takes up)
+ * ARCTIME = 1333ms (time it takes to expand and contract arc)
+ * ARCSTARTROT = 216 degrees (how much the start location of the arc
+ * should rotate each time, 216 gives us a
+ * 5 pointed star shape (it's 360/5 * 3).
+ * For a 7 pointed star, we might do
+ * 360/7 * 3 = 154.286)
+ * SHRINK_TIME = 400ms
+ */
+
+ :host {
+ display: inline-block;
+ position: relative;
+ width: 28px;
+ height: 28px;
+
+ /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
+ --paper-spinner-container-rotation-duration: 1568ms;
+
+ /* ARCTIME */
+ --paper-spinner-expand-contract-duration: 1333ms;
+
+ /* 4 * ARCTIME */
+ --paper-spinner-full-cycle-duration: 5332ms;
+
+ /* SHRINK_TIME */
+ --paper-spinner-cooldown-duration: 400ms;
+ }
+
+ #spinnerContainer {
+ width: 100%;
+ height: 100%;
+
+ /* The spinner does not have any contents that would have to be
+ * flipped if the direction changes. Always use ltr so that the
+ * style works out correctly in both cases. */
+ direction: ltr;
+ }
+
+ #spinnerContainer.active {
+ -webkit-animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite;
+ animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite;
+ }
+
+ @-webkit-keyframes container-rotate {
+ to { -webkit-transform: rotate(360deg) }
+ }
+
+ @keyframes container-rotate {
+ to { transform: rotate(360deg) }
+ }
+
+ .spinner-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ white-space: nowrap;
+ border-color: var(--paper-spinner-color, --google-blue-500);
+ }
+
+ .layer-1 {
+ border-color: var(--paper-spinner-layer-1-color, --google-blue-500);
+ }
+
+ .layer-2 {
+ border-color: var(--paper-spinner-layer-2-color, --google-red-500);
+ }
+
+ .layer-3 {
+ border-color: var(--paper-spinner-layer-3-color, --google-yellow-500);
+ }
+
+ .layer-4 {
+ border-color: var(--paper-spinner-layer-4-color, --google-green-500);
+ }
+
+ /**
+ * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
+ *
+ * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
+ * guarantee that the animation will start _exactly_ after that value. So we avoid using
+ * animation-delay and instead set custom keyframes for each color (as layer-2undant as it
+ * seems).
+ */
+ .active .spinner-layer {
+ -webkit-animation-name: fill-unfill-rotate;
+ -webkit-animation-duration: var(--paper-spinner-full-cycle-duration);
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
+ -webkit-animation-iteration-count: infinite;
+ animation-name: fill-unfill-rotate;
+ animation-duration: var(--paper-spinner-full-cycle-duration);
+ animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
+ animation-iteration-count: infinite;
+ opacity: 1;
+ }
+
+ .active .spinner-layer.layer-1 {
+ -webkit-animation-name: fill-unfill-rotate, layer-1-fade-in-out;
+ animation-name: fill-unfill-rotate, layer-1-fade-in-out;
+ }
+
+ .active .spinner-layer.layer-2 {
+ -webkit-animation-name: fill-unfill-rotate, layer-2-fade-in-out;
+ animation-name: fill-unfill-rotate, layer-2-fade-in-out;
+ }
+
+ .active .spinner-layer.layer-3 {
+ -webkit-animation-name: fill-unfill-rotate, layer-3-fade-in-out;
+ animation-name: fill-unfill-rotate, layer-3-fade-in-out;
+ }
+
+ .active .spinner-layer.layer-4 {
+ -webkit-animation-name: fill-unfill-rotate, layer-4-fade-in-out;
+ animation-name: fill-unfill-rotate, layer-4-fade-in-out;
+ }
+
+ @-webkit-keyframes fill-unfill-rotate {
+ 12.5% { -webkit-transform: rotate(135deg) } /* 0.5 * ARCSIZE */
+ 25% { -webkit-transform: rotate(270deg) } /* 1 * ARCSIZE */
+ 37.5% { -webkit-transform: rotate(405deg) } /* 1.5 * ARCSIZE */
+ 50% { -webkit-transform: rotate(540deg) } /* 2 * ARCSIZE */
+ 62.5% { -webkit-transform: rotate(675deg) } /* 2.5 * ARCSIZE */
+ 75% { -webkit-transform: rotate(810deg) } /* 3 * ARCSIZE */
+ 87.5% { -webkit-transform: rotate(945deg) } /* 3.5 * ARCSIZE */
+ to { -webkit-transform: rotate(1080deg) } /* 4 * ARCSIZE */
+ }
+
+ @keyframes fill-unfill-rotate {
+ 12.5% { transform: rotate(135deg) } /* 0.5 * ARCSIZE */
+ 25% { transform: rotate(270deg) } /* 1 * ARCSIZE */
+ 37.5% { transform: rotate(405deg) } /* 1.5 * ARCSIZE */
+ 50% { transform: rotate(540deg) } /* 2 * ARCSIZE */
+ 62.5% { transform: rotate(675deg) } /* 2.5 * ARCSIZE */
+ 75% { transform: rotate(810deg) } /* 3 * ARCSIZE */
+ 87.5% { transform: rotate(945deg) } /* 3.5 * ARCSIZE */
+ to { transform: rotate(1080deg) } /* 4 * ARCSIZE */
+ }
+
+ @-webkit-keyframes layer-1-fade-in-out {
+ 0% { opacity: 1 }
+ 25% { opacity: 1 }
+ 26% { opacity: 0 }
+ 89% { opacity: 0 }
+ 90% { opacity: 1 }
+ to { opacity: 1 }
+ }
+
+ @keyframes layer-1-fade-in-out {
+ 0% { opacity: 1 }
+ 25% { opacity: 1 }
+ 26% { opacity: 0 }
+ 89% { opacity: 0 }
+ 90% { opacity: 1 }
+ to { opacity: 1 }
+ }
+
+ @-webkit-keyframes layer-2-fade-in-out {
+ 0% { opacity: 0 }
+ 15% { opacity: 0 }
+ 25% { opacity: 1 }
+ 50% { opacity: 1 }
+ 51% { opacity: 0 }
+ to { opacity: 0 }
+ }
+
+ @keyframes layer-2-fade-in-out {
+ 0% { opacity: 0 }
+ 15% { opacity: 0 }
+ 25% { opacity: 1 }
+ 50% { opacity: 1 }
+ 51% { opacity: 0 }
+ to { opacity: 0 }
+ }
+
+ @-webkit-keyframes layer-3-fade-in-out {
+ 0% { opacity: 0 }
+ 40% { opacity: 0 }
+ 50% { opacity: 1 }
+ 75% { opacity: 1 }
+ 76% { opacity: 0 }
+ to { opacity: 0 }
+ }
+
+ @keyframes layer-3-fade-in-out {
+ 0% { opacity: 0 }
+ 40% { opacity: 0 }
+ 50% { opacity: 1 }
+ 75% { opacity: 1 }
+ 76% { opacity: 0 }
+ to { opacity: 0 }
+ }
+
+ @-webkit-keyframes layer-4-fade-in-out {
+ 0% { opacity: 0 }
+ 65% { opacity: 0 }
+ 75% { opacity: 1 }
+ 90% { opacity: 1 }
+ to { opacity: 0 }
+ }
+
+ @keyframes layer-4-fade-in-out {
+ 0% { opacity: 0 }
+ 65% { opacity: 0 }
+ 75% { opacity: 1 }
+ 90% { opacity: 1 }
+ to { opacity: 0 }
+ }
+
+ .circle-clipper {
+ display: inline-block;
+ position: relative;
+ width: 50%;
+ height: 100%;
+ overflow: hidden;
+ border-color: inherit;
+ }
+
+ /**
+ * Patch the gap that appear between the two adjacent div.circle-clipper while the
+ * spinner is rotating (appears on Chrome 50, Safari 9.1.1, and Edge).
+ */
+ .spinner-layer::after {
+ left: 45%;
+ width: 10%;
+ border-top-style: solid;
+ }
+
+ .spinner-layer::after,
+ .circle-clipper::after {
+ content: '';
+ box-sizing: border-box;
+ position: absolute;
+ top: 0;
+ border-width: var(--paper-spinner-stroke-width, 3px);
+ border-color: inherit;
+ border-radius: 50%;
+ }
+
+ .circle-clipper::after {
+ bottom: 0;
+ width: 200%;
+ border-style: solid;
+ border-bottom-color: transparent !important;
+ }
+
+ .circle-clipper.left::after {
+ left: 0;
+ border-right-color: transparent !important;
+ -webkit-transform: rotate(129deg);
+ transform: rotate(129deg);
+ }
+
+ .circle-clipper.right::after {
+ left: -100%;
+ border-left-color: transparent !important;
+ -webkit-transform: rotate(-129deg);
+ transform: rotate(-129deg);
+ }
+
+ .active .gap-patch::after,
+ .active .circle-clipper::after {
+ -webkit-animation-duration: var(--paper-spinner-expand-contract-duration);
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
+ -webkit-animation-iteration-count: infinite;
+ animation-duration: var(--paper-spinner-expand-contract-duration);
+ animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
+ animation-iteration-count: infinite;
+ }
+
+ .active .circle-clipper.left::after {
+ -webkit-animation-name: left-spin;
+ animation-name: left-spin;
+ }
+
+ .active .circle-clipper.right::after {
+ -webkit-animation-name: right-spin;
+ animation-name: right-spin;
+ }
+
+ @-webkit-keyframes left-spin {
+ 0% { -webkit-transform: rotate(130deg) }
+ 50% { -webkit-transform: rotate(-5deg) }
+ to { -webkit-transform: rotate(130deg) }
+ }
+
+ @keyframes left-spin {
+ 0% { transform: rotate(130deg) }
+ 50% { transform: rotate(-5deg) }
+ to { transform: rotate(130deg) }
+ }
+
+ @-webkit-keyframes right-spin {
+ 0% { -webkit-transform: rotate(-130deg) }
+ 50% { -webkit-transform: rotate(5deg) }
+ to { -webkit-transform: rotate(-130deg) }
+ }
+
+ @keyframes right-spin {
+ 0% { transform: rotate(-130deg) }
+ 50% { transform: rotate(5deg) }
+ to { transform: rotate(-130deg) }
+ }
+
+ #spinnerContainer.cooldown {
+ -webkit-animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cubic-bezier(0.4, 0.0, 0.2, 1);
+ animation: container-rotate var(--paper-spinner-container-rotation-duration) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cubic-bezier(0.4, 0.0, 0.2, 1);
+ }
+
+ @-webkit-keyframes fade-out {
+ 0% { opacity: 1 }
+ to { opacity: 0 }
+ }
+
+ @keyframes fade-out {
+ 0% { opacity: 1 }
+ to { opacity: 0 }
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner.html b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner.html
new file mode 100644
index 00000000000..54ff8bc09c7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-spinner/paper-spinner.html
@@ -0,0 +1,91 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../paper-styles/color.html">
+<link rel="import" href="paper-spinner-behavior.html">
+<link rel="import" href="paper-spinner-styles.html">
+
+<!--
+Material design: [Progress & activity](https://www.google.com/design/spec/components/progress-activity.html)
+
+Element providing a multiple color material design circular spinner.
+
+ <paper-spinner active></paper-spinner>
+
+The default spinner cycles between four layers of colors; by default they are
+blue, red, yellow and green. It can be customized to cycle between four different
+colors. Use <paper-spinner-lite> for single color spinners.
+
+### Accessibility
+
+Alt attribute should be set to provide adequate context for accessibility. If not provided,
+it defaults to 'loading'.
+Empty alt can be provided to mark the element as decorative if alternative content is provided
+in another form (e.g. a text block following the spinner).
+
+ <paper-spinner alt="Loading contacts list" active></paper-spinner>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-spinner-layer-1-color` | Color of the first spinner rotation | `--google-blue-500`
+`--paper-spinner-layer-2-color` | Color of the second spinner rotation | `--google-red-500`
+`--paper-spinner-layer-3-color` | Color of the third spinner rotation | `--google-yellow-500`
+`--paper-spinner-layer-4-color` | Color of the fourth spinner rotation | `--google-green-500`
+`--paper-spinner-stroke-width` | The width of the spinner stroke | 3px
+
+@group Paper Elements
+@element paper-spinner
+@hero hero.svg
+@demo demo/index.html
+-->
+
+<dom-module id="paper-spinner">
+ <template strip-whitespace>
+ <style include="paper-spinner-styles"></style>
+
+ <div id="spinnerContainer" class-name="[[__computeContainerClasses(active, __coolingDown)]]">
+ <div class="spinner-layer layer-1">
+ <div class="circle-clipper left"></div>
+ <div class="circle-clipper right"></div>
+ </div>
+
+ <div class="spinner-layer layer-2">
+ <div class="circle-clipper left"></div>
+ <div class="circle-clipper right"></div>
+ </div>
+
+ <div class="spinner-layer layer-3">
+ <div class="circle-clipper left"></div>
+ <div class="circle-clipper right"></div>
+ </div>
+
+ <div class="spinner-layer layer-4">
+ <div class="circle-clipper left"></div>
+ <div class="circle-clipper right"></div>
+ </div>
+ </div>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-spinner',
+
+ behaviors: [
+ Polymer.PaperSpinnerBehavior
+ ]
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/.bower.json
new file mode 100644
index 00000000000..ae677ef3e72
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/.bower.json
@@ -0,0 +1,42 @@
+{
+ "name": "paper-styles",
+ "version": "1.1.4",
+ "description": "Common (global) styles for Material Design elements.",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-component",
+ "polymer",
+ "style"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-styles.git"
+ },
+ "main": "paper-styles.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/polymerelements/paper-styles/",
+ "ignore": [
+ "/.*"
+ ],
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "font-roboto": "PolymerElements/font-roboto#^1.0.1",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "web-component-tester": "^4.0.0"
+ },
+ "_release": "1.1.4",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.4",
+ "commit": "885bbd74db88dab4fb5dc229cdf994c55fb2b31b"
+ },
+ "_source": "git://github.com/PolymerElements/paper-styles.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-styles"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/README.md
new file mode 100644
index 00000000000..ca555bdb32d
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/README.md
@@ -0,0 +1,49 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-styles.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-styles.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-styles)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-styles)_
+
+
+##&lt;paper-styles&gt;
+
+The `<paper-styles>` component provides simple ways to use Material Design CSS styles
+in your application. The following imports are available:
+
+1. [color.html](https://github.com/PolymerElements/paper-styles/blob/master/color.html):
+a complete list of the colors defined in the Material Design [palette](https://www.google.com/design/spec/style/color.html)
+
+
+1. [default-theme.html](https://github.com/PolymerElements/paper-styles/blob/master/default-theme.html): text,
+background and accent colors that match the default Material Design theme
+
+
+1. [shadow.html](https://github.com/PolymerElements/paper-styles/blob/master/shadow.html): Material Design
+[elevation](https://www.google.com/design/spec/what-is-material/elevation-shadows.html) and shadow styles
+
+
+1. [typography.html](https://github.com/PolymerElements/paper-styles/blob/master/typography.html):
+Material Design [font](http://www.google.com/design/spec/style/typography.html#typography-styles) styles and sizes
+
+
+1. [demo-pages.html](https://github.com/PolymerElements/paper-styles/blob/master/demo-pages.html): generic styles
+used in the PolymerElements demo pages
+
+
+
+We recommend importing each of these individual files, and using the style mixins
+available in each ones, rather than the aggregated `paper-styles.html` as a whole.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/bower.json
new file mode 100644
index 00000000000..f3330c3ca33
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "paper-styles",
+ "version": "1.1.4",
+ "description": "Common (global) styles for Material Design elements.",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-component",
+ "polymer",
+ "style"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-styles.git"
+ },
+ "main": "paper-styles.html",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/polymerelements/paper-styles/",
+ "ignore": [
+ "/.*"
+ ],
+ "dependencies": {
+ "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+ "font-roboto": "PolymerElements/font-roboto#^1.0.1",
+ "polymer": "Polymer/polymer#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
+ "web-component-tester": "^4.0.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/global.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/global.html
new file mode 100644
index 00000000000..6f0d5ddee1e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/global.html
@@ -0,0 +1,96 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../paper-styles-classes.html">
+
+<!--
+A set of base styles that are applied to the document and standard elements that
+match the Material Design spec.
+-->
+<style>
+/*
+Note that there is a lot of style duplication here. The hope is that the Polymer
+0.8 styling solution will allow for inheritance of properties so that we can
+eventually avoid it.
+*/
+
+/* Mixins */
+
+/* [paper-font] */
+body {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ -webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */
+}
+
+/* [paper-font=display2] */
+h1 {
+ font-size: 45px;
+ font-weight: 400;
+ letter-spacing: -.018em;
+ line-height: 48px;
+}
+
+/* [paper-font=display1] */
+h2 {
+ font-size: 34px;
+ font-weight: 400;
+ letter-spacing: -.01em;
+ line-height: 40px;
+}
+
+/* [paper-font=headline] */
+h3 {
+ font-size: 24px;
+ font-weight: 400;
+ letter-spacing: -.012em;
+ line-height: 32px;
+}
+
+/* [paper-font=subhead] */
+h4 {
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+}
+
+/* [paper-font=body2] */
+h5, h6 {
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 24px;
+}
+
+/* [paper-font=button] */
+a {
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: 0.018em;
+ line-height: 24px;
+ text-transform: uppercase;
+}
+
+/* Overrides */
+
+body, a {
+ color: #212121;
+}
+
+h1, h2, h3, h4, h5, h6, p {
+ margin: 0 0 20px 0;
+}
+
+h1, h2, h3, h4, h5, h6, a {
+ text-rendering: optimizeLegibility;
+}
+
+a {
+ text-decoration: none;
+}
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow-layout.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow-layout.html
new file mode 100644
index 00000000000..fe55ec80a2b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow-layout.html
@@ -0,0 +1,302 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<style>
+
+ /*******************************
+ Flex Layout
+ *******************************/
+
+ html /deep/ .layout.horizontal,
+ html /deep/ .layout.horizontal-reverse,
+ html /deep/ .layout.vertical,
+ html /deep/ .layout.vertical-reverse {
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ html /deep/ .layout.inline {
+ display: -ms-inline-flexbox;
+ display: -webkit-inline-flex;
+ display: inline-flex;
+ }
+
+ html /deep/ .layout.horizontal {
+ -ms-flex-direction: row;
+ -webkit-flex-direction: row;
+ flex-direction: row;
+ }
+
+ html /deep/ .layout.horizontal-reverse {
+ -ms-flex-direction: row-reverse;
+ -webkit-flex-direction: row-reverse;
+ flex-direction: row-reverse;
+ }
+
+ html /deep/ .layout.vertical {
+ -ms-flex-direction: column;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ }
+
+ html /deep/ .layout.vertical-reverse {
+ -ms-flex-direction: column-reverse;
+ -webkit-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ }
+
+ html /deep/ .layout.wrap {
+ -ms-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ flex-wrap: wrap;
+ }
+
+ html /deep/ .layout.wrap-reverse {
+ -ms-flex-wrap: wrap-reverse;
+ -webkit-flex-wrap: wrap-reverse;
+ flex-wrap: wrap-reverse;
+ }
+
+ html /deep/ .flex-auto {
+ -ms-flex: 1 1 auto;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ }
+
+ html /deep/ .flex-none {
+ -ms-flex: none;
+ -webkit-flex: none;
+ flex: none;
+ }
+
+ html /deep/ .flex,
+ html /deep/ .flex-1 {
+ -ms-flex: 1;
+ -webkit-flex: 1;
+ flex: 1;
+ }
+
+ html /deep/ .flex-2 {
+ -ms-flex: 2;
+ -webkit-flex: 2;
+ flex: 2;
+ }
+
+ html /deep/ .flex-3 {
+ -ms-flex: 3;
+ -webkit-flex: 3;
+ flex: 3;
+ }
+
+ html /deep/ .flex-4 {
+ -ms-flex: 4;
+ -webkit-flex: 4;
+ flex: 4;
+ }
+
+ html /deep/ .flex-5 {
+ -ms-flex: 5;
+ -webkit-flex: 5;
+ flex: 5;
+ }
+
+ html /deep/ .flex-6 {
+ -ms-flex: 6;
+ -webkit-flex: 6;
+ flex: 6;
+ }
+
+ html /deep/ .flex-7 {
+ -ms-flex: 7;
+ -webkit-flex: 7;
+ flex: 7;
+ }
+
+ html /deep/ .flex-8 {
+ -ms-flex: 8;
+ -webkit-flex: 8;
+ flex: 8;
+ }
+
+ html /deep/ .flex-9 {
+ -ms-flex: 9;
+ -webkit-flex: 9;
+ flex: 9;
+ }
+
+ html /deep/ .flex-10 {
+ -ms-flex: 10;
+ -webkit-flex: 10;
+ flex: 10;
+ }
+
+ html /deep/ .flex-11 {
+ -ms-flex: 11;
+ -webkit-flex: 11;
+ flex: 11;
+ }
+
+ html /deep/ .flex-12 {
+ -ms-flex: 12;
+ -webkit-flex: 12;
+ flex: 12;
+ }
+
+ /* alignment in cross axis */
+
+ html /deep/ .layout.start {
+ -ms-flex-align: start;
+ -webkit-align-items: flex-start;
+ align-items: flex-start;
+ }
+
+ html /deep/ .layout.center,
+ html /deep/ .layout.center-center {
+ -ms-flex-align: center;
+ -webkit-align-items: center;
+ align-items: center;
+ }
+
+ html /deep/ .layout.end {
+ -ms-flex-align: end;
+ -webkit-align-items: flex-end;
+ align-items: flex-end;
+ }
+
+ /* alignment in main axis */
+
+ html /deep/ .layout.start-justified {
+ -ms-flex-pack: start;
+ -webkit-justify-content: flex-start;
+ justify-content: flex-start;
+ }
+
+ html /deep/ .layout.center-justified,
+ html /deep/ .layout.center-center {
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ }
+
+ html /deep/ .layout.end-justified {
+ -ms-flex-pack: end;
+ -webkit-justify-content: flex-end;
+ justify-content: flex-end;
+ }
+
+ html /deep/ .layout.around-justified {
+ -ms-flex-pack: around;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ }
+
+ html /deep/ .layout.justified {
+ -ms-flex-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ }
+
+ /* self alignment */
+
+ html /deep/ .self-start {
+ -ms-align-self: flex-start;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ }
+
+ html /deep/ .self-center {
+ -ms-align-self: center;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+
+ html /deep/ .self-end {
+ -ms-align-self: flex-end;
+ -webkit-align-self: flex-end;
+ align-self: flex-end;
+ }
+
+ html /deep/ .self-stretch {
+ -ms-align-self: stretch;
+ -webkit-align-self: stretch;
+ align-self: stretch;
+ }
+
+ /*******************************
+ Other Layout
+ *******************************/
+
+ html /deep/ .block {
+ display: block;
+ }
+
+ /* IE 10 support for HTML5 hidden attr */
+ html /deep/ [hidden] {
+ display: none !important;
+ }
+
+ html /deep/ .invisible {
+ visibility: hidden !important;
+ }
+
+ html /deep/ .relative {
+ position: relative;
+ }
+
+ html /deep/ .fit {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ body.fullbleed {
+ margin: 0;
+ height: 100vh;
+ }
+
+ html /deep/ .scroll {
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ }
+
+ .fixed-bottom,
+ .fixed-left,
+ .fixed-right,
+ .fixed-top {
+ position: fixed;
+ }
+
+ html /deep/ .fixed-top {
+ top: 0;
+ left: 0;
+ right: 0;
+ }
+
+ html /deep/ .fixed-right {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ }
+
+ html /deep/ .fixed-bottom {
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+ html /deep/ .fixed-left {
+ top: 0;
+ bottom: 0;
+ left: 0;
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow.html
new file mode 100644
index 00000000000..4c40a147a5b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/shadow.html
@@ -0,0 +1,52 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<style>
+.shadow-transition {
+ transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.shadow-elevation-2dp {
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 5px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 1px -2px rgba(0, 0, 0, 0.2);
+}
+
+.shadow-elevation-3dp {
+ box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 8px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 3px -2px rgba(0, 0, 0, 0.4);
+}
+
+.shadow-elevation-4dp {
+ box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 10px 0 rgba(0, 0, 0, 0.12),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.4);
+}
+
+.shadow-elevation-6dp {
+ box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 5px -1px rgba(0, 0, 0, 0.4);
+}
+
+.shadow-elevation-8dp {
+ box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12),
+ 0 5px 5px -3px rgba(0, 0, 0, 0.4);
+}
+
+.shadow-elevation-16dp {
+ box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14),
+ 0 6px 30px 5px rgba(0, 0, 0, 0.12),
+ 0 8px 10px -5px rgba(0, 0, 0, 0.4);
+}
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/typography.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/typography.html
new file mode 100644
index 00000000000..e6163a8176a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/classes/typography.html
@@ -0,0 +1,169 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../font-roboto/roboto.html">
+
+<!--
+Typographic styles are provided matching the Material Design standard styles:
+http://www.google.com/design/spec/style/typography.html#typography-standard-styles
+
+To make use of them, apply a `paper-font-<style>` class to elements, matching
+the font style you wish it to inherit.
+
+ <header class="paper-font-display2">Hey there!</header>
+
+Note that these are English/Latin centric styles. You may need to further adjust
+line heights and weights for CJK typesetting. See the notes in the Material
+Design typography section.
+-->
+<style>
+
+.paper-font-display4,
+.paper-font-display3,
+.paper-font-display2,
+.paper-font-display1,
+.paper-font-headline,
+.paper-font-title,
+.paper-font-subhead,
+.paper-font-body2,
+.paper-font-body1,
+.paper-font-caption,
+.paper-font-menu,
+.paper-font-button {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ -webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */
+}
+
+.paper-font-code2,
+.paper-font-code1 {
+ font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
+ -webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */
+}
+
+/* Opt for better kerning for headers & other short labels. */
+.paper-font-display4,
+.paper-font-display3,
+.paper-font-display2,
+.paper-font-display1,
+.paper-font-headline,
+.paper-font-title,
+.paper-font-subhead,
+.paper-font-menu,
+.paper-font-button {
+ text-rendering: optimizeLegibility;
+}
+
+/*
+"Line wrapping only applies to Body, Subhead, Headline, and the smaller Display
+styles. All other styles should exist as single lines."
+*/
+.paper-font-display4,
+.paper-font-display3,
+.paper-font-title,
+.paper-font-caption,
+.paper-font-menu,
+.paper-font-button {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.paper-font-display4 {
+ font-size: 112px;
+ font-weight: 300;
+ letter-spacing: -.044em;
+ line-height: 120px;
+}
+
+.paper-font-display3 {
+ font-size: 56px;
+ font-weight: 400;
+ letter-spacing: -.026em;
+ line-height: 60px;
+}
+
+.paper-font-display2 {
+ font-size: 45px;
+ font-weight: 400;
+ letter-spacing: -.018em;
+ line-height: 48px;
+}
+
+.paper-font-display1 {
+ font-size: 34px;
+ font-weight: 400;
+ letter-spacing: -.01em;
+ line-height: 40px;
+}
+
+.paper-font-headline {
+ font-size: 24px;
+ font-weight: 400;
+ letter-spacing: -.012em;
+ line-height: 32px;
+}
+
+.paper-font-title {
+ font-size: 20px;
+ font-weight: 500;
+ line-height: 28px;
+}
+
+.paper-font-subhead {
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+}
+
+.paper-font-body2 {
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 24px;
+}
+
+.paper-font-body1 {
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 20px;
+}
+
+.paper-font-caption {
+ font-size: 12px;
+ font-weight: 400;
+ letter-spacing: 0.011em;
+ line-height: 20px;
+}
+
+.paper-font-menu {
+ font-size: 13px;
+ font-weight: 500;
+ line-height: 24px;
+}
+
+.paper-font-button {
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: 0.018em;
+ line-height: 24px;
+ text-transform: uppercase;
+}
+
+.paper-font-code2 {
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 20px;
+}
+
+.paper-font-code1 {
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 20px;
+}
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/color.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/color.html
new file mode 100644
index 00000000000..51887901356
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/color.html
@@ -0,0 +1,333 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<style is="custom-style">
+
+ :root {
+
+ /* Material Design color palette for Google products */
+
+ --google-red-100: #f4c7c3;
+ --google-red-300: #e67c73;
+ --google-red-500: #db4437;
+ --google-red-700: #c53929;
+
+ --google-blue-100: #c6dafc;
+ --google-blue-300: #7baaf7;
+ --google-blue-500: #4285f4;
+ --google-blue-700: #3367d6;
+
+ --google-green-100: #b7e1cd;
+ --google-green-300: #57bb8a;
+ --google-green-500: #0f9d58;
+ --google-green-700: #0b8043;
+
+ --google-yellow-100: #fce8b2;
+ --google-yellow-300: #f7cb4d;
+ --google-yellow-500: #f4b400;
+ --google-yellow-700: #f09300;
+
+ --google-grey-100: #f5f5f5;
+ --google-grey-300: #e0e0e0;
+ --google-grey-500: #9e9e9e;
+ --google-grey-700: #616161;
+
+ /* Material Design color palette from online spec document */
+
+ --paper-red-50: #ffebee;
+ --paper-red-100: #ffcdd2;
+ --paper-red-200: #ef9a9a;
+ --paper-red-300: #e57373;
+ --paper-red-400: #ef5350;
+ --paper-red-500: #f44336;
+ --paper-red-600: #e53935;
+ --paper-red-700: #d32f2f;
+ --paper-red-800: #c62828;
+ --paper-red-900: #b71c1c;
+ --paper-red-a100: #ff8a80;
+ --paper-red-a200: #ff5252;
+ --paper-red-a400: #ff1744;
+ --paper-red-a700: #d50000;
+
+ --paper-pink-50: #fce4ec;
+ --paper-pink-100: #f8bbd0;
+ --paper-pink-200: #f48fb1;
+ --paper-pink-300: #f06292;
+ --paper-pink-400: #ec407a;
+ --paper-pink-500: #e91e63;
+ --paper-pink-600: #d81b60;
+ --paper-pink-700: #c2185b;
+ --paper-pink-800: #ad1457;
+ --paper-pink-900: #880e4f;
+ --paper-pink-a100: #ff80ab;
+ --paper-pink-a200: #ff4081;
+ --paper-pink-a400: #f50057;
+ --paper-pink-a700: #c51162;
+
+ --paper-purple-50: #f3e5f5;
+ --paper-purple-100: #e1bee7;
+ --paper-purple-200: #ce93d8;
+ --paper-purple-300: #ba68c8;
+ --paper-purple-400: #ab47bc;
+ --paper-purple-500: #9c27b0;
+ --paper-purple-600: #8e24aa;
+ --paper-purple-700: #7b1fa2;
+ --paper-purple-800: #6a1b9a;
+ --paper-purple-900: #4a148c;
+ --paper-purple-a100: #ea80fc;
+ --paper-purple-a200: #e040fb;
+ --paper-purple-a400: #d500f9;
+ --paper-purple-a700: #aa00ff;
+
+ --paper-deep-purple-50: #ede7f6;
+ --paper-deep-purple-100: #d1c4e9;
+ --paper-deep-purple-200: #b39ddb;
+ --paper-deep-purple-300: #9575cd;
+ --paper-deep-purple-400: #7e57c2;
+ --paper-deep-purple-500: #673ab7;
+ --paper-deep-purple-600: #5e35b1;
+ --paper-deep-purple-700: #512da8;
+ --paper-deep-purple-800: #4527a0;
+ --paper-deep-purple-900: #311b92;
+ --paper-deep-purple-a100: #b388ff;
+ --paper-deep-purple-a200: #7c4dff;
+ --paper-deep-purple-a400: #651fff;
+ --paper-deep-purple-a700: #6200ea;
+
+ --paper-indigo-50: #e8eaf6;
+ --paper-indigo-100: #c5cae9;
+ --paper-indigo-200: #9fa8da;
+ --paper-indigo-300: #7986cb;
+ --paper-indigo-400: #5c6bc0;
+ --paper-indigo-500: #3f51b5;
+ --paper-indigo-600: #3949ab;
+ --paper-indigo-700: #303f9f;
+ --paper-indigo-800: #283593;
+ --paper-indigo-900: #1a237e;
+ --paper-indigo-a100: #8c9eff;
+ --paper-indigo-a200: #536dfe;
+ --paper-indigo-a400: #3d5afe;
+ --paper-indigo-a700: #304ffe;
+
+ --paper-blue-50: #e3f2fd;
+ --paper-blue-100: #bbdefb;
+ --paper-blue-200: #90caf9;
+ --paper-blue-300: #64b5f6;
+ --paper-blue-400: #42a5f5;
+ --paper-blue-500: #2196f3;
+ --paper-blue-600: #1e88e5;
+ --paper-blue-700: #1976d2;
+ --paper-blue-800: #1565c0;
+ --paper-blue-900: #0d47a1;
+ --paper-blue-a100: #82b1ff;
+ --paper-blue-a200: #448aff;
+ --paper-blue-a400: #2979ff;
+ --paper-blue-a700: #2962ff;
+
+ --paper-light-blue-50: #e1f5fe;
+ --paper-light-blue-100: #b3e5fc;
+ --paper-light-blue-200: #81d4fa;
+ --paper-light-blue-300: #4fc3f7;
+ --paper-light-blue-400: #29b6f6;
+ --paper-light-blue-500: #03a9f4;
+ --paper-light-blue-600: #039be5;
+ --paper-light-blue-700: #0288d1;
+ --paper-light-blue-800: #0277bd;
+ --paper-light-blue-900: #01579b;
+ --paper-light-blue-a100: #80d8ff;
+ --paper-light-blue-a200: #40c4ff;
+ --paper-light-blue-a400: #00b0ff;
+ --paper-light-blue-a700: #0091ea;
+
+ --paper-cyan-50: #e0f7fa;
+ --paper-cyan-100: #b2ebf2;
+ --paper-cyan-200: #80deea;
+ --paper-cyan-300: #4dd0e1;
+ --paper-cyan-400: #26c6da;
+ --paper-cyan-500: #00bcd4;
+ --paper-cyan-600: #00acc1;
+ --paper-cyan-700: #0097a7;
+ --paper-cyan-800: #00838f;
+ --paper-cyan-900: #006064;
+ --paper-cyan-a100: #84ffff;
+ --paper-cyan-a200: #18ffff;
+ --paper-cyan-a400: #00e5ff;
+ --paper-cyan-a700: #00b8d4;
+
+ --paper-teal-50: #e0f2f1;
+ --paper-teal-100: #b2dfdb;
+ --paper-teal-200: #80cbc4;
+ --paper-teal-300: #4db6ac;
+ --paper-teal-400: #26a69a;
+ --paper-teal-500: #009688;
+ --paper-teal-600: #00897b;
+ --paper-teal-700: #00796b;
+ --paper-teal-800: #00695c;
+ --paper-teal-900: #004d40;
+ --paper-teal-a100: #a7ffeb;
+ --paper-teal-a200: #64ffda;
+ --paper-teal-a400: #1de9b6;
+ --paper-teal-a700: #00bfa5;
+
+ --paper-green-50: #e8f5e9;
+ --paper-green-100: #c8e6c9;
+ --paper-green-200: #a5d6a7;
+ --paper-green-300: #81c784;
+ --paper-green-400: #66bb6a;
+ --paper-green-500: #4caf50;
+ --paper-green-600: #43a047;
+ --paper-green-700: #388e3c;
+ --paper-green-800: #2e7d32;
+ --paper-green-900: #1b5e20;
+ --paper-green-a100: #b9f6ca;
+ --paper-green-a200: #69f0ae;
+ --paper-green-a400: #00e676;
+ --paper-green-a700: #00c853;
+
+ --paper-light-green-50: #f1f8e9;
+ --paper-light-green-100: #dcedc8;
+ --paper-light-green-200: #c5e1a5;
+ --paper-light-green-300: #aed581;
+ --paper-light-green-400: #9ccc65;
+ --paper-light-green-500: #8bc34a;
+ --paper-light-green-600: #7cb342;
+ --paper-light-green-700: #689f38;
+ --paper-light-green-800: #558b2f;
+ --paper-light-green-900: #33691e;
+ --paper-light-green-a100: #ccff90;
+ --paper-light-green-a200: #b2ff59;
+ --paper-light-green-a400: #76ff03;
+ --paper-light-green-a700: #64dd17;
+
+ --paper-lime-50: #f9fbe7;
+ --paper-lime-100: #f0f4c3;
+ --paper-lime-200: #e6ee9c;
+ --paper-lime-300: #dce775;
+ --paper-lime-400: #d4e157;
+ --paper-lime-500: #cddc39;
+ --paper-lime-600: #c0ca33;
+ --paper-lime-700: #afb42b;
+ --paper-lime-800: #9e9d24;
+ --paper-lime-900: #827717;
+ --paper-lime-a100: #f4ff81;
+ --paper-lime-a200: #eeff41;
+ --paper-lime-a400: #c6ff00;
+ --paper-lime-a700: #aeea00;
+
+ --paper-yellow-50: #fffde7;
+ --paper-yellow-100: #fff9c4;
+ --paper-yellow-200: #fff59d;
+ --paper-yellow-300: #fff176;
+ --paper-yellow-400: #ffee58;
+ --paper-yellow-500: #ffeb3b;
+ --paper-yellow-600: #fdd835;
+ --paper-yellow-700: #fbc02d;
+ --paper-yellow-800: #f9a825;
+ --paper-yellow-900: #f57f17;
+ --paper-yellow-a100: #ffff8d;
+ --paper-yellow-a200: #ffff00;
+ --paper-yellow-a400: #ffea00;
+ --paper-yellow-a700: #ffd600;
+
+ --paper-amber-50: #fff8e1;
+ --paper-amber-100: #ffecb3;
+ --paper-amber-200: #ffe082;
+ --paper-amber-300: #ffd54f;
+ --paper-amber-400: #ffca28;
+ --paper-amber-500: #ffc107;
+ --paper-amber-600: #ffb300;
+ --paper-amber-700: #ffa000;
+ --paper-amber-800: #ff8f00;
+ --paper-amber-900: #ff6f00;
+ --paper-amber-a100: #ffe57f;
+ --paper-amber-a200: #ffd740;
+ --paper-amber-a400: #ffc400;
+ --paper-amber-a700: #ffab00;
+
+ --paper-orange-50: #fff3e0;
+ --paper-orange-100: #ffe0b2;
+ --paper-orange-200: #ffcc80;
+ --paper-orange-300: #ffb74d;
+ --paper-orange-400: #ffa726;
+ --paper-orange-500: #ff9800;
+ --paper-orange-600: #fb8c00;
+ --paper-orange-700: #f57c00;
+ --paper-orange-800: #ef6c00;
+ --paper-orange-900: #e65100;
+ --paper-orange-a100: #ffd180;
+ --paper-orange-a200: #ffab40;
+ --paper-orange-a400: #ff9100;
+ --paper-orange-a700: #ff6500;
+
+ --paper-deep-orange-50: #fbe9e7;
+ --paper-deep-orange-100: #ffccbc;
+ --paper-deep-orange-200: #ffab91;
+ --paper-deep-orange-300: #ff8a65;
+ --paper-deep-orange-400: #ff7043;
+ --paper-deep-orange-500: #ff5722;
+ --paper-deep-orange-600: #f4511e;
+ --paper-deep-orange-700: #e64a19;
+ --paper-deep-orange-800: #d84315;
+ --paper-deep-orange-900: #bf360c;
+ --paper-deep-orange-a100: #ff9e80;
+ --paper-deep-orange-a200: #ff6e40;
+ --paper-deep-orange-a400: #ff3d00;
+ --paper-deep-orange-a700: #dd2c00;
+
+ --paper-brown-50: #efebe9;
+ --paper-brown-100: #d7ccc8;
+ --paper-brown-200: #bcaaa4;
+ --paper-brown-300: #a1887f;
+ --paper-brown-400: #8d6e63;
+ --paper-brown-500: #795548;
+ --paper-brown-600: #6d4c41;
+ --paper-brown-700: #5d4037;
+ --paper-brown-800: #4e342e;
+ --paper-brown-900: #3e2723;
+
+ --paper-grey-50: #fafafa;
+ --paper-grey-100: #f5f5f5;
+ --paper-grey-200: #eeeeee;
+ --paper-grey-300: #e0e0e0;
+ --paper-grey-400: #bdbdbd;
+ --paper-grey-500: #9e9e9e;
+ --paper-grey-600: #757575;
+ --paper-grey-700: #616161;
+ --paper-grey-800: #424242;
+ --paper-grey-900: #212121;
+
+ --paper-blue-grey-50: #eceff1;
+ --paper-blue-grey-100: #cfd8dc;
+ --paper-blue-grey-200: #b0bec5;
+ --paper-blue-grey-300: #90a4ae;
+ --paper-blue-grey-400: #78909c;
+ --paper-blue-grey-500: #607d8b;
+ --paper-blue-grey-600: #546e7a;
+ --paper-blue-grey-700: #455a64;
+ --paper-blue-grey-800: #37474f;
+ --paper-blue-grey-900: #263238;
+
+ /* opacity for dark text on a light background */
+ --dark-divider-opacity: 0.12;
+ --dark-disabled-opacity: 0.38; /* or hint text or icon */
+ --dark-secondary-opacity: 0.54;
+ --dark-primary-opacity: 0.87;
+
+ /* opacity for light text on a dark background */
+ --light-divider-opacity: 0.12;
+ --light-disabled-opacity: 0.3; /* or hint text or icon */
+ --light-secondary-opacity: 0.7;
+ --light-primary-opacity: 1.0;
+
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/default-theme.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/default-theme.html
new file mode 100644
index 00000000000..cc6972812cf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/default-theme.html
@@ -0,0 +1,72 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="color.html">
+
+<!-- Taken from https://www.google.com/design/spec/style/color.html#color-ui-color-application -->
+
+<style is="custom-style">
+
+ :root {
+ /*
+ * You can use these generic variables in your elements for easy theming.
+ * For example, if all your elements use `--primary-text-color` as its main
+ * color, then switching from a light to a dark theme is just a matter of
+ * changing the value of `--primary-text-color` in your application.
+ */
+ --primary-text-color: var(--light-theme-text-color);
+ --primary-background-color: var(--light-theme-background-color);
+ --secondary-text-color: var(--light-theme-secondary-color);
+ --disabled-text-color: var(--light-theme-disabled-color);
+ --divider-color: var(--light-theme-divider-color);
+ --error-color: var(--paper-deep-orange-a700);
+
+ /*
+ * Primary and accent colors. Also see color.html for more colors.
+ */
+ --primary-color: var(--paper-indigo-500);
+ --light-primary-color: var(--paper-indigo-100);
+ --dark-primary-color: var(--paper-indigo-700);
+
+ --accent-color: var(--paper-pink-a200);
+ --light-accent-color: var(--paper-pink-a100);
+ --dark-accent-color: var(--paper-pink-a400);
+
+
+ /*
+ * Material Design Light background theme
+ */
+ --light-theme-background-color: #ffffff;
+ --light-theme-base-color: #000000;
+ --light-theme-text-color: var(--paper-grey-900);
+ --light-theme-secondary-color: #737373; /* for secondary text and icons */
+ --light-theme-disabled-color: #9b9b9b; /* disabled/hint text */
+ --light-theme-divider-color: #dbdbdb;
+
+ /*
+ * Material Design Dark background theme
+ */
+ --dark-theme-background-color: var(--paper-grey-900);
+ --dark-theme-base-color: #ffffff;
+ --dark-theme-text-color: #ffffff;
+ --dark-theme-secondary-color: #bcbcbc; /* for secondary text and icons */
+ --dark-theme-disabled-color: #646464; /* disabled/hint text */
+ --dark-theme-divider-color: #3c3c3c;
+
+ /*
+ * Deprecated values because of their confusing names.
+ */
+ --text-primary-color: var(--dark-theme-text-color);
+ --default-primary-color: var(--primary-color);
+
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo-pages.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo-pages.html
new file mode 100644
index 00000000000..6e900ad163f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo-pages.html
@@ -0,0 +1,72 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+
+<link rel="import" href="color.html">
+<link rel="import" href="typography.html">
+<link rel="import" href="shadow.html">
+
+<style is="custom-style">
+
+ body {
+ @apply(--paper-font-common-base);
+ font-size: 14px;
+ margin: 0;
+ padding: 24px;
+ background-color: var(--paper-grey-50);
+ }
+
+ .horizontal-section-container {
+ @apply(--layout-horizontal);
+ @apply(--layout-center-justified);
+ @apply(--layout-wrap);
+ }
+
+ .vertical-section-container {
+ @apply(--layout-vertical);
+ @apply(--center-justified);
+ }
+
+ .horizontal-section {
+ background-color: white;
+ padding: 24px;
+ margin-right: 24px;
+ min-width: 200px;
+
+ @apply(--shadow-elevation-2dp);
+ }
+
+ .vertical-section {
+ background-color: white;
+ padding: 24px;
+ margin: 0 24px 24px 24px;
+
+ @apply(--shadow-elevation-2dp);
+ }
+
+ .centered {
+ max-width: 400px;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ code {
+ color: var(--google-grey-700);
+ }
+
+ /* TODO: remove this hack and use horizontal-section-container instead */
+ body > div.layout.horizontal.center-justified {
+ @apply(--layout-wrap);
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo.css b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo.css
new file mode 100644
index 00000000000..efd8b471b50
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo.css
@@ -0,0 +1,25 @@
+/**
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+
+*/
+body {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ font-size: 14px;
+ margin: 0;
+ padding: 24px;
+}
+
+section {
+ padding: 20px 0;
+}
+
+section > div {
+ padding: 14px;
+ font-size: 16px;
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo/index.html
new file mode 100644
index 00000000000..1080cc66ddc
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/demo/index.html
@@ -0,0 +1,339 @@
+<!doctype html>
+
+<!--
+ @license
+ Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<html>
+ <head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>paper-styles demo</title>
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../color.html">
+ <link rel="import" href="../typography.html">
+ <link rel="import" href="../default-theme.html">
+ <link rel="import" href="../demo-pages.html">
+ </head>
+
+ <style>
+ .redlines {
+ background: linear-gradient(0deg, transparent, transparent 3.5px, rgba(255,0,0,0.2) 3.5px, rgba(255,0,0,0.2) 4px);
+ background-size: 100% 4px;
+ }
+
+ .paragraph {
+ margin-bottom: 20px;
+ }
+ </style>
+ <style is="custom-style">
+ .paper-font-display4 {
+ @apply(--paper-font-display4);
+ }
+
+ .paper-font-display3 {
+ @apply(--paper-font-display3);
+ }
+
+ .paper-font-display2 {
+ @apply(--paper-font-display2);
+ }
+
+ .paper-font-display1 {
+ @apply(--paper-font-display1);
+ }
+
+ .paper-font-headline {
+ @apply(--paper-font-headline);
+ }
+
+ .paper-font-title {
+ @apply(--paper-font-title);
+ }
+
+ .paper-font-subhead {
+ @apply(--paper-font-subhead);
+ }
+
+ .paper-font-body2 {
+ @apply(--paper-font-body2);
+ }
+
+ .paper-font-body1 {
+ @apply(--paper-font-body1);
+ }
+
+ .paper-font-caption {
+ @apply(--paper-font-caption);
+ }
+
+ .paper-font-menu {
+ @apply(--paper-font-menu);
+ }
+
+ .paper-font-button {
+ @apply(--paper-font-button);
+ }
+
+ .mobile-app {
+ max-width: 320px;
+ }
+
+ .toolbar {
+ height: 144px;
+ padding: 16px;
+
+ background: var(--default-primary-color);
+ color: var(--text-primary-color);
+ @apply(--paper-font-display1);
+ }
+
+ .item, .disabled-item {
+ position: relative;
+ padding: 8px;
+ border: 1px solid;
+ border-color: var(--divider-color);
+ border-top: 0;
+ }
+
+ .item .primary {
+ color: var(--primary-text-color);
+
+ @apply(--paper-font-body2);
+ }
+
+ .item .secondary {
+ color: var(--secondary-text-color);
+
+ @apply(--paper-font-body1);
+ }
+
+ .disabled-item {
+ color: var(--disabled-text-color);
+
+ @apply(--paper-font-body2);
+ }
+
+ .fab {
+ position: absolute;
+ box-sizing: border-box;
+ padding: 8px;
+ width: 56px;
+ height: 56px;
+ right: 16px;
+ top: -28px;
+ border-radius: 50%;
+ text-align: center;
+
+ background: var(--accent-color);
+ color: var(--text-primary-color);
+ @apply(--paper-font-display1);
+ }
+
+ .shadow {
+ display: inline-block;
+ padding: 8px;
+ margin: 16px;
+ height: 50px;
+ width: 50px;
+ }
+
+ .shadow-2dp {
+ @apply(--shadow-elevation-2dp);
+ }
+
+ .shadow-3dp {
+ @apply(--shadow-elevation-3dp);
+ }
+
+ .shadow-4dp {
+ @apply(--shadow-elevation-4dp);
+ }
+
+ .shadow-6dp {
+ @apply(--shadow-elevation-6dp);
+ }
+
+ .shadow-8dp {
+ @apply(--shadow-elevation-8dp);
+ }
+
+ .shadow-12dp {
+ @apply(--shadow-elevation-12dp);
+ }
+
+ .shadow-16dp {
+ @apply(--shadow-elevation-16dp);
+ }
+ </style>
+
+ <body unresolved>
+ <h1>paper-styles</h1>
+
+ <section id="default-theme">
+ <h2>default-theme.html</h2>
+
+ <section class="mobile-app">
+ <div class="toolbar">
+ Title
+ </div>
+ <div class="item">
+ <div class="fab">+</div>
+ <div class="primary">Primary text</div>
+ <div class="secondary">Secondary text</div>
+ </div>
+ <div class="disabled-item">
+ Disabled
+ </div>
+ </section>
+ </section>
+
+ <section id="typography">
+ <h2>typography.html</h2>
+ <p>
+ Grumpy wizards make toxic brew for the evil Queen and Jack.
+ </p>
+ <section class="redlines paragraph">
+ <div class="paper-font-display4">Display 4</div>
+ <div class="paper-font-display3">Display 3</div>
+ <div class="paper-font-display2">Display 2</div>
+ <div class="paper-font-display1">Display 1</div>
+ <div class="paper-font-headline">Headline</div>
+ <div class="paper-font-title">Title</div>
+ <div class="paper-font-subhead">Subhead</div>
+ <div class="paper-font-body2">Body 2</div>
+ <div class="paper-font-body1">Body 1</div>
+ <div class="paper-font-caption">Caption</div>
+ <div class="paper-font-menu">Menu</div>
+ <div class="paper-font-button">Button</div>
+ </section>
+
+ <h3>Paragraphs</h3>
+
+ <h4>body2</h4>
+ <section class="paper-font-body2 redlines">
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
+ tincidunt dui sit amet mi auctor, ac gravida magna aliquam. Fusce quis
+ purus elementum, tempus nisi vel, volutpat nulla. Vestibulum mollis
+ dictum tellus, vulputate porttitor arcu. Curabitur imperdiet risus id
+ egestas accumsan. Donec lectus felis, dignissim id iaculis sit amet,
+ faucibus in leo.
+ </p>
+ <p>
+ Mauris id urna ac ante ultrices commodo a imperdiet elit. Vivamus
+ interdum neque magna, eget dapibus est auctor et. Donec accumsan
+ libero nec augue scelerisque, ac egestas ante tincidunt. Proin
+ sollicitudin, mi eget sagittis mollis, arcu orci scelerisque turpis, a
+ sollicitudin tellus quam non sapien.
+ </p>
+ </section>
+
+ <h4>body1</h4>
+ <section class="paper-font-body1 redlines">
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
+ tincidunt dui sit amet mi auctor, ac gravida magna aliquam. Fusce quis
+ purus elementum, tempus nisi vel, volutpat nulla. Vestibulum mollis
+ dictum tellus, vulputate porttitor arcu. Curabitur imperdiet risus id
+ egestas accumsan. Donec lectus felis, dignissim id iaculis sit amet,
+ faucibus in leo.
+ </p>
+ <p>
+ Mauris id urna ac ante ultrices commodo a imperdiet elit. Vivamus
+ interdum neque magna, eget dapibus est auctor et. Donec accumsan
+ libero nec augue scelerisque, ac egestas ante tincidunt. Proin
+ sollicitudin, mi eget sagittis mollis, arcu orci scelerisque turpis, a
+ sollicitudin tellus quam non sapien.
+ </p>
+ </section>
+ </section>
+
+ <section id="shadow">
+ <h2>shadow.html</h2>
+ <div class="shadow shadow-2dp">2dp</div>
+ <div class="shadow shadow-3dp">3dp</div>
+ <div class="shadow shadow-4dp">4dp</div>
+ <div class="shadow shadow-6dp">6dp</div>
+ <div class="shadow shadow-8dp">8dp</div>
+ <div class="shadow shadow-12dp">12dp</div>
+ <div class="shadow shadow-16dp">16dp</div>
+ </section>
+
+ <section id="demo-page">
+ <h2>demo-pages.html</h2>
+
+ <h3>Horizontal sections</h3>
+ <div class="horizontal-section-container">
+ <div>
+ <h4>Column 1</h4>
+ <div class="horizontal-section">
+ <div>Oxygen</div>
+ <div>Carbon</div>
+ <div>Hydrogen</div>
+ <div>Nitrogen</div>
+ <div>Calcium</div>
+ </div>
+ </div>
+
+ <div>
+ <h4>Column 2</h4>
+ <div class="horizontal-section">
+ <div>Oxygen</div>
+ <div>Carbon</div>
+ <div>Hydrogen</div>
+ <div>Nitrogen</div>
+ <div>Calcium</div>
+ </div>
+ </div>
+
+ <div>
+ <h4>Column 3</h4>
+ <div class="horizontal-section">
+ <div>Oxygen</div>
+ <div>Carbon</div>
+ <div>Hydrogen</div>
+ <div>Nitrogen</div>
+ <div>Calcium</div>
+ </div>
+ </div>
+ </div>
+
+ <h3>Vertical sections</h3>
+ <div class="vertical-section-container">
+ <div>
+ <h4>Section 1</h4>
+ <div class="vertical-section">
+ <div>Oxygen</div>
+ <div>Carbon</div>
+ <div>Hydrogen</div>
+ <div>Nitrogen</div>
+ <div>Calcium</div>
+ </div>
+ </div>
+ </div>
+
+ <div class="vertical-section-container centered">
+ <h4>Section 2 (centered)</h4>
+ <div class="vertical-section">
+ <div>Oxygen</div>
+ <div>Carbon</div>
+ <div>Hydrogen</div>
+ <div>Nitrogen</div>
+ <div>Calcium</div>
+ </div>
+ </div>
+ </section>
+
+ </body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/index.html
new file mode 100644
index 00000000000..8e96ebe00c0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/index.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <title>paper-styles</title>
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles-classes.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles-classes.html
new file mode 100644
index 00000000000..ae315a57f82
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles-classes.html
@@ -0,0 +1,14 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-flex-layout/classes/iron-flex-layout.html">
+
+<link rel="import" href="classes/typography.html">
+<link rel="import" href="classes/shadow.html">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles.html
new file mode 100644
index 00000000000..9eca03a7735
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/paper-styles.html
@@ -0,0 +1,44 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="../iron-flex-layout/classes/iron-flex-layout.html">
+
+<!--
+The `<paper-styles>` component provides simple ways to use Material Design CSS styles
+in your application. The following imports are available:
+
+1. [color.html](https://github.com/PolymerElements/paper-styles/blob/master/color.html):
+a complete list of the colors defined in the Material Design [palette](https://www.google.com/design/spec/style/color.html)
+
+2. [default-theme.html](https://github.com/PolymerElements/paper-styles/blob/master/default-theme.html): text,
+background and accent colors that match the default Material Design theme
+
+3. [shadow.html](https://github.com/PolymerElements/paper-styles/blob/master/shadow.html): Material Design
+[elevation](https://www.google.com/design/spec/what-is-material/elevation-shadows.html) and shadow styles
+
+4. [typography.html](https://github.com/PolymerElements/paper-styles/blob/master/typography.html):
+Material Design [font](http://www.google.com/design/spec/style/typography.html#typography-styles) styles and sizes
+
+5. [demo-pages.html](https://github.com/PolymerElements/paper-styles/blob/master/demo-pages.html): generic styles
+used in the PolymerElements demo pages
+
+We recommend importing each of these individual files, and using the style mixins
+available in each ones, rather than the aggregated `paper-styles.html` as a whole.
+
+@group Paper Elements
+@pseudoElement paper-styles
+@demo demo/index.html
+-->
+
+<link rel="import" href="color.html">
+<link rel="import" href="default-theme.html">
+<link rel="import" href="shadow.html">
+<link rel="import" href="typography.html">
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/shadow.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/shadow.html
new file mode 100644
index 00000000000..c511e696f24
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/shadow.html
@@ -0,0 +1,71 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<style is="custom-style">
+
+ :root {
+
+ --shadow-transition: {
+ transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
+ };
+
+ --shadow-none: {
+ box-shadow: none;
+ };
+
+ /* from http://codepen.io/shyndman/pen/c5394ddf2e8b2a5c9185904b57421cdb */
+
+ --shadow-elevation-2dp: {
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 5px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 1px -2px rgba(0, 0, 0, 0.2);
+ };
+
+ --shadow-elevation-3dp: {
+ box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 8px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 3px -2px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-4dp: {
+ box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 10px 0 rgba(0, 0, 0, 0.12),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-6dp: {
+ box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 5px -1px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-8dp: {
+ box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12),
+ 0 5px 5px -3px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-12dp: {
+ box-shadow: 0 12px 16px 1px rgba(0, 0, 0, 0.14),
+ 0 4px 22px 3px rgba(0, 0, 0, 0.12),
+ 0 6px 7px -4px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-16dp: {
+ box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14),
+ 0 6px 30px 5px rgba(0, 0, 0, 0.12),
+ 0 8px 10px -5px rgba(0, 0, 0, 0.4);
+ };
+
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-styles/typography.html b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/typography.html
new file mode 100644
index 00000000000..055b5f99ce6
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-styles/typography.html
@@ -0,0 +1,169 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../font-roboto/roboto.html">
+
+<style is="custom-style">
+
+ :root {
+
+ /* Shared Styles */
+ --paper-font-common-base: {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ };
+
+ --paper-font-common-code: {
+ font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
+ -webkit-font-smoothing: antialiased;
+ };
+
+ --paper-font-common-expensive-kerning: {
+ text-rendering: optimizeLegibility;
+ };
+
+ --paper-font-common-nowrap: {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ };
+
+ /* Material Font Styles */
+
+ --paper-font-display4: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 112px;
+ font-weight: 300;
+ letter-spacing: -.044em;
+ line-height: 120px;
+ };
+
+ --paper-font-display3: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 56px;
+ font-weight: 400;
+ letter-spacing: -.026em;
+ line-height: 60px;
+ };
+
+ --paper-font-display2: {
+ @apply(--paper-font-common-base);
+
+ font-size: 45px;
+ font-weight: 400;
+ letter-spacing: -.018em;
+ line-height: 48px;
+ };
+
+ --paper-font-display1: {
+ @apply(--paper-font-common-base);
+
+ font-size: 34px;
+ font-weight: 400;
+ letter-spacing: -.01em;
+ line-height: 40px;
+ };
+
+ --paper-font-headline: {
+ @apply(--paper-font-common-base);
+
+ font-size: 24px;
+ font-weight: 400;
+ letter-spacing: -.012em;
+ line-height: 32px;
+ };
+
+ --paper-font-title: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 20px;
+ font-weight: 500;
+ line-height: 28px;
+ };
+
+ --paper-font-subhead: {
+ @apply(--paper-font-common-base);
+
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+ };
+
+ --paper-font-body2: {
+ @apply(--paper-font-common-base);
+
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 24px;
+ };
+
+ --paper-font-body1: {
+ @apply(--paper-font-common-base);
+
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 20px;
+ };
+
+ --paper-font-caption: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 12px;
+ font-weight: 400;
+ letter-spacing: 0.011em;
+ line-height: 20px;
+ };
+
+ --paper-font-menu: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 13px;
+ font-weight: 500;
+ line-height: 24px;
+ };
+
+ --paper-font-button: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: 0.018em;
+ line-height: 24px;
+ text-transform: uppercase;
+ };
+
+ --paper-font-code2: {
+ @apply(--paper-font-common-code);
+
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 20px;
+ };
+
+ --paper-font-code1: {
+ @apply(--paper-font-common-code);
+
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 20px;
+ };
+
+ }
+
+</style>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/.bower.json
new file mode 100644
index 00000000000..b635aa1d2b2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/.bower.json
@@ -0,0 +1,45 @@
+{
+ "name": "paper-toast",
+ "version": "1.3.0",
+ "description": "A material design notification toast",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "toast",
+ "notification"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-toast.git"
+ },
+ "main": "paper-toast.html",
+ "dependencies": {
+ "iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#^1.0.0",
+ "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.9",
+ "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.1.0",
+ "polymer": "Polymer/polymer#^1.5.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/paper-toast",
+ "_release": "1.3.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.3.0",
+ "commit": "f20ce41a3b4a81a9d277d1ed33f1621cf3e42ec0"
+ },
+ "_source": "git://github.com/PolymerElements/paper-toast.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-toast"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/CONTRIBUTING.md
new file mode 100644
index 00000000000..093090d4354
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/README.md
new file mode 100644
index 00000000000..1a639d19744
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/README.md
@@ -0,0 +1,72 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-toast.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-toast.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-toast)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-toast)_
+
+
+##&lt;paper-toast&gt;
+
+Material design: [Snackbards & toasts](https://www.google.com/design/spec/components/snackbars-toasts.html)
+
+`paper-toast` provides a subtle notification toast. Only one `paper-toast` will
+be visible on screen.
+
+Use `opened` to show the toast:
+
+Example:
+
+```html
+<paper-toast text="Hello world!" opened></paper-toast>
+```
+
+Also `open()` or `show()` can be used to show the toast:
+
+Example:
+
+```html
+<paper-button on-click="openToast">Open Toast</paper-button>
+<paper-toast id="toast" text="Hello world!"></paper-toast>
+
+...
+
+openToast: function() {
+ this.$.toast.open();
+}
+```
+
+Set `duration` to 0, a negative number or Infinity to persist the toast on screen:
+
+Example:
+
+```html
+<paper-toast text="Terms and conditions" opened duration="0">
+ <a href="#">Show more</a>
+</paper-toast>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-toast-background-color` | The paper-toast background-color | `#323232` |
+| `--paper-toast-color` | The paper-toast color | `#f1f1f1` |
+
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/bower.json
new file mode 100644
index 00000000000..ee2edaac574
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "paper-toast",
+ "version": "1.3.0",
+ "description": "A material design notification toast",
+ "private": true,
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "toast",
+ "notification"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-toast.git"
+ },
+ "main": "paper-toast.html",
+ "dependencies": {
+ "iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#^1.0.0",
+ "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.9",
+ "iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.1.0",
+ "polymer": "Polymer/polymer#^1.5.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "paper-button": "PolymerElements/paper-button#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo.html b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo.html
new file mode 100644
index 00000000000..c2098931248
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo.html
@@ -0,0 +1,63 @@
+<!--
+ @license
+ Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<!doctype html>
+<html>
+<head>
+ <title>paper-toast</title>
+
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <script src="../webcomponentsjs/webcomponents.js"></script>
+
+ <link rel="import" href="paper-toast.html">
+ <link rel="import" href="../font-roboto/roboto.html" >
+ <link rel="import" href="../paper-button/paper-button.html" >
+
+ <style>
+
+ html, body {
+ height: 100%;
+ }
+
+ body {
+ overflow: hidden;
+ margin: 0;
+ font-family: RobotoDraft, 'Helvetica Neue', Helvetica, Arial;
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+ -webkit-touch-callout: none;
+ }
+
+ paper-button {
+ margin: 20px;
+ }
+
+ </style>
+
+</head>
+<body unresolved>
+
+ <paper-button raised onclick="document.querySelector('#toast1').show()">Discard Draft</paper-button>
+
+ <paper-button raised onclick="document.querySelector('#toast2').show()">Get Messages</paper-button>
+
+ <paper-button raised onclick="document.querySelector('#toast3').show()">Send Message</paper-button>
+
+ <paper-toast id="toast1" text="Your draft has been discarded."></paper-toast>
+
+ <paper-toast id="toast2" role="alert" text="Connection timed out. Showing limited messages.">
+ <div style="color: #eeff41;" onclick="console.log('RETRY')">Retry</div>
+ </paper-toast>
+
+ <paper-toast id="toast3" class="capsule" text="Message sent" style="padding-right: 60px;"></paper-toast>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo/index.html
new file mode 100644
index 00000000000..126388349b5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/demo/index.html
@@ -0,0 +1,96 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+
+<head>
+ <title>paper-toast</title>
+
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../paper-toast.html">
+ <link rel="import" href="../../paper-button/paper-button.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles"></style>
+
+</head>
+
+<body unresolved class="centered">
+ <h3>Toast auto-closes after 3 seconds. Only one toast per time will be visible</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-button raised onclick="toast0.open()">Default toast</paper-button>
+ <paper-toast id="toast0" text="This toast auto-closes after 3 seconds"></paper-toast>
+ </template>
+ </demo-snippet>
+
+ <h3>Toast does not auto-close when <code>duration</code> is negative, <code>0</code>, or <code>Infinity</code></h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style>
+ .yellow-button {
+ text-transform: none;
+ color: #eeff41;
+ }
+ </style>
+
+ <paper-button raised onclick="toast1.open()">Persistent toast</paper-button>
+
+ <paper-toast id="toast1" duration="0" text="This toast will stay opened until you close it, or open another toast.">
+ <paper-button onclick="toast1.toggle()" class="yellow-button">Close now!</paper-button>
+ </paper-toast>
+ </template>
+ </demo-snippet>
+
+ <h3>Toast can be styled</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ #toast2 {
+ --paper-toast-background-color: red;
+ --paper-toast-color: white;
+ }
+ </style>
+
+ <paper-button raised onclick="toast2.open()">Styled toast</paper-button>
+
+ <paper-toast id="toast2" class="fit-bottom" text="This toast is red and fits bottom!"></paper-toast>
+ </template>
+ </demo-snippet>
+
+ <h3>Toast can fit into any element</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style>
+ #container {
+ padding: 100px;
+ border: 1px solid gray;
+ }
+ </style>
+ <div id="container">
+ <paper-button raised onclick="toast3.open()">Open toast</paper-button>
+ </div>
+ <paper-toast id="toast3" class="fit-bottom" text="This toast fits into the container."></paper-toast>
+
+ <script>
+ toast3.fitInto = container;
+ </script>
+
+ </template>
+ </demo-snippet>
+</body>
+
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/hero.svg b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/hero.svg
new file mode 100755
index 00000000000..bfdc1808bdd
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/hero.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
+<g id="background" display="none">
+ <rect display="inline" fill="#B0BEC5" width="225" height="126"/>
+</g>
+<g id="label">
+</g>
+<g id="art">
+ <path d="M164,114H13V88h151V114z M15,112h147V90H15V112z"/>
+ <rect x="26" y="100" width="79" height="2"/>
+ <rect x="135" y="100" width="16" height="2"/>
+ <g id="ic_x5F_add_x0D_">
+ </g>
+</g>
+<g id="Guides">
+</g>
+</svg>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/index.html
new file mode 100644
index 00000000000..487bb5c38a5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/index.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/metadata.html b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/metadata.html
new file mode 100644
index 00000000000..6c9c211e286
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/metadata.html
@@ -0,0 +1,20 @@
+<!--
+ @license
+ Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<x-meta id="paper-toast" label="Toast" group="Paper" isContainer>
+
+ <template>
+ <paper-toast text="Toast!"></paper-toast>
+ </template>
+
+ <template id="imports">
+ <link rel="import" href="paper-toast.html">
+ </template>
+
+</x-meta>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.css b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.css
new file mode 100644
index 00000000000..a677104648a
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.css
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+*/
+
+:host {
+ display: inline-block;
+ background: #323232;
+ color: #f1f1f1;
+ min-height: 48px;
+ min-width: 288px;
+ padding: 16px 24px 12px;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+ border-radius: 2px;
+ bottom: 12px;
+ left: 12px;
+ font-size: 14px;
+ cursor: default;
+}
+
+:host(.capsule) {
+ border-radius: 24px;
+}
+
+:host(.fit-bottom) {
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ min-width: 0;
+ border-radius: 0;
+}
+
+:host(.core-transition.dragging) {
+ transition: none;
+}
+
+:host(.core-transition.fade-out-down),
+:host(.core-transition.fade-out-up),
+:host(.core-transition.fade-out-right),
+:host(.core-transition.fade-out-left) {
+ opacity: 0;
+ transition: -webkit-transform 0.08s ease-in-out, opacity 0.08s ease-in-out;
+ transition: transform 0.08s ease-in-out, opacity 0.08s ease-in-out;
+}
+
+:host(.core-transition.fade-out-down) {
+ -webkit-transform: translate(0, 100%);
+ transform: translate(0, 100%);
+}
+
+:host(.core-transition.fade-out-up) {
+ -webkit-transform: translate(0, -100%);
+ transform: translate(0, -100%);
+}
+
+:host(.core-transition.fade-out-right) {
+ -webkit-transform: translate(100%, 0);
+ transform: translate(100%, 0);
+}
+
+:host(.core-transition.fade-out-left) {
+ -webkit-transform: translate(-100%, 0);
+ transform: translate(-100%, 0);
+}
+
+.toast-container {
+ overflow: hidden;
+}
+
+.toast-action {
+ padding-left: 24px;
+ cursor: pointer;
+ text-transform: uppercase;
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.html b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.html
new file mode 100644
index 00000000000..46260dab497
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-toast/paper-toast.html
@@ -0,0 +1,323 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-a11y-announcer/iron-a11y-announcer.html">
+<link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html">
+
+<!--
+Material design: [Snackbards & toasts](https://www.google.com/design/spec/components/snackbars-toasts.html)
+
+`paper-toast` provides a subtle notification toast. Only one `paper-toast` will
+be visible on screen.
+
+Use `opened` to show the toast:
+
+Example:
+
+ <paper-toast text="Hello world!" opened></paper-toast>
+
+Also `open()` or `show()` can be used to show the toast:
+
+Example:
+
+ <paper-button on-click="openToast">Open Toast</paper-button>
+ <paper-toast id="toast" text="Hello world!"></paper-toast>
+
+ ...
+
+ openToast: function() {
+ this.$.toast.open();
+ }
+
+Set `duration` to 0, a negative number or Infinity to persist the toast on screen:
+
+Example:
+
+ <paper-toast text="Terms and conditions" opened duration="0">
+ <a href="#">Show more</a>
+ </paper-toast>
+
+
+### Styling
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-toast-background-color` | The paper-toast background-color | `#323232`
+`--paper-toast-color` | The paper-toast color | `#f1f1f1`
+
+This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
+In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
+
+@group Paper Elements
+@element paper-toast
+@demo demo/index.html
+@hero hero.svg
+-->
+
+<dom-module id="paper-toast">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: fixed;
+ background-color: var(--paper-toast-background-color, #323232);
+ color: var(--paper-toast-color, #f1f1f1);
+ min-height: 48px;
+ min-width: 288px;
+ padding: 16px 24px;
+ box-sizing: border-box;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+ border-radius: 2px;
+ margin: 12px;
+ font-size: 14px;
+ cursor: default;
+ -webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
+ transition: transform 0.3s, opacity 0.3s;
+ opacity: 0;
+ -webkit-transform: translateY(100px);
+ transform: translateY(100px);
+ @apply(--paper-font-common-base);
+ }
+
+ :host(.capsule) {
+ border-radius: 24px;
+ }
+
+ :host(.fit-bottom) {
+ width: 100%;
+ min-width: 0;
+ border-radius: 0;
+ margin: 0;
+ }
+
+ :host(.paper-toast-open) {
+ opacity: 1;
+ -webkit-transform: translateY(0px);
+ transform: translateY(0px);
+ }
+ </style>
+
+ <span id="label">{{text}}</span>
+ <content></content>
+ </template>
+
+ <script>
+ (function() {
+ // Keeps track of the toast currently opened.
+ var currentToast = null;
+
+ Polymer({
+ is: 'paper-toast',
+
+ behaviors: [
+ Polymer.IronOverlayBehavior
+ ],
+
+ properties: {
+ /**
+ * The element to fit `this` into.
+ * Overridden from `Polymer.IronFitBehavior`.
+ */
+ fitInto: {
+ type: Object,
+ value: window,
+ observer: '_onFitIntoChanged'
+ },
+
+ /**
+ * The orientation against which to align the dropdown content
+ * horizontally relative to `positionTarget`.
+ * Overridden from `Polymer.IronFitBehavior`.
+ */
+ horizontalAlign: {
+ type: String,
+ value: 'left'
+ },
+
+ /**
+ * The orientation against which to align the dropdown content
+ * vertically relative to `positionTarget`.
+ * Overridden from `Polymer.IronFitBehavior`.
+ */
+ verticalAlign: {
+ type: String,
+ value: 'bottom'
+ },
+
+ /**
+ * The duration in milliseconds to show the toast.
+ * Set to `0`, a negative number, or `Infinity`, to disable the
+ * toast auto-closing.
+ */
+ duration: {
+ type: Number,
+ value: 3000
+ },
+
+ /**
+ * The text to display in the toast.
+ */
+ text: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ * Set to false to enable closing of the toast by clicking outside it.
+ */
+ noCancelOnOutsideClick: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ * Set to true to disable auto-focusing the toast or child nodes with
+ * the `autofocus` attribute` when the overlay is opened.
+ */
+ noAutoFocus: {
+ type: Boolean,
+ value: true
+ }
+ },
+
+ listeners: {
+ 'transitionend': '__onTransitionEnd'
+ },
+
+ /**
+ * Read-only. Deprecated. Use `opened` from `IronOverlayBehavior`.
+ * @property visible
+ * @deprecated
+ */
+ get visible() {
+ Polymer.Base._warn('`visible` is deprecated, use `opened` instead');
+ return this.opened;
+ },
+
+ /**
+ * Read-only. Can auto-close if duration is a positive finite number.
+ * @property _canAutoClose
+ */
+ get _canAutoClose() {
+ return this.duration > 0 && this.duration !== Infinity;
+ },
+
+ created: function() {
+ this._autoClose = null;
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ },
+
+ /**
+ * Show the toast. Without arguments, this is the same as `open()` from `IronOverlayBehavior`.
+ * @param {(Object|string)=} properties Properties to be set before opening the toast.
+ * e.g. `toast.show('hello')` or `toast.show({text: 'hello', duration: 3000})`
+ */
+ show: function(properties) {
+ if (typeof properties == 'string') {
+ properties = { text: properties };
+ }
+ for (var property in properties) {
+ if (property.indexOf('_') === 0) {
+ Polymer.Base._warn('The property "' + property + '" is private and was not set.');
+ } else if (property in this) {
+ this[property] = properties[property];
+ } else {
+ Polymer.Base._warn('The property "' + property + '" is not valid.');
+ }
+ }
+ this.open();
+ },
+
+ /**
+ * Hide the toast. Same as `close()` from `IronOverlayBehavior`.
+ */
+ hide: function() {
+ this.close();
+ },
+
+ /**
+ * Called on transitions of the toast, indicating a finished animation
+ * @private
+ */
+ __onTransitionEnd: function(e) {
+ // there are different transitions that are happening when opening and
+ // closing the toast. The last one so far is for `opacity`.
+ // This marks the end of the transition, so we check for this to determine if this
+ // is the correct event.
+ if (e && e.target === this && e.propertyName === 'opacity') {
+ if (this.opened) {
+ this._finishRenderOpened();
+ } else {
+ this._finishRenderClosed();
+ }
+ }
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ * Called when the value of `opened` changes.
+ */
+ _openedChanged: function() {
+ if (this._autoClose !== null) {
+ this.cancelAsync(this._autoClose);
+ this._autoClose = null;
+ }
+ if (this.opened) {
+ if (currentToast && currentToast !== this) {
+ currentToast.close();
+ }
+ currentToast = this;
+ this.fire('iron-announce', {
+ text: this.text
+ });
+ if (this._canAutoClose) {
+ this._autoClose = this.async(this.close, this.duration);
+ }
+ } else if (currentToast === this) {
+ currentToast = null;
+ }
+ Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ */
+ _renderOpened: function() {
+ this.classList.add('paper-toast-open');
+ },
+
+ /**
+ * Overridden from `IronOverlayBehavior`.
+ */
+ _renderClosed: function() {
+ this.classList.remove('paper-toast-open');
+ },
+
+ /**
+ * @private
+ */
+ _onFitIntoChanged: function(fitInto) {
+ this.positionTarget = fitInto;
+ }
+
+ /**
+ * Fired when `paper-toast` is opened.
+ *
+ * @event 'iron-announce'
+ * @param {{text: string}} detail Contains text that will be announced.
+ */
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.bower.json
new file mode 100644
index 00000000000..3df87bd84c7
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.bower.json
@@ -0,0 +1,45 @@
+{
+ "name": "paper-tooltip",
+ "version": "1.1.2",
+ "description": "Material design tooltip popup for content",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "tooltip"
+ ],
+ "main": "paper-tooltip.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-tooltip.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-tooltip",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
+ },
+ "_release": "1.1.2",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.1.2",
+ "commit": "6be894127678900f6e506b56fc9622ab768c03aa"
+ },
+ "_source": "git://github.com/PolymerElements/paper-tooltip.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/paper-tooltip"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.travis.yml b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.travis.yml
new file mode 100644
index 00000000000..0eacffa20f9
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/.travis.yml
@@ -0,0 +1,25 @@
+language: node_js
+sudo: false
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: NudIyPu1Tu0dPOHLbeKEc9GZk3tQt5s285nWES8LJWhhuiRMn7xYqLlU/PDXc89ClURC8YkPt1fQct+inxVNmT/YvFyRh+ZVDRmVYZHZFDl4M3mNfTVCG985pTB7IyYTBQBojoXab01DHbKzR79wRNIb6KypoJxaO1DIvXIOfgFCbam+xyibkayCUuu7S+GVkMuka26SEfllOQ9aHF2tCFuAHKcdLuwmjn/j5ffS/cP73JIulkf2IA1NOolvRd8kXWT8OQ4Hdw1r6DRipDSzlcsCmqur0LdFYfNAm5sZ+xHeuwdocGvKyZSReWMJcUwBuA3F+gXngKqZiTfGFAf0Ygd0rfaJ4WztjW1LkFR/3S8hhUtN2WC5wZYYaY7aQlepA3uecGxbbaVsBp7z1bBtMvllRUf7zs2YAw5mBgA5bD9dYgNb2N0u+IWWvlxBjvwIDfWIVJUJ7QMYM+6rWy4VCR7lfeeQBIXTyzLScLmjskMkbeY3WlvcEaHkAyZd7Y4rRL0eytOqE4jaG8kwpDQgjpKCbdwhl2HHzzktutfjD+JCn2nX8XF1ONw/LimDC/pUlv8zpyf4IByx3B1ObWZ86qO/t52FjLcuv8EtoAT0SFQWxoKZMGI8kNTjCje/jhGWTtT4FMkcksfnJYU68XXfduglLQADbTUQKO58CgICs9Y=
+ - secure: Bkrv2j17+bp9z+nQvDAQSFTMtk5SgXWHP71vnPsrO6BISUUzq5/3XOgiG8VN17JliNGkkD9d6oZ5izSvmi2ywVtg75+AkEa+4BLrCUQec6XT6I2xE8Sq0R28cAHBScxdm3M53BYekAPgMHJqJCrIVKUKkCbxIbsMJbCCTlXI8YmUP9bM1LNOsDYI1SOsW9YwcTarK4I3WD+G2sHOqQr9Sj4OrtAENUOTdDZlrEfYXi6z4unJKho7cwh4gJDJwEbvdhFLPfih6osqo70lv/Jx0QBwpFEsyOxIbWV7pVFOYzsHPxNgve4YyrfctlXeXYfef2tCD1AAgON+6xL4a9AK05cG9RwC0UN2apoIn5BFrz/XghBJ0arb9lwEePrb7lHLMB33vHn1+oZE3y+EewwQbAXoA3OAKrR0L00vP6TZVqpBeIDS27BMj9fp/l+GOwDwEK7jYGCxO7XUJlClZGMxLTRGNpxP057i2dYcWK5cTZ4e6UQS6hr6NqyvWctSs+BUZoDOHwFuFtCTF3G4ffOZ7VuPurViIRuOLEMLuc3titYd7FOqI+Q5XOGpE7dd1qzLJSh8FK8XUBV4/oyIYwFd/98sh0PwzrYorlxKlOygfXhV7D1FRZqJdPTvv9Qh1OjLIn182PYoctUZKzepfsqO3OdesxBxBYm35Bg9ph573Do=
+ - CXX=g++-4.8
+node_js: stable
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ - ubuntu-toolchain-r-test
+ packages:
+ - google-chrome-stable
+ - g++-4.8
+ sauce_connect: true
+script:
+ - xvfb-run wct
+ - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/CONTRIBUTING.md b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/CONTRIBUTING.md
new file mode 100644
index 00000000000..f147978a3e1
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/README.md b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/README.md
new file mode 100644
index 00000000000..b20a34b52a0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/README.md
@@ -0,0 +1,62 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+paper-tooltip.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/paper-tooltip.svg?branch=master)](https://travis-ci.org/PolymerElements/paper-tooltip)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/paper-tooltip)_
+
+
+##&lt;paper-tooltip&gt;
+
+Material design: [Tooltips](https://www.google.com/design/spec/components/tooltips.html)
+
+`<paper-tooltip>` is a label that appears on hover and focus when the user
+hovers over an element with the cursor or with the keyboard. It will be centered
+to an anchor element specified in the `for` attribute, or, if that doesn't exist,
+centered to the parent node containing it.
+
+Example:
+
+```html
+<div style="display:inline-block">
+ <button>Click me!</button>
+ <paper-tooltip>Tooltip text</paper-tooltip>
+</div>
+
+<div>
+ <button id="btn">Click me!</button>
+ <paper-tooltip for="btn">Tooltip text</paper-tooltip>
+</div>
+```
+
+The tooltip can be positioned on the top|bottom|left|right of the anchor using
+the `position` attribute. The default position is bottom.
+
+```html
+<paper-tooltip for="btn" position="left">Tooltip text</paper-tooltip>
+<paper-tooltip for="btn" position="top">Tooltip text</paper-tooltip>
+```
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+| Custom property | Description | Default |
+| --- | --- | --- |
+| `--paper-tooltip-background` | The background color of the tooltip | `#616161` |
+| `--paper-tooltip-opacity` | The opacity of the tooltip | `0.9` |
+| `--paper-tooltip-text-color` | The text color of the tooltip | `white` |
+| `--paper-tooltip` | Mixin applied to the tooltip | `{}` |
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/bower.json b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/bower.json
new file mode 100644
index 00000000000..423c88f3530
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/bower.json
@@ -0,0 +1,36 @@
+{
+ "name": "paper-tooltip",
+ "version": "1.1.2",
+ "description": "Material design tooltip popup for content",
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "keywords": [
+ "web-components",
+ "polymer",
+ "tooltip"
+ ],
+ "main": "paper-tooltip.html",
+ "private": true,
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/paper-tooltip.git"
+ },
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "homepage": "https://github.com/PolymerElements/paper-tooltip",
+ "ignore": [],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0",
+ "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+ "neon-animation": "PolymerElements/neon-animation#^1.0.0"
+ },
+ "devDependencies": {
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+ "web-component-tester": "^4.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
+ "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
+ "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
+ }
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/index.html
new file mode 100644
index 00000000000..7d7cab86553
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/index.html
@@ -0,0 +1,133 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html lang="en">
+<head>
+ <title>paper-tooltip demo</title>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+ <link rel="import" href="../../iron-icons/iron-icons.html">
+ <link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+ <link rel="import" href="../../paper-styles/color.html">
+ <link rel="import" href="../paper-tooltip.html">
+ <link rel="import" href="test-button.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ paper-icon-button, input, .avatar {
+ margin: 0 10px;
+ }
+
+ .avatar {
+ box-sizing: border-box;
+ width: 40px;
+ height: 40px;
+ padding: 8px;
+ border-radius: 50%;
+ cursor: pointer;
+ }
+
+ .blue {
+ background-color: var(--paper-light-blue-300);
+ }
+ .orange {
+ background-color: var(--paper-amber-500);
+ }
+ .green {
+ background-color: var(--paper-green-500);
+ }
+ .red {
+ background-color: var(--paper-pink-500);
+ }
+ </style>
+</head>
+<body unresolved>
+ <div class="vertical-section-container centered">
+ <h3>Tooltips can be anchored to elements using their ID</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <paper-icon-button id="id_1" icon="favorite" alt="heart"></paper-icon-button>
+ <paper-icon-button id="id_2" icon="alarm-on" alt="go back"></paper-icon-button>
+ <div id="id_3" class="avatar blue" tabindex="0"></div>
+ <div id="id_4" class="avatar orange" tabindex="0"></div>
+
+ <!-- paper-icon-buttons have an inherent padding that will push the tooltip down. offset undoes it -->
+ <paper-tooltip for="id_1" offset="0">&lt;3 &lt;3 &lt;3 </paper-tooltip>
+ <paper-tooltip for="id_2" offset="0">wake up!</paper-tooltip>
+ <paper-tooltip for="id_3" offset="0">halp I am trapped in a tooltip</paper-tooltip>
+ <paper-tooltip for="id_4" offset="0">meow!</paper-tooltip>
+ </template>
+ </demo-snippet>
+
+ <h3>Tooltips can be anchored to elements relative to their parent</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <!-- Adding a tabindex so that we can show the tooltip when the whole box is tabbed to -->
+ <div tabindex="0">
+ <input type="checkbox">allosaurus
+ <paper-tooltip>the name means "different lizard"</paper-tooltip>
+ </div>
+ <div tabindex="0">
+ <input type="checkbox">brontosaurus
+ <paper-tooltip>the name means "thunder lizard"</paper-tooltip>
+ </div>
+ <div tabindex="0">
+ <input type="checkbox">megalosaurus
+ <paper-tooltip>the name means "roof lizard"</paper-tooltip>
+ </div>
+ </div>
+ </template>
+ </demo-snippet>
+
+ <h3>Tooltips can open in different directions</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <div id="dir_1" class="avatar red" tabindex="0"></div>
+ <div id="dir_2" class="avatar blue" tabindex="0"></div>
+ <div id="dir_3" class="avatar green" tabindex="0"></div>
+ <div id="dir_4" class="avatar orange" tabindex="0"></div>
+
+ <paper-tooltip for="dir_1" position="left" animation-delay="0">👈</paper-tooltip>
+ <paper-tooltip for="dir_2" position="right" animation-delay="0">👉</paper-tooltip>
+ <paper-tooltip for="dir_3" position="top" animation-delay="0">👍</paper-tooltip>
+ <paper-tooltip for="dir_4" position="bottom" animation-delay="0">👎</paper-tooltip>
+ </template>
+ </demo-snippet>
+
+ <h3>Tooltips can contain rich text (though against the Material Design spec)</h3>
+ <demo-snippet class="centered-demo">
+ <template>
+ <style is="custom-style">
+ paper-tooltip.custom img {
+ width: 40px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+ float: left;
+ }
+ .custom {
+ --paper-tooltip-background: black;
+ --paper-tooltip-text-color: var(--paper-pink-100);
+ width: 160px;
+ }
+ </style>
+ <paper-icon-button id="demo4_icon1" icon="favorite" alt="heart"></paper-icon-button>
+ <paper-tooltip for="demo4_icon1" class="custom" animation-delay="0">
+ <img src="http://i.imgur.com/OuUe8Da.jpg">
+ Rich-text tooltips are doable but against the Material Design spec.
+ </paper-tooltip>
+ </template>
+ </demo-snippet>
+ </div>
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/test-button.html b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/test-button.html
new file mode 100644
index 00000000000..0942f58cb76
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/demo/test-button.html
@@ -0,0 +1,37 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../../paper-icon-button/paper-icon-button.html">
+<link rel="import" href="../../iron-icons/iron-icons.html">
+<link rel="import" href="../paper-tooltip.html">
+
+<dom-module id="test-button">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ }
+
+ paper-icon-button {
+ padding: 0;
+ }
+ </style>
+
+ <paper-icon-button id="m" icon="menu" alt="menu"></paper-icon-button>
+ <paper-tooltip for="m" offset="8">hot dogs</paper-tooltip>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'test-button'
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/index.html b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/index.html
new file mode 100644
index 00000000000..848f0426571
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <title>paper-tooltip</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+<iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html
new file mode 100644
index 00000000000..d3d5982e530
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html
@@ -0,0 +1,372 @@
+<!--
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
+<link rel="import" href="../neon-animation/animations/fade-in-animation.html">
+<link rel="import" href="../neon-animation/animations/fade-out-animation.html">
+
+<!--
+Material design: [Tooltips](https://www.google.com/design/spec/components/tooltips.html)
+
+`<paper-tooltip>` is a label that appears on hover and focus when the user
+hovers over an element with the cursor or with the keyboard. It will be centered
+to an anchor element specified in the `for` attribute, or, if that doesn't exist,
+centered to the parent node containing it.
+
+Example:
+
+ <div style="display:inline-block">
+ <button>Click me!</button>
+ <paper-tooltip>Tooltip text</paper-tooltip>
+ </div>
+
+ <div>
+ <button id="btn">Click me!</button>
+ <paper-tooltip for="btn">Tooltip text</paper-tooltip>
+ </div>
+
+The tooltip can be positioned on the top|bottom|left|right of the anchor using
+the `position` attribute. The default position is bottom.
+
+ <paper-tooltip for="btn" position="left">Tooltip text</paper-tooltip>
+ <paper-tooltip for="btn" position="top">Tooltip text</paper-tooltip>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-tooltip-background` | The background color of the tooltip | `#616161`
+`--paper-tooltip-opacity` | The opacity of the tooltip | `0.9`
+`--paper-tooltip-text-color` | The text color of the tooltip | `white`
+`--paper-tooltip` | Mixin applied to the tooltip | `{}`
+
+@group Paper Elements
+@element paper-tooltip
+@demo demo/index.html
+-->
+
+<dom-module id="paper-tooltip">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: absolute;
+ outline: none;
+ z-index: 1002;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: default;
+ }
+
+ #tooltip {
+ display: block;
+ outline: none;
+ @apply(--paper-font-common-base);
+ font-size: 10px;
+ line-height: 1;
+
+ background-color: var(--paper-tooltip-background, #616161);
+ opacity: var(--paper-tooltip-opacity, 0.9);
+ color: var(--paper-tooltip-text-color, white);
+
+ padding: 8px;
+ border-radius: 2px;
+
+ @apply(--paper-tooltip);
+ }
+
+ /* Thanks IE 10. */
+ .hidden {
+ display: none !important;
+ }
+ </style>
+
+ <div id="tooltip" class="hidden">
+ <content></content>
+ </div>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-tooltip',
+
+ hostAttributes: {
+ role: 'tooltip',
+ tabindex: -1
+ },
+
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+ /**
+ * The id of the element that the tooltip is anchored to. This element
+ * must be a sibling of the tooltip.
+ */
+ for: {
+ type: String,
+ observer: '_forChanged'
+ },
+
+ /**
+ * Set this to true if you want to manually control when the tooltip
+ * is shown or hidden.
+ */
+ manualMode: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Positions the tooltip to the top, right, bottom, left of its content.
+ */
+ position: {
+ type: String,
+ value: 'bottom'
+ },
+
+ /**
+ * If true, no parts of the tooltip will ever be shown offscreen.
+ */
+ fitToVisibleBounds: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The spacing between the top of the tooltip and the element it is
+ * anchored to.
+ */
+ offset: {
+ type: Number,
+ value: 14
+ },
+
+ /**
+ * This property is deprecated, but left over so that it doesn't
+ * break exiting code. Please use `offset` instead. If both `offset` and
+ * `marginTop` are provided, `marginTop` will be ignored.
+ * @deprecated since version 1.0.3
+ */
+ marginTop: {
+ type: Number,
+ value: 14
+ },
+
+ /**
+ * The delay that will be applied before the `entry` animation is
+ * played when showing the tooltip.
+ */
+ animationDelay: {
+ type: Number,
+ value: 500
+ },
+
+ /**
+ * The entry and exit animations that will be played when showing and
+ * hiding the tooltip. If you want to override this, you must ensure
+ * that your animationConfig has the exact format below.
+ */
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'fade-in-animation',
+ node: this,
+ timing: {delay: 0}
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this
+ }]
+ }
+ }
+ },
+
+ _showing: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onAnimationFinish',
+ 'mouseenter': 'hide'
+ },
+
+ /**
+ * Returns the target element that this tooltip is anchored to. It is
+ * either the element given by the `for` attribute, or the immediate parent
+ * of the tooltip.
+ */
+ get target () {
+ var parentNode = Polymer.dom(this).parentNode;
+ // If the parentNode is a document fragment, then we need to use the host.
+ var ownerRoot = Polymer.dom(this).getOwnerRoot();
+
+ var target;
+ if (this.for) {
+ target = Polymer.dom(ownerRoot).querySelector('#' + this.for);
+ } else {
+ target = parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ?
+ ownerRoot.host : parentNode;
+ }
+
+ return target;
+ },
+
+ attached: function() {
+ this._target = this.target;
+
+ if (this.manualMode)
+ return;
+
+ this.listen(this._target, 'mouseenter', 'show');
+ this.listen(this._target, 'focus', 'show');
+ this.listen(this._target, 'mouseleave', 'hide');
+ this.listen(this._target, 'blur', 'hide');
+ this.listen(this._target, 'tap', 'hide');
+ },
+
+ detached: function() {
+ if (this._target && !this.manualMode) {
+ this.unlisten(this._target, 'mouseenter', 'show');
+ this.unlisten(this._target, 'focus', 'show');
+ this.unlisten(this._target, 'mouseleave', 'hide');
+ this.unlisten(this._target, 'blur', 'hide');
+ this.unlisten(this._target, 'tap', 'hide');
+ }
+ },
+
+ show: function() {
+ // If the tooltip is already showing, there's nothing to do.
+ if (this._showing)
+ return;
+
+ if (Polymer.dom(this).textContent.trim() === '')
+ return;
+
+
+ this.cancelAnimation();
+ this._showing = true;
+ this.toggleClass('hidden', false, this.$.tooltip);
+ this.updatePosition();
+
+ this.animationConfig.entry[0].timing.delay = this.animationDelay;
+ this._animationPlaying = true;
+ this.playAnimation('entry');
+ },
+
+ hide: function() {
+ // If the tooltip is already hidden, there's nothing to do.
+ if (!this._showing) {
+ return;
+ }
+
+ // If the entry animation is still playing, don't try to play the exit
+ // animation since this will reset the opacity to 1. Just end the animation.
+ if (this._animationPlaying) {
+ this.cancelAnimation();
+ this._showing = false;
+ this._onAnimationFinish();
+ return;
+ }
+
+ this._showing = false;
+ this._animationPlaying = true;
+ this.playAnimation('exit');
+ },
+
+ _forChanged: function() {
+ this._target = this.target;
+ },
+
+ updatePosition: function() {
+ if (!this._target || !this.offsetParent)
+ return;
+
+ var offset = this.offset;
+ // If a marginTop has been provided by the user (pre 1.0.3), use it.
+ if (this.marginTop != 14 && this.offset == 14)
+ offset = this.marginTop;
+
+ var parentRect = this.offsetParent.getBoundingClientRect();
+ var targetRect = this._target.getBoundingClientRect();
+ var thisRect = this.getBoundingClientRect();
+
+ var horizontalCenterOffset = (targetRect.width - thisRect.width) / 2;
+ var verticalCenterOffset = (targetRect.height - thisRect.height) / 2;
+
+ var targetLeft = targetRect.left - parentRect.left;
+ var targetTop = targetRect.top - parentRect.top;
+
+ var tooltipLeft, tooltipTop;
+
+ switch (this.position) {
+ case 'top':
+ tooltipLeft = targetLeft + horizontalCenterOffset;
+ tooltipTop = targetTop - thisRect.height - offset;
+ break;
+ case 'bottom':
+ tooltipLeft = targetLeft + horizontalCenterOffset;
+ tooltipTop = targetTop + targetRect.height + offset;
+ break;
+ case 'left':
+ tooltipLeft = targetLeft - thisRect.width - offset;
+ tooltipTop = targetTop + verticalCenterOffset;
+ break;
+ case 'right':
+ tooltipLeft = targetLeft + targetRect.width + offset;
+ tooltipTop = targetTop + verticalCenterOffset;
+ break;
+ }
+
+ // TODO(noms): This should use IronFitBehavior if possible.
+ if (this.fitToVisibleBounds) {
+ // Clip the left/right side.
+ if (tooltipLeft + thisRect.width > window.innerWidth) {
+ this.style.right = '0px';
+ this.style.left = 'auto';
+ } else {
+ this.style.left = Math.max(0, tooltipLeft) + 'px';
+ this.style.right = 'auto';
+ }
+
+ // Clip the top/bottom side.
+ if (tooltipTop + thisRect.height > window.innerHeight) {
+ this.style.bottom = '0px';
+ this.style.top = 'auto';
+ } else {
+ this.style.top = Math.max(0, tooltipTop) + 'px';
+ this.style.bottom = 'auto';
+ }
+ } else {
+ this.style.left = tooltipLeft + 'px';
+ this.style.top = tooltipTop + 'px';
+ }
+
+ },
+
+ _onAnimationFinish: function() {
+ this._animationPlaying = false;
+ if (!this._showing) {
+ this.toggleClass('hidden', true, this.$.tooltip);
+ }
+ },
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/polymer/.bower.json
new file mode 100644
index 00000000000..36ef2ed8724
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/.bower.json
@@ -0,0 +1,44 @@
+{
+ "name": "polymer",
+ "version": "1.6.0",
+ "main": [
+ "polymer.html",
+ "polymer-mini.html",
+ "polymer-micro.html"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "ignore": [
+ "/.*",
+ "/test/",
+ "/util/",
+ "/explainer/",
+ "gulpfile.js",
+ "PRIMER.md",
+ "CONTRIBUTING.md",
+ "CHANGELOG.md"
+ ],
+ "authors": [
+ "The Polymer Authors (http://polymer.github.io/AUTHORS.txt)"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Polymer/polymer.git"
+ },
+ "dependencies": {
+ "webcomponentsjs": "^0.7.20"
+ },
+ "devDependencies": {
+ "web-component-tester": "*"
+ },
+ "private": true,
+ "homepage": "https://github.com/Polymer/polymer",
+ "_release": "1.6.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.6.0",
+ "commit": "8715c83bf04a228de00ec662ed43eb6141e61b91"
+ },
+ "_source": "git://github.com/Polymer/polymer.git",
+ "_target": "^1.0.0",
+ "_originalSource": "Polymer/polymer"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/LICENSE.txt b/chromium/third_party/catapult/third_party/polymer/components/polymer/LICENSE.txt
new file mode 100644
index 00000000000..95987bac868
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/LICENSE.txt
@@ -0,0 +1,27 @@
+// Copyright (c) 2014 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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
+// OWNER 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.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/bower.json b/chromium/third_party/catapult/third_party/polymer/components/polymer/bower.json
new file mode 100644
index 00000000000..52783a4398c
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/bower.json
@@ -0,0 +1,34 @@
+{
+ "name": "polymer",
+ "version": "1.6.0",
+ "main": [
+ "polymer.html",
+ "polymer-mini.html",
+ "polymer-micro.html"
+ ],
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "ignore": [
+ "/.*",
+ "/test/",
+ "/util/",
+ "/explainer/",
+ "gulpfile.js",
+ "PRIMER.md",
+ "CONTRIBUTING.md",
+ "CHANGELOG.md"
+ ],
+ "authors": [
+ "The Polymer Authors (http://polymer.github.io/AUTHORS.txt)"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Polymer/polymer.git"
+ },
+ "dependencies": {
+ "webcomponentsjs": "^0.7.20"
+ },
+ "devDependencies": {
+ "web-component-tester": "*"
+ },
+ "private": true
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/build.log b/chromium/third_party/catapult/third_party/polymer/components/polymer/build.log
new file mode 100644
index 00000000000..e4f8ba662e8
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/build.log
@@ -0,0 +1,473 @@
+BUILD LOG
+---------
+Build Time: 2016-06-29T11:29:07-0700
+
+NODEJS INFORMATION
+==================
+nodejs: v6.0.0
+acorn-jsx: 3.0.1
+ansi-escapes: 1.4.0
+caller-path: 0.1.0
+callsites: 0.2.0
+camelcase: 2.1.1
+camelcase-keys: 2.1.0
+cli-width: 2.1.0
+clone-stats: 0.0.1
+argparse: 1.0.7
+currently-unhandled: 0.4.1
+decamelize: 1.2.0
+del: 2.2.0
+dom5: 1.3.1
+doctrine: 1.2.2
+dom-serializer: 0.1.0
+duplexer: 0.1.1
+es6-map: 0.1.4
+escope: 3.6.0
+escape-regexp-component: 1.0.2
+esrecurse: 4.1.0
+estraverse: 4.2.0
+espree: 3.1.4
+fancy-log: 1.2.0
+fast-levenshtein: 1.1.3
+figures: 1.7.0
+find-up: 1.1.2
+globals: 9.8.0
+globby: 4.1.0
+gulp-eslint: 2.0.0
+gulp-rename: 1.2.2
+gulp-vulcanize: 6.0.1
+hosted-git-info: 2.1.5
+imurmurhash: 0.1.4
+ignore: 3.1.2
+inquirer: 0.12.0
+json-schema: 0.2.2
+lazypipe: 1.0.1
+levn: 0.3.0
+keep-alive-agent: 0.0.1
+lodash._root: 3.0.1
+lodash.isarguments: 3.0.8
+loud-rejection: 1.4.1
+match-stream: 0.0.2
+object-component: 0.0.3
+optionator: 0.8.1
+parse5: 1.5.1
+parsejson: 0.0.1
+parseqs: 0.0.2
+parseuri: 0.0.4
+polyclean: 1.2.0
+pluralize: 1.2.1
+require-uncached: 1.0.2
+resolve-from: 1.0.1
+slice-ansi: 0.0.4
+spdx-license-ids: 1.2.1
+stream-combiner: 0.2.2
+streamsearch: 0.1.2
+table: 3.7.8
+test-fixture: 1.1.0
+time-stamp: 1.0.1
+text-table: 0.2.0
+to-array: 0.1.4
+tv4: 1.2.7
+wordwrap: 1.0.0
+xregexp: 3.1.1
+acorn: 3.2.0
+eslint: 2.12.0
+esprima: 2.7.2
+jade: 0.26.3
+js-yaml: 3.6.1
+shelljs: 0.6.0
+ansi-styles: 2.1.0
+accepts: 1.2.13
+ansi-regex: 2.0.0
+accessibility-developer-tools: 2.10.0
+array-union: 1.0.1
+append-field: 0.1.0
+array-differ: 1.0.0
+arrify: 1.0.1
+array-find-index: 1.0.1
+after: 0.8.1
+array-uniq: 1.0.2
+asn1: 0.1.11
+archiver: 0.14.4
+array-flatten: 1.1.1
+arraybuffer.slice: 0.0.6
+adm-zip: 0.4.7
+assert-plus: 0.1.5
+assertion-error: 1.0.1
+async: 1.5.2
+backoff: 2.4.1
+balanced-match: 0.3.0
+backo2: 1.0.2
+aws4: 1.2.1
+base64-arraybuffer: 0.1.2
+better-assert: 1.0.2
+beeper: 1.1.0
+benchmark: 1.0.0
+base64id: 0.1.0
+base64-js: 0.0.8
+binary: 0.3.0
+bluebird: 2.10.2
+bl: 0.9.5
+brace-expansion: 1.1.2
+body-parser: 1.14.2
+blob: 0.0.4
+bufferstreams: 1.1.0
+boom: 0.4.2
+browserstack: 1.3.1
+buffers: 0.1.1
+buffer-crc32: 0.2.5
+builtin-modules: 1.1.1
+bytes: 2.2.0
+capture-stack-trace: 1.0.0
+callsite: 1.0.0
+busboy: 0.2.12
+chalk: 1.1.1
+chainsaw: 0.1.0
+caseless: 0.8.0
+clone: 1.0.2
+combined-stream: 0.0.7
+cleankill: 1.0.2
+chai: 3.5.0
+cli-cursor: 1.0.2
+commander: 2.3.0
+component-bind: 1.0.0
+code-point-at: 1.0.0
+aws-sign2: 0.5.0
+component-inherit: 0.0.3
+concat-map: 0.0.1
+compress-commons: 0.2.9
+component-emitter: 1.1.2
+configstore: 1.4.0
+content-type: 1.0.1
+content-disposition: 0.5.1
+concat-stream: 1.5.1
+crc32-stream: 0.3.4
+core-util-is: 1.0.2
+cookie-signature: 1.0.6
+cookie: 0.1.5
+crc: 3.2.1
+create-error-class: 2.0.1
+cryptiles: 0.2.2
+csv-generate: 0.0.6
+csv-parse: 1.0.1
+ctype: 0.5.3
+csv-stringify: 0.0.8
+csv: 0.4.6
+d: 0.1.1
+debug: 2.2.0
+deep-eql: 0.1.3
+delayed-stream: 0.0.5
+dashdash: 1.12.2
+deep-extend: 0.4.1
+depd: 1.1.0
+diff: 1.4.0
+deep-is: 0.1.3
+destroy: 1.0.4
+dicer: 0.2.5
+domutils: 1.5.1
+domhandler: 2.3.0
+duplexer2: 0.0.2
+domelementtype: 1.3.0
+ecc-jsbn: 0.1.1
+end-of-stream: 1.1.0
+dtrace-provider: 0.6.0
+ee-first: 1.1.1
+engine.io-parser: 1.2.4
+entities: 1.1.1
+engine.io-client: 1.6.8
+engine.io: 1.6.8
+es6-set: 0.1.4
+es6-iterator: 2.0.0
+es5-ext: 0.10.11
+error-ex: 1.3.0
+es6-weak-map: 2.0.1
+es6-symbol: 3.0.2
+escape-string-regexp: 1.0.4
+escape-html: 1.0.3
+esutils: 2.0.2
+eslint-plugin-html: 1.3.0
+event-emitter: 0.3.4
+exit-hook: 1.1.1
+file-entry-cache: 1.2.4
+etag: 1.7.0
+extsprintf: 1.2.0
+extend: 3.0.0
+express: 4.13.4
+forever-agent: 0.5.2
+findup-sync: 0.2.1
+finalhandler: 0.4.1
+freeport: 1.0.5
+formatio: 1.1.1
+flat-cache: 1.0.10
+form-data: 0.2.0
+generate-function: 2.0.0
+formidable: 1.0.17
+generate-object-property: 1.2.0
+forwarded: 0.1.0
+fresh: 0.3.0
+get-stdin: 4.0.1
+glob: 5.0.15
+fstream: 0.1.31
+graceful-fs: 4.1.3
+got: 5.4.1
+glogg: 1.0.0
+gulp-audit: 1.0.0
+gulp-replace: 0.5.4
+graceful-readlink: 1.0.1
+gulp-util: 3.0.7
+growl: 1.8.1
+has-ansi: 2.0.0
+gulplog: 1.0.0
+has-color: 0.1.7
+has-gulplog: 0.1.0
+has-binary: 0.1.7
+hawk: 1.1.1
+has-cors: 1.1.0
+hoek: 0.9.1
+http-signature: 0.11.0
+http-errors: 1.3.1
+inflight: 1.0.4
+htmlparser2: 3.9.0
+inherits: 2.0.1
+is-absolute: 0.1.7
+indent-string: 2.1.0
+iconv-lite: 0.4.13
+is-finite: 1.0.1
+is-path-cwd: 1.0.0
+is-my-json-valid: 2.12.4
+is-builtin-module: 1.0.0
+is-path-in-cwd: 1.0.0
+is-arrayish: 0.2.1
+is-npm: 1.0.0
+is-fullwidth-code-point: 1.0.0
+is-redirect: 1.0.0
+is-path-inside: 1.0.0
+is-plain-obj: 1.1.0
+is-property: 1.0.2
+is-resolvable: 1.0.0
+isarray: 0.0.1
+is-typedarray: 1.0.0
+is-retry-allowed: 1.0.0
+is-utf8: 0.2.1
+isexe: 1.1.1
+isstream: 0.1.2
+is-stream: 1.0.1
+jodid25519: 1.0.2
+json-stable-stringify: 1.0.1
+ipaddr.js: 1.0.5
+jsbn: 0.1.0
+json-stringify-safe: 5.0.1
+jsonify: 0.0.0
+jsonpointer: 2.0.0
+jsprim: 1.2.2
+lazystream: 0.1.0
+latest-version: 2.0.0
+launchpad: 0.5.1
+lodash._basecopy: 3.0.1
+lodash._basevalues: 3.0.0
+lodash._basetostring: 3.0.1
+lodash._getnative: 3.9.1
+lodash: 3.10.1
+lodash._isiterateecall: 3.0.9
+lodash._reinterpolate: 3.0.0
+lodash._reevaluate: 3.0.0
+lodash._reescape: 3.0.0
+lodash.escape: 3.2.0
+json3: 3.2.6
+lodash.restparam: 3.6.1
+lodash.isarray: 3.0.4
+load-json-file: 1.1.0
+lodash.templatesettings: 3.1.1
+lru-cache: 2.7.3
+lodash.keys: 3.1.2
+lowercase-keys: 1.0.0
+map-obj: 1.0.1
+meow: 3.7.0
+lolex: 1.3.2
+mime-db: 1.21.0
+minimatch: 3.0.0
+media-typer: 0.3.0
+merge-descriptors: 1.0.1
+methods: 1.1.2
+minimist: 0.0.8
+ms: 0.7.1
+mime-types: 2.1.9
+multipipe: 0.1.2
+nan: 2.2.0
+mv: 2.1.1
+multer: 1.1.0
+node-int64: 0.3.3
+mute-stream: 0.0.5
+negotiator: 0.5.3
+object-assign: 4.0.1
+normalize-package-data: 2.3.5
+node-status-codes: 1.0.0
+lodash.template: 3.6.2
+number-is-nan: 1.0.0
+nomnom: 1.8.1
+onetime: 1.1.0
+on-finished: 2.3.0
+once: 1.3.3
+oauth-sign: 0.5.0
+os-homedir: 1.0.1
+options: 0.0.6
+os-tmpdir: 1.0.1
+osenv: 0.1.3
+parse-json: 2.2.0
+over: 0.0.5
+package-json: 2.3.0
+path-is-inside: 1.0.1
+path-is-absolute: 1.0.0
+path-exists: 2.1.0
+pify: 2.3.0
+parseurl: 1.3.1
+pinkie-promise: 2.0.0
+pinkie: 2.0.4
+path-to-regexp: 0.1.7
+path-type: 1.1.0
+prelude-ls: 1.1.2
+process-nextick-args: 1.0.6
+prepend-http: 1.0.3
+plist: 1.2.0
+precond: 0.2.3
+progress: 1.1.8
+proxy-addr: 1.0.10
+qs: 5.2.0
+pullstream: 0.4.1
+q: 1.4.1
+range-parser: 1.0.3
+read-all-stream: 3.1.0
+raw-body: 2.1.5
+readable-stream: 2.0.5
+redent: 1.0.0
+read-pkg-up: 1.0.1
+read-json-sync: 1.1.1
+read-pkg: 1.1.0
+registry-url: 3.0.3
+readline2: 1.0.1
+replace-ext: 0.0.1
+repeating: 2.0.0
+is-relative: 0.1.3
+resolve: 1.1.7
+request: 2.51.0
+run-sequence: 1.1.2
+run-async: 0.1.0
+rx-lite: 3.1.2
+safe-json-stringify: 1.0.3
+sauce-connect-launcher: 0.14.0
+samsam: 1.1.2
+restore-cursor: 1.0.1
+send: 0.11.1
+semver-diff: 2.1.0
+server-destroy: 1.0.1
+serve-waterfall: 1.1.1
+serve-static: 1.10.2
+setimmediate: 1.0.4
+sinon: 1.17.3
+signal-exit: 2.1.2
+sigmund: 1.0.1
+slide: 1.1.6
+sntp: 0.2.4
+sinon-chai: 2.8.0
+slice-stream: 1.0.0
+spdx-correct: 1.0.2
+sparkles: 1.0.0
+socket.io: 1.4.5
+socket.io-client: 1.4.5
+socket.io-parser: 2.2.6
+socket.io-adapter: 0.4.0
+spdx-expression-parse: 1.0.2
+spdx-exceptions: 1.0.4
+spdy: 1.32.5
+statuses: 1.2.1
+sprintf-js: 1.0.3
+stacky: 1.3.1
+string-length: 1.0.1
+stream-transform: 0.1.1
+string_decoder: 0.10.31
+stringstream: 0.0.5
+supports-color: 2.0.0
+string-width: 1.0.1
+strip-ansi: 3.0.0
+strip-bom: 2.0.0
+tar-stream: 1.1.5
+through: 2.3.8
+timed-out: 2.0.0
+tryit: 1.0.2
+through2: 2.0.1
+trim-newlines: 1.0.0
+traverse: 0.3.9
+tunnel-agent: 0.4.2
+type-check: 0.3.2
+tough-cookie: 2.2.1
+typedarray: 0.0.6
+tweetnacl: 0.13.3
+temp: 0.8.3
+type-detect: 1.0.0
+type-is: 1.6.11
+unzip: 0.1.11
+unpipe: 1.0.0
+url-parse-lax: 1.0.0
+underscore: 1.6.0
+user-home: 2.0.0
+update-notifier: 0.6.0
+unzip-response: 1.0.0
+underscore.string: 3.0.3
+util-deprecate: 1.0.2
+uuid: 2.0.1
+utf8: 2.1.0
+urijs: 1.16.1
+ultron: 1.0.2
+vargs: 0.1.0
+utils-merge: 1.0.0
+util: 0.10.3
+vasync: 1.6.3
+wct-local: 2.0.1
+vary: 1.0.1
+validate-npm-package-license: 3.0.1
+verror: 1.6.1
+vinyl: 0.5.3
+wct-sauce: 1.8.3
+write-file-atomic: 1.1.4
+wrappy: 1.0.1
+ws: 1.0.1
+indexof: 0.0.1
+write: 0.2.1
+xdg-basedir: 2.0.0
+xmlhttprequest-ssl: 1.5.1
+bunyan: 1.5.1
+xmldom: 0.1.22
+ini: 1.3.4
+dateformat: 1.0.12
+xmlbuilder: 4.0.0
+gulp: 3.9.0
+har-validator: 2.0.6
+xtend: 4.0.1
+mime: 1.3.4
+mkdirp: 0.5.1
+mocha: 2.4.5
+ncp: 2.0.0
+rc: 1.1.6
+rimraf: 2.5.1
+restify: 4.0.3
+selenium-standalone: 4.9.0
+semver: 5.1.0
+node-uuid: 1.4.7
+sshpk: 1.7.3
+yeast: 0.1.2
+strip-json-comments: 1.0.4
+strip-indent: 1.0.1
+zip-stream: 0.5.2
+web-component-tester: 4.2.0
+wd: 0.3.12
+which: 1.2.4
+
+REPO REVISIONS
+==============
+polymer: 9b44ac25b66e88a57172b33a4621cbdb5454c635
+
+BUILD HASHES
+============
+polymer-mini.html: 8f052eaa5290a7fb6fbffc109a3020e06ac42401
+polymer-micro.html: e7d1b0ee189eeb5276a5cdc37a1608aefef2fd25
+polymer.html: 8bec5d873aa2570fb7a332ee8f0356f8c81ff9cf \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-micro.html b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-micro.html
new file mode 100644
index 00000000000..2445d3fb904
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-micro.html
@@ -0,0 +1,715 @@
+<!--
+@license
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+--><script>(function () {
+function resolve() {
+document.body.removeAttribute('unresolved');
+}
+if (window.WebComponents) {
+addEventListener('WebComponentsReady', resolve);
+} else {
+if (document.readyState === 'interactive' || document.readyState === 'complete') {
+resolve();
+} else {
+addEventListener('DOMContentLoaded', resolve);
+}
+}
+}());window.Polymer = {
+Settings: function () {
+var settings = window.Polymer || {};
+var parts = location.search.slice(1).split('&');
+for (var i = 0, o; i < parts.length && (o = parts[i]); i++) {
+o = o.split('=');
+o[0] && (settings[o[0]] = o[1] || true);
+}
+settings.wantShadow = settings.dom === 'shadow';
+settings.hasShadow = Boolean(Element.prototype.createShadowRoot);
+settings.nativeShadow = settings.hasShadow && !window.ShadowDOMPolyfill;
+settings.useShadow = settings.wantShadow && settings.hasShadow;
+settings.hasNativeImports = Boolean('import' in document.createElement('link'));
+settings.useNativeImports = settings.hasNativeImports;
+settings.useNativeCustomElements = !window.CustomElements || window.CustomElements.useNative;
+settings.useNativeShadow = settings.useShadow && settings.nativeShadow;
+settings.usePolyfillProto = !settings.useNativeCustomElements && !Object.__proto__;
+settings.hasNativeCSSProperties = !navigator.userAgent.match('AppleWebKit/601') && window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)');
+settings.useNativeCSSProperties = settings.hasNativeCSSProperties && settings.lazyRegister && settings.useNativeCSSProperties;
+return settings;
+}()
+};(function () {
+var userPolymer = window.Polymer;
+window.Polymer = function (prototype) {
+if (typeof prototype === 'function') {
+prototype = prototype.prototype;
+}
+if (!prototype) {
+prototype = {};
+}
+var factory = desugar(prototype);
+prototype = factory.prototype;
+var options = { prototype: prototype };
+if (prototype.extends) {
+options.extends = prototype.extends;
+}
+Polymer.telemetry._registrate(prototype);
+document.registerElement(prototype.is, options);
+return factory;
+};
+var desugar = function (prototype) {
+var base = Polymer.Base;
+if (prototype.extends) {
+base = Polymer.Base._getExtendedPrototype(prototype.extends);
+}
+prototype = Polymer.Base.chainObject(prototype, base);
+prototype.registerCallback();
+return prototype.constructor;
+};
+if (userPolymer) {
+for (var i in userPolymer) {
+Polymer[i] = userPolymer[i];
+}
+}
+Polymer.Class = desugar;
+}());
+Polymer.telemetry = {
+registrations: [],
+_regLog: function (prototype) {
+console.log('[' + prototype.is + ']: registered');
+},
+_registrate: function (prototype) {
+this.registrations.push(prototype);
+Polymer.log && this._regLog(prototype);
+},
+dumpRegistrations: function () {
+this.registrations.forEach(this._regLog);
+}
+};Object.defineProperty(window, 'currentImport', {
+enumerable: true,
+configurable: true,
+get: function () {
+return (document._currentScript || document.currentScript).ownerDocument;
+}
+});Polymer.RenderStatus = {
+_ready: false,
+_callbacks: [],
+whenReady: function (cb) {
+if (this._ready) {
+cb();
+} else {
+this._callbacks.push(cb);
+}
+},
+_makeReady: function () {
+this._ready = true;
+for (var i = 0; i < this._callbacks.length; i++) {
+this._callbacks[i]();
+}
+this._callbacks = [];
+},
+_catchFirstRender: function () {
+requestAnimationFrame(function () {
+Polymer.RenderStatus._makeReady();
+});
+},
+_afterNextRenderQueue: [],
+_waitingNextRender: false,
+afterNextRender: function (element, fn, args) {
+this._watchNextRender();
+this._afterNextRenderQueue.push([
+element,
+fn,
+args
+]);
+},
+hasRendered: function () {
+return this._ready;
+},
+_watchNextRender: function () {
+if (!this._waitingNextRender) {
+this._waitingNextRender = true;
+var fn = function () {
+Polymer.RenderStatus._flushNextRender();
+};
+if (!this._ready) {
+this.whenReady(fn);
+} else {
+requestAnimationFrame(fn);
+}
+}
+},
+_flushNextRender: function () {
+var self = this;
+setTimeout(function () {
+self._flushRenderCallbacks(self._afterNextRenderQueue);
+self._afterNextRenderQueue = [];
+self._waitingNextRender = false;
+});
+},
+_flushRenderCallbacks: function (callbacks) {
+for (var i = 0, h; i < callbacks.length; i++) {
+h = callbacks[i];
+h[1].apply(h[0], h[2] || Polymer.nar);
+}
+}
+};
+if (window.HTMLImports) {
+HTMLImports.whenReady(function () {
+Polymer.RenderStatus._catchFirstRender();
+});
+} else {
+Polymer.RenderStatus._catchFirstRender();
+}
+Polymer.ImportStatus = Polymer.RenderStatus;
+Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;(function () {
+'use strict';
+var settings = Polymer.Settings;
+Polymer.Base = {
+__isPolymerInstance__: true,
+_addFeature: function (feature) {
+this.extend(this, feature);
+},
+registerCallback: function () {
+this._desugarBehaviors();
+this._doBehavior('beforeRegister');
+this._registerFeatures();
+if (!settings.lazyRegister) {
+this.ensureRegisterFinished();
+}
+},
+createdCallback: function () {
+if (!this.__hasRegisterFinished) {
+this._ensureRegisterFinished(this.__proto__);
+}
+Polymer.telemetry.instanceCount++;
+this.root = this;
+this._doBehavior('created');
+this._initFeatures();
+},
+ensureRegisterFinished: function () {
+this._ensureRegisterFinished(this);
+},
+_ensureRegisterFinished: function (proto) {
+if (proto.__hasRegisterFinished !== proto.is) {
+proto.__hasRegisterFinished = proto.is;
+if (proto._finishRegisterFeatures) {
+proto._finishRegisterFeatures();
+}
+proto._doBehavior('registered');
+if (settings.usePolyfillProto && proto !== this) {
+proto.extend(this, proto);
+}
+}
+},
+attachedCallback: function () {
+var self = this;
+Polymer.RenderStatus.whenReady(function () {
+self.isAttached = true;
+self._doBehavior('attached');
+});
+},
+detachedCallback: function () {
+var self = this;
+Polymer.RenderStatus.whenReady(function () {
+self.isAttached = false;
+self._doBehavior('detached');
+});
+},
+attributeChangedCallback: function (name, oldValue, newValue) {
+this._attributeChangedImpl(name);
+this._doBehavior('attributeChanged', [
+name,
+oldValue,
+newValue
+]);
+},
+_attributeChangedImpl: function (name) {
+this._setAttributeToProperty(this, name);
+},
+extend: function (prototype, api) {
+if (prototype && api) {
+var n$ = Object.getOwnPropertyNames(api);
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
+this.copyOwnProperty(n, api, prototype);
+}
+}
+return prototype || api;
+},
+mixin: function (target, source) {
+for (var i in source) {
+target[i] = source[i];
+}
+return target;
+},
+copyOwnProperty: function (name, source, target) {
+var pd = Object.getOwnPropertyDescriptor(source, name);
+if (pd) {
+Object.defineProperty(target, name, pd);
+}
+},
+_logger: function (level, args) {
+if (args.length === 1 && Array.isArray(args[0])) {
+args = args[0];
+}
+switch (level) {
+case 'log':
+case 'warn':
+case 'error':
+console[level].apply(console, args);
+break;
+}
+},
+_log: function () {
+var args = Array.prototype.slice.call(arguments, 0);
+this._logger('log', args);
+},
+_warn: function () {
+var args = Array.prototype.slice.call(arguments, 0);
+this._logger('warn', args);
+},
+_error: function () {
+var args = Array.prototype.slice.call(arguments, 0);
+this._logger('error', args);
+},
+_logf: function () {
+return this._logPrefix.concat(this.is).concat(Array.prototype.slice.call(arguments, 0));
+}
+};
+Polymer.Base._logPrefix = function () {
+var color = window.chrome && !/edge/i.test(navigator.userAgent) || /firefox/i.test(navigator.userAgent);
+return color ? [
+'%c[%s::%s]:',
+'font-weight: bold; background-color:#EEEE00;'
+] : ['[%s::%s]:'];
+}();
+Polymer.Base.chainObject = function (object, inherited) {
+if (object && inherited && object !== inherited) {
+if (!Object.__proto__) {
+object = Polymer.Base.extend(Object.create(inherited), object);
+}
+object.__proto__ = inherited;
+}
+return object;
+};
+Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
+if (window.CustomElements) {
+Polymer.instanceof = CustomElements.instanceof;
+} else {
+Polymer.instanceof = function (obj, ctor) {
+return obj instanceof ctor;
+};
+}
+Polymer.isInstance = function (obj) {
+return Boolean(obj && obj.__isPolymerInstance__);
+};
+Polymer.telemetry.instanceCount = 0;
+}());(function () {
+var modules = {};
+var lcModules = {};
+var findModule = function (id) {
+return modules[id] || lcModules[id.toLowerCase()];
+};
+var DomModule = function () {
+return document.createElement('dom-module');
+};
+DomModule.prototype = Object.create(HTMLElement.prototype);
+Polymer.Base.extend(DomModule.prototype, {
+constructor: DomModule,
+createdCallback: function () {
+this.register();
+},
+register: function (id) {
+id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
+if (id) {
+this.id = id;
+modules[id] = this;
+lcModules[id.toLowerCase()] = this;
+}
+},
+import: function (id, selector) {
+if (id) {
+var m = findModule(id);
+if (!m) {
+forceDomModulesUpgrade();
+m = findModule(id);
+}
+if (m && selector) {
+m = m.querySelector(selector);
+}
+return m;
+}
+}
+});
+var cePolyfill = window.CustomElements && !CustomElements.useNative;
+document.registerElement('dom-module', DomModule);
+function forceDomModulesUpgrade() {
+if (cePolyfill) {
+var script = document._currentScript || document.currentScript;
+var doc = script && script.ownerDocument || document;
+var modules = doc.querySelectorAll('dom-module');
+for (var i = modules.length - 1, m; i >= 0 && (m = modules[i]); i--) {
+if (m.__upgraded__) {
+return;
+} else {
+CustomElements.upgrade(m);
+}
+}
+}
+}
+}());Polymer.Base._addFeature({
+_prepIs: function () {
+if (!this.is) {
+var module = (document._currentScript || document.currentScript).parentNode;
+if (module.localName === 'dom-module') {
+var id = module.id || module.getAttribute('name') || module.getAttribute('is');
+this.is = id;
+}
+}
+if (this.is) {
+this.is = this.is.toLowerCase();
+}
+}
+});Polymer.Base._addFeature({
+behaviors: [],
+_desugarBehaviors: function () {
+if (this.behaviors.length) {
+this.behaviors = this._desugarSomeBehaviors(this.behaviors);
+}
+},
+_desugarSomeBehaviors: function (behaviors) {
+var behaviorSet = [];
+behaviors = this._flattenBehaviorsList(behaviors);
+for (var i = behaviors.length - 1; i >= 0; i--) {
+var b = behaviors[i];
+if (behaviorSet.indexOf(b) === -1) {
+this._mixinBehavior(b);
+behaviorSet.unshift(b);
+}
+}
+return behaviorSet;
+},
+_flattenBehaviorsList: function (behaviors) {
+var flat = [];
+for (var i = 0; i < behaviors.length; i++) {
+var b = behaviors[i];
+if (b instanceof Array) {
+flat = flat.concat(this._flattenBehaviorsList(b));
+} else if (b) {
+flat.push(b);
+} else {
+this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
+}
+}
+return flat;
+},
+_mixinBehavior: function (b) {
+var n$ = Object.getOwnPropertyNames(b);
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
+if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
+this.copyOwnProperty(n, b, this);
+}
+}
+},
+_prepBehaviors: function () {
+this._prepFlattenedBehaviors(this.behaviors);
+},
+_prepFlattenedBehaviors: function (behaviors) {
+for (var i = 0, l = behaviors.length; i < l; i++) {
+this._prepBehavior(behaviors[i]);
+}
+this._prepBehavior(this);
+},
+_doBehavior: function (name, args) {
+for (var i = 0; i < this.behaviors.length; i++) {
+this._invokeBehavior(this.behaviors[i], name, args);
+}
+this._invokeBehavior(this, name, args);
+},
+_invokeBehavior: function (b, name, args) {
+var fn = b[name];
+if (fn) {
+fn.apply(this, args || Polymer.nar);
+}
+},
+_marshalBehaviors: function () {
+for (var i = 0; i < this.behaviors.length; i++) {
+this._marshalBehavior(this.behaviors[i]);
+}
+this._marshalBehavior(this);
+}
+});
+Polymer.Base._behaviorProperties = {
+hostAttributes: true,
+beforeRegister: true,
+registered: true,
+properties: true,
+observers: true,
+listeners: true,
+created: true,
+attached: true,
+detached: true,
+attributeChanged: true,
+ready: true
+};Polymer.Base._addFeature({
+_getExtendedPrototype: function (tag) {
+return this._getExtendedNativePrototype(tag);
+},
+_nativePrototypes: {},
+_getExtendedNativePrototype: function (tag) {
+var p = this._nativePrototypes[tag];
+if (!p) {
+var np = this.getNativePrototype(tag);
+p = this.extend(Object.create(np), Polymer.Base);
+this._nativePrototypes[tag] = p;
+}
+return p;
+},
+getNativePrototype: function (tag) {
+return Object.getPrototypeOf(document.createElement(tag));
+}
+});Polymer.Base._addFeature({
+_prepConstructor: function () {
+this._factoryArgs = this.extends ? [
+this.extends,
+this.is
+] : [this.is];
+var ctor = function () {
+return this._factory(arguments);
+};
+if (this.hasOwnProperty('extends')) {
+ctor.extends = this.extends;
+}
+Object.defineProperty(this, 'constructor', {
+value: ctor,
+writable: true,
+configurable: true
+});
+ctor.prototype = this;
+},
+_factory: function (args) {
+var elt = document.createElement.apply(document, this._factoryArgs);
+if (this.factoryImpl) {
+this.factoryImpl.apply(elt, args);
+}
+return elt;
+}
+});Polymer.nob = Object.create(null);
+Polymer.Base._addFeature({
+properties: {},
+getPropertyInfo: function (property) {
+var info = this._getPropertyInfo(property, this.properties);
+if (!info) {
+for (var i = 0; i < this.behaviors.length; i++) {
+info = this._getPropertyInfo(property, this.behaviors[i].properties);
+if (info) {
+return info;
+}
+}
+}
+return info || Polymer.nob;
+},
+_getPropertyInfo: function (property, properties) {
+var p = properties && properties[property];
+if (typeof p === 'function') {
+p = properties[property] = { type: p };
+}
+if (p) {
+p.defined = true;
+}
+return p;
+},
+_prepPropertyInfo: function () {
+this._propertyInfo = {};
+for (var i = 0; i < this.behaviors.length; i++) {
+this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
+}
+this._addPropertyInfo(this._propertyInfo, this.properties);
+this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
+},
+_addPropertyInfo: function (target, source) {
+if (source) {
+var t, s;
+for (var i in source) {
+t = target[i];
+s = source[i];
+if (i[0] === '_' && !s.readOnly) {
+continue;
+}
+if (!target[i]) {
+target[i] = {
+type: typeof s === 'function' ? s : s.type,
+readOnly: s.readOnly,
+attribute: Polymer.CaseMap.camelToDashCase(i)
+};
+} else {
+if (!t.type) {
+t.type = s.type;
+}
+if (!t.readOnly) {
+t.readOnly = s.readOnly;
+}
+}
+}
+}
+}
+});Polymer.CaseMap = {
+_caseMap: {},
+_rx: {
+dashToCamel: /-[a-z]/g,
+camelToDash: /([A-Z])/g
+},
+dashToCamelCase: function (dash) {
+return this._caseMap[dash] || (this._caseMap[dash] = dash.indexOf('-') < 0 ? dash : dash.replace(this._rx.dashToCamel, function (m) {
+return m[1].toUpperCase();
+}));
+},
+camelToDashCase: function (camel) {
+return this._caseMap[camel] || (this._caseMap[camel] = camel.replace(this._rx.camelToDash, '-$1').toLowerCase());
+}
+};Polymer.Base._addFeature({
+_addHostAttributes: function (attributes) {
+if (!this._aggregatedAttributes) {
+this._aggregatedAttributes = {};
+}
+if (attributes) {
+this.mixin(this._aggregatedAttributes, attributes);
+}
+},
+_marshalHostAttributes: function () {
+if (this._aggregatedAttributes) {
+this._applyAttributes(this, this._aggregatedAttributes);
+}
+},
+_applyAttributes: function (node, attr$) {
+for (var n in attr$) {
+if (!this.hasAttribute(n) && n !== 'class') {
+var v = attr$[n];
+this.serializeValueToAttribute(v, n, this);
+}
+}
+},
+_marshalAttributes: function () {
+this._takeAttributesToModel(this);
+},
+_takeAttributesToModel: function (model) {
+if (this.hasAttributes()) {
+for (var i in this._propertyInfo) {
+var info = this._propertyInfo[i];
+if (this.hasAttribute(info.attribute)) {
+this._setAttributeToProperty(model, info.attribute, i, info);
+}
+}
+}
+},
+_setAttributeToProperty: function (model, attribute, property, info) {
+if (!this._serializing) {
+property = property || Polymer.CaseMap.dashToCamelCase(attribute);
+info = info || this._propertyInfo && this._propertyInfo[property];
+if (info && !info.readOnly) {
+var v = this.getAttribute(attribute);
+model[property] = this.deserialize(v, info.type);
+}
+}
+},
+_serializing: false,
+reflectPropertyToAttribute: function (property, attribute, value) {
+this._serializing = true;
+value = value === undefined ? this[property] : value;
+this.serializeValueToAttribute(value, attribute || Polymer.CaseMap.camelToDashCase(property));
+this._serializing = false;
+},
+serializeValueToAttribute: function (value, attribute, node) {
+var str = this.serialize(value);
+node = node || this;
+if (str === undefined) {
+node.removeAttribute(attribute);
+} else {
+node.setAttribute(attribute, str);
+}
+},
+deserialize: function (value, type) {
+switch (type) {
+case Number:
+value = Number(value);
+break;
+case Boolean:
+value = value != null;
+break;
+case Object:
+try {
+value = JSON.parse(value);
+} catch (x) {
+}
+break;
+case Array:
+try {
+value = JSON.parse(value);
+} catch (x) {
+value = null;
+console.warn('Polymer::Attributes: couldn`t decode Array as JSON');
+}
+break;
+case Date:
+value = new Date(value);
+break;
+case String:
+default:
+break;
+}
+return value;
+},
+serialize: function (value) {
+switch (typeof value) {
+case 'boolean':
+return value ? '' : undefined;
+case 'object':
+if (value instanceof Date) {
+return value.toString();
+} else if (value) {
+try {
+return JSON.stringify(value);
+} catch (x) {
+return '';
+}
+}
+default:
+return value != null ? value : undefined;
+}
+}
+});Polymer.version = '1.6.0';Polymer.Base._addFeature({
+_registerFeatures: function () {
+this._prepIs();
+this._prepBehaviors();
+this._prepConstructor();
+this._prepPropertyInfo();
+},
+_prepBehavior: function (b) {
+this._addHostAttributes(b.hostAttributes);
+},
+_marshalBehavior: function (b) {
+},
+_initFeatures: function () {
+this._marshalHostAttributes();
+this._marshalBehaviors();
+}
+});</script>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-mini.html b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-mini.html
new file mode 100644
index 00000000000..f6dd537e812
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer-mini.html
@@ -0,0 +1,2164 @@
+<!--
+@license
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+--><link rel="import" href="polymer-micro.html">
+
+<script>Polymer.Base._addFeature({
+_prepTemplate: function () {
+if (this._template === undefined) {
+this._template = Polymer.DomModule.import(this.is, 'template');
+}
+if (this._template && this._template.hasAttribute('is')) {
+this._warn(this._logf('_prepTemplate', 'top-level Polymer template ' + 'must not be a type-extension, found', this._template, 'Move inside simple <template>.'));
+}
+if (this._template && !this._template.content && window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
+HTMLTemplateElement.decorate(this._template);
+}
+},
+_stampTemplate: function () {
+if (this._template) {
+this.root = this.instanceTemplate(this._template);
+}
+},
+instanceTemplate: function (template) {
+var dom = document.importNode(template._content || template.content, true);
+return dom;
+}
+});(function () {
+var baseAttachedCallback = Polymer.Base.attachedCallback;
+Polymer.Base._addFeature({
+_hostStack: [],
+ready: function () {
+},
+_registerHost: function (host) {
+this.dataHost = host = host || Polymer.Base._hostStack[Polymer.Base._hostStack.length - 1];
+if (host && host._clients) {
+host._clients.push(this);
+}
+this._clients = null;
+this._clientsReadied = false;
+},
+_beginHosting: function () {
+Polymer.Base._hostStack.push(this);
+if (!this._clients) {
+this._clients = [];
+}
+},
+_endHosting: function () {
+Polymer.Base._hostStack.pop();
+},
+_tryReady: function () {
+this._readied = false;
+if (this._canReady()) {
+this._ready();
+}
+},
+_canReady: function () {
+return !this.dataHost || this.dataHost._clientsReadied;
+},
+_ready: function () {
+this._beforeClientsReady();
+if (this._template) {
+this._setupRoot();
+this._readyClients();
+}
+this._clientsReadied = true;
+this._clients = null;
+this._afterClientsReady();
+this._readySelf();
+},
+_readyClients: function () {
+this._beginDistribute();
+var c$ = this._clients;
+if (c$) {
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+c._ready();
+}
+}
+this._finishDistribute();
+},
+_readySelf: function () {
+this._doBehavior('ready');
+this._readied = true;
+if (this._attachedPending) {
+this._attachedPending = false;
+this.attachedCallback();
+}
+},
+_beforeClientsReady: function () {
+},
+_afterClientsReady: function () {
+},
+_beforeAttached: function () {
+},
+attachedCallback: function () {
+if (this._readied) {
+this._beforeAttached();
+baseAttachedCallback.call(this);
+} else {
+this._attachedPending = true;
+}
+}
+});
+}());Polymer.ArraySplice = function () {
+function newSplice(index, removed, addedCount) {
+return {
+index: index,
+removed: removed,
+addedCount: addedCount
+};
+}
+var EDIT_LEAVE = 0;
+var EDIT_UPDATE = 1;
+var EDIT_ADD = 2;
+var EDIT_DELETE = 3;
+function ArraySplice() {
+}
+ArraySplice.prototype = {
+calcEditDistances: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
+var rowCount = oldEnd - oldStart + 1;
+var columnCount = currentEnd - currentStart + 1;
+var distances = new Array(rowCount);
+for (var i = 0; i < rowCount; i++) {
+distances[i] = new Array(columnCount);
+distances[i][0] = i;
+}
+for (var j = 0; j < columnCount; j++)
+distances[0][j] = j;
+for (i = 1; i < rowCount; i++) {
+for (j = 1; j < columnCount; j++) {
+if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
+distances[i][j] = distances[i - 1][j - 1];
+else {
+var north = distances[i - 1][j] + 1;
+var west = distances[i][j - 1] + 1;
+distances[i][j] = north < west ? north : west;
+}
+}
+}
+return distances;
+},
+spliceOperationsFromEditDistances: function (distances) {
+var i = distances.length - 1;
+var j = distances[0].length - 1;
+var current = distances[i][j];
+var edits = [];
+while (i > 0 || j > 0) {
+if (i == 0) {
+edits.push(EDIT_ADD);
+j--;
+continue;
+}
+if (j == 0) {
+edits.push(EDIT_DELETE);
+i--;
+continue;
+}
+var northWest = distances[i - 1][j - 1];
+var west = distances[i - 1][j];
+var north = distances[i][j - 1];
+var min;
+if (west < north)
+min = west < northWest ? west : northWest;
+else
+min = north < northWest ? north : northWest;
+if (min == northWest) {
+if (northWest == current) {
+edits.push(EDIT_LEAVE);
+} else {
+edits.push(EDIT_UPDATE);
+current = northWest;
+}
+i--;
+j--;
+} else if (min == west) {
+edits.push(EDIT_DELETE);
+i--;
+current = west;
+} else {
+edits.push(EDIT_ADD);
+j--;
+current = north;
+}
+}
+edits.reverse();
+return edits;
+},
+calcSplices: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
+var prefixCount = 0;
+var suffixCount = 0;
+var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
+if (currentStart == 0 && oldStart == 0)
+prefixCount = this.sharedPrefix(current, old, minLength);
+if (currentEnd == current.length && oldEnd == old.length)
+suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
+currentStart += prefixCount;
+oldStart += prefixCount;
+currentEnd -= suffixCount;
+oldEnd -= suffixCount;
+if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
+return [];
+if (currentStart == currentEnd) {
+var splice = newSplice(currentStart, [], 0);
+while (oldStart < oldEnd)
+splice.removed.push(old[oldStart++]);
+return [splice];
+} else if (oldStart == oldEnd)
+return [newSplice(currentStart, [], currentEnd - currentStart)];
+var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
+splice = undefined;
+var splices = [];
+var index = currentStart;
+var oldIndex = oldStart;
+for (var i = 0; i < ops.length; i++) {
+switch (ops[i]) {
+case EDIT_LEAVE:
+if (splice) {
+splices.push(splice);
+splice = undefined;
+}
+index++;
+oldIndex++;
+break;
+case EDIT_UPDATE:
+if (!splice)
+splice = newSplice(index, [], 0);
+splice.addedCount++;
+index++;
+splice.removed.push(old[oldIndex]);
+oldIndex++;
+break;
+case EDIT_ADD:
+if (!splice)
+splice = newSplice(index, [], 0);
+splice.addedCount++;
+index++;
+break;
+case EDIT_DELETE:
+if (!splice)
+splice = newSplice(index, [], 0);
+splice.removed.push(old[oldIndex]);
+oldIndex++;
+break;
+}
+}
+if (splice) {
+splices.push(splice);
+}
+return splices;
+},
+sharedPrefix: function (current, old, searchLength) {
+for (var i = 0; i < searchLength; i++)
+if (!this.equals(current[i], old[i]))
+return i;
+return searchLength;
+},
+sharedSuffix: function (current, old, searchLength) {
+var index1 = current.length;
+var index2 = old.length;
+var count = 0;
+while (count < searchLength && this.equals(current[--index1], old[--index2]))
+count++;
+return count;
+},
+calculateSplices: function (current, previous) {
+return this.calcSplices(current, 0, current.length, previous, 0, previous.length);
+},
+equals: function (currentValue, previousValue) {
+return currentValue === previousValue;
+}
+};
+return new ArraySplice();
+}();Polymer.domInnerHTML = function () {
+var escapeAttrRegExp = /[&\u00A0"]/g;
+var escapeDataRegExp = /[&\u00A0<>]/g;
+function escapeReplace(c) {
+switch (c) {
+case '&':
+return '&amp;';
+case '<':
+return '&lt;';
+case '>':
+return '&gt;';
+case '"':
+return '&quot;';
+case '\xA0':
+return '&nbsp;';
+}
+}
+function escapeAttr(s) {
+return s.replace(escapeAttrRegExp, escapeReplace);
+}
+function escapeData(s) {
+return s.replace(escapeDataRegExp, escapeReplace);
+}
+function makeSet(arr) {
+var set = {};
+for (var i = 0; i < arr.length; i++) {
+set[arr[i]] = true;
+}
+return set;
+}
+var voidElements = makeSet([
+'area',
+'base',
+'br',
+'col',
+'command',
+'embed',
+'hr',
+'img',
+'input',
+'keygen',
+'link',
+'meta',
+'param',
+'source',
+'track',
+'wbr'
+]);
+var plaintextParents = makeSet([
+'style',
+'script',
+'xmp',
+'iframe',
+'noembed',
+'noframes',
+'plaintext',
+'noscript'
+]);
+function getOuterHTML(node, parentNode, composed) {
+switch (node.nodeType) {
+case Node.ELEMENT_NODE:
+var tagName = node.localName;
+var s = '<' + tagName;
+var attrs = node.attributes;
+for (var i = 0, attr; attr = attrs[i]; i++) {
+s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
+}
+s += '>';
+if (voidElements[tagName]) {
+return s;
+}
+return s + getInnerHTML(node, composed) + '</' + tagName + '>';
+case Node.TEXT_NODE:
+var data = node.data;
+if (parentNode && plaintextParents[parentNode.localName]) {
+return data;
+}
+return escapeData(data);
+case Node.COMMENT_NODE:
+return '<!--' + node.data + '-->';
+default:
+console.error(node);
+throw new Error('not implemented');
+}
+}
+function getInnerHTML(node, composed) {
+if (node instanceof HTMLTemplateElement)
+node = node.content;
+var s = '';
+var c$ = Polymer.dom(node).childNodes;
+for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
+s += getOuterHTML(child, node, composed);
+}
+return s;
+}
+return { getInnerHTML: getInnerHTML };
+}();(function () {
+'use strict';
+var nativeInsertBefore = Element.prototype.insertBefore;
+var nativeAppendChild = Element.prototype.appendChild;
+var nativeRemoveChild = Element.prototype.removeChild;
+Polymer.TreeApi = {
+arrayCopyChildNodes: function (parent) {
+var copy = [], i = 0;
+for (var n = parent.firstChild; n; n = n.nextSibling) {
+copy[i++] = n;
+}
+return copy;
+},
+arrayCopyChildren: function (parent) {
+var copy = [], i = 0;
+for (var n = parent.firstElementChild; n; n = n.nextElementSibling) {
+copy[i++] = n;
+}
+return copy;
+},
+arrayCopy: function (a$) {
+var l = a$.length;
+var copy = new Array(l);
+for (var i = 0; i < l; i++) {
+copy[i] = a$[i];
+}
+return copy;
+}
+};
+Polymer.TreeApi.Logical = {
+hasParentNode: function (node) {
+return Boolean(node.__dom && node.__dom.parentNode);
+},
+hasChildNodes: function (node) {
+return Boolean(node.__dom && node.__dom.childNodes !== undefined);
+},
+getChildNodes: function (node) {
+return this.hasChildNodes(node) ? this._getChildNodes(node) : node.childNodes;
+},
+_getChildNodes: function (node) {
+if (!node.__dom.childNodes) {
+node.__dom.childNodes = [];
+for (var n = node.__dom.firstChild; n; n = n.__dom.nextSibling) {
+node.__dom.childNodes.push(n);
+}
+}
+return node.__dom.childNodes;
+},
+getParentNode: function (node) {
+return node.__dom && node.__dom.parentNode !== undefined ? node.__dom.parentNode : node.parentNode;
+},
+getFirstChild: function (node) {
+return node.__dom && node.__dom.firstChild !== undefined ? node.__dom.firstChild : node.firstChild;
+},
+getLastChild: function (node) {
+return node.__dom && node.__dom.lastChild !== undefined ? node.__dom.lastChild : node.lastChild;
+},
+getNextSibling: function (node) {
+return node.__dom && node.__dom.nextSibling !== undefined ? node.__dom.nextSibling : node.nextSibling;
+},
+getPreviousSibling: function (node) {
+return node.__dom && node.__dom.previousSibling !== undefined ? node.__dom.previousSibling : node.previousSibling;
+},
+getFirstElementChild: function (node) {
+return node.__dom && node.__dom.firstChild !== undefined ? this._getFirstElementChild(node) : node.firstElementChild;
+},
+_getFirstElementChild: function (node) {
+var n = node.__dom.firstChild;
+while (n && n.nodeType !== Node.ELEMENT_NODE) {
+n = n.__dom.nextSibling;
+}
+return n;
+},
+getLastElementChild: function (node) {
+return node.__dom && node.__dom.lastChild !== undefined ? this._getLastElementChild(node) : node.lastElementChild;
+},
+_getLastElementChild: function (node) {
+var n = node.__dom.lastChild;
+while (n && n.nodeType !== Node.ELEMENT_NODE) {
+n = n.__dom.previousSibling;
+}
+return n;
+},
+getNextElementSibling: function (node) {
+return node.__dom && node.__dom.nextSibling !== undefined ? this._getNextElementSibling(node) : node.nextElementSibling;
+},
+_getNextElementSibling: function (node) {
+var n = node.__dom.nextSibling;
+while (n && n.nodeType !== Node.ELEMENT_NODE) {
+n = n.__dom.nextSibling;
+}
+return n;
+},
+getPreviousElementSibling: function (node) {
+return node.__dom && node.__dom.previousSibling !== undefined ? this._getPreviousElementSibling(node) : node.previousElementSibling;
+},
+_getPreviousElementSibling: function (node) {
+var n = node.__dom.previousSibling;
+while (n && n.nodeType !== Node.ELEMENT_NODE) {
+n = n.__dom.previousSibling;
+}
+return n;
+},
+saveChildNodes: function (node) {
+if (!this.hasChildNodes(node)) {
+node.__dom = node.__dom || {};
+node.__dom.firstChild = node.firstChild;
+node.__dom.lastChild = node.lastChild;
+node.__dom.childNodes = [];
+for (var n = node.firstChild; n; n = n.nextSibling) {
+n.__dom = n.__dom || {};
+n.__dom.parentNode = node;
+node.__dom.childNodes.push(n);
+n.__dom.nextSibling = n.nextSibling;
+n.__dom.previousSibling = n.previousSibling;
+}
+}
+},
+recordInsertBefore: function (node, container, ref_node) {
+container.__dom.childNodes = null;
+if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+for (var n = node.firstChild; n; n = n.nextSibling) {
+this._linkNode(n, container, ref_node);
+}
+} else {
+this._linkNode(node, container, ref_node);
+}
+},
+_linkNode: function (node, container, ref_node) {
+node.__dom = node.__dom || {};
+container.__dom = container.__dom || {};
+if (ref_node) {
+ref_node.__dom = ref_node.__dom || {};
+}
+node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling : container.__dom.lastChild;
+if (node.__dom.previousSibling) {
+node.__dom.previousSibling.__dom.nextSibling = node;
+}
+node.__dom.nextSibling = ref_node || null;
+if (node.__dom.nextSibling) {
+node.__dom.nextSibling.__dom.previousSibling = node;
+}
+node.__dom.parentNode = container;
+if (ref_node) {
+if (ref_node === container.__dom.firstChild) {
+container.__dom.firstChild = node;
+}
+} else {
+container.__dom.lastChild = node;
+if (!container.__dom.firstChild) {
+container.__dom.firstChild = node;
+}
+}
+container.__dom.childNodes = null;
+},
+recordRemoveChild: function (node, container) {
+node.__dom = node.__dom || {};
+container.__dom = container.__dom || {};
+if (node === container.__dom.firstChild) {
+container.__dom.firstChild = node.__dom.nextSibling;
+}
+if (node === container.__dom.lastChild) {
+container.__dom.lastChild = node.__dom.previousSibling;
+}
+var p = node.__dom.previousSibling;
+var n = node.__dom.nextSibling;
+if (p) {
+p.__dom.nextSibling = n;
+}
+if (n) {
+n.__dom.previousSibling = p;
+}
+node.__dom.parentNode = node.__dom.previousSibling = node.__dom.nextSibling = undefined;
+container.__dom.childNodes = null;
+}
+};
+Polymer.TreeApi.Composed = {
+getChildNodes: function (node) {
+return Polymer.TreeApi.arrayCopyChildNodes(node);
+},
+getParentNode: function (node) {
+return node.parentNode;
+},
+clearChildNodes: function (node) {
+node.textContent = '';
+},
+insertBefore: function (parentNode, newChild, refChild) {
+return nativeInsertBefore.call(parentNode, newChild, refChild || null);
+},
+appendChild: function (parentNode, newChild) {
+return nativeAppendChild.call(parentNode, newChild);
+},
+removeChild: function (parentNode, node) {
+return nativeRemoveChild.call(parentNode, node);
+}
+};
+}());Polymer.DomApi = function () {
+'use strict';
+var Settings = Polymer.Settings;
+var TreeApi = Polymer.TreeApi;
+var DomApi = function (node) {
+this.node = needsToWrap ? DomApi.wrap(node) : node;
+};
+var needsToWrap = Settings.hasShadow && !Settings.nativeShadow;
+DomApi.wrap = window.wrap ? window.wrap : function (node) {
+return node;
+};
+DomApi.prototype = {
+flush: function () {
+Polymer.dom.flush();
+},
+deepContains: function (node) {
+if (this.node.contains(node)) {
+return true;
+}
+var n = node;
+var doc = node.ownerDocument;
+while (n && n !== doc && n !== this.node) {
+n = Polymer.dom(n).parentNode || n.host;
+}
+return n === this.node;
+},
+queryDistributedElements: function (selector) {
+var c$ = this.getEffectiveChildNodes();
+var list = [];
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+if (c.nodeType === Node.ELEMENT_NODE && DomApi.matchesSelector.call(c, selector)) {
+list.push(c);
+}
+}
+return list;
+},
+getEffectiveChildNodes: function () {
+var list = [];
+var c$ = this.childNodes;
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+if (c.localName === CONTENT) {
+var d$ = dom(c).getDistributedNodes();
+for (var j = 0; j < d$.length; j++) {
+list.push(d$[j]);
+}
+} else {
+list.push(c);
+}
+}
+return list;
+},
+observeNodes: function (callback) {
+if (callback) {
+if (!this.observer) {
+this.observer = this.node.localName === CONTENT ? new DomApi.DistributedNodesObserver(this) : new DomApi.EffectiveNodesObserver(this);
+}
+return this.observer.addListener(callback);
+}
+},
+unobserveNodes: function (handle) {
+if (this.observer) {
+this.observer.removeListener(handle);
+}
+},
+notifyObserver: function () {
+if (this.observer) {
+this.observer.notify();
+}
+},
+_query: function (matcher, node, halter) {
+node = node || this.node;
+var list = [];
+this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
+return list;
+},
+_queryElements: function (elements, matcher, halter, list) {
+for (var i = 0, l = elements.length, c; i < l && (c = elements[i]); i++) {
+if (c.nodeType === Node.ELEMENT_NODE) {
+if (this._queryElement(c, matcher, halter, list)) {
+return true;
+}
+}
+}
+},
+_queryElement: function (node, matcher, halter, list) {
+var result = matcher(node);
+if (result) {
+list.push(node);
+}
+if (halter && halter(result)) {
+return result;
+}
+this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
+}
+};
+var CONTENT = DomApi.CONTENT = 'content';
+var dom = DomApi.factory = function (node) {
+node = node || document;
+if (!node.__domApi) {
+node.__domApi = new DomApi.ctor(node);
+}
+return node.__domApi;
+};
+DomApi.hasApi = function (node) {
+return Boolean(node.__domApi);
+};
+DomApi.ctor = DomApi;
+Polymer.dom = function (obj, patch) {
+if (obj instanceof Event) {
+return Polymer.EventApi.factory(obj);
+} else {
+return DomApi.factory(obj, patch);
+}
+};
+var p = Element.prototype;
+DomApi.matchesSelector = p.matches || p.matchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector || p.webkitMatchesSelector;
+return DomApi;
+}();(function () {
+'use strict';
+var Settings = Polymer.Settings;
+var DomApi = Polymer.DomApi;
+var dom = DomApi.factory;
+var TreeApi = Polymer.TreeApi;
+var getInnerHTML = Polymer.domInnerHTML.getInnerHTML;
+var CONTENT = DomApi.CONTENT;
+if (Settings.useShadow) {
+return;
+}
+var nativeCloneNode = Element.prototype.cloneNode;
+var nativeImportNode = Document.prototype.importNode;
+Polymer.Base.extend(DomApi.prototype, {
+_lazyDistribute: function (host) {
+if (host.shadyRoot && host.shadyRoot._distributionClean) {
+host.shadyRoot._distributionClean = false;
+Polymer.dom.addDebouncer(host.debounce('_distribute', host._distributeContent));
+}
+},
+appendChild: function (node) {
+return this.insertBefore(node);
+},
+insertBefore: function (node, ref_node) {
+if (ref_node && TreeApi.Logical.getParentNode(ref_node) !== this.node) {
+throw Error('The ref_node to be inserted before is not a child ' + 'of this node');
+}
+if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
+var parent = TreeApi.Logical.getParentNode(node);
+if (parent) {
+if (DomApi.hasApi(parent)) {
+dom(parent).notifyObserver();
+}
+this._removeNode(node);
+} else {
+this._removeOwnerShadyRoot(node);
+}
+}
+if (!this._addNode(node, ref_node)) {
+if (ref_node) {
+ref_node = ref_node.localName === CONTENT ? this._firstComposedNode(ref_node) : ref_node;
+}
+var container = this.node._isShadyRoot ? this.node.host : this.node;
+if (ref_node) {
+TreeApi.Composed.insertBefore(container, node, ref_node);
+} else {
+TreeApi.Composed.appendChild(container, node);
+}
+}
+this.notifyObserver();
+return node;
+},
+_addNode: function (node, ref_node) {
+var root = this.getOwnerRoot();
+if (root) {
+var ipAdded = this._maybeAddInsertionPoint(node, this.node);
+if (!root._invalidInsertionPoints) {
+root._invalidInsertionPoints = ipAdded;
+}
+this._addNodeToHost(root.host, node);
+}
+if (TreeApi.Logical.hasChildNodes(this.node)) {
+TreeApi.Logical.recordInsertBefore(node, this.node, ref_node);
+}
+var handled = this._maybeDistribute(node) || this.node.shadyRoot;
+if (handled) {
+if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+while (node.firstChild) {
+TreeApi.Composed.removeChild(node, node.firstChild);
+}
+} else {
+var parent = TreeApi.Composed.getParentNode(node);
+if (parent) {
+TreeApi.Composed.removeChild(parent, node);
+}
+}
+}
+return handled;
+},
+removeChild: function (node) {
+if (TreeApi.Logical.getParentNode(node) !== this.node) {
+throw Error('The node to be removed is not a child of this node: ' + node);
+}
+if (!this._removeNode(node)) {
+var container = this.node._isShadyRoot ? this.node.host : this.node;
+var parent = TreeApi.Composed.getParentNode(node);
+if (container === parent) {
+TreeApi.Composed.removeChild(container, node);
+}
+}
+this.notifyObserver();
+return node;
+},
+_removeNode: function (node) {
+var logicalParent = TreeApi.Logical.hasParentNode(node) && TreeApi.Logical.getParentNode(node);
+var distributed;
+var root = this._ownerShadyRootForNode(node);
+if (logicalParent) {
+distributed = dom(node)._maybeDistributeParent();
+TreeApi.Logical.recordRemoveChild(node, logicalParent);
+if (root && this._removeDistributedChildren(root, node)) {
+root._invalidInsertionPoints = true;
+this._lazyDistribute(root.host);
+}
+}
+this._removeOwnerShadyRoot(node);
+if (root) {
+this._removeNodeFromHost(root.host, node);
+}
+return distributed;
+},
+replaceChild: function (node, ref_node) {
+this.insertBefore(node, ref_node);
+this.removeChild(ref_node);
+return node;
+},
+_hasCachedOwnerRoot: function (node) {
+return Boolean(node._ownerShadyRoot !== undefined);
+},
+getOwnerRoot: function () {
+return this._ownerShadyRootForNode(this.node);
+},
+_ownerShadyRootForNode: function (node) {
+if (!node) {
+return;
+}
+var root = node._ownerShadyRoot;
+if (root === undefined) {
+if (node._isShadyRoot) {
+root = node;
+} else {
+var parent = TreeApi.Logical.getParentNode(node);
+if (parent) {
+root = parent._isShadyRoot ? parent : this._ownerShadyRootForNode(parent);
+} else {
+root = null;
+}
+}
+if (root || document.documentElement.contains(node)) {
+node._ownerShadyRoot = root;
+}
+}
+return root;
+},
+_maybeDistribute: function (node) {
+var fragContent = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent && dom(node).querySelector(CONTENT);
+var wrappedContent = fragContent && TreeApi.Logical.getParentNode(fragContent).nodeType !== Node.DOCUMENT_FRAGMENT_NODE;
+var hasContent = fragContent || node.localName === CONTENT;
+if (hasContent) {
+var root = this.getOwnerRoot();
+if (root) {
+this._lazyDistribute(root.host);
+}
+}
+var needsDist = this._nodeNeedsDistribution(this.node);
+if (needsDist) {
+this._lazyDistribute(this.node);
+}
+return needsDist || hasContent && !wrappedContent;
+},
+_maybeAddInsertionPoint: function (node, parent) {
+var added;
+if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent) {
+var c$ = dom(node).querySelectorAll(CONTENT);
+for (var i = 0, n, np, na; i < c$.length && (n = c$[i]); i++) {
+np = TreeApi.Logical.getParentNode(n);
+if (np === node) {
+np = parent;
+}
+na = this._maybeAddInsertionPoint(n, np);
+added = added || na;
+}
+} else if (node.localName === CONTENT) {
+TreeApi.Logical.saveChildNodes(parent);
+TreeApi.Logical.saveChildNodes(node);
+added = true;
+}
+return added;
+},
+_updateInsertionPoints: function (host) {
+var i$ = host.shadyRoot._insertionPoints = dom(host.shadyRoot).querySelectorAll(CONTENT);
+for (var i = 0, c; i < i$.length; i++) {
+c = i$[i];
+TreeApi.Logical.saveChildNodes(c);
+TreeApi.Logical.saveChildNodes(TreeApi.Logical.getParentNode(c));
+}
+},
+_nodeNeedsDistribution: function (node) {
+return node && node.shadyRoot && DomApi.hasInsertionPoint(node.shadyRoot);
+},
+_addNodeToHost: function (host, node) {
+if (host._elementAdd) {
+host._elementAdd(node);
+}
+},
+_removeNodeFromHost: function (host, node) {
+if (host._elementRemove) {
+host._elementRemove(node);
+}
+},
+_removeDistributedChildren: function (root, container) {
+var hostNeedsDist;
+var ip$ = root._insertionPoints;
+for (var i = 0; i < ip$.length; i++) {
+var content = ip$[i];
+if (this._contains(container, content)) {
+var dc$ = dom(content).getDistributedNodes();
+for (var j = 0; j < dc$.length; j++) {
+hostNeedsDist = true;
+var node = dc$[j];
+var parent = TreeApi.Composed.getParentNode(node);
+if (parent) {
+TreeApi.Composed.removeChild(parent, node);
+}
+}
+}
+}
+return hostNeedsDist;
+},
+_contains: function (container, node) {
+while (node) {
+if (node == container) {
+return true;
+}
+node = TreeApi.Logical.getParentNode(node);
+}
+},
+_removeOwnerShadyRoot: function (node) {
+if (this._hasCachedOwnerRoot(node)) {
+var c$ = TreeApi.Logical.getChildNodes(node);
+for (var i = 0, l = c$.length, n; i < l && (n = c$[i]); i++) {
+this._removeOwnerShadyRoot(n);
+}
+}
+node._ownerShadyRoot = undefined;
+},
+_firstComposedNode: function (content) {
+var n$ = dom(content).getDistributedNodes();
+for (var i = 0, l = n$.length, n, p$; i < l && (n = n$[i]); i++) {
+p$ = dom(n).getDestinationInsertionPoints();
+if (p$[p$.length - 1] === content) {
+return n;
+}
+}
+},
+querySelector: function (selector) {
+var result = this._query(function (n) {
+return DomApi.matchesSelector.call(n, selector);
+}, this.node, function (n) {
+return Boolean(n);
+})[0];
+return result || null;
+},
+querySelectorAll: function (selector) {
+return this._query(function (n) {
+return DomApi.matchesSelector.call(n, selector);
+}, this.node);
+},
+getDestinationInsertionPoints: function () {
+return this.node._destinationInsertionPoints || [];
+},
+getDistributedNodes: function () {
+return this.node._distributedNodes || [];
+},
+_clear: function () {
+while (this.childNodes.length) {
+this.removeChild(this.childNodes[0]);
+}
+},
+setAttribute: function (name, value) {
+this.node.setAttribute(name, value);
+this._maybeDistributeParent();
+},
+removeAttribute: function (name) {
+this.node.removeAttribute(name);
+this._maybeDistributeParent();
+},
+_maybeDistributeParent: function () {
+if (this._nodeNeedsDistribution(this.parentNode)) {
+this._lazyDistribute(this.parentNode);
+return true;
+}
+},
+cloneNode: function (deep) {
+var n = nativeCloneNode.call(this.node, false);
+if (deep) {
+var c$ = this.childNodes;
+var d = dom(n);
+for (var i = 0, nc; i < c$.length; i++) {
+nc = dom(c$[i]).cloneNode(true);
+d.appendChild(nc);
+}
+}
+return n;
+},
+importNode: function (externalNode, deep) {
+var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
+var n = nativeImportNode.call(doc, externalNode, false);
+if (deep) {
+var c$ = TreeApi.Logical.getChildNodes(externalNode);
+var d = dom(n);
+for (var i = 0, nc; i < c$.length; i++) {
+nc = dom(doc).importNode(c$[i], true);
+d.appendChild(nc);
+}
+}
+return n;
+},
+_getComposedInnerHTML: function () {
+return getInnerHTML(this.node, true);
+}
+});
+Object.defineProperties(DomApi.prototype, {
+activeElement: {
+get: function () {
+var active = document.activeElement;
+if (!active) {
+return null;
+}
+var isShadyRoot = !!this.node._isShadyRoot;
+if (this.node !== document) {
+if (!isShadyRoot) {
+return null;
+}
+if (this.node.host === active || !this.node.host.contains(active)) {
+return null;
+}
+}
+var activeRoot = dom(active).getOwnerRoot();
+while (activeRoot && activeRoot !== this.node) {
+active = activeRoot.host;
+activeRoot = dom(active).getOwnerRoot();
+}
+if (this.node === document) {
+return activeRoot ? null : active;
+} else {
+return activeRoot === this.node ? active : null;
+}
+},
+configurable: true
+},
+childNodes: {
+get: function () {
+var c$ = TreeApi.Logical.getChildNodes(this.node);
+return Array.isArray(c$) ? c$ : TreeApi.arrayCopyChildNodes(this.node);
+},
+configurable: true
+},
+children: {
+get: function () {
+if (TreeApi.Logical.hasChildNodes(this.node)) {
+return Array.prototype.filter.call(this.childNodes, function (n) {
+return n.nodeType === Node.ELEMENT_NODE;
+});
+} else {
+return TreeApi.arrayCopyChildren(this.node);
+}
+},
+configurable: true
+},
+parentNode: {
+get: function () {
+return TreeApi.Logical.getParentNode(this.node);
+},
+configurable: true
+},
+firstChild: {
+get: function () {
+return TreeApi.Logical.getFirstChild(this.node);
+},
+configurable: true
+},
+lastChild: {
+get: function () {
+return TreeApi.Logical.getLastChild(this.node);
+},
+configurable: true
+},
+nextSibling: {
+get: function () {
+return TreeApi.Logical.getNextSibling(this.node);
+},
+configurable: true
+},
+previousSibling: {
+get: function () {
+return TreeApi.Logical.getPreviousSibling(this.node);
+},
+configurable: true
+},
+firstElementChild: {
+get: function () {
+return TreeApi.Logical.getFirstElementChild(this.node);
+},
+configurable: true
+},
+lastElementChild: {
+get: function () {
+return TreeApi.Logical.getLastElementChild(this.node);
+},
+configurable: true
+},
+nextElementSibling: {
+get: function () {
+return TreeApi.Logical.getNextElementSibling(this.node);
+},
+configurable: true
+},
+previousElementSibling: {
+get: function () {
+return TreeApi.Logical.getPreviousElementSibling(this.node);
+},
+configurable: true
+},
+textContent: {
+get: function () {
+var nt = this.node.nodeType;
+if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
+return this.node.textContent;
+} else {
+var tc = [];
+for (var i = 0, cn = this.childNodes, c; c = cn[i]; i++) {
+if (c.nodeType !== Node.COMMENT_NODE) {
+tc.push(c.textContent);
+}
+}
+return tc.join('');
+}
+},
+set: function (text) {
+var nt = this.node.nodeType;
+if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
+this.node.textContent = text;
+} else {
+this._clear();
+if (text) {
+this.appendChild(document.createTextNode(text));
+}
+}
+},
+configurable: true
+},
+innerHTML: {
+get: function () {
+var nt = this.node.nodeType;
+if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
+return null;
+} else {
+return getInnerHTML(this.node);
+}
+},
+set: function (text) {
+var nt = this.node.nodeType;
+if (nt !== Node.TEXT_NODE || nt !== Node.COMMENT_NODE) {
+this._clear();
+var d = document.createElement('div');
+d.innerHTML = text;
+var c$ = TreeApi.arrayCopyChildNodes(d);
+for (var i = 0; i < c$.length; i++) {
+this.appendChild(c$[i]);
+}
+}
+},
+configurable: true
+}
+});
+DomApi.hasInsertionPoint = function (root) {
+return Boolean(root && root._insertionPoints.length);
+};
+}());(function () {
+'use strict';
+var Settings = Polymer.Settings;
+var TreeApi = Polymer.TreeApi;
+var DomApi = Polymer.DomApi;
+if (!Settings.useShadow) {
+return;
+}
+Polymer.Base.extend(DomApi.prototype, {
+querySelectorAll: function (selector) {
+return TreeApi.arrayCopy(this.node.querySelectorAll(selector));
+},
+getOwnerRoot: function () {
+var n = this.node;
+while (n) {
+if (n.nodeType === Node.DOCUMENT_FRAGMENT_NODE && n.host) {
+return n;
+}
+n = n.parentNode;
+}
+},
+importNode: function (externalNode, deep) {
+var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
+return doc.importNode(externalNode, deep);
+},
+getDestinationInsertionPoints: function () {
+var n$ = this.node.getDestinationInsertionPoints && this.node.getDestinationInsertionPoints();
+return n$ ? TreeApi.arrayCopy(n$) : [];
+},
+getDistributedNodes: function () {
+var n$ = this.node.getDistributedNodes && this.node.getDistributedNodes();
+return n$ ? TreeApi.arrayCopy(n$) : [];
+}
+});
+Object.defineProperties(DomApi.prototype, {
+activeElement: {
+get: function () {
+var node = DomApi.wrap(this.node);
+var activeElement = node.activeElement;
+return node.contains(activeElement) ? activeElement : null;
+},
+configurable: true
+},
+childNodes: {
+get: function () {
+return TreeApi.arrayCopyChildNodes(this.node);
+},
+configurable: true
+},
+children: {
+get: function () {
+return TreeApi.arrayCopyChildren(this.node);
+},
+configurable: true
+},
+textContent: {
+get: function () {
+return this.node.textContent;
+},
+set: function (value) {
+return this.node.textContent = value;
+},
+configurable: true
+},
+innerHTML: {
+get: function () {
+return this.node.innerHTML;
+},
+set: function (value) {
+return this.node.innerHTML = value;
+},
+configurable: true
+}
+});
+var forwardMethods = function (m$) {
+for (var i = 0; i < m$.length; i++) {
+forwardMethod(m$[i]);
+}
+};
+var forwardMethod = function (method) {
+DomApi.prototype[method] = function () {
+return this.node[method].apply(this.node, arguments);
+};
+};
+forwardMethods([
+'cloneNode',
+'appendChild',
+'insertBefore',
+'removeChild',
+'replaceChild',
+'setAttribute',
+'removeAttribute',
+'querySelector'
+]);
+var forwardProperties = function (f$) {
+for (var i = 0; i < f$.length; i++) {
+forwardProperty(f$[i]);
+}
+};
+var forwardProperty = function (name) {
+Object.defineProperty(DomApi.prototype, name, {
+get: function () {
+return this.node[name];
+},
+configurable: true
+});
+};
+forwardProperties([
+'parentNode',
+'firstChild',
+'lastChild',
+'nextSibling',
+'previousSibling',
+'firstElementChild',
+'lastElementChild',
+'nextElementSibling',
+'previousElementSibling'
+]);
+}());Polymer.Base.extend(Polymer.dom, {
+_flushGuard: 0,
+_FLUSH_MAX: 100,
+_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
+_debouncers: [],
+_staticFlushList: [],
+_finishDebouncer: null,
+flush: function () {
+this._flushGuard = 0;
+this._prepareFlush();
+while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
+while (this._debouncers.length) {
+this._debouncers.shift().complete();
+}
+if (this._finishDebouncer) {
+this._finishDebouncer.complete();
+}
+this._prepareFlush();
+this._flushGuard++;
+}
+if (this._flushGuard >= this._FLUSH_MAX) {
+console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
+}
+},
+_prepareFlush: function () {
+if (this._needsTakeRecords) {
+CustomElements.takeRecords();
+}
+for (var i = 0; i < this._staticFlushList.length; i++) {
+this._staticFlushList[i]();
+}
+},
+addStaticFlush: function (fn) {
+this._staticFlushList.push(fn);
+},
+removeStaticFlush: function (fn) {
+var i = this._staticFlushList.indexOf(fn);
+if (i >= 0) {
+this._staticFlushList.splice(i, 1);
+}
+},
+addDebouncer: function (debouncer) {
+this._debouncers.push(debouncer);
+this._finishDebouncer = Polymer.Debounce(this._finishDebouncer, this._finishFlush);
+},
+_finishFlush: function () {
+Polymer.dom._debouncers = [];
+}
+});Polymer.EventApi = function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+DomApi.Event = function (event) {
+this.event = event;
+};
+if (Settings.useShadow) {
+DomApi.Event.prototype = {
+get rootTarget() {
+return this.event.path[0];
+},
+get localTarget() {
+return this.event.target;
+},
+get path() {
+var path = this.event.path;
+if (!Array.isArray(path)) {
+path = Array.prototype.slice.call(path);
+}
+return path;
+}
+};
+} else {
+DomApi.Event.prototype = {
+get rootTarget() {
+return this.event.target;
+},
+get localTarget() {
+var current = this.event.currentTarget;
+var currentRoot = current && Polymer.dom(current).getOwnerRoot();
+var p$ = this.path;
+for (var i = 0; i < p$.length; i++) {
+if (Polymer.dom(p$[i]).getOwnerRoot() === currentRoot) {
+return p$[i];
+}
+}
+},
+get path() {
+if (!this.event._path) {
+var path = [];
+var current = this.rootTarget;
+while (current) {
+path.push(current);
+var insertionPoints = Polymer.dom(current).getDestinationInsertionPoints();
+if (insertionPoints.length) {
+for (var i = 0; i < insertionPoints.length - 1; i++) {
+path.push(insertionPoints[i]);
+}
+current = insertionPoints[insertionPoints.length - 1];
+} else {
+current = Polymer.dom(current).parentNode || current.host;
+}
+}
+path.push(window);
+this.event._path = path;
+}
+return this.event._path;
+}
+};
+}
+var factory = function (event) {
+if (!event.__eventApi) {
+event.__eventApi = new DomApi.Event(event);
+}
+return event.__eventApi;
+};
+return { factory: factory };
+}();(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var useShadow = Polymer.Settings.useShadow;
+Object.defineProperty(DomApi.prototype, 'classList', {
+get: function () {
+if (!this._classList) {
+this._classList = new DomApi.ClassList(this);
+}
+return this._classList;
+},
+configurable: true
+});
+DomApi.ClassList = function (host) {
+this.domApi = host;
+this.node = host.node;
+};
+DomApi.ClassList.prototype = {
+add: function () {
+this.node.classList.add.apply(this.node.classList, arguments);
+this._distributeParent();
+},
+remove: function () {
+this.node.classList.remove.apply(this.node.classList, arguments);
+this._distributeParent();
+},
+toggle: function () {
+this.node.classList.toggle.apply(this.node.classList, arguments);
+this._distributeParent();
+},
+_distributeParent: function () {
+if (!useShadow) {
+this.domApi._maybeDistributeParent();
+}
+},
+contains: function () {
+return this.node.classList.contains.apply(this.node.classList, arguments);
+}
+};
+}());(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+DomApi.EffectiveNodesObserver = function (domApi) {
+this.domApi = domApi;
+this.node = this.domApi.node;
+this._listeners = [];
+};
+DomApi.EffectiveNodesObserver.prototype = {
+addListener: function (callback) {
+if (!this._isSetup) {
+this._setup();
+this._isSetup = true;
+}
+var listener = {
+fn: callback,
+_nodes: []
+};
+this._listeners.push(listener);
+this._scheduleNotify();
+return listener;
+},
+removeListener: function (handle) {
+var i = this._listeners.indexOf(handle);
+if (i >= 0) {
+this._listeners.splice(i, 1);
+handle._nodes = [];
+}
+if (!this._hasListeners()) {
+this._cleanup();
+this._isSetup = false;
+}
+},
+_setup: function () {
+this._observeContentElements(this.domApi.childNodes);
+},
+_cleanup: function () {
+this._unobserveContentElements(this.domApi.childNodes);
+},
+_hasListeners: function () {
+return Boolean(this._listeners.length);
+},
+_scheduleNotify: function () {
+if (this._debouncer) {
+this._debouncer.stop();
+}
+this._debouncer = Polymer.Debounce(this._debouncer, this._notify);
+this._debouncer.context = this;
+Polymer.dom.addDebouncer(this._debouncer);
+},
+notify: function () {
+if (this._hasListeners()) {
+this._scheduleNotify();
+}
+},
+_notify: function () {
+this._beforeCallListeners();
+this._callListeners();
+},
+_beforeCallListeners: function () {
+this._updateContentElements();
+},
+_updateContentElements: function () {
+this._observeContentElements(this.domApi.childNodes);
+},
+_observeContentElements: function (elements) {
+for (var i = 0, n; i < elements.length && (n = elements[i]); i++) {
+if (this._isContent(n)) {
+n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
+if (!n.__observeNodesMap.has(this)) {
+n.__observeNodesMap.set(this, this._observeContent(n));
+}
+}
+}
+},
+_observeContent: function (content) {
+var self = this;
+var h = Polymer.dom(content).observeNodes(function () {
+self._scheduleNotify();
+});
+h._avoidChangeCalculation = true;
+return h;
+},
+_unobserveContentElements: function (elements) {
+for (var i = 0, n, h; i < elements.length && (n = elements[i]); i++) {
+if (this._isContent(n)) {
+h = n.__observeNodesMap.get(this);
+if (h) {
+Polymer.dom(n).unobserveNodes(h);
+n.__observeNodesMap.delete(this);
+}
+}
+}
+},
+_isContent: function (node) {
+return node.localName === 'content';
+},
+_callListeners: function () {
+var o$ = this._listeners;
+var nodes = this._getEffectiveNodes();
+for (var i = 0, o; i < o$.length && (o = o$[i]); i++) {
+var info = this._generateListenerInfo(o, nodes);
+if (info || o._alwaysNotify) {
+this._callListener(o, info);
+}
+}
+},
+_getEffectiveNodes: function () {
+return this.domApi.getEffectiveChildNodes();
+},
+_generateListenerInfo: function (listener, newNodes) {
+if (listener._avoidChangeCalculation) {
+return true;
+}
+var oldNodes = listener._nodes;
+var info = {
+target: this.node,
+addedNodes: [],
+removedNodes: []
+};
+var splices = Polymer.ArraySplice.calculateSplices(newNodes, oldNodes);
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
+info.removedNodes.push(n);
+}
+}
+for (i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (j = s.index; j < s.index + s.addedCount; j++) {
+info.addedNodes.push(newNodes[j]);
+}
+}
+listener._nodes = newNodes;
+if (info.addedNodes.length || info.removedNodes.length) {
+return info;
+}
+},
+_callListener: function (listener, info) {
+return listener.fn.call(this.node, info);
+},
+enableShadowAttributeTracking: function () {
+}
+};
+if (Settings.useShadow) {
+var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
+var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
+Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
+_setup: function () {
+if (!this._observer) {
+var self = this;
+this._mutationHandler = function (mxns) {
+if (mxns && mxns.length) {
+self._scheduleNotify();
+}
+};
+this._observer = new MutationObserver(this._mutationHandler);
+this._boundFlush = function () {
+self._flush();
+};
+Polymer.dom.addStaticFlush(this._boundFlush);
+this._observer.observe(this.node, { childList: true });
+}
+baseSetup.call(this);
+},
+_cleanup: function () {
+this._observer.disconnect();
+this._observer = null;
+this._mutationHandler = null;
+Polymer.dom.removeStaticFlush(this._boundFlush);
+baseCleanup.call(this);
+},
+_flush: function () {
+if (this._observer) {
+this._mutationHandler(this._observer.takeRecords());
+}
+},
+enableShadowAttributeTracking: function () {
+if (this._observer) {
+this._makeContentListenersAlwaysNotify();
+this._observer.disconnect();
+this._observer.observe(this.node, {
+childList: true,
+attributes: true,
+subtree: true
+});
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host && Polymer.dom(host).observer) {
+Polymer.dom(host).observer.enableShadowAttributeTracking();
+}
+}
+},
+_makeContentListenersAlwaysNotify: function () {
+for (var i = 0, h; i < this._listeners.length; i++) {
+h = this._listeners[i];
+h._alwaysNotify = h._isContentListener;
+}
+}
+});
+}
+}());(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+DomApi.DistributedNodesObserver = function (domApi) {
+DomApi.EffectiveNodesObserver.call(this, domApi);
+};
+DomApi.DistributedNodesObserver.prototype = Object.create(DomApi.EffectiveNodesObserver.prototype);
+Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
+_setup: function () {
+},
+_cleanup: function () {
+},
+_beforeCallListeners: function () {
+},
+_getEffectiveNodes: function () {
+return this.domApi.getDistributedNodes();
+}
+});
+if (Settings.useShadow) {
+Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
+_setup: function () {
+if (!this._observer) {
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host) {
+var self = this;
+this._observer = Polymer.dom(host).observeNodes(function () {
+self._scheduleNotify();
+});
+this._observer._isContentListener = true;
+if (this._hasAttrSelect()) {
+Polymer.dom(host).observer.enableShadowAttributeTracking();
+}
+}
+}
+},
+_hasAttrSelect: function () {
+var select = this.node.getAttribute('select');
+return select && select.match(/[[.]+/);
+},
+_cleanup: function () {
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host) {
+Polymer.dom(host).unobserveNodes(this._observer);
+}
+this._observer = null;
+}
+});
+}
+}());(function () {
+var DomApi = Polymer.DomApi;
+var TreeApi = Polymer.TreeApi;
+Polymer.Base._addFeature({
+_prepShady: function () {
+this._useContent = this._useContent || Boolean(this._template);
+},
+_setupShady: function () {
+this.shadyRoot = null;
+if (!this.__domApi) {
+this.__domApi = null;
+}
+if (!this.__dom) {
+this.__dom = null;
+}
+if (!this._ownerShadyRoot) {
+this._ownerShadyRoot = undefined;
+}
+},
+_poolContent: function () {
+if (this._useContent) {
+TreeApi.Logical.saveChildNodes(this);
+}
+},
+_setupRoot: function () {
+if (this._useContent) {
+this._createLocalRoot();
+if (!this.dataHost) {
+upgradeLogicalChildren(TreeApi.Logical.getChildNodes(this));
+}
+}
+},
+_createLocalRoot: function () {
+this.shadyRoot = this.root;
+this.shadyRoot._distributionClean = false;
+this.shadyRoot._hasDistributed = false;
+this.shadyRoot._isShadyRoot = true;
+this.shadyRoot._dirtyRoots = [];
+var i$ = this.shadyRoot._insertionPoints = !this._notes || this._notes._hasContent ? this.shadyRoot.querySelectorAll('content') : [];
+TreeApi.Logical.saveChildNodes(this.shadyRoot);
+for (var i = 0, c; i < i$.length; i++) {
+c = i$[i];
+TreeApi.Logical.saveChildNodes(c);
+TreeApi.Logical.saveChildNodes(c.parentNode);
+}
+this.shadyRoot.host = this;
+},
+get domHost() {
+var root = Polymer.dom(this).getOwnerRoot();
+return root && root.host;
+},
+distributeContent: function (updateInsertionPoints) {
+if (this.shadyRoot) {
+this.shadyRoot._invalidInsertionPoints = this.shadyRoot._invalidInsertionPoints || updateInsertionPoints;
+var host = getTopDistributingHost(this);
+Polymer.dom(this)._lazyDistribute(host);
+}
+},
+_distributeContent: function () {
+if (this._useContent && !this.shadyRoot._distributionClean) {
+if (this.shadyRoot._invalidInsertionPoints) {
+Polymer.dom(this)._updateInsertionPoints(this);
+this.shadyRoot._invalidInsertionPoints = false;
+}
+this._beginDistribute();
+this._distributeDirtyRoots();
+this._finishDistribute();
+}
+},
+_beginDistribute: function () {
+if (this._useContent && DomApi.hasInsertionPoint(this.shadyRoot)) {
+this._resetDistribution();
+this._distributePool(this.shadyRoot, this._collectPool());
+}
+},
+_distributeDirtyRoots: function () {
+var c$ = this.shadyRoot._dirtyRoots;
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+c._distributeContent();
+}
+this.shadyRoot._dirtyRoots = [];
+},
+_finishDistribute: function () {
+if (this._useContent) {
+this.shadyRoot._distributionClean = true;
+if (DomApi.hasInsertionPoint(this.shadyRoot)) {
+this._composeTree();
+notifyContentObservers(this.shadyRoot);
+} else {
+if (!this.shadyRoot._hasDistributed) {
+TreeApi.Composed.clearChildNodes(this);
+this.appendChild(this.shadyRoot);
+} else {
+var children = this._composeNode(this);
+this._updateChildNodes(this, children);
+}
+}
+if (!this.shadyRoot._hasDistributed) {
+notifyInitialDistribution(this);
+}
+this.shadyRoot._hasDistributed = true;
+}
+},
+elementMatches: function (selector, node) {
+node = node || this;
+return DomApi.matchesSelector.call(node, selector);
+},
+_resetDistribution: function () {
+var children = TreeApi.Logical.getChildNodes(this);
+for (var i = 0; i < children.length; i++) {
+var child = children[i];
+if (child._destinationInsertionPoints) {
+child._destinationInsertionPoints = undefined;
+}
+if (isInsertionPoint(child)) {
+clearDistributedDestinationInsertionPoints(child);
+}
+}
+var root = this.shadyRoot;
+var p$ = root._insertionPoints;
+for (var j = 0; j < p$.length; j++) {
+p$[j]._distributedNodes = [];
+}
+},
+_collectPool: function () {
+var pool = [];
+var children = TreeApi.Logical.getChildNodes(this);
+for (var i = 0; i < children.length; i++) {
+var child = children[i];
+if (isInsertionPoint(child)) {
+pool.push.apply(pool, child._distributedNodes);
+} else {
+pool.push(child);
+}
+}
+return pool;
+},
+_distributePool: function (node, pool) {
+var p$ = node._insertionPoints;
+for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
+this._distributeInsertionPoint(p, pool);
+maybeRedistributeParent(p, this);
+}
+},
+_distributeInsertionPoint: function (content, pool) {
+var anyDistributed = false;
+for (var i = 0, l = pool.length, node; i < l; i++) {
+node = pool[i];
+if (!node) {
+continue;
+}
+if (this._matchesContentSelect(node, content)) {
+distributeNodeInto(node, content);
+pool[i] = undefined;
+anyDistributed = true;
+}
+}
+if (!anyDistributed) {
+var children = TreeApi.Logical.getChildNodes(content);
+for (var j = 0; j < children.length; j++) {
+distributeNodeInto(children[j], content);
+}
+}
+},
+_composeTree: function () {
+this._updateChildNodes(this, this._composeNode(this));
+var p$ = this.shadyRoot._insertionPoints;
+for (var i = 0, l = p$.length, p, parent; i < l && (p = p$[i]); i++) {
+parent = TreeApi.Logical.getParentNode(p);
+if (!parent._useContent && parent !== this && parent !== this.shadyRoot) {
+this._updateChildNodes(parent, this._composeNode(parent));
+}
+}
+},
+_composeNode: function (node) {
+var children = [];
+var c$ = TreeApi.Logical.getChildNodes(node.shadyRoot || node);
+for (var i = 0; i < c$.length; i++) {
+var child = c$[i];
+if (isInsertionPoint(child)) {
+var distributedNodes = child._distributedNodes;
+for (var j = 0; j < distributedNodes.length; j++) {
+var distributedNode = distributedNodes[j];
+if (isFinalDestination(child, distributedNode)) {
+children.push(distributedNode);
+}
+}
+} else {
+children.push(child);
+}
+}
+return children;
+},
+_updateChildNodes: function (container, children) {
+var composed = TreeApi.Composed.getChildNodes(container);
+var splices = Polymer.ArraySplice.calculateSplices(children, composed);
+for (var i = 0, d = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
+if (TreeApi.Composed.getParentNode(n) === container) {
+TreeApi.Composed.removeChild(container, n);
+}
+composed.splice(s.index + d, 1);
+}
+d -= s.addedCount;
+}
+for (var i = 0, s, next; i < splices.length && (s = splices[i]); i++) {
+next = composed[s.index];
+for (j = s.index, n; j < s.index + s.addedCount; j++) {
+n = children[j];
+TreeApi.Composed.insertBefore(container, n, next);
+composed.splice(j, 0, n);
+}
+}
+},
+_matchesContentSelect: function (node, contentElement) {
+var select = contentElement.getAttribute('select');
+if (!select) {
+return true;
+}
+select = select.trim();
+if (!select) {
+return true;
+}
+if (!(node instanceof Element)) {
+return false;
+}
+var validSelectors = /^(:not\()?[*.#[a-zA-Z_|]/;
+if (!validSelectors.test(select)) {
+return false;
+}
+return this.elementMatches(select, node);
+},
+_elementAdd: function () {
+},
+_elementRemove: function () {
+}
+});
+function distributeNodeInto(child, insertionPoint) {
+insertionPoint._distributedNodes.push(child);
+var points = child._destinationInsertionPoints;
+if (!points) {
+child._destinationInsertionPoints = [insertionPoint];
+} else {
+points.push(insertionPoint);
+}
+}
+function clearDistributedDestinationInsertionPoints(content) {
+var e$ = content._distributedNodes;
+if (e$) {
+for (var i = 0; i < e$.length; i++) {
+var d = e$[i]._destinationInsertionPoints;
+if (d) {
+d.splice(d.indexOf(content) + 1, d.length);
+}
+}
+}
+}
+function maybeRedistributeParent(content, host) {
+var parent = TreeApi.Logical.getParentNode(content);
+if (parent && parent.shadyRoot && DomApi.hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) {
+parent.shadyRoot._distributionClean = false;
+host.shadyRoot._dirtyRoots.push(parent);
+}
+}
+function isFinalDestination(insertionPoint, node) {
+var points = node._destinationInsertionPoints;
+return points && points[points.length - 1] === insertionPoint;
+}
+function isInsertionPoint(node) {
+return node.localName == 'content';
+}
+function getTopDistributingHost(host) {
+while (host && hostNeedsRedistribution(host)) {
+host = host.domHost;
+}
+return host;
+}
+function hostNeedsRedistribution(host) {
+var c$ = TreeApi.Logical.getChildNodes(host);
+for (var i = 0, c; i < c$.length; i++) {
+c = c$[i];
+if (c.localName && c.localName === 'content') {
+return host.domHost;
+}
+}
+}
+function notifyContentObservers(root) {
+for (var i = 0, c; i < root._insertionPoints.length; i++) {
+c = root._insertionPoints[i];
+if (DomApi.hasApi(c)) {
+Polymer.dom(c).notifyObserver();
+}
+}
+}
+function notifyInitialDistribution(host) {
+if (DomApi.hasApi(host)) {
+Polymer.dom(host).notifyObserver();
+}
+}
+var needsUpgrade = window.CustomElements && !CustomElements.useNative;
+function upgradeLogicalChildren(children) {
+if (needsUpgrade && children) {
+for (var i = 0; i < children.length; i++) {
+CustomElements.upgrade(children[i]);
+}
+}
+}
+}());if (Polymer.Settings.useShadow) {
+Polymer.Base._addFeature({
+_poolContent: function () {
+},
+_beginDistribute: function () {
+},
+distributeContent: function () {
+},
+_distributeContent: function () {
+},
+_finishDistribute: function () {
+},
+_createLocalRoot: function () {
+this.createShadowRoot();
+this.shadowRoot.appendChild(this.root);
+this.root = this.shadowRoot;
+}
+});
+}Polymer.Async = {
+_currVal: 0,
+_lastVal: 0,
+_callbacks: [],
+_twiddleContent: 0,
+_twiddle: document.createTextNode(''),
+run: function (callback, waitTime) {
+if (waitTime > 0) {
+return ~setTimeout(callback, waitTime);
+} else {
+this._twiddle.textContent = this._twiddleContent++;
+this._callbacks.push(callback);
+return this._currVal++;
+}
+},
+cancel: function (handle) {
+if (handle < 0) {
+clearTimeout(~handle);
+} else {
+var idx = handle - this._lastVal;
+if (idx >= 0) {
+if (!this._callbacks[idx]) {
+throw 'invalid async handle: ' + handle;
+}
+this._callbacks[idx] = null;
+}
+}
+},
+_atEndOfMicrotask: function () {
+var len = this._callbacks.length;
+for (var i = 0; i < len; i++) {
+var cb = this._callbacks[i];
+if (cb) {
+try {
+cb();
+} catch (e) {
+i++;
+this._callbacks.splice(0, i);
+this._lastVal += i;
+this._twiddle.textContent = this._twiddleContent++;
+throw e;
+}
+}
+}
+this._callbacks.splice(0, len);
+this._lastVal += len;
+}
+};
+new window.MutationObserver(function () {
+Polymer.Async._atEndOfMicrotask();
+}).observe(Polymer.Async._twiddle, { characterData: true });Polymer.Debounce = function () {
+var Async = Polymer.Async;
+var Debouncer = function (context) {
+this.context = context;
+var self = this;
+this.boundComplete = function () {
+self.complete();
+};
+};
+Debouncer.prototype = {
+go: function (callback, wait) {
+var h;
+this.finish = function () {
+Async.cancel(h);
+};
+h = Async.run(this.boundComplete, wait);
+this.callback = callback;
+},
+stop: function () {
+if (this.finish) {
+this.finish();
+this.finish = null;
+this.callback = null;
+}
+},
+complete: function () {
+if (this.finish) {
+var callback = this.callback;
+this.stop();
+callback.call(this.context);
+}
+}
+};
+function debounce(debouncer, callback, wait) {
+if (debouncer) {
+debouncer.stop();
+} else {
+debouncer = new Debouncer(this);
+}
+debouncer.go(callback, wait);
+return debouncer;
+}
+return debounce;
+}();Polymer.Base._addFeature({
+_setupDebouncers: function () {
+this._debouncers = {};
+},
+debounce: function (jobName, callback, wait) {
+return this._debouncers[jobName] = Polymer.Debounce.call(this, this._debouncers[jobName], callback, wait);
+},
+isDebouncerActive: function (jobName) {
+var debouncer = this._debouncers[jobName];
+return !!(debouncer && debouncer.finish);
+},
+flushDebouncer: function (jobName) {
+var debouncer = this._debouncers[jobName];
+if (debouncer) {
+debouncer.complete();
+}
+},
+cancelDebouncer: function (jobName) {
+var debouncer = this._debouncers[jobName];
+if (debouncer) {
+debouncer.stop();
+}
+}
+});Polymer.DomModule = document.createElement('dom-module');
+Polymer.Base._addFeature({
+_registerFeatures: function () {
+this._prepIs();
+this._prepBehaviors();
+this._prepConstructor();
+this._prepTemplate();
+this._prepShady();
+this._prepPropertyInfo();
+},
+_prepBehavior: function (b) {
+this._addHostAttributes(b.hostAttributes);
+},
+_initFeatures: function () {
+this._registerHost();
+if (this._template) {
+this._poolContent();
+this._beginHosting();
+this._stampTemplate();
+this._endHosting();
+}
+this._marshalHostAttributes();
+this._setupDebouncers();
+this._marshalBehaviors();
+this._tryReady();
+},
+_marshalBehavior: function (b) {
+}
+});</script>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer.html b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer.html
new file mode 100644
index 00000000000..3e158701bbb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/polymer/polymer.html
@@ -0,0 +1,5226 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+--><!--
+@license
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+--><link rel="import" href="polymer-mini.html">
+
+<script>Polymer.nar = [];
+Polymer.Annotations = {
+parseAnnotations: function (template) {
+var list = [];
+var content = template._content || template.content;
+this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
+return list;
+},
+_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
+return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
+},
+_bindingRegex: function () {
+var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
+var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
+var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
+var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
+var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
+var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
+var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
+var ARGUMENT_LIST = '(?:' + '\\(\\s*' + '(?:' + ARGUMENTS + '?' + ')' + '\\)\\s*' + ')';
+var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')';
+var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
+var CLOSE_BRACKET = '(?:]]|}})';
+var NEGATE = '(?:(!)\\s*)?';
+var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
+return new RegExp(EXPRESSION, 'g');
+}(),
+_parseBindings: function (text) {
+var re = this._bindingRegex;
+var parts = [];
+var lastIndex = 0;
+var m;
+while ((m = re.exec(text)) !== null) {
+if (m.index > lastIndex) {
+parts.push({ literal: text.slice(lastIndex, m.index) });
+}
+var mode = m[1][0];
+var negate = Boolean(m[2]);
+var value = m[3].trim();
+var customEvent, notifyEvent, colon;
+if (mode == '{' && (colon = value.indexOf('::')) > 0) {
+notifyEvent = value.substring(colon + 2);
+value = value.substring(0, colon);
+customEvent = true;
+}
+parts.push({
+compoundIndex: parts.length,
+value: value,
+mode: mode,
+negate: negate,
+event: notifyEvent,
+customEvent: customEvent
+});
+lastIndex = re.lastIndex;
+}
+if (lastIndex && lastIndex < text.length) {
+var literal = text.substring(lastIndex);
+if (literal) {
+parts.push({ literal: literal });
+}
+}
+if (parts.length) {
+return parts;
+}
+},
+_literalFromParts: function (parts) {
+var s = '';
+for (var i = 0; i < parts.length; i++) {
+var literal = parts[i].literal;
+s += literal || '';
+}
+return s;
+},
+_parseTextNodeAnnotation: function (node, list) {
+var parts = this._parseBindings(node.textContent);
+if (parts) {
+node.textContent = this._literalFromParts(parts) || ' ';
+var annote = {
+bindings: [{
+kind: 'text',
+name: 'textContent',
+parts: parts,
+isCompound: parts.length !== 1
+}]
+};
+list.push(annote);
+return annote;
+}
+},
+_parseElementAnnotations: function (element, list, stripWhiteSpace) {
+var annote = {
+bindings: [],
+events: []
+};
+if (element.localName === 'content') {
+list._hasContent = true;
+}
+this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
+if (element.attributes) {
+this._parseNodeAttributeAnnotations(element, annote, list);
+if (this.prepElement) {
+this.prepElement(element);
+}
+}
+if (annote.bindings.length || annote.events.length || annote.id) {
+list.push(annote);
+}
+return annote;
+},
+_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
+if (root.firstChild) {
+var node = root.firstChild;
+var i = 0;
+while (node) {
+var next = node.nextSibling;
+if (node.localName === 'template' && !node.hasAttribute('preserve-content')) {
+this._parseTemplate(node, i, list, annote);
+}
+if (node.nodeType === Node.TEXT_NODE) {
+var n = next;
+while (n && n.nodeType === Node.TEXT_NODE) {
+node.textContent += n.textContent;
+next = n.nextSibling;
+root.removeChild(n);
+n = next;
+}
+if (stripWhiteSpace && !node.textContent.trim()) {
+root.removeChild(node);
+i--;
+}
+}
+if (node.parentNode) {
+var childAnnotation = this._parseNodeAnnotations(node, list, stripWhiteSpace);
+if (childAnnotation) {
+childAnnotation.parent = annote;
+childAnnotation.index = i;
+}
+}
+node = next;
+i++;
+}
+}
+},
+_parseTemplate: function (node, index, list, parent) {
+var content = document.createDocumentFragment();
+content._notes = this.parseAnnotations(node);
+content.appendChild(node.content);
+list.push({
+bindings: Polymer.nar,
+events: Polymer.nar,
+templateContent: content,
+parent: parent,
+index: index
+});
+},
+_parseNodeAttributeAnnotations: function (node, annotation) {
+var attrs = Array.prototype.slice.call(node.attributes);
+for (var i = attrs.length - 1, a; a = attrs[i]; i--) {
+var n = a.name;
+var v = a.value;
+var b;
+if (n.slice(0, 3) === 'on-') {
+node.removeAttribute(n);
+annotation.events.push({
+name: n.slice(3),
+value: v
+});
+} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
+annotation.bindings.push(b);
+} else if (n === 'id') {
+annotation.id = v;
+}
+}
+},
+_parseNodeAttributeAnnotation: function (node, name, value) {
+var parts = this._parseBindings(value);
+if (parts) {
+var origName = name;
+var kind = 'property';
+if (name[name.length - 1] == '$') {
+name = name.slice(0, -1);
+kind = 'attribute';
+}
+var literal = this._literalFromParts(parts);
+if (literal && kind == 'attribute') {
+node.setAttribute(name, literal);
+}
+if (node.localName === 'input' && origName === 'value') {
+node.setAttribute(origName, '');
+}
+node.removeAttribute(origName);
+var propertyName = Polymer.CaseMap.dashToCamelCase(name);
+if (kind === 'property') {
+name = propertyName;
+}
+return {
+kind: kind,
+name: name,
+propertyName: propertyName,
+parts: parts,
+literal: literal,
+isCompound: parts.length !== 1
+};
+}
+},
+findAnnotatedNode: function (root, annote) {
+var parent = annote.parent && Polymer.Annotations.findAnnotatedNode(root, annote.parent);
+if (parent) {
+for (var n = parent.firstChild, i = 0; n; n = n.nextSibling) {
+if (annote.index === i++) {
+return n;
+}
+}
+} else {
+return root;
+}
+}
+};(function () {
+function resolveCss(cssText, ownerDocument) {
+return cssText.replace(CSS_URL_RX, function (m, pre, url, post) {
+return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + post;
+});
+}
+function resolveAttrs(element, ownerDocument) {
+for (var name in URL_ATTRS) {
+var a$ = URL_ATTRS[name];
+for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) {
+if (name === '*' || element.localName === name) {
+at = element.attributes[a];
+v = at && at.value;
+if (v && v.search(BINDING_RX) < 0) {
+at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocument);
+}
+}
+}
+}
+}
+function resolve(url, ownerDocument) {
+if (url && url[0] === '#') {
+return url;
+}
+var resolver = getUrlResolver(ownerDocument);
+resolver.href = url;
+return resolver.href || url;
+}
+var tempDoc;
+var tempDocBase;
+function resolveUrl(url, baseUri) {
+if (!tempDoc) {
+tempDoc = document.implementation.createHTMLDocument('temp');
+tempDocBase = tempDoc.createElement('base');
+tempDoc.head.appendChild(tempDocBase);
+}
+tempDocBase.href = baseUri;
+return resolve(url, tempDoc);
+}
+function getUrlResolver(ownerDocument) {
+return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocument.createElement('a'));
+}
+var CSS_URL_RX = /(url\()([^)]*)(\))/g;
+var URL_ATTRS = {
+'*': [
+'href',
+'src',
+'style',
+'url'
+],
+form: ['action']
+};
+var BINDING_RX = /\{\{|\[\[/;
+Polymer.ResolveUrl = {
+resolveCss: resolveCss,
+resolveAttrs: resolveAttrs,
+resolveUrl: resolveUrl
+};
+}());Polymer.Base._addFeature({
+_prepAnnotations: function () {
+if (!this._template) {
+this._notes = [];
+} else {
+var self = this;
+Polymer.Annotations.prepElement = function (element) {
+self._prepElement(element);
+};
+if (this._template._content && this._template._content._notes) {
+this._notes = this._template._content._notes;
+} else {
+this._notes = Polymer.Annotations.parseAnnotations(this._template);
+this._processAnnotations(this._notes);
+}
+Polymer.Annotations.prepElement = null;
+}
+},
+_processAnnotations: function (notes) {
+for (var i = 0; i < notes.length; i++) {
+var note = notes[i];
+for (var j = 0; j < note.bindings.length; j++) {
+var b = note.bindings[j];
+for (var k = 0; k < b.parts.length; k++) {
+var p = b.parts[k];
+if (!p.literal) {
+var signature = this._parseMethod(p.value);
+if (signature) {
+p.signature = signature;
+} else {
+p.model = this._modelForPath(p.value);
+}
+}
+}
+}
+if (note.templateContent) {
+this._processAnnotations(note.templateContent._notes);
+var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(note.templateContent._notes);
+var bindings = [];
+for (var prop in pp) {
+var name = '_parent_' + prop;
+bindings.push({
+index: note.index,
+kind: 'property',
+name: name,
+propertyName: name,
+parts: [{
+mode: '{',
+model: prop,
+value: prop
+}]
+});
+}
+note.bindings = note.bindings.concat(bindings);
+}
+}
+},
+_discoverTemplateParentProps: function (notes) {
+var pp = {};
+for (var i = 0, n; i < notes.length && (n = notes[i]); i++) {
+for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) {
+for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) {
+if (p.signature) {
+var args = p.signature.args;
+for (var kk = 0; kk < args.length; kk++) {
+var model = args[kk].model;
+if (model) {
+pp[model] = true;
+}
+}
+if (p.signature.dynamicFn) {
+pp[p.signature.method] = true;
+}
+} else {
+if (p.model) {
+pp[p.model] = true;
+}
+}
+}
+}
+if (n.templateContent) {
+var tpp = n.templateContent._parentProps;
+Polymer.Base.mixin(pp, tpp);
+}
+}
+return pp;
+},
+_prepElement: function (element) {
+Polymer.ResolveUrl.resolveAttrs(element, this._template.ownerDocument);
+},
+_findAnnotatedNode: Polymer.Annotations.findAnnotatedNode,
+_marshalAnnotationReferences: function () {
+if (this._template) {
+this._marshalIdNodes();
+this._marshalAnnotatedNodes();
+this._marshalAnnotatedListeners();
+}
+},
+_configureAnnotationReferences: function () {
+var notes = this._notes;
+var nodes = this._nodes;
+for (var i = 0; i < notes.length; i++) {
+var note = notes[i];
+var node = nodes[i];
+this._configureTemplateContent(note, node);
+this._configureCompoundBindings(note, node);
+}
+},
+_configureTemplateContent: function (note, node) {
+if (note.templateContent) {
+node._content = note.templateContent;
+}
+},
+_configureCompoundBindings: function (note, node) {
+var bindings = note.bindings;
+for (var i = 0; i < bindings.length; i++) {
+var binding = bindings[i];
+if (binding.isCompound) {
+var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {});
+var parts = binding.parts;
+var literals = new Array(parts.length);
+for (var j = 0; j < parts.length; j++) {
+literals[j] = parts[j].literal;
+}
+var name = binding.name;
+storage[name] = literals;
+if (binding.literal && binding.kind == 'property') {
+if (node._configValue) {
+node._configValue(name, binding.literal);
+} else {
+node[name] = binding.literal;
+}
+}
+}
+}
+},
+_marshalIdNodes: function () {
+this.$ = {};
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
+if (a.id) {
+this.$[a.id] = this._findAnnotatedNode(this.root, a);
+}
+}
+},
+_marshalAnnotatedNodes: function () {
+if (this._notes && this._notes.length) {
+var r = new Array(this._notes.length);
+for (var i = 0; i < this._notes.length; i++) {
+r[i] = this._findAnnotatedNode(this.root, this._notes[i]);
+}
+this._nodes = r;
+}
+},
+_marshalAnnotatedListeners: function () {
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
+if (a.events && a.events.length) {
+var node = this._findAnnotatedNode(this.root, a);
+for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
+this.listen(node, e.name, e.value);
+}
+}
+}
+}
+});Polymer.Base._addFeature({
+listeners: {},
+_listenListeners: function (listeners) {
+var node, name, eventName;
+for (eventName in listeners) {
+if (eventName.indexOf('.') < 0) {
+node = this;
+name = eventName;
+} else {
+name = eventName.split('.');
+node = this.$[name[0]];
+name = name[1];
+}
+this.listen(node, name, listeners[eventName]);
+}
+},
+listen: function (node, eventName, methodName) {
+var handler = this._recallEventHandler(this, eventName, node, methodName);
+if (!handler) {
+handler = this._createEventHandler(node, eventName, methodName);
+}
+if (handler._listening) {
+return;
+}
+this._listen(node, eventName, handler);
+handler._listening = true;
+},
+_boundListenerKey: function (eventName, methodName) {
+return eventName + ':' + methodName;
+},
+_recordEventHandler: function (host, eventName, target, methodName, handler) {
+var hbl = host.__boundListeners;
+if (!hbl) {
+hbl = host.__boundListeners = new WeakMap();
+}
+var bl = hbl.get(target);
+if (!bl) {
+bl = {};
+hbl.set(target, bl);
+}
+var key = this._boundListenerKey(eventName, methodName);
+bl[key] = handler;
+},
+_recallEventHandler: function (host, eventName, target, methodName) {
+var hbl = host.__boundListeners;
+if (!hbl) {
+return;
+}
+var bl = hbl.get(target);
+if (!bl) {
+return;
+}
+var key = this._boundListenerKey(eventName, methodName);
+return bl[key];
+},
+_createEventHandler: function (node, eventName, methodName) {
+var host = this;
+var handler = function (e) {
+if (host[methodName]) {
+host[methodName](e, e.detail);
+} else {
+host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined'));
+}
+};
+handler._listening = false;
+this._recordEventHandler(host, eventName, node, methodName, handler);
+return handler;
+},
+unlisten: function (node, eventName, methodName) {
+var handler = this._recallEventHandler(this, eventName, node, methodName);
+if (handler) {
+this._unlisten(node, eventName, handler);
+handler._listening = false;
+}
+},
+_listen: function (node, eventName, handler) {
+node.addEventListener(eventName, handler);
+},
+_unlisten: function (node, eventName, handler) {
+node.removeEventListener(eventName, handler);
+}
+});(function () {
+'use strict';
+var wrap = Polymer.DomApi.wrap;
+var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
+var GESTURE_KEY = '__polymerGestures';
+var HANDLED_OBJ = '__polymerGesturesHandled';
+var TOUCH_ACTION = '__polymerGesturesTouchAction';
+var TAP_DISTANCE = 25;
+var TRACK_DISTANCE = 5;
+var TRACK_LENGTH = 2;
+var MOUSE_TIMEOUT = 2500;
+var MOUSE_EVENTS = [
+'mousedown',
+'mousemove',
+'mouseup',
+'click'
+];
+var MOUSE_WHICH_TO_BUTTONS = [
+0,
+1,
+4,
+2
+];
+var MOUSE_HAS_BUTTONS = function () {
+try {
+return new MouseEvent('test', { buttons: 1 }).buttons === 1;
+} catch (e) {
+return false;
+}
+}();
+var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
+var mouseCanceller = function (mouseEvent) {
+mouseEvent[HANDLED_OBJ] = { skip: true };
+if (mouseEvent.type === 'click') {
+var path = Polymer.dom(mouseEvent).path;
+for (var i = 0; i < path.length; i++) {
+if (path[i] === POINTERSTATE.mouse.target) {
+return;
+}
+}
+mouseEvent.preventDefault();
+mouseEvent.stopPropagation();
+}
+};
+function setupTeardownMouseCanceller(setup) {
+for (var i = 0, en; i < MOUSE_EVENTS.length; i++) {
+en = MOUSE_EVENTS[i];
+if (setup) {
+document.addEventListener(en, mouseCanceller, true);
+} else {
+document.removeEventListener(en, mouseCanceller, true);
+}
+}
+}
+function ignoreMouse() {
+if (IS_TOUCH_ONLY) {
+return;
+}
+if (!POINTERSTATE.mouse.mouseIgnoreJob) {
+setupTeardownMouseCanceller(true);
+}
+var unset = function () {
+setupTeardownMouseCanceller();
+POINTERSTATE.mouse.target = null;
+POINTERSTATE.mouse.mouseIgnoreJob = null;
+};
+POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgnoreJob, unset, MOUSE_TIMEOUT);
+}
+function hasLeftMouseButton(ev) {
+var type = ev.type;
+if (MOUSE_EVENTS.indexOf(type) === -1) {
+return false;
+}
+if (type === 'mousemove') {
+var buttons = ev.buttons === undefined ? 1 : ev.buttons;
+if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
+buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
+}
+return Boolean(buttons & 1);
+} else {
+var button = ev.button === undefined ? 0 : ev.button;
+return button === 0;
+}
+}
+function isSyntheticClick(ev) {
+if (ev.type === 'click') {
+if (ev.detail === 0) {
+return true;
+}
+var t = Gestures.findOriginalTarget(ev);
+var bcr = t.getBoundingClientRect();
+var x = ev.pageX, y = ev.pageY;
+return !(x >= bcr.left && x <= bcr.right && (y >= bcr.top && y <= bcr.bottom));
+}
+return false;
+}
+var POINTERSTATE = {
+mouse: {
+target: null,
+mouseIgnoreJob: null
+},
+touch: {
+x: 0,
+y: 0,
+id: -1,
+scrollDecided: false
+}
+};
+function firstTouchAction(ev) {
+var path = Polymer.dom(ev).path;
+var ta = 'auto';
+for (var i = 0, n; i < path.length; i++) {
+n = path[i];
+if (n[TOUCH_ACTION]) {
+ta = n[TOUCH_ACTION];
+break;
+}
+}
+return ta;
+}
+function trackDocument(stateObj, movefn, upfn) {
+stateObj.movefn = movefn;
+stateObj.upfn = upfn;
+document.addEventListener('mousemove', movefn);
+document.addEventListener('mouseup', upfn);
+}
+function untrackDocument(stateObj) {
+document.removeEventListener('mousemove', stateObj.movefn);
+document.removeEventListener('mouseup', stateObj.upfn);
+stateObj.movefn = null;
+stateObj.upfn = null;
+}
+var Gestures = {
+gestures: {},
+recognizers: [],
+deepTargetFind: function (x, y) {
+var node = document.elementFromPoint(x, y);
+var next = node;
+while (next && next.shadowRoot) {
+next = next.shadowRoot.elementFromPoint(x, y);
+if (next) {
+node = next;
+}
+}
+return node;
+},
+findOriginalTarget: function (ev) {
+if (ev.path) {
+return ev.path[0];
+}
+return ev.target;
+},
+handleNative: function (ev) {
+var handled;
+var type = ev.type;
+var node = wrap(ev.currentTarget);
+var gobj = node[GESTURE_KEY];
+if (!gobj) {
+return;
+}
+var gs = gobj[type];
+if (!gs) {
+return;
+}
+if (!ev[HANDLED_OBJ]) {
+ev[HANDLED_OBJ] = {};
+if (type.slice(0, 5) === 'touch') {
+var t = ev.changedTouches[0];
+if (type === 'touchstart') {
+if (ev.touches.length === 1) {
+POINTERSTATE.touch.id = t.identifier;
+}
+}
+if (POINTERSTATE.touch.id !== t.identifier) {
+return;
+}
+if (!HAS_NATIVE_TA) {
+if (type === 'touchstart' || type === 'touchmove') {
+Gestures.handleTouchAction(ev);
+}
+}
+if (type === 'touchend') {
+POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget;
+ignoreMouse();
+}
+}
+}
+handled = ev[HANDLED_OBJ];
+if (handled.skip) {
+return;
+}
+var recognizers = Gestures.recognizers;
+for (var i = 0, r; i < recognizers.length; i++) {
+r = recognizers[i];
+if (gs[r.name] && !handled[r.name]) {
+if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
+r.reset();
+}
+}
+}
+for (i = 0, r; i < recognizers.length; i++) {
+r = recognizers[i];
+if (gs[r.name] && !handled[r.name]) {
+handled[r.name] = true;
+r[type](ev);
+}
+}
+},
+handleTouchAction: function (ev) {
+var t = ev.changedTouches[0];
+var type = ev.type;
+if (type === 'touchstart') {
+POINTERSTATE.touch.x = t.clientX;
+POINTERSTATE.touch.y = t.clientY;
+POINTERSTATE.touch.scrollDecided = false;
+} else if (type === 'touchmove') {
+if (POINTERSTATE.touch.scrollDecided) {
+return;
+}
+POINTERSTATE.touch.scrollDecided = true;
+var ta = firstTouchAction(ev);
+var prevent = false;
+var dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
+var dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
+if (!ev.cancelable) {
+} else if (ta === 'none') {
+prevent = true;
+} else if (ta === 'pan-x') {
+prevent = dy > dx;
+} else if (ta === 'pan-y') {
+prevent = dx > dy;
+}
+if (prevent) {
+ev.preventDefault();
+} else {
+Gestures.prevent('track');
+}
+}
+},
+add: function (node, evType, handler) {
+node = wrap(node);
+var recognizer = this.gestures[evType];
+var deps = recognizer.deps;
+var name = recognizer.name;
+var gobj = node[GESTURE_KEY];
+if (!gobj) {
+node[GESTURE_KEY] = gobj = {};
+}
+for (var i = 0, dep, gd; i < deps.length; i++) {
+dep = deps[i];
+if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1) {
+continue;
+}
+gd = gobj[dep];
+if (!gd) {
+gobj[dep] = gd = { _count: 0 };
+}
+if (gd._count === 0) {
+node.addEventListener(dep, this.handleNative);
+}
+gd[name] = (gd[name] || 0) + 1;
+gd._count = (gd._count || 0) + 1;
+}
+node.addEventListener(evType, handler);
+if (recognizer.touchAction) {
+this.setTouchAction(node, recognizer.touchAction);
+}
+},
+remove: function (node, evType, handler) {
+node = wrap(node);
+var recognizer = this.gestures[evType];
+var deps = recognizer.deps;
+var name = recognizer.name;
+var gobj = node[GESTURE_KEY];
+if (gobj) {
+for (var i = 0, dep, gd; i < deps.length; i++) {
+dep = deps[i];
+gd = gobj[dep];
+if (gd && gd[name]) {
+gd[name] = (gd[name] || 1) - 1;
+gd._count = (gd._count || 1) - 1;
+if (gd._count === 0) {
+node.removeEventListener(dep, this.handleNative);
+}
+}
+}
+}
+node.removeEventListener(evType, handler);
+},
+register: function (recog) {
+this.recognizers.push(recog);
+for (var i = 0; i < recog.emits.length; i++) {
+this.gestures[recog.emits[i]] = recog;
+}
+},
+findRecognizerByEvent: function (evName) {
+for (var i = 0, r; i < this.recognizers.length; i++) {
+r = this.recognizers[i];
+for (var j = 0, n; j < r.emits.length; j++) {
+n = r.emits[j];
+if (n === evName) {
+return r;
+}
+}
+}
+return null;
+},
+setTouchAction: function (node, value) {
+if (HAS_NATIVE_TA) {
+node.style.touchAction = value;
+}
+node[TOUCH_ACTION] = value;
+},
+fire: function (target, type, detail) {
+var ev = Polymer.Base.fire(type, detail, {
+node: target,
+bubbles: true,
+cancelable: true
+});
+if (ev.defaultPrevented) {
+var preventer = detail.preventer || detail.sourceEvent;
+if (preventer && preventer.preventDefault) {
+preventer.preventDefault();
+}
+}
+},
+prevent: function (evName) {
+var recognizer = this.findRecognizerByEvent(evName);
+if (recognizer.info) {
+recognizer.info.prevent = true;
+}
+},
+resetMouseCanceller: function () {
+if (POINTERSTATE.mouse.mouseIgnoreJob) {
+POINTERSTATE.mouse.mouseIgnoreJob.complete();
+}
+}
+};
+Gestures.register({
+name: 'downup',
+deps: [
+'mousedown',
+'touchstart',
+'touchend'
+],
+flow: {
+start: [
+'mousedown',
+'touchstart'
+],
+end: [
+'mouseup',
+'touchend'
+]
+},
+emits: [
+'down',
+'up'
+],
+info: {
+movefn: null,
+upfn: null
+},
+reset: function () {
+untrackDocument(this.info);
+},
+mousedown: function (e) {
+if (!hasLeftMouseButton(e)) {
+return;
+}
+var t = Gestures.findOriginalTarget(e);
+var self = this;
+var movefn = function movefn(e) {
+if (!hasLeftMouseButton(e)) {
+self.fire('up', t, e);
+untrackDocument(self.info);
+}
+};
+var upfn = function upfn(e) {
+if (hasLeftMouseButton(e)) {
+self.fire('up', t, e);
+}
+untrackDocument(self.info);
+};
+trackDocument(this.info, movefn, upfn);
+this.fire('down', t, e);
+},
+touchstart: function (e) {
+this.fire('down', Gestures.findOriginalTarget(e), e.changedTouches[0], e);
+},
+touchend: function (e) {
+this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0], e);
+},
+fire: function (type, target, event, preventer) {
+Gestures.fire(target, type, {
+x: event.clientX,
+y: event.clientY,
+sourceEvent: event,
+preventer: preventer,
+prevent: function (e) {
+return Gestures.prevent(e);
+}
+});
+}
+});
+Gestures.register({
+name: 'track',
+touchAction: 'none',
+deps: [
+'mousedown',
+'touchstart',
+'touchmove',
+'touchend'
+],
+flow: {
+start: [
+'mousedown',
+'touchstart'
+],
+end: [
+'mouseup',
+'touchend'
+]
+},
+emits: ['track'],
+info: {
+x: 0,
+y: 0,
+state: 'start',
+started: false,
+moves: [],
+addMove: function (move) {
+if (this.moves.length > TRACK_LENGTH) {
+this.moves.shift();
+}
+this.moves.push(move);
+},
+movefn: null,
+upfn: null,
+prevent: false
+},
+reset: function () {
+this.info.state = 'start';
+this.info.started = false;
+this.info.moves = [];
+this.info.x = 0;
+this.info.y = 0;
+this.info.prevent = false;
+untrackDocument(this.info);
+},
+hasMovedEnough: function (x, y) {
+if (this.info.prevent) {
+return false;
+}
+if (this.info.started) {
+return true;
+}
+var dx = Math.abs(this.info.x - x);
+var dy = Math.abs(this.info.y - y);
+return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
+},
+mousedown: function (e) {
+if (!hasLeftMouseButton(e)) {
+return;
+}
+var t = Gestures.findOriginalTarget(e);
+var self = this;
+var movefn = function movefn(e) {
+var x = e.clientX, y = e.clientY;
+if (self.hasMovedEnough(x, y)) {
+self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
+if (self.info.state === 'start') {
+Gestures.prevent('tap');
+}
+self.info.addMove({
+x: x,
+y: y
+});
+if (!hasLeftMouseButton(e)) {
+self.info.state = 'end';
+untrackDocument(self.info);
+}
+self.fire(t, e);
+self.info.started = true;
+}
+};
+var upfn = function upfn(e) {
+if (self.info.started) {
+movefn(e);
+}
+untrackDocument(self.info);
+};
+trackDocument(this.info, movefn, upfn);
+this.info.x = e.clientX;
+this.info.y = e.clientY;
+},
+touchstart: function (e) {
+var ct = e.changedTouches[0];
+this.info.x = ct.clientX;
+this.info.y = ct.clientY;
+},
+touchmove: function (e) {
+var t = Gestures.findOriginalTarget(e);
+var ct = e.changedTouches[0];
+var x = ct.clientX, y = ct.clientY;
+if (this.hasMovedEnough(x, y)) {
+if (this.info.state === 'start') {
+Gestures.prevent('tap');
+}
+this.info.addMove({
+x: x,
+y: y
+});
+this.fire(t, ct);
+this.info.state = 'track';
+this.info.started = true;
+}
+},
+touchend: function (e) {
+var t = Gestures.findOriginalTarget(e);
+var ct = e.changedTouches[0];
+if (this.info.started) {
+this.info.state = 'end';
+this.info.addMove({
+x: ct.clientX,
+y: ct.clientY
+});
+this.fire(t, ct, e);
+}
+},
+fire: function (target, touch, preventer) {
+var secondlast = this.info.moves[this.info.moves.length - 2];
+var lastmove = this.info.moves[this.info.moves.length - 1];
+var dx = lastmove.x - this.info.x;
+var dy = lastmove.y - this.info.y;
+var ddx, ddy = 0;
+if (secondlast) {
+ddx = lastmove.x - secondlast.x;
+ddy = lastmove.y - secondlast.y;
+}
+return Gestures.fire(target, 'track', {
+state: this.info.state,
+x: touch.clientX,
+y: touch.clientY,
+dx: dx,
+dy: dy,
+ddx: ddx,
+ddy: ddy,
+sourceEvent: touch,
+preventer: preventer,
+hover: function () {
+return Gestures.deepTargetFind(touch.clientX, touch.clientY);
+}
+});
+}
+});
+Gestures.register({
+name: 'tap',
+deps: [
+'mousedown',
+'click',
+'touchstart',
+'touchend'
+],
+flow: {
+start: [
+'mousedown',
+'touchstart'
+],
+end: [
+'click',
+'touchend'
+]
+},
+emits: ['tap'],
+info: {
+x: NaN,
+y: NaN,
+prevent: false
+},
+reset: function () {
+this.info.x = NaN;
+this.info.y = NaN;
+this.info.prevent = false;
+},
+save: function (e) {
+this.info.x = e.clientX;
+this.info.y = e.clientY;
+},
+mousedown: function (e) {
+if (hasLeftMouseButton(e)) {
+this.save(e);
+}
+},
+click: function (e) {
+if (hasLeftMouseButton(e)) {
+this.forward(e);
+}
+},
+touchstart: function (e) {
+this.save(e.changedTouches[0], e);
+},
+touchend: function (e) {
+this.forward(e.changedTouches[0], e);
+},
+forward: function (e, preventer) {
+var dx = Math.abs(e.clientX - this.info.x);
+var dy = Math.abs(e.clientY - this.info.y);
+var t = Gestures.findOriginalTarget(e);
+if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) {
+if (!this.info.prevent) {
+Gestures.fire(t, 'tap', {
+x: e.clientX,
+y: e.clientY,
+sourceEvent: e,
+preventer: preventer
+});
+}
+}
+}
+});
+var DIRECTION_MAP = {
+x: 'pan-x',
+y: 'pan-y',
+none: 'none',
+all: 'auto'
+};
+Polymer.Base._addFeature({
+_setupGestures: function () {
+this.__polymerGestures = null;
+},
+_listen: function (node, eventName, handler) {
+if (Gestures.gestures[eventName]) {
+Gestures.add(node, eventName, handler);
+} else {
+node.addEventListener(eventName, handler);
+}
+},
+_unlisten: function (node, eventName, handler) {
+if (Gestures.gestures[eventName]) {
+Gestures.remove(node, eventName, handler);
+} else {
+node.removeEventListener(eventName, handler);
+}
+},
+setScrollDirection: function (direction, node) {
+node = node || this;
+Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto');
+}
+});
+Polymer.Gestures = Gestures;
+}());(function () {
+'use strict';
+Polymer.Base._addFeature({
+$$: function (slctr) {
+return Polymer.dom(this.root).querySelector(slctr);
+},
+toggleClass: function (name, bool, node) {
+node = node || this;
+if (arguments.length == 1) {
+bool = !node.classList.contains(name);
+}
+if (bool) {
+Polymer.dom(node).classList.add(name);
+} else {
+Polymer.dom(node).classList.remove(name);
+}
+},
+toggleAttribute: function (name, bool, node) {
+node = node || this;
+if (arguments.length == 1) {
+bool = !node.hasAttribute(name);
+}
+if (bool) {
+Polymer.dom(node).setAttribute(name, '');
+} else {
+Polymer.dom(node).removeAttribute(name);
+}
+},
+classFollows: function (name, toElement, fromElement) {
+if (fromElement) {
+Polymer.dom(fromElement).classList.remove(name);
+}
+if (toElement) {
+Polymer.dom(toElement).classList.add(name);
+}
+},
+attributeFollows: function (name, toElement, fromElement) {
+if (fromElement) {
+Polymer.dom(fromElement).removeAttribute(name);
+}
+if (toElement) {
+Polymer.dom(toElement).setAttribute(name, '');
+}
+},
+getEffectiveChildNodes: function () {
+return Polymer.dom(this).getEffectiveChildNodes();
+},
+getEffectiveChildren: function () {
+var list = Polymer.dom(this).getEffectiveChildNodes();
+return list.filter(function (n) {
+return n.nodeType === Node.ELEMENT_NODE;
+});
+},
+getEffectiveTextContent: function () {
+var cn = this.getEffectiveChildNodes();
+var tc = [];
+for (var i = 0, c; c = cn[i]; i++) {
+if (c.nodeType !== Node.COMMENT_NODE) {
+tc.push(Polymer.dom(c).textContent);
+}
+}
+return tc.join('');
+},
+queryEffectiveChildren: function (slctr) {
+var e$ = Polymer.dom(this).queryDistributedElements(slctr);
+return e$ && e$[0];
+},
+queryAllEffectiveChildren: function (slctr) {
+return Polymer.dom(this).queryDistributedElements(slctr);
+},
+getContentChildNodes: function (slctr) {
+var content = Polymer.dom(this.root).querySelector(slctr || 'content');
+return content ? Polymer.dom(content).getDistributedNodes() : [];
+},
+getContentChildren: function (slctr) {
+return this.getContentChildNodes(slctr).filter(function (n) {
+return n.nodeType === Node.ELEMENT_NODE;
+});
+},
+fire: function (type, detail, options) {
+options = options || Polymer.nob;
+var node = options.node || this;
+detail = detail === null || detail === undefined ? {} : detail;
+var bubbles = options.bubbles === undefined ? true : options.bubbles;
+var cancelable = Boolean(options.cancelable);
+var useCache = options._useCache;
+var event = this._getEvent(type, bubbles, cancelable, useCache);
+event.detail = detail;
+if (useCache) {
+this.__eventCache[type] = null;
+}
+node.dispatchEvent(event);
+if (useCache) {
+this.__eventCache[type] = event;
+}
+return event;
+},
+__eventCache: {},
+_getEvent: function (type, bubbles, cancelable, useCache) {
+var event = useCache && this.__eventCache[type];
+if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) {
+event = new Event(type, {
+bubbles: Boolean(bubbles),
+cancelable: cancelable
+});
+}
+return event;
+},
+async: function (callback, waitTime) {
+var self = this;
+return Polymer.Async.run(function () {
+callback.call(self);
+}, waitTime);
+},
+cancelAsync: function (handle) {
+Polymer.Async.cancel(handle);
+},
+arrayDelete: function (path, item) {
+var index;
+if (Array.isArray(path)) {
+index = path.indexOf(item);
+if (index >= 0) {
+return path.splice(index, 1);
+}
+} else {
+var arr = this._get(path);
+index = arr.indexOf(item);
+if (index >= 0) {
+return this.splice(path, index, 1);
+}
+}
+},
+transform: function (transform, node) {
+node = node || this;
+node.style.webkitTransform = transform;
+node.style.transform = transform;
+},
+translate3d: function (x, y, z, node) {
+node = node || this;
+this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);
+},
+importHref: function (href, onload, onerror, optAsync) {
+var link = document.createElement('link');
+link.rel = 'import';
+link.href = href;
+var list = Polymer.Base.importHref.imported = Polymer.Base.importHref.imported || {};
+var cached = list[link.href];
+var imprt = cached || link;
+var self = this;
+if (onload) {
+var loadListener = function (e) {
+e.target.__firedLoad = true;
+e.target.removeEventListener('load', loadListener);
+return onload.call(self, e);
+};
+imprt.addEventListener('load', loadListener);
+}
+if (onerror) {
+var errorListener = function (e) {
+e.target.__firedError = true;
+e.target.removeEventListener('error', errorListener);
+return onerror.call(self, e);
+};
+imprt.addEventListener('error', errorListener);
+}
+if (cached) {
+if (cached.__firedLoad) {
+cached.dispatchEvent(new Event('load'));
+}
+if (cached.__firedError) {
+cached.dispatchEvent(new Event('error'));
+}
+} else {
+list[link.href] = link;
+optAsync = Boolean(optAsync);
+if (optAsync) {
+link.setAttribute('async', '');
+}
+document.head.appendChild(link);
+}
+return imprt;
+},
+create: function (tag, props) {
+var elt = document.createElement(tag);
+if (props) {
+for (var n in props) {
+elt[n] = props[n];
+}
+}
+return elt;
+},
+isLightDescendant: function (node) {
+return this !== node && this.contains(node) && Polymer.dom(this).getOwnerRoot() === Polymer.dom(node).getOwnerRoot();
+},
+isLocalDescendant: function (node) {
+return this.root === Polymer.dom(node).getOwnerRoot();
+}
+});
+if (!Polymer.Settings.useNativeCustomElements) {
+var importHref = Polymer.Base.importHref;
+Polymer.Base.importHref = function (href, onload, onerror, optAsync) {
+CustomElements.ready = false;
+var loadFn = function (e) {
+CustomElements.upgradeDocumentTree(document);
+CustomElements.ready = true;
+if (onload) {
+return onload.call(this, e);
+}
+};
+return importHref.call(this, href, loadFn, onerror, optAsync);
+};
+}
+}());Polymer.Bind = {
+prepareModel: function (model) {
+Polymer.Base.mixin(model, this._modelApi);
+},
+_modelApi: {
+_notifyChange: function (source, event, value) {
+value = value === undefined ? this[source] : value;
+event = event || Polymer.CaseMap.camelToDashCase(source) + '-changed';
+this.fire(event, { value: value }, {
+bubbles: false,
+cancelable: false,
+_useCache: true
+});
+},
+_propertySetter: function (property, value, effects, fromAbove) {
+var old = this.__data__[property];
+if (old !== value && (old === old || value === value)) {
+this.__data__[property] = value;
+if (typeof value == 'object') {
+this._clearPath(property);
+}
+if (this._propertyChanged) {
+this._propertyChanged(property, value, old);
+}
+if (effects) {
+this._effectEffects(property, value, effects, old, fromAbove);
+}
+}
+return old;
+},
+__setProperty: function (property, value, quiet, node) {
+node = node || this;
+var effects = node._propertyEffects && node._propertyEffects[property];
+if (effects) {
+node._propertySetter(property, value, effects, quiet);
+} else {
+node[property] = value;
+}
+},
+_effectEffects: function (property, value, effects, old, fromAbove) {
+for (var i = 0, l = effects.length, fx; i < l && (fx = effects[i]); i++) {
+fx.fn.call(this, property, this[property], fx.effect, old, fromAbove);
+}
+},
+_clearPath: function (path) {
+for (var prop in this.__data__) {
+if (prop.indexOf(path + '.') === 0) {
+this.__data__[prop] = undefined;
+}
+}
+}
+},
+ensurePropertyEffects: function (model, property) {
+if (!model._propertyEffects) {
+model._propertyEffects = {};
+}
+var fx = model._propertyEffects[property];
+if (!fx) {
+fx = model._propertyEffects[property] = [];
+}
+return fx;
+},
+addPropertyEffect: function (model, property, kind, effect) {
+var fx = this.ensurePropertyEffects(model, property);
+var propEffect = {
+kind: kind,
+effect: effect,
+fn: Polymer.Bind['_' + kind + 'Effect']
+};
+fx.push(propEffect);
+return propEffect;
+},
+createBindings: function (model) {
+var fx$ = model._propertyEffects;
+if (fx$) {
+for (var n in fx$) {
+var fx = fx$[n];
+fx.sort(this._sortPropertyEffects);
+this._createAccessors(model, n, fx);
+}
+}
+},
+_sortPropertyEffects: function () {
+var EFFECT_ORDER = {
+'compute': 0,
+'annotation': 1,
+'annotatedComputation': 2,
+'reflect': 3,
+'notify': 4,
+'observer': 5,
+'complexObserver': 6,
+'function': 7
+};
+return function (a, b) {
+return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind];
+};
+}(),
+_createAccessors: function (model, property, effects) {
+var defun = {
+get: function () {
+return this.__data__[property];
+}
+};
+var setter = function (value) {
+this._propertySetter(property, value, effects);
+};
+var info = model.getPropertyInfo && model.getPropertyInfo(property);
+if (info && info.readOnly) {
+if (!info.computed) {
+model['_set' + this.upper(property)] = setter;
+}
+} else {
+defun.set = setter;
+}
+Object.defineProperty(model, property, defun);
+},
+upper: function (name) {
+return name[0].toUpperCase() + name.substring(1);
+},
+_addAnnotatedListener: function (model, index, property, path, event, negated) {
+if (!model._bindListeners) {
+model._bindListeners = [];
+}
+var fn = this._notedListenerFactory(property, path, this._isStructured(path), negated);
+var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed';
+model._bindListeners.push({
+index: index,
+property: property,
+path: path,
+changedFn: fn,
+event: eventName
+});
+},
+_isStructured: function (path) {
+return path.indexOf('.') > 0;
+},
+_isEventBogus: function (e, target) {
+return e.path && e.path[0] !== target;
+},
+_notedListenerFactory: function (property, path, isStructured, negated) {
+return function (target, value, targetPath) {
+if (targetPath) {
+this._notifyPath(this._fixPath(path, property, targetPath), value);
+} else {
+value = target[property];
+if (negated) {
+value = !value;
+}
+if (!isStructured) {
+this[path] = value;
+} else {
+if (this.__data__[path] != value) {
+this.set(path, value);
+}
+}
+}
+};
+},
+prepareInstance: function (inst) {
+inst.__data__ = Object.create(null);
+},
+setupBindListeners: function (inst) {
+var b$ = inst._bindListeners;
+for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
+var node = inst._nodes[info.index];
+this._addNotifyListener(node, inst, info.event, info.changedFn);
+}
+},
+_addNotifyListener: function (element, context, event, changedFn) {
+element.addEventListener(event, function (e) {
+return context._notifyListener(changedFn, e);
+});
+}
+};Polymer.Base.extend(Polymer.Bind, {
+_shouldAddListener: function (effect) {
+return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{';
+},
+_annotationEffect: function (source, value, effect) {
+if (source != effect.value) {
+value = this._get(effect.value);
+this.__data__[effect.value] = value;
+}
+this._applyEffectValue(effect, value);
+},
+_reflectEffect: function (source, value, effect) {
+this.reflectPropertyToAttribute(source, effect.attribute, value);
+},
+_notifyEffect: function (source, value, effect, old, fromAbove) {
+if (!fromAbove) {
+this._notifyChange(source, effect.event, value);
+}
+},
+_functionEffect: function (source, value, fn, old, fromAbove) {
+fn.call(this, source, value, old, fromAbove);
+},
+_observerEffect: function (source, value, effect, old) {
+var fn = this[effect.method];
+if (fn) {
+fn.call(this, value, old);
+} else {
+this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '` not defined'));
+}
+},
+_complexObserverEffect: function (source, value, effect) {
+var fn = this[effect.method];
+if (fn) {
+var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
+if (args) {
+fn.apply(this, args);
+}
+} else if (effect.dynamicFn) {
+} else {
+this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
+}
+},
+_computeEffect: function (source, value, effect) {
+var fn = this[effect.method];
+if (fn) {
+var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
+if (args) {
+var computedvalue = fn.apply(this, args);
+this.__setProperty(effect.name, computedvalue);
+}
+} else if (effect.dynamicFn) {
+} else {
+this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
+}
+},
+_annotatedComputationEffect: function (source, value, effect) {
+var computedHost = this._rootDataHost || this;
+var fn = computedHost[effect.method];
+if (fn) {
+var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
+if (args) {
+var computedvalue = fn.apply(computedHost, args);
+this._applyEffectValue(effect, computedvalue);
+}
+} else if (effect.dynamicFn) {
+} else {
+computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
+}
+},
+_marshalArgs: function (model, effect, path, value) {
+var values = [];
+var args = effect.args;
+var bailoutEarly = args.length > 1 || effect.dynamicFn;
+for (var i = 0, l = args.length; i < l; i++) {
+var arg = args[i];
+var name = arg.name;
+var v;
+if (arg.literal) {
+v = arg.value;
+} else if (path === name) {
+v = value;
+} else {
+v = model[name];
+if (v === undefined && arg.structured) {
+v = Polymer.Base._get(name, model);
+}
+}
+if (bailoutEarly && v === undefined) {
+return;
+}
+if (arg.wildcard) {
+var matches = path.indexOf(name + '.') === 0;
+values[i] = {
+path: matches ? path : name,
+value: matches ? value : v,
+base: v
+};
+} else {
+values[i] = v;
+}
+}
+return values;
+}
+});Polymer.Base._addFeature({
+_addPropertyEffect: function (property, kind, effect) {
+var prop = Polymer.Bind.addPropertyEffect(this, property, kind, effect);
+prop.pathFn = this['_' + prop.kind + 'PathEffect'];
+},
+_prepEffects: function () {
+Polymer.Bind.prepareModel(this);
+this._addAnnotationEffects(this._notes);
+},
+_prepBindings: function () {
+Polymer.Bind.createBindings(this);
+},
+_addPropertyEffects: function (properties) {
+if (properties) {
+for (var p in properties) {
+var prop = properties[p];
+if (prop.observer) {
+this._addObserverEffect(p, prop.observer);
+}
+if (prop.computed) {
+prop.readOnly = true;
+this._addComputedEffect(p, prop.computed);
+}
+if (prop.notify) {
+this._addPropertyEffect(p, 'notify', { event: Polymer.CaseMap.camelToDashCase(p) + '-changed' });
+}
+if (prop.reflectToAttribute) {
+var attr = Polymer.CaseMap.camelToDashCase(p);
+if (attr[0] === '-') {
+this._warn(this._logf('_addPropertyEffects', 'Property ' + p + ' cannot be reflected to attribute ' + attr + ' because "-" is not a valid starting attribute name. Use a lowercase first letter for the property instead.'));
+} else {
+this._addPropertyEffect(p, 'reflect', { attribute: attr });
+}
+}
+if (prop.readOnly) {
+Polymer.Bind.ensurePropertyEffects(this, p);
+}
+}
+}
+},
+_addComputedEffect: function (name, expression) {
+var sig = this._parseMethod(expression);
+var dynamicFn = sig.dynamicFn;
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
+this._addPropertyEffect(arg.model, 'compute', {
+method: sig.method,
+args: sig.args,
+trigger: arg,
+name: name,
+dynamicFn: dynamicFn
+});
+}
+if (dynamicFn) {
+this._addPropertyEffect(sig.method, 'compute', {
+method: sig.method,
+args: sig.args,
+trigger: null,
+name: name,
+dynamicFn: dynamicFn
+});
+}
+},
+_addObserverEffect: function (property, observer) {
+this._addPropertyEffect(property, 'observer', {
+method: observer,
+property: property
+});
+},
+_addComplexObserverEffects: function (observers) {
+if (observers) {
+for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
+this._addComplexObserverEffect(o);
+}
+}
+},
+_addComplexObserverEffect: function (observer) {
+var sig = this._parseMethod(observer);
+if (!sig) {
+throw new Error('Malformed observer expression \'' + observer + '\'');
+}
+var dynamicFn = sig.dynamicFn;
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
+this._addPropertyEffect(arg.model, 'complexObserver', {
+method: sig.method,
+args: sig.args,
+trigger: arg,
+dynamicFn: dynamicFn
+});
+}
+if (dynamicFn) {
+this._addPropertyEffect(sig.method, 'complexObserver', {
+method: sig.method,
+args: sig.args,
+trigger: null,
+dynamicFn: dynamicFn
+});
+}
+},
+_addAnnotationEffects: function (notes) {
+for (var i = 0, note; i < notes.length && (note = notes[i]); i++) {
+var b$ = note.bindings;
+for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) {
+this._addAnnotationEffect(binding, i);
+}
+}
+},
+_addAnnotationEffect: function (note, index) {
+if (Polymer.Bind._shouldAddListener(note)) {
+Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event, note.parts[0].negate);
+}
+for (var i = 0; i < note.parts.length; i++) {
+var part = note.parts[i];
+if (part.signature) {
+this._addAnnotatedComputationEffect(note, part, index);
+} else if (!part.literal) {
+if (note.kind === 'attribute' && note.name[0] === '-') {
+this._warn(this._logf('_addAnnotationEffect', 'Cannot set attribute ' + note.name + ' because "-" is not a valid attribute starting character'));
+} else {
+this._addPropertyEffect(part.model, 'annotation', {
+kind: note.kind,
+index: index,
+name: note.name,
+propertyName: note.propertyName,
+value: part.value,
+isCompound: note.isCompound,
+compoundIndex: part.compoundIndex,
+event: part.event,
+customEvent: part.customEvent,
+negate: part.negate
+});
+}
+}
+}
+},
+_addAnnotatedComputationEffect: function (note, part, index) {
+var sig = part.signature;
+if (sig.static) {
+this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
+} else {
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
+if (!arg.literal) {
+this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
+}
+}
+if (sig.dynamicFn) {
+this.__addAnnotatedComputationEffect(sig.method, index, note, part, null);
+}
+}
+},
+__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
+this._addPropertyEffect(property, 'annotatedComputation', {
+index: index,
+isCompound: note.isCompound,
+compoundIndex: part.compoundIndex,
+kind: note.kind,
+name: note.name,
+negate: part.negate,
+method: part.signature.method,
+args: part.signature.args,
+trigger: trigger,
+dynamicFn: part.signature.dynamicFn
+});
+},
+_parseMethod: function (expression) {
+var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
+if (m) {
+var sig = {
+method: m[1],
+static: true
+};
+if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
+sig.static = false;
+sig.dynamicFn = true;
+}
+if (m[2].trim()) {
+var args = m[2].replace(/\\,/g, '&comma;').split(',');
+return this._parseArgs(args, sig);
+} else {
+sig.args = Polymer.nar;
+return sig;
+}
+}
+},
+_parseArgs: function (argList, sig) {
+sig.args = argList.map(function (rawArg) {
+var arg = this._parseArg(rawArg);
+if (!arg.literal) {
+sig.static = false;
+}
+return arg;
+}, this);
+return sig;
+},
+_parseArg: function (rawArg) {
+var arg = rawArg.trim().replace(/&comma;/g, ',').replace(/\\(.)/g, '$1');
+var a = { name: arg };
+var fc = arg[0];
+if (fc === '-') {
+fc = arg[1];
+}
+if (fc >= '0' && fc <= '9') {
+fc = '#';
+}
+switch (fc) {
+case '\'':
+case '"':
+a.value = arg.slice(1, -1);
+a.literal = true;
+break;
+case '#':
+a.value = Number(arg);
+a.literal = true;
+break;
+}
+if (!a.literal) {
+a.model = this._modelForPath(arg);
+a.structured = arg.indexOf('.') > 0;
+if (a.structured) {
+a.wildcard = arg.slice(-2) == '.*';
+if (a.wildcard) {
+a.name = arg.slice(0, -2);
+}
+}
+}
+return a;
+},
+_marshalInstanceEffects: function () {
+Polymer.Bind.prepareInstance(this);
+if (this._bindListeners) {
+Polymer.Bind.setupBindListeners(this);
+}
+},
+_applyEffectValue: function (info, value) {
+var node = this._nodes[info.index];
+var property = info.name;
+value = this._computeFinalAnnotationValue(node, property, value, info);
+if (info.customEvent && node[property] === value) {
+return;
+}
+if (info.kind == 'attribute') {
+this.serializeValueToAttribute(value, property, node);
+} else {
+var pinfo = node._propertyInfo && node._propertyInfo[property];
+if (pinfo && pinfo.readOnly) {
+return;
+}
+this.__setProperty(property, value, false, node);
+}
+},
+_computeFinalAnnotationValue: function (node, property, value, info) {
+if (info.negate) {
+value = !value;
+}
+if (info.isCompound) {
+var storage = node.__compoundStorage__[property];
+storage[info.compoundIndex] = value;
+value = storage.join('');
+}
+if (info.kind !== 'attribute') {
+if (property === 'className') {
+value = this._scopeElementClass(node, value);
+}
+if (property === 'textContent' || node.localName == 'input' && property == 'value') {
+value = value == undefined ? '' : value;
+}
+}
+return value;
+},
+_executeStaticEffects: function () {
+if (this._propertyEffects && this._propertyEffects.__static__) {
+this._effectEffects('__static__', null, this._propertyEffects.__static__);
+}
+}
+});(function () {
+var usePolyfillProto = Polymer.Settings.usePolyfillProto;
+Polymer.Base._addFeature({
+_setupConfigure: function (initialConfig) {
+this._config = {};
+this._handlers = [];
+this._aboveConfig = null;
+if (initialConfig) {
+for (var i in initialConfig) {
+if (initialConfig[i] !== undefined) {
+this._config[i] = initialConfig[i];
+}
+}
+}
+},
+_marshalAttributes: function () {
+this._takeAttributesToModel(this._config);
+},
+_attributeChangedImpl: function (name) {
+var model = this._clientsReadied ? this : this._config;
+this._setAttributeToProperty(model, name);
+},
+_configValue: function (name, value) {
+var info = this._propertyInfo[name];
+if (!info || !info.readOnly) {
+this._config[name] = value;
+}
+},
+_beforeClientsReady: function () {
+this._configure();
+},
+_configure: function () {
+this._configureAnnotationReferences();
+this._aboveConfig = this.mixin({}, this._config);
+var config = {};
+for (var i = 0; i < this.behaviors.length; i++) {
+this._configureProperties(this.behaviors[i].properties, config);
+}
+this._configureProperties(this.properties, config);
+this.mixin(config, this._aboveConfig);
+this._config = config;
+if (this._clients && this._clients.length) {
+this._distributeConfig(this._config);
+}
+},
+_configureProperties: function (properties, config) {
+for (var i in properties) {
+var c = properties[i];
+if (!usePolyfillProto && this.hasOwnProperty(i) && this._propertyEffects && this._propertyEffects[i]) {
+config[i] = this[i];
+delete this[i];
+} else if (c.value !== undefined) {
+var value = c.value;
+if (typeof value == 'function') {
+value = value.call(this, this._config);
+}
+config[i] = value;
+}
+}
+},
+_distributeConfig: function (config) {
+var fx$ = this._propertyEffects;
+if (fx$) {
+for (var p in config) {
+var fx = fx$[p];
+if (fx) {
+for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
+if (x.kind === 'annotation') {
+var node = this._nodes[x.effect.index];
+var name = x.effect.propertyName;
+var isAttr = x.effect.kind == 'attribute';
+var hasEffect = node._propertyEffects && node._propertyEffects[name];
+if (node._configValue && (hasEffect || !isAttr)) {
+var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
+value = this._computeFinalAnnotationValue(node, name, value, x.effect);
+if (isAttr) {
+value = node.deserialize(this.serialize(value), node._propertyInfo[name].type);
+}
+node._configValue(name, value);
+}
+}
+}
+}
+}
+}
+},
+_afterClientsReady: function () {
+this._executeStaticEffects();
+this._applyConfig(this._config, this._aboveConfig);
+this._flushHandlers();
+},
+_applyConfig: function (config, aboveConfig) {
+for (var n in config) {
+if (this[n] === undefined) {
+this.__setProperty(n, config[n], n in aboveConfig);
+}
+}
+},
+_notifyListener: function (fn, e) {
+if (!Polymer.Bind._isEventBogus(e, e.target)) {
+var value, path;
+if (e.detail) {
+value = e.detail.value;
+path = e.detail.path;
+}
+if (!this._clientsReadied) {
+this._queueHandler([
+fn,
+e.target,
+value,
+path
+]);
+} else {
+return fn.call(this, e.target, value, path);
+}
+}
+},
+_queueHandler: function (args) {
+this._handlers.push(args);
+},
+_flushHandlers: function () {
+var h$ = this._handlers;
+for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) {
+h[0].call(this, h[1], h[2], h[3]);
+}
+this._handlers = [];
+}
+});
+}());(function () {
+'use strict';
+Polymer.Base._addFeature({
+notifyPath: function (path, value, fromAbove) {
+var info = {};
+var v = this._get(path, this, info);
+if (arguments.length === 1) {
+value = v;
+}
+if (info.path) {
+this._notifyPath(info.path, value, fromAbove);
+}
+},
+_notifyPath: function (path, value, fromAbove) {
+var old = this._propertySetter(path, value);
+if (old !== value && (old === old || value === value)) {
+this._pathEffector(path, value);
+if (!fromAbove) {
+this._notifyPathUp(path, value);
+}
+return true;
+}
+},
+_getPathParts: function (path) {
+if (Array.isArray(path)) {
+var parts = [];
+for (var i = 0; i < path.length; i++) {
+var args = path[i].toString().split('.');
+for (var j = 0; j < args.length; j++) {
+parts.push(args[j]);
+}
+}
+return parts;
+} else {
+return path.toString().split('.');
+}
+},
+set: function (path, value, root) {
+var prop = root || this;
+var parts = this._getPathParts(path);
+var array;
+var last = parts[parts.length - 1];
+if (parts.length > 1) {
+for (var i = 0; i < parts.length - 1; i++) {
+var part = parts[i];
+if (array && part[0] == '#') {
+prop = Polymer.Collection.get(array).getItem(part);
+} else {
+prop = prop[part];
+if (array && parseInt(part, 10) == part) {
+parts[i] = Polymer.Collection.get(array).getKey(prop);
+}
+}
+if (!prop) {
+return;
+}
+array = Array.isArray(prop) ? prop : null;
+}
+if (array) {
+var coll = Polymer.Collection.get(array);
+var old, key;
+if (last[0] == '#') {
+key = last;
+old = coll.getItem(key);
+last = array.indexOf(old);
+coll.setItem(key, value);
+} else if (parseInt(last, 10) == last) {
+old = prop[last];
+key = coll.getKey(old);
+parts[i] = key;
+coll.setItem(key, value);
+}
+}
+prop[last] = value;
+if (!root) {
+this._notifyPath(parts.join('.'), value);
+}
+} else {
+prop[path] = value;
+}
+},
+get: function (path, root) {
+return this._get(path, root);
+},
+_get: function (path, root, info) {
+var prop = root || this;
+var parts = this._getPathParts(path);
+var array;
+for (var i = 0; i < parts.length; i++) {
+if (!prop) {
+return;
+}
+var part = parts[i];
+if (array && part[0] == '#') {
+prop = Polymer.Collection.get(array).getItem(part);
+} else {
+prop = prop[part];
+if (info && array && parseInt(part, 10) == part) {
+parts[i] = Polymer.Collection.get(array).getKey(prop);
+}
+}
+array = Array.isArray(prop) ? prop : null;
+}
+if (info) {
+info.path = parts.join('.');
+}
+return prop;
+},
+_pathEffector: function (path, value) {
+var model = this._modelForPath(path);
+var fx$ = this._propertyEffects && this._propertyEffects[model];
+if (fx$) {
+for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) {
+var fxFn = fx.pathFn;
+if (fxFn) {
+fxFn.call(this, path, value, fx.effect);
+}
+}
+}
+if (this._boundPaths) {
+this._notifyBoundPaths(path, value);
+}
+},
+_annotationPathEffect: function (path, value, effect) {
+if (effect.value === path || effect.value.indexOf(path + '.') === 0) {
+Polymer.Bind._annotationEffect.call(this, path, value, effect);
+} else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) {
+var node = this._nodes[effect.index];
+if (node && node._notifyPath) {
+var p = this._fixPath(effect.name, effect.value, path);
+node._notifyPath(p, value, true);
+}
+}
+},
+_complexObserverPathEffect: function (path, value, effect) {
+if (this._pathMatchesEffect(path, effect)) {
+Polymer.Bind._complexObserverEffect.call(this, path, value, effect);
+}
+},
+_computePathEffect: function (path, value, effect) {
+if (this._pathMatchesEffect(path, effect)) {
+Polymer.Bind._computeEffect.call(this, path, value, effect);
+}
+},
+_annotatedComputationPathEffect: function (path, value, effect) {
+if (this._pathMatchesEffect(path, effect)) {
+Polymer.Bind._annotatedComputationEffect.call(this, path, value, effect);
+}
+},
+_pathMatchesEffect: function (path, effect) {
+var effectArg = effect.trigger.name;
+return effectArg == path || effectArg.indexOf(path + '.') === 0 || effect.trigger.wildcard && path.indexOf(effectArg + '.') === 0;
+},
+linkPaths: function (to, from) {
+this._boundPaths = this._boundPaths || {};
+if (from) {
+this._boundPaths[to] = from;
+} else {
+this.unlinkPaths(to);
+}
+},
+unlinkPaths: function (path) {
+if (this._boundPaths) {
+delete this._boundPaths[path];
+}
+},
+_notifyBoundPaths: function (path, value) {
+for (var a in this._boundPaths) {
+var b = this._boundPaths[a];
+if (path.indexOf(a + '.') == 0) {
+this._notifyPath(this._fixPath(b, a, path), value);
+} else if (path.indexOf(b + '.') == 0) {
+this._notifyPath(this._fixPath(a, b, path), value);
+}
+}
+},
+_fixPath: function (property, root, path) {
+return property + path.slice(root.length);
+},
+_notifyPathUp: function (path, value) {
+var rootName = this._modelForPath(path);
+var dashCaseName = Polymer.CaseMap.camelToDashCase(rootName);
+var eventName = dashCaseName + this._EVENT_CHANGED;
+this.fire(eventName, {
+path: path,
+value: value
+}, {
+bubbles: false,
+_useCache: true
+});
+},
+_modelForPath: function (path) {
+var dot = path.indexOf('.');
+return dot < 0 ? path : path.slice(0, dot);
+},
+_EVENT_CHANGED: '-changed',
+notifySplices: function (path, splices) {
+var info = {};
+var array = this._get(path, this, info);
+this._notifySplices(array, info.path, splices);
+},
+_notifySplices: function (array, path, splices) {
+var change = {
+keySplices: Polymer.Collection.applySplices(array, splices),
+indexSplices: splices
+};
+var splicesPath = path + '.splices';
+this._notifyPath(splicesPath, change);
+this._notifyPath(path + '.length', array.length);
+this.__data__[splicesPath] = {
+keySplices: null,
+indexSplices: null
+};
+},
+_notifySplice: function (array, path, index, added, removed) {
+this._notifySplices(array, path, [{
+index: index,
+addedCount: added,
+removed: removed,
+object: array,
+type: 'splice'
+}]);
+},
+push: function (path) {
+var info = {};
+var array = this._get(path, this, info);
+var args = Array.prototype.slice.call(arguments, 1);
+var len = array.length;
+var ret = array.push.apply(array, args);
+if (args.length) {
+this._notifySplice(array, info.path, len, args.length, []);
+}
+return ret;
+},
+pop: function (path) {
+var info = {};
+var array = this._get(path, this, info);
+var hadLength = Boolean(array.length);
+var args = Array.prototype.slice.call(arguments, 1);
+var ret = array.pop.apply(array, args);
+if (hadLength) {
+this._notifySplice(array, info.path, array.length, 0, [ret]);
+}
+return ret;
+},
+splice: function (path, start) {
+var info = {};
+var array = this._get(path, this, info);
+if (start < 0) {
+start = array.length - Math.floor(-start);
+} else {
+start = Math.floor(start);
+}
+if (!start) {
+start = 0;
+}
+var args = Array.prototype.slice.call(arguments, 1);
+var ret = array.splice.apply(array, args);
+var addedCount = Math.max(args.length - 2, 0);
+if (addedCount || ret.length) {
+this._notifySplice(array, info.path, start, addedCount, ret);
+}
+return ret;
+},
+shift: function (path) {
+var info = {};
+var array = this._get(path, this, info);
+var hadLength = Boolean(array.length);
+var args = Array.prototype.slice.call(arguments, 1);
+var ret = array.shift.apply(array, args);
+if (hadLength) {
+this._notifySplice(array, info.path, 0, 0, [ret]);
+}
+return ret;
+},
+unshift: function (path) {
+var info = {};
+var array = this._get(path, this, info);
+var args = Array.prototype.slice.call(arguments, 1);
+var ret = array.unshift.apply(array, args);
+if (args.length) {
+this._notifySplice(array, info.path, 0, args.length, []);
+}
+return ret;
+},
+prepareModelNotifyPath: function (model) {
+this.mixin(model, {
+fire: Polymer.Base.fire,
+_getEvent: Polymer.Base._getEvent,
+__eventCache: Polymer.Base.__eventCache,
+notifyPath: Polymer.Base.notifyPath,
+_get: Polymer.Base._get,
+_EVENT_CHANGED: Polymer.Base._EVENT_CHANGED,
+_notifyPath: Polymer.Base._notifyPath,
+_notifyPathUp: Polymer.Base._notifyPathUp,
+_pathEffector: Polymer.Base._pathEffector,
+_annotationPathEffect: Polymer.Base._annotationPathEffect,
+_complexObserverPathEffect: Polymer.Base._complexObserverPathEffect,
+_annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect,
+_computePathEffect: Polymer.Base._computePathEffect,
+_modelForPath: Polymer.Base._modelForPath,
+_pathMatchesEffect: Polymer.Base._pathMatchesEffect,
+_notifyBoundPaths: Polymer.Base._notifyBoundPaths,
+_getPathParts: Polymer.Base._getPathParts
+});
+}
+});
+}());Polymer.Base._addFeature({
+resolveUrl: function (url) {
+var module = Polymer.DomModule.import(this.is);
+var root = '';
+if (module) {
+var assetPath = module.getAttribute('assetpath') || '';
+root = Polymer.ResolveUrl.resolveUrl(assetPath, module.ownerDocument.baseURI);
+}
+return Polymer.ResolveUrl.resolveUrl(url, root);
+}
+});Polymer.CssParse = function () {
+return {
+parse: function (text) {
+text = this._clean(text);
+return this._parseCss(this._lex(text), text);
+},
+_clean: function (cssText) {
+return cssText.replace(this._rx.comments, '').replace(this._rx.port, '');
+},
+_lex: function (text) {
+var root = {
+start: 0,
+end: text.length
+};
+var n = root;
+for (var i = 0, l = text.length; i < l; i++) {
+switch (text[i]) {
+case this.OPEN_BRACE:
+if (!n.rules) {
+n.rules = [];
+}
+var p = n;
+var previous = p.rules[p.rules.length - 1];
+n = {
+start: i + 1,
+parent: p,
+previous: previous
+};
+p.rules.push(n);
+break;
+case this.CLOSE_BRACE:
+n.end = i + 1;
+n = n.parent || root;
+break;
+}
+}
+return root;
+},
+_parseCss: function (node, text) {
+var t = text.substring(node.start, node.end - 1);
+node.parsedCssText = node.cssText = t.trim();
+if (node.parent) {
+var ss = node.previous ? node.previous.end : node.parent.start;
+t = text.substring(ss, node.start - 1);
+t = this._expandUnicodeEscapes(t);
+t = t.replace(this._rx.multipleSpaces, ' ');
+t = t.substring(t.lastIndexOf(';') + 1);
+var s = node.parsedSelector = node.selector = t.trim();
+node.atRule = s.indexOf(this.AT_START) === 0;
+if (node.atRule) {
+if (s.indexOf(this.MEDIA_START) === 0) {
+node.type = this.types.MEDIA_RULE;
+} else if (s.match(this._rx.keyframesRule)) {
+node.type = this.types.KEYFRAMES_RULE;
+node.keyframesName = node.selector.split(this._rx.multipleSpaces).pop();
+}
+} else {
+if (s.indexOf(this.VAR_START) === 0) {
+node.type = this.types.MIXIN_RULE;
+} else {
+node.type = this.types.STYLE_RULE;
+}
+}
+}
+var r$ = node.rules;
+if (r$) {
+for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
+this._parseCss(r, text);
+}
+}
+return node;
+},
+_expandUnicodeEscapes: function (s) {
+return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
+var code = arguments[1], repeat = 6 - code.length;
+while (repeat--) {
+code = '0' + code;
+}
+return '\\' + code;
+});
+},
+stringify: function (node, preserveProperties, text) {
+text = text || '';
+var cssText = '';
+if (node.cssText || node.rules) {
+var r$ = node.rules;
+if (r$ && !this._hasMixinRules(r$)) {
+for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
+cssText = this.stringify(r, preserveProperties, cssText);
+}
+} else {
+cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText);
+cssText = cssText.trim();
+if (cssText) {
+cssText = ' ' + cssText + '\n';
+}
+}
+}
+if (cssText) {
+if (node.selector) {
+text += node.selector + ' ' + this.OPEN_BRACE + '\n';
+}
+text += cssText;
+if (node.selector) {
+text += this.CLOSE_BRACE + '\n\n';
+}
+}
+return text;
+},
+_hasMixinRules: function (rules) {
+return rules[0].selector.indexOf(this.VAR_START) === 0;
+},
+removeCustomProps: function (cssText) {
+cssText = this.removeCustomPropAssignment(cssText);
+return this.removeCustomPropApply(cssText);
+},
+removeCustomPropAssignment: function (cssText) {
+return cssText.replace(this._rx.customProp, '').replace(this._rx.mixinProp, '');
+},
+removeCustomPropApply: function (cssText) {
+return cssText.replace(this._rx.mixinApply, '').replace(this._rx.varApply, '');
+},
+types: {
+STYLE_RULE: 1,
+KEYFRAMES_RULE: 7,
+MEDIA_RULE: 4,
+MIXIN_RULE: 1000
+},
+OPEN_BRACE: '{',
+CLOSE_BRACE: '}',
+_rx: {
+comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
+port: /@import[^;]*;/gim,
+customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
+mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
+mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
+varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
+keyframesRule: /^@[^\s]*keyframes/,
+multipleSpaces: /\s+/g
+},
+VAR_START: '--',
+MEDIA_START: '@media',
+AT_START: '@'
+};
+}();Polymer.StyleUtil = function () {
+var settings = Polymer.Settings;
+return {
+NATIVE_VARIABLES: Polymer.Settings.useNativeCSSProperties,
+MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css], template',
+INCLUDE_ATTR: 'include',
+toCssText: function (rules, callback) {
+if (typeof rules === 'string') {
+rules = this.parser.parse(rules);
+}
+if (callback) {
+this.forEachRule(rules, callback);
+}
+return this.parser.stringify(rules, this.NATIVE_VARIABLES);
+},
+forRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
+if (styles) {
+for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
+this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback);
+}
+}
+},
+forActiveRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
+if (styles) {
+for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
+this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback, true);
+}
+}
+},
+rulesForStyle: function (style) {
+if (!style.__cssRules && style.textContent) {
+style.__cssRules = this.parser.parse(style.textContent);
+}
+return style.__cssRules;
+},
+isKeyframesSelector: function (rule) {
+return rule.parent && rule.parent.type === this.ruleTypes.KEYFRAMES_RULE;
+},
+forEachRuleInStyle: function (style, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
+var rules = this.rulesForStyle(style);
+var styleCallback, keyframeCallback;
+if (styleRuleCallback) {
+styleCallback = function (rule) {
+styleRuleCallback(rule, style);
+};
+}
+if (keyframesRuleCallback) {
+keyframeCallback = function (rule) {
+keyframesRuleCallback(rule, style);
+};
+}
+this.forEachRule(rules, styleCallback, keyframeCallback, onlyActiveRules);
+},
+forEachRule: function (node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
+if (!node) {
+return;
+}
+var skipRules = false;
+if (onlyActiveRules) {
+if (node.type === this.ruleTypes.MEDIA_RULE) {
+var matchMedia = node.selector.match(this.rx.MEDIA_MATCH);
+if (matchMedia) {
+if (!window.matchMedia(matchMedia[1]).matches) {
+skipRules = true;
+}
+}
+}
+}
+if (node.type === this.ruleTypes.STYLE_RULE) {
+styleRuleCallback(node);
+} else if (keyframesRuleCallback && node.type === this.ruleTypes.KEYFRAMES_RULE) {
+keyframesRuleCallback(node);
+} else if (node.type === this.ruleTypes.MIXIN_RULE) {
+skipRules = true;
+}
+var r$ = node.rules;
+if (r$ && !skipRules) {
+for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
+this.forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
+}
+}
+},
+applyCss: function (cssText, moniker, target, contextNode) {
+var style = this.createScopeStyle(cssText, moniker);
+return this.applyStyle(style, target, contextNode);
+},
+applyStyle: function (style, target, contextNode) {
+target = target || document.head;
+var after = contextNode && contextNode.nextSibling || target.firstChild;
+this.__lastHeadApplyNode = style;
+return target.insertBefore(style, after);
+},
+createScopeStyle: function (cssText, moniker) {
+var style = document.createElement('style');
+if (moniker) {
+style.setAttribute('scope', moniker);
+}
+style.textContent = cssText;
+return style;
+},
+__lastHeadApplyNode: null,
+applyStylePlaceHolder: function (moniker) {
+var placeHolder = document.createComment(' Shady DOM styles for ' + moniker + ' ');
+var after = this.__lastHeadApplyNode ? this.__lastHeadApplyNode.nextSibling : null;
+var scope = document.head;
+scope.insertBefore(placeHolder, after || scope.firstChild);
+this.__lastHeadApplyNode = placeHolder;
+return placeHolder;
+},
+cssFromModules: function (moduleIds, warnIfNotFound) {
+var modules = moduleIds.trim().split(' ');
+var cssText = '';
+for (var i = 0; i < modules.length; i++) {
+cssText += this.cssFromModule(modules[i], warnIfNotFound);
+}
+return cssText;
+},
+cssFromModule: function (moduleId, warnIfNotFound) {
+var m = Polymer.DomModule.import(moduleId);
+if (m && !m._cssText) {
+m._cssText = this.cssFromElement(m);
+}
+if (!m && warnIfNotFound) {
+console.warn('Could not find style data in module named', moduleId);
+}
+return m && m._cssText || '';
+},
+cssFromElement: function (element) {
+var cssText = '';
+var content = element.content || element;
+var e$ = Polymer.TreeApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
+for (var i = 0, e; i < e$.length; i++) {
+e = e$[i];
+if (e.localName === 'template') {
+cssText += this.cssFromElement(e);
+} else {
+if (e.localName === 'style') {
+var include = e.getAttribute(this.INCLUDE_ATTR);
+if (include) {
+cssText += this.cssFromModules(include, true);
+}
+e = e.__appliedElement || e;
+e.parentNode.removeChild(e);
+cssText += this.resolveCss(e.textContent, element.ownerDocument);
+} else if (e.import && e.import.body) {
+cssText += this.resolveCss(e.import.body.textContent, e.import);
+}
+}
+}
+return cssText;
+},
+isTargetedBuild: function (buildType) {
+return settings.useNativeShadow ? buildType === 'shadow' : buildType === 'shady';
+},
+cssBuildTypeForModule: function (module) {
+var dm = Polymer.DomModule.import(module);
+if (dm) {
+return this.getCssBuildType(dm);
+}
+},
+getCssBuildType: function (element) {
+return element.getAttribute('css-build');
+},
+rx: {
+VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
+MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,
+VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,()]*)|(?:[^;()]*\([^;)]*\)+))[\s]*?\)/gi,
+VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi,
+ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
+MEDIA_MATCH: /@media[^(]*(\([^)]*\))/,
+IS_VAR: /^--/,
+BRACKETED: /\{[^}]*\}/g,
+HOST_PREFIX: '(?:^|[^.#[:])',
+HOST_SUFFIX: '($|[.:[\\s>+~])'
+},
+resolveCss: Polymer.ResolveUrl.resolveCss,
+parser: Polymer.CssParse,
+ruleTypes: Polymer.CssParse.types
+};
+}();Polymer.StyleTransformer = function () {
+var styleUtil = Polymer.StyleUtil;
+var settings = Polymer.Settings;
+var api = {
+dom: function (node, scope, useAttr, shouldRemoveScope) {
+this._transformDom(node, scope || '', useAttr, shouldRemoveScope);
+},
+_transformDom: function (node, selector, useAttr, shouldRemoveScope) {
+if (node.setAttribute) {
+this.element(node, selector, useAttr, shouldRemoveScope);
+}
+var c$ = Polymer.dom(node).childNodes;
+for (var i = 0; i < c$.length; i++) {
+this._transformDom(c$[i], selector, useAttr, shouldRemoveScope);
+}
+},
+element: function (element, scope, useAttr, shouldRemoveScope) {
+if (useAttr) {
+if (shouldRemoveScope) {
+element.removeAttribute(SCOPE_NAME);
+} else {
+element.setAttribute(SCOPE_NAME, scope);
+}
+} else {
+if (scope) {
+if (element.classList) {
+if (shouldRemoveScope) {
+element.classList.remove(SCOPE_NAME);
+element.classList.remove(scope);
+} else {
+element.classList.add(SCOPE_NAME);
+element.classList.add(scope);
+}
+} else if (element.getAttribute) {
+var c = element.getAttribute(CLASS);
+if (shouldRemoveScope) {
+if (c) {
+element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, ''));
+}
+} else {
+element.setAttribute(CLASS, (c ? c + ' ' : '') + SCOPE_NAME + ' ' + scope);
+}
+}
+}
+}
+},
+elementStyles: function (element, callback) {
+var styles = element._styles;
+var cssText = '';
+var cssBuildType = element.__cssBuild;
+for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
+var rules = styleUtil.rulesForStyle(s);
+cssText += settings.useNativeShadow || cssBuildType === 'shady' ? styleUtil.toCssText(rules, callback) : this.css(rules, element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n';
+}
+return cssText.trim();
+},
+css: function (rules, scope, ext, callback, useAttr) {
+var hostScope = this._calcHostScope(scope, ext);
+scope = this._calcElementScope(scope, useAttr);
+var self = this;
+return styleUtil.toCssText(rules, function (rule) {
+if (!rule.isScoped) {
+self.rule(rule, scope, hostScope);
+rule.isScoped = true;
+}
+if (callback) {
+callback(rule, scope, hostScope);
+}
+});
+},
+_calcElementScope: function (scope, useAttr) {
+if (scope) {
+return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX + scope;
+} else {
+return '';
+}
+},
+_calcHostScope: function (scope, ext) {
+return ext ? '[is=' + scope + ']' : scope;
+},
+rule: function (rule, scope, hostScope) {
+this._transformRule(rule, this._transformComplexSelector, scope, hostScope);
+},
+_transformRule: function (rule, transformer, scope, hostScope) {
+rule.selector = rule.transformedSelector = this._transformRuleCss(rule, transformer, scope, hostScope);
+},
+_transformRuleCss: function (rule, transformer, scope, hostScope) {
+var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
+if (!styleUtil.isKeyframesSelector(rule)) {
+for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
+p$[i] = transformer.call(this, p, scope, hostScope);
+}
+}
+return p$.join(COMPLEX_SELECTOR_SEP);
+},
+_transformComplexSelector: function (selector, scope, hostScope) {
+var stop = false;
+var hostContext = false;
+var self = this;
+selector = selector.trim();
+selector = selector.replace(CONTENT_START, HOST + ' $1');
+selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
+if (!stop) {
+var info = self._transformCompoundSelector(s, c, scope, hostScope);
+stop = stop || info.stop;
+hostContext = hostContext || info.hostContext;
+c = info.combinator;
+s = info.value;
+} else {
+s = s.replace(SCOPE_JUMP, ' ');
+}
+return c + s;
+});
+if (hostContext) {
+selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) {
+return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre + hostScope + paren + post;
+});
+}
+return selector;
+},
+_transformCompoundSelector: function (selector, combinator, scope, hostScope) {
+var jumpIndex = selector.search(SCOPE_JUMP);
+var hostContext = false;
+if (selector.indexOf(HOST_CONTEXT) >= 0) {
+hostContext = true;
+} else if (selector.indexOf(HOST) >= 0) {
+selector = this._transformHostSelector(selector, hostScope);
+} else if (jumpIndex !== 0) {
+selector = scope ? this._transformSimpleSelector(selector, scope) : selector;
+}
+if (selector.indexOf(CONTENT) >= 0) {
+combinator = '';
+}
+var stop;
+if (jumpIndex >= 0) {
+selector = selector.replace(SCOPE_JUMP, ' ');
+stop = true;
+}
+return {
+value: selector,
+combinator: combinator,
+stop: stop,
+hostContext: hostContext
+};
+},
+_transformSimpleSelector: function (selector, scope) {
+var p$ = selector.split(PSEUDO_PREFIX);
+p$[0] += scope;
+return p$.join(PSEUDO_PREFIX);
+},
+_transformHostSelector: function (selector, hostScope) {
+var m = selector.match(HOST_PAREN);
+var paren = m && m[2].trim() || '';
+if (paren) {
+if (!paren[0].match(SIMPLE_SELECTOR_PREFIX)) {
+var typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0];
+if (typeSelector === hostScope) {
+return paren;
+} else {
+return SELECTOR_NO_MATCH;
+}
+} else {
+return selector.replace(HOST_PAREN, function (m, host, paren) {
+return hostScope + paren;
+});
+}
+} else {
+return selector.replace(HOST, hostScope);
+}
+},
+documentRule: function (rule) {
+rule.selector = rule.parsedSelector;
+this.normalizeRootSelector(rule);
+if (!settings.useNativeShadow) {
+this._transformRule(rule, this._transformDocumentSelector);
+}
+},
+normalizeRootSelector: function (rule) {
+if (rule.selector === ROOT) {
+rule.selector = 'html';
+}
+},
+_transformDocumentSelector: function (selector) {
+return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
+},
+SCOPE_NAME: 'style-scope'
+};
+var SCOPE_NAME = api.SCOPE_NAME;
+var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
+var COMPLEX_SELECTOR_SEP = ',';
+var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
+var SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;
+var HOST = ':host';
+var ROOT = ':root';
+var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/;
+var HOST_CONTEXT = ':host-context';
+var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
+var CONTENT = '::content';
+var SCOPE_JUMP = /::content|::shadow|\/deep\//;
+var CSS_CLASS_PREFIX = '.';
+var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
+var CSS_ATTR_SUFFIX = ']';
+var PSEUDO_PREFIX = ':';
+var CLASS = 'class';
+var CONTENT_START = new RegExp('^(' + CONTENT + ')');
+var SELECTOR_NO_MATCH = 'should_not_match';
+return api;
+}();Polymer.StyleExtends = function () {
+var styleUtil = Polymer.StyleUtil;
+return {
+hasExtends: function (cssText) {
+return Boolean(cssText.match(this.rx.EXTEND));
+},
+transform: function (style) {
+var rules = styleUtil.rulesForStyle(style);
+var self = this;
+styleUtil.forEachRule(rules, function (rule) {
+self._mapRuleOntoParent(rule);
+if (rule.parent) {
+var m;
+while (m = self.rx.EXTEND.exec(rule.cssText)) {
+var extend = m[1];
+var extendor = self._findExtendor(extend, rule);
+if (extendor) {
+self._extendRule(rule, extendor);
+}
+}
+}
+rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
+});
+return styleUtil.toCssText(rules, function (rule) {
+if (rule.selector.match(self.rx.STRIP)) {
+rule.cssText = '';
+}
+}, true);
+},
+_mapRuleOntoParent: function (rule) {
+if (rule.parent) {
+var map = rule.parent.map || (rule.parent.map = {});
+var parts = rule.selector.split(',');
+for (var i = 0, p; i < parts.length; i++) {
+p = parts[i];
+map[p.trim()] = rule;
+}
+return map;
+}
+},
+_findExtendor: function (extend, rule) {
+return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findExtendor(extend, rule.parent);
+},
+_extendRule: function (target, source) {
+if (target.parent !== source.parent) {
+this._cloneAndAddRuleToParent(source, target.parent);
+}
+target.extends = target.extends || [];
+target.extends.push(source);
+source.selector = source.selector.replace(this.rx.STRIP, '');
+source.selector = (source.selector && source.selector + ',\n') + target.selector;
+if (source.extends) {
+source.extends.forEach(function (e) {
+this._extendRule(target, e);
+}, this);
+}
+},
+_cloneAndAddRuleToParent: function (rule, parent) {
+rule = Object.create(rule);
+rule.parent = parent;
+if (rule.extends) {
+rule.extends = rule.extends.slice();
+}
+parent.rules.push(rule);
+},
+rx: {
+EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
+STRIP: /%[^,]*$/
+}
+};
+}();Polymer.ApplyShim = function () {
+'use strict';
+var styleUtil = Polymer.StyleUtil;
+var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH;
+var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN;
+var VAR_MATCH = styleUtil.rx.VAR_MATCH;
+var APPLY_NAME_CLEAN = /;\s*/m;
+var MIXIN_VAR_SEP = '_-_';
+var mixinMap = {};
+function mapSet(name, prop) {
+name = name.trim();
+mixinMap[name] = prop;
+}
+function mapGet(name) {
+name = name.trim();
+return mixinMap[name];
+}
+function cssTextToMap(text) {
+var props = text.split(';');
+var out = {};
+for (var i = 0, p, sp; i < props.length; i++) {
+p = props[i];
+if (p) {
+sp = p.split(':');
+if (sp.length > 1) {
+out[sp[0].trim()] = sp.slice(1).join(':');
+}
+}
+}
+return out;
+}
+function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {
+if (valueProperty) {
+VAR_MATCH.lastIndex = 0;
+var m = VAR_MATCH.exec(valueProperty);
+if (m) {
+var value = m[2];
+if (mapGet(value)) {
+valueMixin = '@apply ' + value + ';';
+}
+}
+}
+if (!valueMixin) {
+return matchText;
+}
+var mixinAsProperties = consumeCssProperties(valueMixin);
+var prefix = matchText.slice(0, matchText.indexOf('--'));
+var mixinValues = cssTextToMap(mixinAsProperties);
+var oldProperties = mapGet(propertyName);
+var combinedProps = mixinValues;
+if (oldProperties) {
+combinedProps = Polymer.Base.mixin(oldProperties, mixinValues);
+} else {
+mapSet(propertyName, combinedProps);
+}
+var out = [];
+var p, v;
+for (p in combinedProps) {
+v = mixinValues[p];
+if (v === undefined) {
+v = 'initial';
+}
+out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v);
+}
+return prefix + out.join('; ') + ';';
+}
+function fixVars(matchText, prefix, value, fallback) {
+if (!fallback || fallback.indexOf('--') !== 0) {
+return matchText;
+}
+return [
+prefix,
+'var(',
+value,
+', var(',
+fallback,
+'));'
+].join('');
+}
+function atApplyToCssProperties(mixinName, fallbacks) {
+mixinName = mixinName.replace(APPLY_NAME_CLEAN, '');
+var vars = [];
+var mixinProperties = mapGet(mixinName);
+if (mixinProperties) {
+var p, parts, f;
+for (p in mixinProperties) {
+f = fallbacks && fallbacks[p];
+parts = [
+p,
+': var(',
+mixinName,
+MIXIN_VAR_SEP,
+p
+];
+if (f) {
+parts.push(',', f);
+}
+parts.push(')');
+vars.push(parts.join(''));
+}
+}
+return vars.join('; ');
+}
+function consumeCssProperties(text) {
+var m;
+while (m = MIXIN_MATCH.exec(text)) {
+var matchText = m[0];
+var mixinName = m[1];
+var idx = m.index;
+var applyPos = idx + matchText.indexOf('@apply');
+var afterApplyPos = idx + matchText.length;
+var textBeforeApply = text.slice(0, applyPos);
+var textAfterApply = text.slice(afterApplyPos);
+var defaults = cssTextToMap(textBeforeApply);
+var replacement = atApplyToCssProperties(mixinName, defaults);
+text = [
+textBeforeApply,
+replacement,
+textAfterApply
+].join('');
+MIXIN_MATCH.lastIndex = idx + replacement.length;
+}
+return text;
+}
+var ApplyShim = {
+_map: mixinMap,
+_separator: MIXIN_VAR_SEP,
+transform: function (styles) {
+styleUtil.forRulesInStyles(styles, this._boundTransformRule);
+},
+transformRule: function (rule) {
+rule.cssText = this.transformCssText(rule.parsedCssText);
+if (rule.selector === ':root') {
+rule.selector = ':host > *';
+}
+},
+transformCssText: function (cssText) {
+cssText = cssText.replace(VAR_MATCH, fixVars);
+cssText = cssText.replace(VAR_ASSIGN, produceCssProperties);
+return consumeCssProperties(cssText);
+}
+};
+ApplyShim._boundTransformRule = ApplyShim.transformRule.bind(ApplyShim);
+return ApplyShim;
+}();(function () {
+var prepElement = Polymer.Base._prepElement;
+var nativeShadow = Polymer.Settings.useNativeShadow;
+var styleUtil = Polymer.StyleUtil;
+var styleTransformer = Polymer.StyleTransformer;
+var styleExtends = Polymer.StyleExtends;
+var applyShim = Polymer.ApplyShim;
+var settings = Polymer.Settings;
+Polymer.Base._addFeature({
+_prepElement: function (element) {
+if (this._encapsulateStyle && this.__cssBuild !== 'shady') {
+styleTransformer.element(element, this.is, this._scopeCssViaAttr);
+}
+prepElement.call(this, element);
+},
+_prepStyles: function () {
+if (this._encapsulateStyle === undefined) {
+this._encapsulateStyle = !nativeShadow;
+}
+if (!nativeShadow) {
+this._scopeStyle = styleUtil.applyStylePlaceHolder(this.is);
+}
+this.__cssBuild = styleUtil.cssBuildTypeForModule(this.is);
+},
+_prepShimStyles: function () {
+if (this._template) {
+var hasTargetedCssBuild = styleUtil.isTargetedBuild(this.__cssBuild);
+if (settings.useNativeCSSProperties && this.__cssBuild === 'shadow' && hasTargetedCssBuild) {
+return;
+}
+this._styles = this._styles || this._collectStyles();
+if (settings.useNativeCSSProperties && !this.__cssBuild) {
+applyShim.transform(this._styles);
+}
+var cssText = settings.useNativeCSSProperties && hasTargetedCssBuild ? this._styles.length && this._styles[0].textContent.trim() : styleTransformer.elementStyles(this);
+this._prepStyleProperties();
+if (!this._needsStyleProperties() && cssText) {
+styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null, this._scopeStyle);
+}
+} else {
+this._styles = [];
+}
+},
+_collectStyles: function () {
+var styles = [];
+var cssText = '', m$ = this.styleModules;
+if (m$) {
+for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) {
+cssText += styleUtil.cssFromModule(m);
+}
+}
+cssText += styleUtil.cssFromModule(this.is);
+var p = this._template && this._template.parentNode;
+if (this._template && (!p || p.id.toLowerCase() !== this.is)) {
+cssText += styleUtil.cssFromElement(this._template);
+}
+if (cssText) {
+var style = document.createElement('style');
+style.textContent = cssText;
+if (styleExtends.hasExtends(style.textContent)) {
+cssText = styleExtends.transform(style);
+}
+styles.push(style);
+}
+return styles;
+},
+_elementAdd: function (node) {
+if (this._encapsulateStyle) {
+if (node.__styleScoped) {
+node.__styleScoped = false;
+} else {
+styleTransformer.dom(node, this.is, this._scopeCssViaAttr);
+}
+}
+},
+_elementRemove: function (node) {
+if (this._encapsulateStyle) {
+styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true);
+}
+},
+scopeSubtree: function (container, shouldObserve) {
+if (nativeShadow) {
+return;
+}
+var self = this;
+var scopify = function (node) {
+if (node.nodeType === Node.ELEMENT_NODE) {
+var className = node.getAttribute('class');
+node.setAttribute('class', self._scopeElementClass(node, className));
+var n$ = node.querySelectorAll('*');
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
+className = n.getAttribute('class');
+n.setAttribute('class', self._scopeElementClass(n, className));
+}
+}
+};
+scopify(container);
+if (shouldObserve) {
+var mo = new MutationObserver(function (mxns) {
+for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
+if (m.addedNodes) {
+for (var j = 0; j < m.addedNodes.length; j++) {
+scopify(m.addedNodes[j]);
+}
+}
+}
+});
+mo.observe(container, {
+childList: true,
+subtree: true
+});
+return mo;
+}
+}
+});
+}());Polymer.StyleProperties = function () {
+'use strict';
+var matchesSelector = Polymer.DomApi.matchesSelector;
+var styleUtil = Polymer.StyleUtil;
+var styleTransformer = Polymer.StyleTransformer;
+var settings = Polymer.Settings;
+return {
+decorateStyles: function (styles, scope) {
+var self = this, props = {}, keyframes = [], ruleIndex = 0;
+var scopeSelector = styleTransformer._calcHostScope(scope.is, scope.extends);
+styleUtil.forRulesInStyles(styles, function (rule, style) {
+self.decorateRule(rule);
+rule.index = ruleIndex++;
+self.whenHostOrRootRule(scope, rule, style, function (info) {
+if (rule.parent.type === styleUtil.ruleTypes.MEDIA_RULE) {
+scope.__notStyleScopeCacheable = true;
+}
+if (info.isHost) {
+var hostContextOrFunction = info.selector.split(' ').some(function (s) {
+return s.indexOf(scopeSelector) === 0 && s.length !== scopeSelector.length;
+});
+scope.__notStyleScopeCacheable = scope.__notStyleScopeCacheable || hostContextOrFunction;
+}
+});
+self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
+}, function onKeyframesRule(rule) {
+keyframes.push(rule);
+});
+styles._keyframes = keyframes;
+var names = [];
+for (var i in props) {
+names.push(i);
+}
+return names;
+},
+decorateRule: function (rule) {
+if (rule.propertyInfo) {
+return rule.propertyInfo;
+}
+var info = {}, properties = {};
+var hasProperties = this.collectProperties(rule, properties);
+if (hasProperties) {
+info.properties = properties;
+rule.rules = null;
+}
+info.cssText = this.collectCssText(rule);
+rule.propertyInfo = info;
+return info;
+},
+collectProperties: function (rule, properties) {
+var info = rule.propertyInfo;
+if (info) {
+if (info.properties) {
+Polymer.Base.mixin(properties, info.properties);
+return true;
+}
+} else {
+var m, rx = this.rx.VAR_ASSIGN;
+var cssText = rule.parsedCssText;
+var any;
+while (m = rx.exec(cssText)) {
+properties[m[1].trim()] = (m[2] || m[3]).trim();
+any = true;
+}
+return any;
+}
+},
+collectCssText: function (rule) {
+return this.collectConsumingCssText(rule.parsedCssText);
+},
+collectConsumingCssText: function (cssText) {
+return cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
+},
+collectPropertiesInCssText: function (cssText, props) {
+var m;
+while (m = this.rx.VAR_CONSUMED.exec(cssText)) {
+var name = m[1];
+if (m[2] !== ':') {
+props[name] = true;
+}
+}
+},
+reify: function (props) {
+var names = Object.getOwnPropertyNames(props);
+for (var i = 0, n; i < names.length; i++) {
+n = names[i];
+props[n] = this.valueForProperty(props[n], props);
+}
+},
+valueForProperty: function (property, props) {
+if (property) {
+if (property.indexOf(';') >= 0) {
+property = this.valueForProperties(property, props);
+} else {
+var self = this;
+var fn = function (all, prefix, value, fallback) {
+var propertyValue = self.valueForProperty(props[value], props) || self.valueForProperty(props[fallback] || fallback, props) || fallback;
+return prefix + (propertyValue || '');
+};
+property = property.replace(this.rx.VAR_MATCH, fn);
+}
+}
+return property && property.trim() || '';
+},
+valueForProperties: function (property, props) {
+var parts = property.split(';');
+for (var i = 0, p, m; i < parts.length; i++) {
+if (p = parts[i]) {
+this.rx.MIXIN_MATCH.lastIndex = 0;
+m = this.rx.MIXIN_MATCH.exec(p);
+if (m) {
+p = this.valueForProperty(props[m[1]], props);
+} else {
+var colon = p.indexOf(':');
+if (colon !== -1) {
+var pp = p.substring(colon);
+pp = pp.trim();
+pp = this.valueForProperty(pp, props) || pp;
+p = p.substring(0, colon) + pp;
+}
+}
+parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
+}
+}
+return parts.join(';');
+},
+applyProperties: function (rule, props) {
+var output = '';
+if (!rule.propertyInfo) {
+this.decorateRule(rule);
+}
+if (rule.propertyInfo.cssText) {
+output = this.valueForProperties(rule.propertyInfo.cssText, props);
+}
+rule.cssText = output;
+},
+applyKeyframeTransforms: function (rule, keyframeTransforms) {
+var input = rule.cssText;
+var output = rule.cssText;
+if (rule.hasAnimations == null) {
+rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input);
+}
+if (rule.hasAnimations) {
+var transform;
+if (rule.keyframeNamesToTransform == null) {
+rule.keyframeNamesToTransform = [];
+for (var keyframe in keyframeTransforms) {
+transform = keyframeTransforms[keyframe];
+output = transform(input);
+if (input !== output) {
+input = output;
+rule.keyframeNamesToTransform.push(keyframe);
+}
+}
+} else {
+for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
+transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
+input = transform(input);
+}
+output = input;
+}
+}
+rule.cssText = output;
+},
+propertyDataFromStyles: function (styles, element) {
+var props = {}, self = this;
+var o = [];
+styleUtil.forActiveRulesInStyles(styles, function (rule) {
+if (!rule.propertyInfo) {
+self.decorateRule(rule);
+}
+var selectorToMatch = rule.transformedSelector || rule.parsedSelector;
+if (element && rule.propertyInfo.properties && selectorToMatch) {
+if (matchesSelector.call(element, selectorToMatch)) {
+self.collectProperties(rule, props);
+addToBitMask(rule.index, o);
+}
+}
+});
+return {
+properties: props,
+key: o
+};
+},
+whenHostOrRootRule: function (scope, rule, style, callback) {
+if (!rule.propertyInfo) {
+self.decorateRule(rule);
+}
+if (!rule.propertyInfo.properties) {
+return;
+}
+var hostScope = scope.is ? styleTransformer._calcHostScope(scope.is, scope.extends) : 'html';
+var parsedSelector = rule.parsedSelector;
+var isRoot = parsedSelector === ':root';
+var isHost = parsedSelector.indexOf(':host') === 0;
+var cssBuild = scope.__cssBuild || style.__cssBuild;
+if (cssBuild === 'shady') {
+isRoot = parsedSelector === hostScope + '> *.' + hostScope || parsedSelector.indexOf('html') !== -1;
+isHost = !isRoot && parsedSelector.indexOf(hostScope) === 0;
+}
+if (cssBuild === 'shadow') {
+isRoot = parsedSelector === ':host > *' || parsedSelector === 'html';
+isHost = isHost && !isRoot;
+}
+if (!isRoot && !isHost) {
+return;
+}
+var selectorToMatch = hostScope;
+if (isHost) {
+if (settings.useNativeShadow && !rule.transformedSelector) {
+rule.transformedSelector = styleTransformer._transformRuleCss(rule, styleTransformer._transformComplexSelector, scope.is, hostScope);
+}
+selectorToMatch = rule.transformedSelector || hostScope;
+}
+callback({
+selector: selectorToMatch,
+isHost: isHost,
+isRoot: isRoot
+});
+},
+hostAndRootPropertiesForScope: function (scope) {
+var hostProps = {}, rootProps = {}, self = this;
+styleUtil.forActiveRulesInStyles(scope._styles, function (rule, style) {
+self.whenHostOrRootRule(scope, rule, style, function (info) {
+var element = scope._element || scope;
+if (matchesSelector.call(element, info.selector)) {
+if (info.isHost) {
+self.collectProperties(rule, hostProps);
+} else {
+self.collectProperties(rule, rootProps);
+}
+}
+});
+});
+return {
+rootProps: rootProps,
+hostProps: hostProps
+};
+},
+transformStyles: function (element, properties, scopeSelector) {
+var self = this;
+var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
+var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
+var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
+var keyframeTransforms = this._elementKeyframeTransforms(element, scopeSelector);
+return styleTransformer.elementStyles(element, function (rule) {
+self.applyProperties(rule, properties);
+if (!settings.useNativeShadow && !Polymer.StyleUtil.isKeyframesSelector(rule) && rule.cssText) {
+self.applyKeyframeTransforms(rule, keyframeTransforms);
+self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
+}
+});
+},
+_elementKeyframeTransforms: function (element, scopeSelector) {
+var keyframesRules = element._styles._keyframes;
+var keyframeTransforms = {};
+if (!settings.useNativeShadow && keyframesRules) {
+for (var i = 0, keyframesRule = keyframesRules[i]; i < keyframesRules.length; keyframesRule = keyframesRules[++i]) {
+this._scopeKeyframes(keyframesRule, scopeSelector);
+keyframeTransforms[keyframesRule.keyframesName] = this._keyframesRuleTransformer(keyframesRule);
+}
+}
+return keyframeTransforms;
+},
+_keyframesRuleTransformer: function (keyframesRule) {
+return function (cssText) {
+return cssText.replace(keyframesRule.keyframesNameRx, keyframesRule.transformedKeyframesName);
+};
+},
+_scopeKeyframes: function (rule, scopeId) {
+rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
+rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
+rule.transformedSelector = rule.transformedSelector || rule.selector;
+rule.selector = rule.transformedSelector.replace(rule.keyframesName, rule.transformedKeyframesName);
+},
+_scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
+rule.transformedSelector = rule.transformedSelector || rule.selector;
+var selector = rule.transformedSelector;
+var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
+var parts = selector.split(',');
+for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
+parts[i] = p.match(hostRx) ? p.replace(hostSelector, scope) : scope + ' ' + p;
+}
+rule.selector = parts.join(',');
+},
+applyElementScopeSelector: function (element, selector, old, viaAttr) {
+var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.getAttribute('class') || '';
+var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector;
+if (c !== v) {
+if (viaAttr) {
+element.setAttribute(styleTransformer.SCOPE_NAME, v);
+} else {
+element.setAttribute('class', v);
+}
+}
+},
+applyElementStyle: function (element, properties, selector, style) {
+var cssText = style ? style.textContent || '' : this.transformStyles(element, properties, selector);
+var s = element._customStyle;
+if (s && !settings.useNativeShadow && s !== style) {
+s._useCount--;
+if (s._useCount <= 0 && s.parentNode) {
+s.parentNode.removeChild(s);
+}
+}
+if (settings.useNativeShadow) {
+if (element._customStyle) {
+element._customStyle.textContent = cssText;
+style = element._customStyle;
+} else if (cssText) {
+style = styleUtil.applyCss(cssText, selector, element.root, element._scopeStyle);
+}
+} else {
+if (!style) {
+if (cssText) {
+style = styleUtil.applyCss(cssText, selector, null, element._scopeStyle);
+}
+} else if (!style.parentNode) {
+styleUtil.applyStyle(style, null, element._scopeStyle);
+}
+}
+if (style) {
+style._useCount = style._useCount || 0;
+if (element._customStyle != style) {
+style._useCount++;
+}
+element._customStyle = style;
+}
+return style;
+},
+mixinCustomStyle: function (props, customStyle) {
+var v;
+for (var i in customStyle) {
+v = customStyle[i];
+if (v || v === 0) {
+props[i] = v;
+}
+}
+},
+updateNativeStyleProperties: function (element, properties) {
+for (var i = 0; i < element.style.length; i++) {
+element.style.removeProperty(element.style[i]);
+}
+for (var p in properties) {
+if (properties[p] !== null) {
+element.style.setProperty(p, properties[p]);
+}
+}
+},
+rx: styleUtil.rx,
+XSCOPE_NAME: 'x-scope'
+};
+function addToBitMask(n, bits) {
+var o = parseInt(n / 32);
+var v = 1 << n % 32;
+bits[o] = (bits[o] || 0) | v;
+}
+}();(function () {
+Polymer.StyleCache = function () {
+this.cache = {};
+};
+Polymer.StyleCache.prototype = {
+MAX: 100,
+store: function (is, data, keyValues, keyStyles) {
+data.keyValues = keyValues;
+data.styles = keyStyles;
+var s$ = this.cache[is] = this.cache[is] || [];
+s$.push(data);
+if (s$.length > this.MAX) {
+s$.shift();
+}
+},
+retrieve: function (is, keyValues, keyStyles) {
+var cache = this.cache[is];
+if (cache) {
+for (var i = cache.length - 1, data; i >= 0; i--) {
+data = cache[i];
+if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues)) {
+return data;
+}
+}
+}
+},
+clear: function () {
+this.cache = {};
+},
+_objectsEqual: function (target, source) {
+var t, s;
+for (var i in target) {
+t = target[i], s = source[i];
+if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) {
+return false;
+}
+}
+if (Array.isArray(target)) {
+return target.length === source.length;
+}
+return true;
+},
+_objectsStrictlyEqual: function (target, source) {
+return this._objectsEqual(target, source) && this._objectsEqual(source, target);
+}
+};
+}());Polymer.StyleDefaults = function () {
+var styleProperties = Polymer.StyleProperties;
+var StyleCache = Polymer.StyleCache;
+var nativeVariables = Polymer.Settings.useNativeCSSProperties;
+var api = {
+_styles: [],
+_properties: null,
+customStyle: {},
+_styleCache: new StyleCache(),
+_element: Polymer.DomApi.wrap(document.documentElement),
+addStyle: function (style) {
+this._styles.push(style);
+this._properties = null;
+},
+get _styleProperties() {
+if (!this._properties) {
+styleProperties.decorateStyles(this._styles, this);
+this._styles._scopeStyleProperties = null;
+this._properties = styleProperties.hostAndRootPropertiesForScope(this).rootProps;
+styleProperties.mixinCustomStyle(this._properties, this.customStyle);
+styleProperties.reify(this._properties);
+}
+return this._properties;
+},
+hasStyleProperties: function () {
+return Boolean(this._properties);
+},
+_needsStyleProperties: function () {
+},
+_computeStyleProperties: function () {
+return this._styleProperties;
+},
+updateStyles: function (properties) {
+this._properties = null;
+if (properties) {
+Polymer.Base.mixin(this.customStyle, properties);
+}
+this._styleCache.clear();
+for (var i = 0, s; i < this._styles.length; i++) {
+s = this._styles[i];
+s = s.__importElement || s;
+s._apply();
+}
+if (nativeVariables) {
+styleProperties.updateNativeStyleProperties(document.documentElement, this.customStyle);
+}
+}
+};
+return api;
+}();(function () {
+'use strict';
+var serializeValueToAttribute = Polymer.Base.serializeValueToAttribute;
+var propertyUtils = Polymer.StyleProperties;
+var styleTransformer = Polymer.StyleTransformer;
+var styleDefaults = Polymer.StyleDefaults;
+var nativeShadow = Polymer.Settings.useNativeShadow;
+var nativeVariables = Polymer.Settings.useNativeCSSProperties;
+Polymer.Base._addFeature({
+_prepStyleProperties: function () {
+if (!nativeVariables) {
+this._ownStylePropertyNames = this._styles && this._styles.length ? propertyUtils.decorateStyles(this._styles, this) : null;
+}
+},
+customStyle: null,
+getComputedStyleValue: function (property) {
+return !nativeVariables && this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
+},
+_setupStyleProperties: function () {
+this.customStyle = {};
+this._styleCache = null;
+this._styleProperties = null;
+this._scopeSelector = null;
+this._ownStyleProperties = null;
+this._customStyle = null;
+},
+_needsStyleProperties: function () {
+return Boolean(!nativeVariables && this._ownStylePropertyNames && this._ownStylePropertyNames.length);
+},
+_beforeAttached: function () {
+if ((!this._scopeSelector || this.__stylePropertiesInvalid) && this._needsStyleProperties()) {
+this.__stylePropertiesInvalid = false;
+this._updateStyleProperties();
+}
+},
+_findStyleHost: function () {
+var e = this, root;
+while (root = Polymer.dom(e).getOwnerRoot()) {
+if (Polymer.isInstance(root.host)) {
+return root.host;
+}
+e = root.host;
+}
+return styleDefaults;
+},
+_updateStyleProperties: function () {
+var info, scope = this._findStyleHost();
+if (!scope._styleCache) {
+scope._styleCache = new Polymer.StyleCache();
+}
+var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this);
+var scopeCacheable = !this.__notStyleScopeCacheable;
+if (scopeCacheable) {
+scopeData.key.customStyle = this.customStyle;
+info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles);
+}
+var scopeCached = Boolean(info);
+if (scopeCached) {
+this._styleProperties = info._styleProperties;
+} else {
+this._computeStyleProperties(scopeData.properties);
+}
+this._computeOwnStyleProperties();
+if (!scopeCached) {
+info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles);
+}
+var globalCached = Boolean(info) && !scopeCached;
+var style = this._applyStyleProperties(info);
+if (!scopeCached) {
+style = style && nativeShadow ? style.cloneNode(true) : style;
+info = {
+style: style,
+_scopeSelector: this._scopeSelector,
+_styleProperties: this._styleProperties
+};
+if (scopeCacheable) {
+scopeData.key.customStyle = {};
+this.mixin(scopeData.key.customStyle, this.customStyle);
+scope._styleCache.store(this.is, info, scopeData.key, this._styles);
+}
+if (!globalCached) {
+styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._styles);
+}
+}
+},
+_computeStyleProperties: function (scopeProps) {
+var scope = this._findStyleHost();
+if (!scope._styleProperties) {
+scope._computeStyleProperties();
+}
+var props = Object.create(scope._styleProperties);
+var hostAndRootProps = propertyUtils.hostAndRootPropertiesForScope(this);
+this.mixin(props, hostAndRootProps.hostProps);
+scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, this).properties;
+this.mixin(props, scopeProps);
+this.mixin(props, hostAndRootProps.rootProps);
+propertyUtils.mixinCustomStyle(props, this.customStyle);
+propertyUtils.reify(props);
+this._styleProperties = props;
+},
+_computeOwnStyleProperties: function () {
+var props = {};
+for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) {
+n = this._ownStylePropertyNames[i];
+props[n] = this._styleProperties[n];
+}
+this._ownStyleProperties = props;
+},
+_scopeCount: 0,
+_applyStyleProperties: function (info) {
+var oldScopeSelector = this._scopeSelector;
+this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto__._scopeCount++;
+var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._scopeSelector, info && info.style);
+if (!nativeShadow) {
+propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr);
+}
+return style;
+},
+serializeValueToAttribute: function (value, attribute, node) {
+node = node || this;
+if (attribute === 'class' && !nativeShadow) {
+var host = node === this ? this.domHost || this.dataHost : this;
+if (host) {
+value = host._scopeElementClass(node, value);
+}
+}
+node = this.shadyRoot && this.shadyRoot._hasDistributed ? Polymer.dom(node) : node;
+serializeValueToAttribute.call(this, value, attribute, node);
+},
+_scopeElementClass: function (element, selector) {
+if (!nativeShadow && !this._scopeCssViaAttr) {
+selector = (selector ? selector + ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
+}
+return selector;
+},
+updateStyles: function (properties) {
+if (properties) {
+this.mixin(this.customStyle, properties);
+}
+if (nativeVariables) {
+propertyUtils.updateNativeStyleProperties(this, this.customStyle);
+} else {
+if (this.isAttached) {
+if (this._needsStyleProperties()) {
+this._updateStyleProperties();
+} else {
+this._styleProperties = null;
+}
+} else {
+this.__stylePropertiesInvalid = true;
+}
+if (this._styleCache) {
+this._styleCache.clear();
+}
+this._updateRootStyles();
+}
+},
+_updateRootStyles: function (root) {
+root = root || this.root;
+var c$ = Polymer.dom(root)._query(function (e) {
+return e.shadyRoot || e.shadowRoot;
+});
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+if (c.updateStyles) {
+c.updateStyles();
+}
+}
+}
+});
+Polymer.updateStyles = function (properties) {
+styleDefaults.updateStyles(properties);
+Polymer.Base._updateRootStyles(document);
+};
+var styleCache = new Polymer.StyleCache();
+Polymer.customStyleCache = styleCache;
+var SCOPE_NAME = styleTransformer.SCOPE_NAME;
+var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
+}());Polymer.Base._addFeature({
+_registerFeatures: function () {
+this._prepIs();
+this._prepConstructor();
+this._prepStyles();
+},
+_finishRegisterFeatures: function () {
+this._prepTemplate();
+this._prepShimStyles();
+this._prepAnnotations();
+this._prepEffects();
+this._prepBehaviors();
+this._prepPropertyInfo();
+this._prepBindings();
+this._prepShady();
+},
+_prepBehavior: function (b) {
+this._addPropertyEffects(b.properties);
+this._addComplexObserverEffects(b.observers);
+this._addHostAttributes(b.hostAttributes);
+},
+_initFeatures: function () {
+this._setupGestures();
+this._setupConfigure();
+this._setupStyleProperties();
+this._setupDebouncers();
+this._setupShady();
+this._registerHost();
+if (this._template) {
+this._poolContent();
+this._beginHosting();
+this._stampTemplate();
+this._endHosting();
+this._marshalAnnotationReferences();
+}
+this._marshalInstanceEffects();
+this._marshalBehaviors();
+this._marshalHostAttributes();
+this._marshalAttributes();
+this._tryReady();
+},
+_marshalBehavior: function (b) {
+if (b.listeners) {
+this._listenListeners(b.listeners);
+}
+}
+});(function () {
+var propertyUtils = Polymer.StyleProperties;
+var styleUtil = Polymer.StyleUtil;
+var cssParse = Polymer.CssParse;
+var styleDefaults = Polymer.StyleDefaults;
+var styleTransformer = Polymer.StyleTransformer;
+var applyShim = Polymer.ApplyShim;
+var debounce = Polymer.Debounce;
+var settings = Polymer.Settings;
+var updateDebouncer;
+Polymer({
+is: 'custom-style',
+extends: 'style',
+_template: null,
+properties: { include: String },
+ready: function () {
+this.__appliedElement = this.__appliedElement || this;
+this.__cssBuild = styleUtil.getCssBuildType(this);
+if (this.__appliedElement !== this) {
+this.__appliedElement.__cssBuild = this.__cssBuild;
+}
+this._tryApply();
+},
+attached: function () {
+this._tryApply();
+},
+_tryApply: function () {
+if (!this._appliesToDocument) {
+if (this.parentNode && this.parentNode.localName !== 'dom-module') {
+this._appliesToDocument = true;
+var e = this.__appliedElement;
+if (!settings.useNativeCSSProperties) {
+this.__needsUpdateStyles = styleDefaults.hasStyleProperties();
+styleDefaults.addStyle(e);
+}
+if (e.textContent || this.include) {
+this._apply(true);
+} else {
+var self = this;
+var observer = new MutationObserver(function () {
+observer.disconnect();
+self._apply(true);
+});
+observer.observe(e, { childList: true });
+}
+}
+}
+},
+_updateStyles: function () {
+Polymer.updateStyles();
+},
+_apply: function (initialApply) {
+var e = this.__appliedElement;
+if (this.include) {
+e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
+}
+if (!e.textContent) {
+return;
+}
+var buildType = this.__cssBuild;
+var targetedBuild = styleUtil.isTargetedBuild(buildType);
+if (settings.useNativeCSSProperties && targetedBuild) {
+return;
+}
+var styleRules = styleUtil.rulesForStyle(e);
+if (!targetedBuild) {
+styleUtil.forEachRule(styleRules, function (rule) {
+styleTransformer.documentRule(rule);
+if (settings.useNativeCSSProperties && !buildType) {
+applyShim.transformRule(rule);
+}
+});
+}
+if (settings.useNativeCSSProperties) {
+e.textContent = styleUtil.toCssText(styleRules);
+} else {
+var self = this;
+var fn = function fn() {
+self._flushCustomProperties();
+};
+if (initialApply) {
+Polymer.RenderStatus.whenReady(fn);
+} else {
+fn();
+}
+}
+},
+_flushCustomProperties: function () {
+if (this.__needsUpdateStyles) {
+this.__needsUpdateStyles = false;
+updateDebouncer = debounce(updateDebouncer, this._updateStyles);
+} else {
+this._applyCustomProperties();
+}
+},
+_applyCustomProperties: function () {
+var element = this.__appliedElement;
+this._computeStyleProperties();
+var props = this._styleProperties;
+var rules = styleUtil.rulesForStyle(element);
+if (!rules) {
+return;
+}
+element.textContent = styleUtil.toCssText(rules, function (rule) {
+var css = rule.cssText = rule.parsedCssText;
+if (rule.propertyInfo && rule.propertyInfo.cssText) {
+css = cssParse.removeCustomPropAssignment(css);
+rule.cssText = propertyUtils.valueForProperties(css, props);
+}
+});
+}
+});
+}());Polymer.Templatizer = {
+properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } },
+_instanceProps: Polymer.nob,
+_parentPropPrefix: '_parent_',
+templatize: function (template) {
+this._templatized = template;
+if (!template._content) {
+template._content = template.content;
+}
+if (template._content._ctor) {
+this.ctor = template._content._ctor;
+this._prepParentProperties(this.ctor.prototype, template);
+return;
+}
+var archetype = Object.create(Polymer.Base);
+this._customPrepAnnotations(archetype, template);
+this._prepParentProperties(archetype, template);
+archetype._prepEffects();
+this._customPrepEffects(archetype);
+archetype._prepBehaviors();
+archetype._prepPropertyInfo();
+archetype._prepBindings();
+archetype._notifyPathUp = this._notifyPathUpImpl;
+archetype._scopeElementClass = this._scopeElementClassImpl;
+archetype.listen = this._listenImpl;
+archetype._showHideChildren = this._showHideChildrenImpl;
+archetype.__setPropertyOrig = this.__setProperty;
+archetype.__setProperty = this.__setPropertyImpl;
+var _constructor = this._constructorImpl;
+var ctor = function TemplateInstance(model, host) {
+_constructor.call(this, model, host);
+};
+ctor.prototype = archetype;
+archetype.constructor = ctor;
+template._content._ctor = ctor;
+this.ctor = ctor;
+},
+_getRootDataHost: function () {
+return this.dataHost && this.dataHost._rootDataHost || this.dataHost;
+},
+_showHideChildrenImpl: function (hide) {
+var c = this._children;
+for (var i = 0; i < c.length; i++) {
+var n = c[i];
+if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
+if (n.nodeType === Node.TEXT_NODE) {
+if (hide) {
+n.__polymerTextContent__ = n.textContent;
+n.textContent = '';
+} else {
+n.textContent = n.__polymerTextContent__;
+}
+} else if (n.style) {
+if (hide) {
+n.__polymerDisplay__ = n.style.display;
+n.style.display = 'none';
+} else {
+n.style.display = n.__polymerDisplay__;
+}
+}
+}
+n.__hideTemplateChildren__ = hide;
+}
+},
+__setPropertyImpl: function (property, value, fromAbove, node) {
+if (node && node.__hideTemplateChildren__ && property == 'textContent') {
+property = '__polymerTextContent__';
+}
+this.__setPropertyOrig(property, value, fromAbove, node);
+},
+_debounceTemplate: function (fn) {
+Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
+},
+_flushTemplates: function () {
+Polymer.dom.flush();
+},
+_customPrepEffects: function (archetype) {
+var parentProps = archetype._parentProps;
+for (var prop in parentProps) {
+archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
+}
+for (prop in this._instanceProps) {
+archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
+}
+},
+_customPrepAnnotations: function (archetype, template) {
+archetype._template = template;
+var c = template._content;
+if (!c._notes) {
+var rootDataHost = archetype._rootDataHost;
+if (rootDataHost) {
+Polymer.Annotations.prepElement = function () {
+rootDataHost._prepElement();
+};
+}
+c._notes = Polymer.Annotations.parseAnnotations(template);
+Polymer.Annotations.prepElement = null;
+this._processAnnotations(c._notes);
+}
+archetype._notes = c._notes;
+archetype._parentProps = c._parentProps;
+},
+_prepParentProperties: function (archetype, template) {
+var parentProps = this._parentProps = archetype._parentProps;
+if (this._forwardParentProp && parentProps) {
+var proto = archetype._parentPropProto;
+var prop;
+if (!proto) {
+for (prop in this._instanceProps) {
+delete parentProps[prop];
+}
+proto = archetype._parentPropProto = Object.create(null);
+if (template != this) {
+Polymer.Bind.prepareModel(proto);
+Polymer.Base.prepareModelNotifyPath(proto);
+}
+for (prop in parentProps) {
+var parentProp = this._parentPropPrefix + prop;
+var effects = [
+{
+kind: 'function',
+effect: this._createForwardPropEffector(prop),
+fn: Polymer.Bind._functionEffect
+},
+{
+kind: 'notify',
+fn: Polymer.Bind._notifyEffect,
+effect: { event: Polymer.CaseMap.camelToDashCase(parentProp) + '-changed' }
+}
+];
+Polymer.Bind._createAccessors(proto, parentProp, effects);
+}
+}
+var self = this;
+if (template != this) {
+Polymer.Bind.prepareInstance(template);
+template._forwardParentProp = function (source, value) {
+self._forwardParentProp(source, value);
+};
+}
+this._extendTemplate(template, proto);
+template._pathEffector = function (path, value, fromAbove) {
+return self._pathEffectorImpl(path, value, fromAbove);
+};
+}
+},
+_createForwardPropEffector: function (prop) {
+return function (source, value) {
+this._forwardParentProp(prop, value);
+};
+},
+_createHostPropEffector: function (prop) {
+var prefix = this._parentPropPrefix;
+return function (source, value) {
+this.dataHost._templatized[prefix + prop] = value;
+};
+},
+_createInstancePropEffector: function (prop) {
+return function (source, value, old, fromAbove) {
+if (!fromAbove) {
+this.dataHost._forwardInstanceProp(this, prop, value);
+}
+};
+},
+_extendTemplate: function (template, proto) {
+var n$ = Object.getOwnPropertyNames(proto);
+if (proto._propertySetter) {
+template._propertySetter = proto._propertySetter;
+}
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
+var val = template[n];
+var pd = Object.getOwnPropertyDescriptor(proto, n);
+Object.defineProperty(template, n, pd);
+if (val !== undefined) {
+template._propertySetter(n, val);
+}
+}
+},
+_showHideChildren: function (hidden) {
+},
+_forwardInstancePath: function (inst, path, value) {
+},
+_forwardInstanceProp: function (inst, prop, value) {
+},
+_notifyPathUpImpl: function (path, value) {
+var dataHost = this.dataHost;
+var dot = path.indexOf('.');
+var root = dot < 0 ? path : path.slice(0, dot);
+dataHost._forwardInstancePath.call(dataHost, this, path, value);
+if (root in dataHost._parentProps) {
+dataHost._templatized._notifyPath(dataHost._parentPropPrefix + path, value);
+}
+},
+_pathEffectorImpl: function (path, value, fromAbove) {
+if (this._forwardParentPath) {
+if (path.indexOf(this._parentPropPrefix) === 0) {
+var subPath = path.substring(this._parentPropPrefix.length);
+var model = this._modelForPath(subPath);
+if (model in this._parentProps) {
+this._forwardParentPath(subPath, value);
+}
+}
+}
+Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove);
+},
+_constructorImpl: function (model, host) {
+this._rootDataHost = host._getRootDataHost();
+this._setupConfigure(model);
+this._registerHost(host);
+this._beginHosting();
+this.root = this.instanceTemplate(this._template);
+this.root.__noContent = !this._notes._hasContent;
+this.root.__styleScoped = true;
+this._endHosting();
+this._marshalAnnotatedNodes();
+this._marshalInstanceEffects();
+this._marshalAnnotatedListeners();
+var children = [];
+for (var n = this.root.firstChild; n; n = n.nextSibling) {
+children.push(n);
+n._templateInstance = this;
+}
+this._children = children;
+if (host.__hideTemplateChildren__) {
+this._showHideChildren(true);
+}
+this._tryReady();
+},
+_listenImpl: function (node, eventName, methodName) {
+var model = this;
+var host = this._rootDataHost;
+var handler = host._createEventHandler(node, eventName, methodName);
+var decorated = function (e) {
+e.model = model;
+handler(e);
+};
+host._listen(node, eventName, decorated);
+},
+_scopeElementClassImpl: function (node, value) {
+var host = this._rootDataHost;
+if (host) {
+return host._scopeElementClass(node, value);
+}
+return value;
+},
+stamp: function (model) {
+model = model || {};
+if (this._parentProps) {
+var templatized = this._templatized;
+for (var prop in this._parentProps) {
+if (model[prop] === undefined) {
+model[prop] = templatized[this._parentPropPrefix + prop];
+}
+}
+}
+return new this.ctor(model, this);
+},
+modelForElement: function (el) {
+var model;
+while (el) {
+if (model = el._templateInstance) {
+if (model.dataHost != this) {
+el = model.dataHost;
+} else {
+return model;
+}
+} else {
+el = el.parentNode;
+}
+}
+}
+};Polymer({
+is: 'dom-template',
+extends: 'template',
+_template: null,
+behaviors: [Polymer.Templatizer],
+ready: function () {
+this.templatize(this);
+}
+});Polymer._collections = new WeakMap();
+Polymer.Collection = function (userArray) {
+Polymer._collections.set(userArray, this);
+this.userArray = userArray;
+this.store = userArray.slice();
+this.initMap();
+};
+Polymer.Collection.prototype = {
+constructor: Polymer.Collection,
+initMap: function () {
+var omap = this.omap = new WeakMap();
+var pmap = this.pmap = {};
+var s = this.store;
+for (var i = 0; i < s.length; i++) {
+var item = s[i];
+if (item && typeof item == 'object') {
+omap.set(item, i);
+} else {
+pmap[item] = i;
+}
+}
+},
+add: function (item) {
+var key = this.store.push(item) - 1;
+if (item && typeof item == 'object') {
+this.omap.set(item, key);
+} else {
+this.pmap[item] = key;
+}
+return '#' + key;
+},
+removeKey: function (key) {
+if (key = this._parseKey(key)) {
+this._removeFromMap(this.store[key]);
+delete this.store[key];
+}
+},
+_removeFromMap: function (item) {
+if (item && typeof item == 'object') {
+this.omap.delete(item);
+} else {
+delete this.pmap[item];
+}
+},
+remove: function (item) {
+var key = this.getKey(item);
+this.removeKey(key);
+return key;
+},
+getKey: function (item) {
+var key;
+if (item && typeof item == 'object') {
+key = this.omap.get(item);
+} else {
+key = this.pmap[item];
+}
+if (key != undefined) {
+return '#' + key;
+}
+},
+getKeys: function () {
+return Object.keys(this.store).map(function (key) {
+return '#' + key;
+});
+},
+_parseKey: function (key) {
+if (key && key[0] == '#') {
+return key.slice(1);
+}
+},
+setItem: function (key, item) {
+if (key = this._parseKey(key)) {
+var old = this.store[key];
+if (old) {
+this._removeFromMap(old);
+}
+if (item && typeof item == 'object') {
+this.omap.set(item, key);
+} else {
+this.pmap[item] = key;
+}
+this.store[key] = item;
+}
+},
+getItem: function (key) {
+if (key = this._parseKey(key)) {
+return this.store[key];
+}
+},
+getItems: function () {
+var items = [], store = this.store;
+for (var key in store) {
+items.push(store[key]);
+}
+return items;
+},
+_applySplices: function (splices) {
+var keyMap = {}, key;
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+s.addedKeys = [];
+for (var j = 0; j < s.removed.length; j++) {
+key = this.getKey(s.removed[j]);
+keyMap[key] = keyMap[key] ? null : -1;
+}
+for (j = 0; j < s.addedCount; j++) {
+var item = this.userArray[s.index + j];
+key = this.getKey(item);
+key = key === undefined ? this.add(item) : key;
+keyMap[key] = keyMap[key] ? null : 1;
+s.addedKeys.push(key);
+}
+}
+var removed = [];
+var added = [];
+for (key in keyMap) {
+if (keyMap[key] < 0) {
+this.removeKey(key);
+removed.push(key);
+}
+if (keyMap[key] > 0) {
+added.push(key);
+}
+}
+return [{
+removed: removed,
+added: added
+}];
+}
+};
+Polymer.Collection.get = function (userArray) {
+return Polymer._collections.get(userArray) || new Polymer.Collection(userArray);
+};
+Polymer.Collection.applySplices = function (userArray, splices) {
+var coll = Polymer._collections.get(userArray);
+return coll ? coll._applySplices(splices) : null;
+};Polymer({
+is: 'dom-repeat',
+extends: 'template',
+_template: null,
+properties: {
+items: { type: Array },
+as: {
+type: String,
+value: 'item'
+},
+indexAs: {
+type: String,
+value: 'index'
+},
+sort: {
+type: Function,
+observer: '_sortChanged'
+},
+filter: {
+type: Function,
+observer: '_filterChanged'
+},
+observe: {
+type: String,
+observer: '_observeChanged'
+},
+delay: Number,
+renderedItemCount: {
+type: Number,
+notify: true,
+readOnly: true
+},
+initialCount: {
+type: Number,
+observer: '_initializeChunking'
+},
+targetFramerate: {
+type: Number,
+value: 20
+},
+_targetFrameTime: {
+type: Number,
+computed: '_computeFrameTime(targetFramerate)'
+}
+},
+behaviors: [Polymer.Templatizer],
+observers: ['_itemsChanged(items.*)'],
+created: function () {
+this._instances = [];
+this._pool = [];
+this._limit = Infinity;
+var self = this;
+this._boundRenderChunk = function () {
+self._renderChunk();
+};
+},
+detached: function () {
+this.__isDetached = true;
+for (var i = 0; i < this._instances.length; i++) {
+this._detachInstance(i);
+}
+},
+attached: function () {
+if (this.__isDetached) {
+this.__isDetached = false;
+var parent = Polymer.dom(Polymer.dom(this).parentNode);
+for (var i = 0; i < this._instances.length; i++) {
+this._attachInstance(i, parent);
+}
+}
+},
+ready: function () {
+this._instanceProps = { __key__: true };
+this._instanceProps[this.as] = true;
+this._instanceProps[this.indexAs] = true;
+if (!this.ctor) {
+this.templatize(this);
+}
+},
+_sortChanged: function (sort) {
+var dataHost = this._getRootDataHost();
+this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
+return dataHost[sort].apply(dataHost, arguments);
+});
+this._needFullRefresh = true;
+if (this.items) {
+this._debounceTemplate(this._render);
+}
+},
+_filterChanged: function (filter) {
+var dataHost = this._getRootDataHost();
+this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
+return dataHost[filter].apply(dataHost, arguments);
+});
+this._needFullRefresh = true;
+if (this.items) {
+this._debounceTemplate(this._render);
+}
+},
+_computeFrameTime: function (rate) {
+return Math.ceil(1000 / rate);
+},
+_initializeChunking: function () {
+if (this.initialCount) {
+this._limit = this.initialCount;
+this._chunkCount = this.initialCount;
+this._lastChunkTime = performance.now();
+}
+},
+_tryRenderChunk: function () {
+if (this.items && this._limit < this.items.length) {
+this.debounce('renderChunk', this._requestRenderChunk);
+}
+},
+_requestRenderChunk: function () {
+requestAnimationFrame(this._boundRenderChunk);
+},
+_renderChunk: function () {
+var currChunkTime = performance.now();
+var ratio = this._targetFrameTime / (currChunkTime - this._lastChunkTime);
+this._chunkCount = Math.round(this._chunkCount * ratio) || 1;
+this._limit += this._chunkCount;
+this._lastChunkTime = currChunkTime;
+this._debounceTemplate(this._render);
+},
+_observeChanged: function () {
+this._observePaths = this.observe && this.observe.replace('.*', '.').split(' ');
+},
+_itemsChanged: function (change) {
+if (change.path == 'items') {
+if (Array.isArray(this.items)) {
+this.collection = Polymer.Collection.get(this.items);
+} else if (!this.items) {
+this.collection = null;
+} else {
+this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items));
+}
+this._keySplices = [];
+this._indexSplices = [];
+this._needFullRefresh = true;
+this._initializeChunking();
+this._debounceTemplate(this._render);
+} else if (change.path == 'items.splices') {
+this._keySplices = this._keySplices.concat(change.value.keySplices);
+this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
+this._debounceTemplate(this._render);
+} else {
+var subpath = change.path.slice(6);
+this._forwardItemPath(subpath, change.value);
+this._checkObservedPaths(subpath);
+}
+},
+_checkObservedPaths: function (path) {
+if (this._observePaths) {
+path = path.substring(path.indexOf('.') + 1);
+var paths = this._observePaths;
+for (var i = 0; i < paths.length; i++) {
+if (path.indexOf(paths[i]) === 0) {
+this._needFullRefresh = true;
+if (this.delay) {
+this.debounce('render', this._render, this.delay);
+} else {
+this._debounceTemplate(this._render);
+}
+return;
+}
+}
+}
+},
+render: function () {
+this._needFullRefresh = true;
+this._debounceTemplate(this._render);
+this._flushTemplates();
+},
+_render: function () {
+if (this._needFullRefresh) {
+this._applyFullRefresh();
+this._needFullRefresh = false;
+} else if (this._keySplices.length) {
+if (this._sortFn) {
+this._applySplicesUserSort(this._keySplices);
+} else {
+if (this._filterFn) {
+this._applyFullRefresh();
+} else {
+this._applySplicesArrayOrder(this._indexSplices);
+}
+}
+} else {
+}
+this._keySplices = [];
+this._indexSplices = [];
+var keyToIdx = this._keyToInstIdx = {};
+for (var i = this._instances.length - 1; i >= 0; i--) {
+var inst = this._instances[i];
+if (inst.isPlaceholder && i < this._limit) {
+inst = this._insertInstance(i, inst.__key__);
+} else if (!inst.isPlaceholder && i >= this._limit) {
+inst = this._downgradeInstance(i, inst.__key__);
+}
+keyToIdx[inst.__key__] = i;
+if (!inst.isPlaceholder) {
+inst.__setProperty(this.indexAs, i, true);
+}
+}
+this._pool.length = 0;
+this._setRenderedItemCount(this._instances.length);
+this.fire('dom-change');
+this._tryRenderChunk();
+},
+_applyFullRefresh: function () {
+var c = this.collection;
+var keys;
+if (this._sortFn) {
+keys = c ? c.getKeys() : [];
+} else {
+keys = [];
+var items = this.items;
+if (items) {
+for (var i = 0; i < items.length; i++) {
+keys.push(c.getKey(items[i]));
+}
+}
+}
+var self = this;
+if (this._filterFn) {
+keys = keys.filter(function (a) {
+return self._filterFn(c.getItem(a));
+});
+}
+if (this._sortFn) {
+keys.sort(function (a, b) {
+return self._sortFn(c.getItem(a), c.getItem(b));
+});
+}
+for (i = 0; i < keys.length; i++) {
+var key = keys[i];
+var inst = this._instances[i];
+if (inst) {
+inst.__key__ = key;
+if (!inst.isPlaceholder && i < this._limit) {
+inst.__setProperty(this.as, c.getItem(key), true);
+}
+} else if (i < this._limit) {
+this._insertInstance(i, key);
+} else {
+this._insertPlaceholder(i, key);
+}
+}
+for (var j = this._instances.length - 1; j >= i; j--) {
+this._detachAndRemoveInstance(j);
+}
+},
+_numericSort: function (a, b) {
+return a - b;
+},
+_applySplicesUserSort: function (splices) {
+var c = this.collection;
+var keyMap = {};
+var key;
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0; j < s.removed.length; j++) {
+key = s.removed[j];
+keyMap[key] = keyMap[key] ? null : -1;
+}
+for (j = 0; j < s.added.length; j++) {
+key = s.added[j];
+keyMap[key] = keyMap[key] ? null : 1;
+}
+}
+var removedIdxs = [];
+var addedKeys = [];
+for (key in keyMap) {
+if (keyMap[key] === -1) {
+removedIdxs.push(this._keyToInstIdx[key]);
+}
+if (keyMap[key] === 1) {
+addedKeys.push(key);
+}
+}
+if (removedIdxs.length) {
+removedIdxs.sort(this._numericSort);
+for (i = removedIdxs.length - 1; i >= 0; i--) {
+var idx = removedIdxs[i];
+if (idx !== undefined) {
+this._detachAndRemoveInstance(idx);
+}
+}
+}
+var self = this;
+if (addedKeys.length) {
+if (this._filterFn) {
+addedKeys = addedKeys.filter(function (a) {
+return self._filterFn(c.getItem(a));
+});
+}
+addedKeys.sort(function (a, b) {
+return self._sortFn(c.getItem(a), c.getItem(b));
+});
+var start = 0;
+for (i = 0; i < addedKeys.length; i++) {
+start = this._insertRowUserSort(start, addedKeys[i]);
+}
+}
+},
+_insertRowUserSort: function (start, key) {
+var c = this.collection;
+var item = c.getItem(key);
+var end = this._instances.length - 1;
+var idx = -1;
+while (start <= end) {
+var mid = start + end >> 1;
+var midKey = this._instances[mid].__key__;
+var cmp = this._sortFn(c.getItem(midKey), item);
+if (cmp < 0) {
+start = mid + 1;
+} else if (cmp > 0) {
+end = mid - 1;
+} else {
+idx = mid;
+break;
+}
+}
+if (idx < 0) {
+idx = end + 1;
+}
+this._insertPlaceholder(idx, key);
+return idx;
+},
+_applySplicesArrayOrder: function (splices) {
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0; j < s.removed.length; j++) {
+this._detachAndRemoveInstance(s.index);
+}
+for (j = 0; j < s.addedKeys.length; j++) {
+this._insertPlaceholder(s.index + j, s.addedKeys[j]);
+}
+}
+},
+_detachInstance: function (idx) {
+var inst = this._instances[idx];
+if (!inst.isPlaceholder) {
+for (var i = 0; i < inst._children.length; i++) {
+var el = inst._children[i];
+Polymer.dom(inst.root).appendChild(el);
+}
+return inst;
+}
+},
+_attachInstance: function (idx, parent) {
+var inst = this._instances[idx];
+if (!inst.isPlaceholder) {
+parent.insertBefore(inst.root, this);
+}
+},
+_detachAndRemoveInstance: function (idx) {
+var inst = this._detachInstance(idx);
+if (inst) {
+this._pool.push(inst);
+}
+this._instances.splice(idx, 1);
+},
+_insertPlaceholder: function (idx, key) {
+this._instances.splice(idx, 0, {
+isPlaceholder: true,
+__key__: key
+});
+},
+_stampInstance: function (idx, key) {
+var model = { __key__: key };
+model[this.as] = this.collection.getItem(key);
+model[this.indexAs] = idx;
+return this.stamp(model);
+},
+_insertInstance: function (idx, key) {
+var inst = this._pool.pop();
+if (inst) {
+inst.__setProperty(this.as, this.collection.getItem(key), true);
+inst.__setProperty('__key__', key, true);
+} else {
+inst = this._stampInstance(idx, key);
+}
+var beforeRow = this._instances[idx + 1];
+var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this;
+var parentNode = Polymer.dom(this).parentNode;
+Polymer.dom(parentNode).insertBefore(inst.root, beforeNode);
+this._instances[idx] = inst;
+return inst;
+},
+_downgradeInstance: function (idx, key) {
+var inst = this._detachInstance(idx);
+if (inst) {
+this._pool.push(inst);
+}
+inst = {
+isPlaceholder: true,
+__key__: key
+};
+this._instances[idx] = inst;
+return inst;
+},
+_showHideChildren: function (hidden) {
+for (var i = 0; i < this._instances.length; i++) {
+this._instances[i]._showHideChildren(hidden);
+}
+},
+_forwardInstanceProp: function (inst, prop, value) {
+if (prop == this.as) {
+var idx;
+if (this._sortFn || this._filterFn) {
+idx = this.items.indexOf(this.collection.getItem(inst.__key__));
+} else {
+idx = inst[this.indexAs];
+}
+this.set('items.' + idx, value);
+}
+},
+_forwardInstancePath: function (inst, path, value) {
+if (path.indexOf(this.as + '.') === 0) {
+this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
+}
+},
+_forwardParentProp: function (prop, value) {
+var i$ = this._instances;
+for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
+if (!inst.isPlaceholder) {
+inst.__setProperty(prop, value, true);
+}
+}
+},
+_forwardParentPath: function (path, value) {
+var i$ = this._instances;
+for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
+if (!inst.isPlaceholder) {
+inst._notifyPath(path, value, true);
+}
+}
+},
+_forwardItemPath: function (path, value) {
+if (this._keyToInstIdx) {
+var dot = path.indexOf('.');
+var key = path.substring(0, dot < 0 ? path.length : dot);
+var idx = this._keyToInstIdx[key];
+var inst = this._instances[idx];
+if (inst && !inst.isPlaceholder) {
+if (dot >= 0) {
+path = this.as + '.' + path.substring(dot + 1);
+inst._notifyPath(path, value, true);
+} else {
+inst.__setProperty(this.as, value, true);
+}
+}
+}
+},
+itemForElement: function (el) {
+var instance = this.modelForElement(el);
+return instance && instance[this.as];
+},
+keyForElement: function (el) {
+var instance = this.modelForElement(el);
+return instance && instance.__key__;
+},
+indexForElement: function (el) {
+var instance = this.modelForElement(el);
+return instance && instance[this.indexAs];
+}
+});Polymer({
+is: 'array-selector',
+_template: null,
+properties: {
+items: {
+type: Array,
+observer: 'clearSelection'
+},
+multi: {
+type: Boolean,
+value: false,
+observer: 'clearSelection'
+},
+selected: {
+type: Object,
+notify: true
+},
+selectedItem: {
+type: Object,
+notify: true
+},
+toggle: {
+type: Boolean,
+value: false
+}
+},
+clearSelection: function () {
+if (Array.isArray(this.selected)) {
+for (var i = 0; i < this.selected.length; i++) {
+this.unlinkPaths('selected.' + i);
+}
+} else {
+this.unlinkPaths('selected');
+this.unlinkPaths('selectedItem');
+}
+if (this.multi) {
+if (!this.selected || this.selected.length) {
+this.selected = [];
+this._selectedColl = Polymer.Collection.get(this.selected);
+}
+} else {
+this.selected = null;
+this._selectedColl = null;
+}
+this.selectedItem = null;
+},
+isSelected: function (item) {
+if (this.multi) {
+return this._selectedColl.getKey(item) !== undefined;
+} else {
+return this.selected == item;
+}
+},
+deselect: function (item) {
+if (this.multi) {
+if (this.isSelected(item)) {
+var skey = this._selectedColl.getKey(item);
+this.arrayDelete('selected', item);
+this.unlinkPaths('selected.' + skey);
+}
+} else {
+this.selected = null;
+this.selectedItem = null;
+this.unlinkPaths('selected');
+this.unlinkPaths('selectedItem');
+}
+},
+select: function (item) {
+var icol = Polymer.Collection.get(this.items);
+var key = icol.getKey(item);
+if (this.multi) {
+if (this.isSelected(item)) {
+if (this.toggle) {
+this.deselect(item);
+}
+} else {
+this.push('selected', item);
+var skey = this._selectedColl.getKey(item);
+this.linkPaths('selected.' + skey, 'items.' + key);
+}
+} else {
+if (this.toggle && item == this.selected) {
+this.deselect();
+} else {
+this.selected = item;
+this.selectedItem = item;
+this.linkPaths('selected', 'items.' + key);
+this.linkPaths('selectedItem', 'items.' + key);
+}
+}
+}
+});Polymer({
+is: 'dom-if',
+extends: 'template',
+_template: null,
+properties: {
+'if': {
+type: Boolean,
+value: false,
+observer: '_queueRender'
+},
+restamp: {
+type: Boolean,
+value: false,
+observer: '_queueRender'
+}
+},
+behaviors: [Polymer.Templatizer],
+_queueRender: function () {
+this._debounceTemplate(this._render);
+},
+detached: function () {
+if (!this.parentNode || this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (!Polymer.Settings.hasShadow || !(this.parentNode instanceof ShadowRoot))) {
+this._teardownInstance();
+}
+},
+attached: function () {
+if (this.if && this.ctor) {
+this.async(this._ensureInstance);
+}
+},
+render: function () {
+this._flushTemplates();
+},
+_render: function () {
+if (this.if) {
+if (!this.ctor) {
+this.templatize(this);
+}
+this._ensureInstance();
+this._showHideChildren();
+} else if (this.restamp) {
+this._teardownInstance();
+}
+if (!this.restamp && this._instance) {
+this._showHideChildren();
+}
+if (this.if != this._lastIf) {
+this.fire('dom-change');
+this._lastIf = this.if;
+}
+},
+_ensureInstance: function () {
+var parentNode = Polymer.dom(this).parentNode;
+if (parentNode) {
+var parent = Polymer.dom(parentNode);
+if (!this._instance) {
+this._instance = this.stamp();
+var root = this._instance.root;
+parent.insertBefore(root, this);
+} else {
+var c$ = this._instance._children;
+if (c$ && c$.length) {
+var lastChild = Polymer.dom(this).previousSibling;
+if (lastChild !== c$[c$.length - 1]) {
+for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
+parent.insertBefore(n, this);
+}
+}
+}
+}
+}
+},
+_teardownInstance: function () {
+if (this._instance) {
+var c$ = this._instance._children;
+if (c$ && c$.length) {
+var parent = Polymer.dom(Polymer.dom(c$[0]).parentNode);
+for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
+parent.removeChild(n);
+}
+}
+this._instance = null;
+}
+},
+_showHideChildren: function () {
+var hidden = this.__hideTemplateChildren__ || !this.if;
+if (this._instance) {
+this._instance._showHideChildren(hidden);
+}
+},
+_forwardParentProp: function (prop, value) {
+if (this._instance) {
+this._instance[prop] = value;
+}
+},
+_forwardParentPath: function (path, value) {
+if (this._instance) {
+this._instance._notifyPath(path, value, true);
+}
+}
+});Polymer({
+is: 'dom-bind',
+extends: 'template',
+_template: null,
+created: function () {
+var self = this;
+Polymer.RenderStatus.whenReady(function () {
+if (document.readyState == 'loading') {
+document.addEventListener('DOMContentLoaded', function () {
+self._markImportsReady();
+});
+} else {
+self._markImportsReady();
+}
+});
+},
+_ensureReady: function () {
+if (!this._readied) {
+this._readySelf();
+}
+},
+_markImportsReady: function () {
+this._importsReady = true;
+this._ensureReady();
+},
+_registerFeatures: function () {
+this._prepConstructor();
+},
+_insertChildren: function () {
+var parentDom = Polymer.dom(Polymer.dom(this).parentNode);
+parentDom.insertBefore(this.root, this);
+},
+_removeChildren: function () {
+if (this._children) {
+for (var i = 0; i < this._children.length; i++) {
+this.root.appendChild(this._children[i]);
+}
+}
+},
+_initFeatures: function () {
+},
+_scopeElementClass: function (element, selector) {
+if (this.dataHost) {
+return this.dataHost._scopeElementClass(element, selector);
+} else {
+return selector;
+}
+},
+_prepConfigure: function () {
+var config = {};
+for (var prop in this._propertyEffects) {
+config[prop] = this[prop];
+}
+var setupConfigure = this._setupConfigure;
+this._setupConfigure = function () {
+setupConfigure.call(this, config);
+};
+},
+attached: function () {
+if (this._importsReady) {
+this.render();
+}
+},
+detached: function () {
+this._removeChildren();
+},
+render: function () {
+this._ensureReady();
+if (!this._children) {
+this._template = this;
+this._prepAnnotations();
+this._prepEffects();
+this._prepBehaviors();
+this._prepConfigure();
+this._prepBindings();
+this._prepPropertyInfo();
+Polymer.Base._initFeatures.call(this);
+this._children = Polymer.TreeApi.arrayCopyChildNodes(this.root);
+}
+this._insertChildren();
+this.fire('dom-change');
+}
+});</script>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/.bower.json
new file mode 100644
index 00000000000..dd39e422aef
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "web-animations-js",
+ "description": "JavaScript implementation of the Web Animations API",
+ "homepage": "https://github.com/web-animations/web-animations-js",
+ "main": "web-animations.min.js",
+ "moduleType": [
+ "globals"
+ ],
+ "keywords": [
+ "animations",
+ "polyfill"
+ ],
+ "license": "Apache-2.0",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "templates",
+ "test",
+ "src",
+ "Gruntfile.js",
+ "package.json",
+ "target-config.js",
+ "target-loader.js",
+ "web-animations.dev.html",
+ "web-animations.dev.js",
+ "web-animations-next.dev.html",
+ "web-animations-next.dev.js",
+ "web-animations-next-lite.dev.html",
+ "web-animations-next-lite.dev.js"
+ ],
+ "version": "2.2.1",
+ "_release": "2.2.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "2.2.1",
+ "commit": "45d8e40300e82ff02ccfbbc78c89500de0f5616f"
+ },
+ "_source": "git://github.com/web-animations/web-animations-js.git",
+ "_target": "^2.2.0",
+ "_originalSource": "web-animations/web-animations-js"
+} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/COPYING b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/COPYING
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/History.md b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/History.md
new file mode 100644
index 00000000000..9f2d5e9f4b5
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/History.md
@@ -0,0 +1,203 @@
+### 2.2.1 - *April 28 2016*
+ * [Deprecated invalid timing inputs](https://github.com/web-animations/web-animations-next/pull/437) as they will soon throw [TypeErrors](https://github.com/web-animations/web-animations-next/pull/426) in native browsers.
+
+ For example, this is deprecated and will eventually throw a TypeError:
+
+ element.animate([], {
+ duration: -1,
+ iterationStart: -1,
+ iterations: -1,
+ easing: 'garbage string',
+ });
+
+ * [Fixed polyfill crash in browsers based on Chromium 36 to 46.](https://github.com/web-animations/web-animations-next/pull/434)
+
+ * [Increased cubic-bezier accuracy.](https://github.com/web-animations/web-animations-next/pull/428)
+
+ * [Added support for grad and turn units for angles.](https://github.com/web-animations/web-animations-next/pull/427)
+
+### 2.2.0 - *April 6 2016*
+ * Deprecated the use of hyphens in property names.
+
+ For example, this is deprecated:
+
+ element.animate([{'font-size': '0px'}, {'font-size': '10px'}]);
+
+ and this should be used instead:
+
+ element.animate([{fontSize: '0px'}, {fontSize: '10px'}]);
+
+ * Added arbitrary easing capitalisation.
+
+ * Added "id" effect option. (http://w3c.github.io/web-animations/#dom-keyframeanimationoptions-id)
+
+ * Added "oncancel" event handler.
+
+ * Added value list keyframe syntax.
+
+ As as alternative to:
+
+ element.animate([{color: 'red'}, {color: 'green'}, {color: 'blue'}]);
+
+ you can now use:
+
+ element.animate({color: ['red', 'green', 'blue']});
+
+ * Fixed easing TypeError in FireFox Nightly when using groups.
+
+ * Fixed delayed animation updates on Safari and Firefox
+
+ * Fixed infinite recursion when setting onfinish to null.
+
+### 2.1.4 - *December 1 2015*
+ * Use `Date.now()` instead of `performace.now()` for mobile Safari.
+
+### 2.1.3 - *October 12 2015*
+ * Removed web-animations.min.js.gz
+
+### 2.1.2 - *July 8 2015*
+ * Fix a bug where onfinish was being called for GroupEffects before they were finished.
+
+### 2.1.1 - *July 1 2015*
+ * Add Animation.timeline getter
+ * Add AnimationEffect.parent getter
+ * Make AnimationEffectTiming (returned by AnimationEffect.timing) attributes mutable
+ * Expose the Animation constructor
+ * Change custom effects from AnimationEffects to onsample functions. Custom effects should now be created by setting the onsample attribute of a KeyframeEffect.
+
+ For example, this is deprecated:
+
+ var myEffect = new KeyframeEffect(
+ element,
+ function(timeFraction, target, effect) {
+ target.style.opacity = timeFraction;
+ },
+ 1000);
+ var myAnimation = document.timeline.play(myEffect);
+
+ and this should be used insead:
+
+ var myEffect = new KeyframeEffect(element, [], 1000);
+ effect.onsample = function(timeFraction, effect, animation) {
+ effect.target.style.opacity = timeFraction;
+ };
+ var myAnimation = document.timeline.play(myEffect);
+
+### 2.1.0 - *June 15 2015*
+ * Fix bug affecting GroupEffects with infinite iteration children
+ * Add GroupEffect.firstChild and GroupEffect.lastChild
+ * Add initial values for most CSS properties
+ * Allow `timeline.play()` to be called with no arguments
+ * Add AnimationEffect.clone
+ * Add GroupEffect.append and GroupEffect.prepend
+ * Add AnimationEffect.remove
+ * Add Animation.ready and Animation.finished promises
+
+### 2.0.0 - *April 5 2015*
+
+ * Improve behavior of group Animation playback rate.
+ * Rename Animation to KeyframeEffect.
+ * Rename AnimationSequence to SequenceEffect.
+ * Rename AnimationGroup to GroupEffect.
+ * Rename AnimationPlayer to Animation.
+ * Remove KeyframeEffect.effect and add KeyframeEffect.getFrames.
+ * Rename Animation.source to Animation.effect.
+ * Rename Timeline.getAnimationPlayers to Timeline.getAnimations.
+ * Rename Element.getAnimationPlayers to Element.getAnimations.
+
+### 1.0.7 - *March 10 2015*
+
+ * Improve performance of constructing groups and sequences.
+ * Remove support for animating zoom.
+ * Add bower file.
+
+### 1.0.6 - *February 5 2015*
+
+ * Implement playbackRate setter for group players.
+ * Fix pausing a group player before its first tick.
+ * Fix cancelling a group player before its first tick.
+ * Fix excess CPU use on idle pages where custom effects and groups were used.
+ * Suppress AnimationTiming.playbackRate deprecation warning for cases where AnimationTiming.playbackRate == 1.
+
+### 1.0.5 - *January 6 2015*
+
+ * Fix loading the polyfill in an SVG document
+ * Fix a problem where groups didn't take effect in their first frame
+ * Don't rely on performance.now
+
+### 1.0.4 - *December 8 2014*
+
+ * Fix a critical bug where deprecation logic wasn't being loaded
+ when `web-animations-next` and `web-animations-next-lite` were
+ executed on top of a native `element.animate`.
+
+### 1.0.3 - *December 4 2014*
+
+ * Fix a critical bug on iOS 7 and Safari <= 6. Due to limitations,
+ inline style patching is not supported on these platforms.
+
+### 1.0.2 - *November 28 2014*
+
+ * Deprecated `AnimationTiming.playbackRate`.
+
+ For example, this is no longer supported:
+
+ var player = element.animate(
+ keyframes,
+ {duration: 1000, playbackRate: 2});
+
+ Use `AnimationPlayer.playbackRate` instead:
+
+ var player = element.animate(
+ keyframes,
+ {duration: 1000});
+ player.playbackRate = 2;
+
+ If you have any feedback on this change, please start a discussion
+ on the public-fx mailing list:
+ http://lists.w3.org/Archives/Public/public-fx/
+
+ Or file an issue against the specification on GitHub:
+ https://github.com/w3c/web-animations/issues/new
+
+### 1.0.1 - *November 26 2014*
+
+ * Players should be constructed in idle state
+ * `play()` and `reverse()` should not force a start times
+ * Add `requestAnimationFrame` ids and `cancelAnimationFrame`
+
+### 1.0.0 — *November 21 2014*
+
+ The web-animations-js hackers are pleased to announce the release of
+ a new codebase for the Web Animations Polyfill:
+ https://github.com/web-animations/web-animations-js
+
+ The previous polyfill has been moved to:
+ https://github.com/web-animations/web-animations-js-legacy
+
+ The new codebase is focused on code-size -- our smallest target is
+ now only 33kb or 11kb after gzip.
+
+ We've implemented native fallback. If the target browser provides
+ Web Animations features natively, the Polyfill will use them.
+
+ We now provide three different build targets:
+
+ `web-animations.min.js` - Tracks the Web Animations features that
+ are supported natively in browsers. Today that means Element.animate
+ and Playback Control in Chrome. If you’re not sure what features you
+ will need, start with this.
+
+ `web-animations-next.min.js` - All of web-animations.min.js plus
+ features that are still undergoing discussion or have yet to be
+ implemented natively.
+
+ `web-animations-next-lite.min.js` - A cut down version of
+ web-animations-next, removes several lesser used property handlers
+ and some of the larger and less used features such as matrix
+ interpolation/decomposition.
+
+ Not all features of the previous polyfill have been ported to the
+ new codebase; most notably mutation of Animations and Groups and
+ Additive Animations are not yet supported. These features are still
+ important and will be implemented in the coming weeks.
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/README.md b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/README.md
new file mode 100644
index 00000000000..c61df59836b
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/README.md
@@ -0,0 +1,172 @@
+
+Quick Start
+-----------
+
+To provide native Chrome Web Animation features (`Element.animate` and Playback
+Control) in other browsers, use `web-animations.min.js`. To explore all of the
+proposed Web Animations API, use `web-animations-next.min.js`.
+
+What is Web Animations?
+-----------------------
+
+Web Animations is a new JavaScript API for driving animated content on the web.
+By unifying the animation features of SVG and CSS, Web Animations unlocks
+features previously only usable declaratively, and exposes powerful,
+high-performance animation capabilities to developers.
+
+For more details see the
+[W3C specification](http://w3c.github.io/web-animations/).
+
+What is the polyfill?
+---------------------
+
+The polyfill is a JavaScript implementation of the Web Animations API. It is
+supported on modern versions of all major browsers, including:
+
+* Chrome
+* Firefox 27+
+* IE10+ (including Edge)
+* Safari (iOS) 7.1+
+* Safari (Mac) 9+
+
+Getting Started
+---------------
+
+Here's a simple example of an animation that scales and changes the opacity of
+a `<div>` over 0.5 seconds. The animation alternates producing a pulsing
+effect.
+
+```html
+<script src="web-animations.min.js"></script>
+<div class="pulse" style="width:150px;">Hello world!</div>
+<script>
+ var elem = document.querySelector('.pulse');
+ var animation = elem.animate([
+ {opacity: 0.5, transform: "scale(0.5)"},
+ {opacity: 1.0, transform: "scale(1)"}
+ ], {
+ direction: 'alternate',
+ duration: 500,
+ iterations: Infinity
+ });
+</script>
+```
+
+Web Animations supports off-main-thread animations, and also allows procedural
+generation of animations and fine-grained control of animation playback. See
+<http://web-animations.github.io> for ideas and inspiration - or [web-animations-codelabs](https://github.com/web-animations/web-animations-codelabs).
+
+Native Fallback
+---------------
+
+When the polyfill runs on a browser that implements `Element.animate` and
+`Animation` Playback Control it will detect and use the underlying native
+features.
+
+Different Build Targets
+-----------------------
+
+### web-animations.min.js
+
+Tracks the Web Animations features that are supported natively in browsers.
+Today that means Element.animate and Playback Control in Chrome. If you’re not
+sure what features you will need, start with this.
+
+### web-animations-next.min.js
+
+Contains all of web-animations.min.js plus features that are still undergoing
+discussion or have yet to be implemented natively.
+
+### web-animations-next-lite.min.js
+
+A cut down version of web-animations-next, it removes several lesser used
+property handlers and some of the larger and less used features such as matrix
+interpolation/decomposition.
+
+### Build Target Comparison
+
+| | web-animations | web-animations-next | web-animations-next-lite |
+|------------------------|:--------------:|:-------------------:|:------------------------:|
+|Size (gzipped) | 12.5kb | 14kb | 10.5kb |
+|Element.animate | ✔ | ✔ | ✔ |
+|Timing input (easings, duration, fillMode, etc.) for animation effects| ✔ | ✔ | ✔ |
+|Playback control | ✔ | ✔ | ✔ |
+|Support for animating lengths, transforms and opacity| ✔ | ✔ | ✔ |
+|Support for animating other CSS properties| ✔ | ✔ | 🚫 |
+|Matrix fallback for transform animations | ✔ | ✔ | 🚫 |
+|KeyframeEffect constructor | 🚫 | ✔ | ✔ |
+|Simple GroupEffects & SequenceEffects | 🚫 | ✔ | ✔ |
+|Custom Effects | 🚫 | ✔ | ✔ |
+|Timing input (easings, duration, fillMode, etc.) for groups</div>| 🚫 | 🚫\* | 🚫 |
+|Additive animation | 🚫\* | 🚫\* | 🚫 |
+|Motion path | 🚫\* | 🚫\* | 🚫 |
+|Modifiable keyframe effect timing| 🚫 | 🚫\* | 🚫\* |
+|Modifiable group timing | 🚫 | 🚫\* | 🚫\* |
+|Usable inline style\*\* | ✔ | ✔ | 🚫 |
+
+\* support is planned for these features.
+\*\* see inline style caveat below.
+
+Caveats
+-------
+
+Some things won’t ever be faithful to the native implementation due to browser
+and CSS API limitations. These include:
+
+### Inline Style
+
+Inline style modification is the mechanism used by the polyfill to animate
+properties. Both web-animations and web-animations-next incorporate a module
+that emulates a vanilla inline style object, so that style modification from
+JavaScript can still work in the presence of animations. However, to keep the
+size of web-animations-next-lite as small as possible, the style emulation
+module is not included. When using this version of the polyfill, JavaScript
+inline style modification will be overwritten by animations.
+Due to browser constraints inline style modification is not supported on iOS 7
+or Safari 6 (or earlier versions).
+
+### Prefix handling
+
+The polyfill will automatically detect the correctly prefixed name to use when
+writing animated properties back to the platform. Where possible, the polyfill
+will only accept unprefixed versions of experimental features. For example:
+
+```js
+var effect = new KeyframeEffect(elem, {"transform": "translate(100px, 100px)"}, 2000);
+```
+
+will work in all browsers that implement a conforming version of transform, but
+
+```js
+var effect = new KeyframeEffect(elem, {"-webkit-transform": "translate(100px, 100px)"}, 2000);
+```
+
+will not work anywhere.
+
+API and Specification Feedback
+------------------------------
+
+File an issue on GitHub: <https://github.com/w3c/web-animations/issues/new>.
+Alternatively, send an email to <public-fx@w3.org> with subject line
+“[web-animations] … message topic …”
+([archives](http://lists.w3.org/Archives/Public/public-fx/)).
+
+Polyfill Issues
+---------------
+
+Report any issues with this implementation on GitHub:
+<https://github.com/web-animations/web-animations-next/issues/new>.
+
+Breaking changes
+----------------
+
+When we make a potentially breaking change to the polyfill's API
+surface (like a rename) we will, where possible, continue supporting the
+old version, deprecated, for three months, and ensure that there are
+console warnings to indicate that a change is pending. After three
+months, the old version of the API surface (e.g. the old version of a
+function name) will be removed. *If you see deprecation warnings you
+can't avoid it by not updating*.
+
+We also announce anything that isn't a bug fix on
+[web-animations-changes@googlegroups.com](https://groups.google.com/forum/#!forum/web-animations-changes).
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/bower.json b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/bower.json
new file mode 100644
index 00000000000..22f26b5e5c2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "web-animations-js",
+ "description": "JavaScript implementation of the Web Animations API",
+ "homepage": "https://github.com/web-animations/web-animations-js",
+ "main": "web-animations.min.js",
+ "moduleType": [
+ "globals"
+ ],
+ "keywords": [
+ "animations",
+ "polyfill"
+ ],
+ "license": "Apache-2.0",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "templates",
+ "test",
+ "src",
+ "Gruntfile.js",
+ "package.json",
+ "target-config.js",
+ "target-loader.js",
+ "web-animations.dev.html",
+ "web-animations.dev.js",
+ "web-animations-next.dev.html",
+ "web-animations-next.dev.js",
+ "web-animations-next-lite.dev.html",
+ "web-animations-next-lite.dev.js"
+ ]
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js
new file mode 100644
index 00000000000..c7b56bdac3e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js
@@ -0,0 +1,17 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+!function(a,b){var c={},d={},e={},f=null;!function(a,b){function c(a){if("number"==typeof a)return a;var b={};for(var c in a)b[c]=a[c];return b}function d(){this._delay=0,this._endDelay=0,this._fill="none",this._iterationStart=0,this._iterations=1,this._duration=0,this._playbackRate=1,this._direction="normal",this._easing="linear",this._easingFunction=w}function e(){return a.isDeprecated("Invalid timing inputs","2016-03-02","TypeError exceptions will be thrown instead.",!0)}function f(b,c,e){var f=new d;return c&&(f.fill="both",f.duration="auto"),"number"!=typeof b||isNaN(b)?void 0!==b&&Object.getOwnPropertyNames(b).forEach(function(c){if("auto"!=b[c]){if(("number"==typeof f[c]||"duration"==c)&&("number"!=typeof b[c]||isNaN(b[c])))return;if("fill"==c&&-1==u.indexOf(b[c]))return;if("direction"==c&&-1==v.indexOf(b[c]))return;if("playbackRate"==c&&1!==b[c]&&a.isDeprecated("AnimationEffectTiming.playbackRate","2014-11-28","Use Animation.playbackRate instead."))return;f[c]=b[c]}}):f.duration=b,f}function g(a){return"number"==typeof a&&(a=isNaN(a)?{duration:0}:{duration:a}),a}function h(b,c){return b=a.numericTimingToObject(b),f(b,c)}function i(a,b,c,d){return 0>a||a>1||0>c||c>1?w:function(e){function f(a,b,c){return 3*a*(1-c)*(1-c)*c+3*b*(1-c)*c*c+c*c*c}if(0==e||1==e)return e;for(var g=0,h=1;;){var i=(g+h)/2,j=f(a,c,i);if(Math.abs(e-j)<1e-4)return f(b,d,i);e>j?g=i:h=i}}}function j(a,b){return function(c){if(c>=1)return 1;var d=1/a;return c+=b*d,c-c%d}}function k(a){B||(B=document.createElement("div").style),B.animationTimingFunction="",B.animationTimingFunction=a;var b=B.animationTimingFunction;if(""==b&&e())throw new TypeError(a+" is not a valid value for easing");var c=D.exec(b);if(c)return i.apply(this,c.slice(1).map(Number));var d=E.exec(b);if(d)return j(Number(d[1]),{start:x,middle:y,end:z}[d[2]]);var f=A[b];return f?f:w}function l(a){return Math.abs(m(a)/a.playbackRate)}function m(a){return a.duration*a.iterations}function n(a,b,c){return null==b?F:b<c.delay?G:b>=c.delay+a?H:I}function o(a,b,c,d,e){switch(d){case G:return"backwards"==b||"both"==b?0:null;case I:return c-e;case H:return"forwards"==b||"both"==b?a:null;case F:return null}}function p(a,b,c,d){return(d.playbackRate<0?b-a:b)*d.playbackRate+c}function q(a,b,c,d,e){return c===1/0||c===-(1/0)||c-d==b&&e.iterations&&(e.iterations+e.iterationStart)%1==0?a:c%a}function r(a,b,c,d){return 0===c?0:b==a?d.iterationStart+d.iterations-1:Math.floor(c/a)}function s(a,b,c,d){var e=a%2>=1,f="normal"==d.direction||d.direction==(e?"alternate-reverse":"alternate"),g=f?c:b-c,h=g/b;return b*d._easingFunction(h)}function t(a,b,c){var d=n(a,b,c),e=o(a,c.fill,b,d,c.delay);if(null===e)return null;if(0===a)return d===G?0:1;var f=c.iterationStart*c.duration,g=p(a,e,f,c),h=q(c.duration,m(c),g,f,c),i=r(c.duration,h,g,c);return s(i,c.duration,h,c)/c.duration}var u="backwards|forwards|both|none".split("|"),v="reverse|alternate|alternate-reverse".split("|"),w=function(a){return a};d.prototype={_setMember:function(b,c){this["_"+b]=c,this._effect&&(this._effect._timingInput[b]=c,this._effect._timing=a.normalizeTimingInput(this._effect._timingInput),this._effect.activeDuration=a.calculateActiveDuration(this._effect._timing),this._effect._animation&&this._effect._animation._rebuildUnderlyingAnimation())},get playbackRate(){return this._playbackRate},set delay(a){this._setMember("delay",a)},get delay(){return this._delay},set endDelay(a){this._setMember("endDelay",a)},get endDelay(){return this._endDelay},set fill(a){this._setMember("fill",a)},get fill(){return this._fill},set iterationStart(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterationStart must be a non-negative number, received: "+timing.iterationStart);this._setMember("iterationStart",a)},get iterationStart(){return this._iterationStart},set duration(a){if("auto"!=a&&(isNaN(a)||0>a)&&e())throw new TypeError("duration must be non-negative or auto, received: "+a);this._setMember("duration",a)},get duration(){return this._duration},set direction(a){this._setMember("direction",a)},get direction(){return this._direction},set easing(a){this._easingFunction=k(a),this._setMember("easing",a)},get easing(){return this._easing},set iterations(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterations must be non-negative, received: "+a);this._setMember("iterations",a)},get iterations(){return this._iterations}};var x=1,y=.5,z=0,A={ease:i(.25,.1,.25,1),"ease-in":i(.42,0,1,1),"ease-out":i(0,0,.58,1),"ease-in-out":i(.42,0,.58,1),"step-start":j(1,x),"step-middle":j(1,y),"step-end":j(1,z)},B=null,C="\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*",D=new RegExp("cubic-bezier\\("+C+","+C+","+C+","+C+"\\)"),E=/steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/,F=0,G=1,H=2,I=3;a.cloneTimingInput=c,a.makeTiming=f,a.numericTimingToObject=g,a.normalizeTimingInput=h,a.calculateActiveDuration=l,a.calculateTimeFraction=t,a.calculatePhase=n,a.toTimingFunction=k}(c,f),function(a,b){function c(a,b){return a in j?j[a][b]||b:b}function d(a,b,d){var e=g[a];if(e){h.style[a]=b;for(var f in e){var i=e[f],j=h.style[i];d[i]=c(i,j)}}else d[a]=c(a,b)}function e(a){var b=[];for(var c in a)if(!(c in["easing","offset","composite"])){var d=a[c];Array.isArray(d)||(d=[d]);for(var e,f=d.length,g=0;f>g;g++)e={},"offset"in a?e.offset=a.offset:1==f?e.offset=1:e.offset=g/(f-1),"easing"in a&&(e.easing=a.easing),"composite"in a&&(e.composite=a.composite),e[c]=d[g],b.push(e)}return b.sort(function(a,b){return a.offset-b.offset}),b}function f(a){function b(){var a=c.length;null==c[a-1].offset&&(c[a-1].offset=1),a>1&&null==c[0].offset&&(c[0].offset=0);for(var b=0,d=c[0].offset,e=1;a>e;e++){var f=c[e].offset;if(null!=f){for(var g=1;e-b>g;g++)c[b+g].offset=d+(f-d)*g/(e-b);b=e,d=f}}}if(null==a)return[];window.Symbol&&Symbol.iterator&&Array.prototype.from&&a[Symbol.iterator]&&(a=Array.from(a)),Array.isArray(a)||(a=e(a));for(var c=a.map(function(a){var b={};for(var c in a){var e=a[c];if("offset"==c){if(null!=e&&(e=Number(e),!isFinite(e)))throw new TypeError("keyframe offsets must be numbers.")}else{if("composite"==c)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"add compositing is not supported"};e=""+e}d(c,e,b)}return void 0==b.offset&&(b.offset=null),b}),f=!0,g=-(1/0),h=0;h<c.length;h++){var i=c[h].offset;if(null!=i){if(g>i)throw{code:DOMException.INVALID_MODIFICATION_ERR,name:"InvalidModificationError",message:"Keyframes are not loosely sorted by offset. Sort or specify offsets."};g=i}else f=!1}return c=c.filter(function(a){return a.offset>=0&&a.offset<=1}),f||b(),c}var g={background:["backgroundImage","backgroundPosition","backgroundSize","backgroundRepeat","backgroundAttachment","backgroundOrigin","backgroundClip","backgroundColor"],border:["borderTopColor","borderTopStyle","borderTopWidth","borderRightColor","borderRightStyle","borderRightWidth","borderBottomColor","borderBottomStyle","borderBottomWidth","borderLeftColor","borderLeftStyle","borderLeftWidth"],borderBottom:["borderBottomWidth","borderBottomStyle","borderBottomColor"],borderColor:["borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],borderLeft:["borderLeftWidth","borderLeftStyle","borderLeftColor"],borderRadius:["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],borderRight:["borderRightWidth","borderRightStyle","borderRightColor"],borderTop:["borderTopWidth","borderTopStyle","borderTopColor"],borderWidth:["borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"],flex:["flexGrow","flexShrink","flexBasis"],font:["fontFamily","fontSize","fontStyle","fontVariant","fontWeight","lineHeight"],margin:["marginTop","marginRight","marginBottom","marginLeft"],outline:["outlineColor","outlineStyle","outlineWidth"],padding:["paddingTop","paddingRight","paddingBottom","paddingLeft"]},h=document.createElementNS("http://www.w3.org/1999/xhtml","div"),i={thin:"1px",medium:"3px",thick:"5px"},j={borderBottomWidth:i,borderLeftWidth:i,borderRightWidth:i,borderTopWidth:i,fontSize:{"xx-small":"60%","x-small":"75%",small:"89%",medium:"100%",large:"120%","x-large":"150%","xx-large":"200%"},fontWeight:{normal:"400",bold:"700"},outlineWidth:i,textShadow:{none:"0px 0px 0px transparent"},boxShadow:{none:"0px 0px 0px 0px transparent"}};a.convertToArrayForm=e,a.normalizeKeyframes=f}(c,f),function(a){var b={};a.isDeprecated=function(a,c,d,e){var f=e?"are":"is",g=new Date,h=new Date(c);return h.setMonth(h.getMonth()+3),h>g?(a in b||console.warn("Web Animations: "+a+" "+f+" deprecated and will stop working on "+h.toDateString()+". "+d),b[a]=!0,!1):!0},a.deprecated=function(b,c,d,e){var f=e?"are":"is";if(a.isDeprecated(b,c,d,e))throw new Error(b+" "+f+" no longer supported. "+d)}}(c),function(){if(document.documentElement.animate){var a=document.documentElement.animate([],0),b=!0;if(a&&(b=!1,"play|currentTime|pause|reverse|playbackRate|cancel|finish|startTime|playState".split("|").forEach(function(c){void 0===a[c]&&(b=!0)})),!b)return}!function(a,b,c){function d(a){for(var b={},c=0;c<a.length;c++)for(var d in a[c])if("offset"!=d&&"easing"!=d&&"composite"!=d){var e={offset:a[c].offset,easing:a[c].easing,value:a[c][d]};b[d]=b[d]||[],b[d].push(e)}for(var f in b){var g=b[f];if(0!=g[0].offset||1!=g[g.length-1].offset)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"Partial keyframes are not supported"}}return b}function e(c){var d=[];for(var e in c)for(var f=c[e],g=0;g<f.length-1;g++){var h=f[g].offset,i=f[g+1].offset,j=f[g].value,k=f[g+1].value,l=f[g].easing;h==i&&(1==i?j=k:k=j),d.push({startTime:h,endTime:i,easing:a.toTimingFunction(l?l:"linear"),property:e,interpolation:b.propertyInterpolation(e,j,k)})}return d.sort(function(a,b){return a.startTime-b.startTime}),d}b.convertEffectInput=function(c){var f=a.normalizeKeyframes(c),g=d(f),h=e(g);return function(a,c){if(null!=c)h.filter(function(a){return 0>=c&&0==a.startTime||c>=1&&1==a.endTime||c>=a.startTime&&c<=a.endTime}).forEach(function(d){var e=c-d.startTime,f=d.endTime-d.startTime,g=0==f?0:d.easing(e/f);b.apply(a,d.property,d.interpolation(g))});else for(var d in g)"offset"!=d&&"easing"!=d&&"composite"!=d&&b.clear(a,d)}}}(c,d,f),function(a,b,c){function d(a){return a.replace(/-(.)/g,function(a,b){return b.toUpperCase()})}function e(a,b,c){h[c]=h[c]||[],h[c].push([a,b])}function f(a,b,c){for(var f=0;f<c.length;f++){var g=c[f];e(a,b,d(g))}}function g(c,e,f){var g=c;/-/.test(c)&&!a.isDeprecated("Hyphenated property names","2016-03-22","Use camelCase instead.",!0)&&(g=d(c)),"initial"!=e&&"initial"!=f||("initial"==e&&(e=i[g]),"initial"==f&&(f=i[g]));for(var j=e==f?[]:h[g],k=0;j&&k<j.length;k++){var l=j[k][0](e),m=j[k][0](f);if(void 0!==l&&void 0!==m){var n=j[k][1](l,m);if(n){var o=b.Interpolation.apply(null,n);return function(a){return 0==a?e:1==a?f:o(a)}}}}return b.Interpolation(!1,!0,function(a){return a?f:e})}var h={};b.addPropertiesHandler=f;var i={backgroundColor:"transparent",backgroundPosition:"0% 0%",borderBottomColor:"currentColor",borderBottomLeftRadius:"0px",borderBottomRightRadius:"0px",borderBottomWidth:"3px",borderLeftColor:"currentColor",borderLeftWidth:"3px",borderRightColor:"currentColor",borderRightWidth:"3px",borderSpacing:"2px",borderTopColor:"currentColor",borderTopLeftRadius:"0px",borderTopRightRadius:"0px",borderTopWidth:"3px",bottom:"auto",clip:"rect(0px, 0px, 0px, 0px)",color:"black",fontSize:"100%",fontWeight:"400",height:"auto",left:"auto",letterSpacing:"normal",lineHeight:"120%",marginBottom:"0px",marginLeft:"0px",marginRight:"0px",marginTop:"0px",maxHeight:"none",maxWidth:"none",minHeight:"0px",minWidth:"0px",opacity:"1.0",outlineColor:"invert",outlineOffset:"0px",outlineWidth:"3px",paddingBottom:"0px",paddingLeft:"0px",paddingRight:"0px",paddingTop:"0px",right:"auto",textIndent:"0px",textShadow:"0px 0px 0px transparent",top:"auto",transform:"",verticalAlign:"0px",visibility:"visible",width:"auto",wordSpacing:"normal",zIndex:"auto"};b.propertyInterpolation=g}(c,d,f),function(a,b,c){function d(b){var c=a.calculateActiveDuration(b),d=function(d){return a.calculateTimeFraction(c,d,b)};return d._totalDuration=b.delay+c+b.endDelay,d._isCurrent=function(d){var e=a.calculatePhase(c,d,b);return e===PhaseActive||e===PhaseBefore},d}b.KeyframeEffect=function(c,e,f,g){var h,i=d(a.normalizeTimingInput(f)),j=b.convertEffectInput(e),k=function(){j(c,h)};return k._update=function(a){return h=i(a),null!==h},k._clear=function(){j(c,null)},k._hasSameTarget=function(a){return c===a},k._isCurrent=i._isCurrent,k._totalDuration=i._totalDuration,k._id=g,k},b.NullEffect=function(a){var b=function(){a&&(a(),a=null)};return b._update=function(){return null},b._totalDuration=0,b._isCurrent=function(){return!1},b._hasSameTarget=function(){return!1},b}}(c,d,f),function(a,b){a.apply=function(b,c,d){b.style[a.propertyName(c)]=d},a.clear=function(b,c){b.style[a.propertyName(c)]=""}}(d,f),function(a){window.Element.prototype.animate=function(b,c){var d="";return c&&c.id&&(d=c.id),a.timeline._play(a.KeyframeEffect(this,b,c,d))}}(d),function(a,b){function c(a,b,d){if("number"==typeof a&&"number"==typeof b)return a*(1-d)+b*d;if("boolean"==typeof a&&"boolean"==typeof b)return.5>d?a:b;if(a.length==b.length){for(var e=[],f=0;f<a.length;f++)e.push(c(a[f],b[f],d));return e}throw"Mismatched interpolation arguments "+a+":"+b}a.Interpolation=function(a,b,d){return function(e){return d(c(a,b,e))}}}(d,f),function(a,b,c){a.sequenceNumber=0;var d=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="finish",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()};b.Animation=function(b){this.id="",b&&b._id&&(this.id=b._id),this._sequenceNumber=a.sequenceNumber++,this._currentTime=0,this._startTime=null,this._paused=!1,this._playbackRate=1,this._inTimeline=!0,this._finishedFlag=!0,this.onfinish=null,this._finishHandlers=[],this._effect=b,this._inEffect=this._effect._update(0),this._idle=!0,this._currentTimePending=!1},b.Animation.prototype={_ensureAlive:function(){this.playbackRate<0&&0===this.currentTime?this._inEffect=this._effect._update(-1):this._inEffect=this._effect._update(this.currentTime),this._inTimeline||!this._inEffect&&this._finishedFlag||(this._inTimeline=!0,b.timeline._animations.push(this))},_tickCurrentTime:function(a,b){a!=this._currentTime&&(this._currentTime=a,this._isFinished&&!b&&(this._currentTime=this._playbackRate>0?this._totalDuration:0),this._ensureAlive())},get currentTime(){return this._idle||this._currentTimePending?null:this._currentTime},set currentTime(a){a=+a,isNaN(a)||(b.restart(),this._paused||null==this._startTime||(this._startTime=this._timeline.currentTime-a/this._playbackRate),this._currentTimePending=!1,this._currentTime!=a&&(this._tickCurrentTime(a,!0),b.invalidateEffects()))},get startTime(){return this._startTime},set startTime(a){a=+a,isNaN(a)||this._paused||this._idle||(this._startTime=a,this._tickCurrentTime((this._timeline.currentTime-this._startTime)*this.playbackRate),b.invalidateEffects())},get playbackRate(){return this._playbackRate},set playbackRate(a){if(a!=this._playbackRate){var b=this.currentTime;this._playbackRate=a,this._startTime=null,"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!=b&&(this.currentTime=b)}},get _isFinished(){return!this._idle&&(this._playbackRate>0&&this._currentTime>=this._totalDuration||this._playbackRate<0&&this._currentTime<=0)},get _totalDuration(){return this._effect._totalDuration},get playState(){return this._idle?"idle":null==this._startTime&&!this._paused&&0!=this.playbackRate||this._currentTimePending?"pending":this._paused?"paused":this._isFinished?"finished":"running"},play:function(){this._paused=!1,(this._isFinished||this._idle)&&(this._currentTime=this._playbackRate>0?0:this._totalDuration,this._startTime=null),this._finishedFlag=!1,this._idle=!1,this._ensureAlive(),b.invalidateEffects()},pause:function(){this._isFinished||this._paused||this._idle||(this._currentTimePending=!0),this._startTime=null,this._paused=!0},finish:function(){this._idle||(this.currentTime=this._playbackRate>0?this._totalDuration:0,this._startTime=this._totalDuration-this.currentTime,this._currentTimePending=!1,b.invalidateEffects())},cancel:function(){this._inEffect&&(this._inEffect=!1,this._idle=!0,this._finishedFlag=!0,this.currentTime=0,this._startTime=null,this._effect._update(null),b.invalidateEffects())},reverse:function(){this.playbackRate*=-1,this.play()},addEventListener:function(a,b){"function"==typeof b&&"finish"==a&&this._finishHandlers.push(b)},removeEventListener:function(a,b){if("finish"==a){var c=this._finishHandlers.indexOf(b);c>=0&&this._finishHandlers.splice(c,1)}},_fireEvents:function(a){if(this._isFinished){if(!this._finishedFlag){var b=new d(this,this._currentTime,a),c=this._finishHandlers.concat(this.onfinish?[this.onfinish]:[]);setTimeout(function(){c.forEach(function(a){a.call(b.target,b)})},0),this._finishedFlag=!0}}else this._finishedFlag=!1},_tick:function(a,b){this._idle||this._paused||(null==this._startTime?b&&(this.startTime=a-this._currentTime/this.playbackRate):this._isFinished||this._tickCurrentTime((a-this._startTime)*this.playbackRate)),b&&(this._currentTimePending=!1,this._fireEvents(a))},get _needsTick(){return this.playState in{pending:1,running:1}||!this._finishedFlag}}}(c,d,f),function(a,b,c){function d(a){var b=j;j=[],a<p.currentTime&&(a=p.currentTime),h(a,!0),b.forEach(function(b){b[1](a)}),g(),l=void 0}function e(a,b){return a._sequenceNumber-b._sequenceNumber}function f(){this._animations=[],this.currentTime=window.performance&&performance.now?performance.now():0}function g(){o.forEach(function(a){a()}),o.length=0}function h(a,c){n=!1;var d=b.timeline;d.currentTime=a,d._animations.sort(e),m=!1;var f=d._animations;d._animations=[];var g=[],h=[];f=f.filter(function(b){b._tick(a,c),b._inEffect?h.push(b._effect):g.push(b._effect),b._needsTick&&(m=!0);var d=b._inEffect||b._needsTick;return b._inTimeline=d,d}),o.push.apply(o,g),o.push.apply(o,h),d._animations.push.apply(d._animations,f),m&&requestAnimationFrame(function(){})}var i=window.requestAnimationFrame,j=[],k=0;window.requestAnimationFrame=function(a){var b=k++;return 0==j.length&&i(d),j.push([b,a]),b},window.cancelAnimationFrame=function(a){j.forEach(function(b){b[0]==a&&(b[1]=function(){})})},f.prototype={_play:function(c){c._timing=a.normalizeTimingInput(c.timing);var d=new b.Animation(c);return d._idle=!1,d._timeline=this,this._animations.push(d),b.restart(),b.invalidateEffects(),d}};var l=void 0,m=!1,n=!1;b.restart=function(){return m||(m=!0,requestAnimationFrame(function(){}),n=!0),n},b.invalidateEffects=function(){h(b.timeline.currentTime,!1),g()};var o=[],p=new f;b.timeline=p}(c,d,f),function(a){function b(a,b){var c=a.exec(b);return c?(c=a.ignoreCase?c[0].toLowerCase():c[0],[c,b.substr(c.length)]):void 0}function c(a,b){b=b.replace(/^\s*/,"");var c=a(b);return c?[c[0],c[1].replace(/^\s*/,"")]:void 0}function d(a,d,e){a=c.bind(null,a);for(var f=[];;){var g=a(e);if(!g)return[f,e];if(f.push(g[0]),e=g[1],g=b(d,e),!g||""==g[1])return[f,e];e=g[1]}}function e(a,b){for(var c=0,d=0;d<b.length&&(!/\s|,/.test(b[d])||0!=c);d++)if("("==b[d])c++;else if(")"==b[d]&&(c--,0==c&&d++,0>=c))break;var e=a(b.substr(0,d));return void 0==e?void 0:[e,b.substr(d)]}function f(a,b){for(var c=a,d=b;c&&d;)c>d?c%=d:d%=c;return c=a*b/(c+d)}function g(a){return function(b){var c=a(b);return c&&(c[0]=void 0),c}}function h(a,b){return function(c){var d=a(c);return d?d:[b,c]}}function i(b,c){for(var d=[],e=0;e<b.length;e++){var f=a.consumeTrimmed(b[e],c);if(!f||""==f[0])return;void 0!==f[0]&&d.push(f[0]),c=f[1]}return""==c?d:void 0}function j(a,b,c,d,e){for(var g=[],h=[],i=[],j=f(d.length,e.length),k=0;j>k;k++){var l=b(d[k%d.length],e[k%e.length]);if(!l)return;g.push(l[0]),h.push(l[1]),i.push(l[2])}return[g,h,function(b){var d=b.map(function(a,b){return i[b](a)}).join(c);return a?a(d):d}]}function k(a,b,c){for(var d=[],e=[],f=[],g=0,h=0;h<c.length;h++)if("function"==typeof c[h]){var i=c[h](a[g],b[g++]);d.push(i[0]),e.push(i[1]),f.push(i[2])}else!function(a){d.push(!1),e.push(!1),f.push(function(){return c[a]})}(h);return[d,e,function(a){for(var b="",c=0;c<a.length;c++)b+=f[c](a[c]);return b}]}a.consumeToken=b,a.consumeTrimmed=c,a.consumeRepeated=d,a.consumeParenthesised=e,a.ignore=g,a.optional=h,a.consumeList=i,a.mergeNestedRepeated=j.bind(null,null),a.mergeWrappedNestedRepeated=j,a.mergeList=k}(d),function(a){function b(b){function c(b){var c=a.consumeToken(/^inset/i,b);if(c)return d.inset=!0,c;var c=a.consumeLengthOrPercent(b);if(c)return d.lengths.push(c[0]),c;var c=a.consumeColor(b);return c?(d.color=c[0],c):void 0}var d={inset:!1,lengths:[],color:null},e=a.consumeRepeated(c,/^/,b);return e&&e[0].length?[d,e[1]]:void 0}function c(c){var d=a.consumeRepeated(b,/^,/,c);return d&&""==d[1]?d[0]:void 0}function d(b,c){for(;b.lengths.length<Math.max(b.lengths.length,c.lengths.length);)b.lengths.push({px:0});for(;c.lengths.length<Math.max(b.lengths.length,c.lengths.length);)c.lengths.push({px:0});if(b.inset==c.inset&&!!b.color==!!c.color){for(var d,e=[],f=[[],0],g=[[],0],h=0;h<b.lengths.length;h++){var i=a.mergeDimensions(b.lengths[h],c.lengths[h],2==h);f[0].push(i[0]),g[0].push(i[1]),e.push(i[2])}if(b.color&&c.color){var j=a.mergeColors(b.color,c.color);f[1]=j[0],g[1]=j[1],d=j[2]}return[f,g,function(a){for(var c=b.inset?"inset ":" ",f=0;f<e.length;f++)c+=e[f](a[0][f])+" ";return d&&(c+=d(a[1])),c}]}}function e(b,c,d,e){function f(a){return{inset:a,color:[0,0,0,0],lengths:[{px:0},{px:0},{px:0},{px:0}]}}for(var g=[],h=[],i=0;i<d.length||i<e.length;i++){var j=d[i]||f(e[i].inset),k=e[i]||f(d[i].inset);g.push(j),h.push(k)}return a.mergeNestedRepeated(b,c,g,h)}var f=e.bind(null,d,", ");a.addPropertiesHandler(c,f,["box-shadow","text-shadow"])}(d),function(a,b){function c(a){return a.toFixed(3).replace(".000","")}function d(a,b,c){return Math.min(b,Math.max(a,c))}function e(a){return/^\s*[-+]?(\d*\.)?\d+\s*$/.test(a)?Number(a):void 0}function f(a,b){return[a,b,c]}function g(a,b){return 0!=a?i(0,1/0)(a,b):void 0}function h(a,b){return[a,b,function(a){return Math.round(d(1,1/0,a))}]}function i(a,b){return function(e,f){return[e,f,function(e){return c(d(a,b,e))}]}}function j(a,b){return[a,b,Math.round]}a.clamp=d,a.addPropertiesHandler(e,i(0,1/0),["border-image-width","line-height"]),a.addPropertiesHandler(e,i(0,1),["opacity","shape-image-threshold"]),a.addPropertiesHandler(e,g,["flex-grow","flex-shrink"]),a.addPropertiesHandler(e,h,["orphans","widows"]),a.addPropertiesHandler(e,j,["z-index"]),a.parseNumber=e,a.mergeNumbers=f,a.numberToString=c}(d,f),function(a,b){function c(a,b){return"visible"==a||"visible"==b?[0,1,function(c){return 0>=c?a:c>=1?b:"visible"}]:void 0}a.addPropertiesHandler(String,c,["visibility"])}(d),function(a,b){function c(a){a=a.trim(),f.fillStyle="#000",f.fillStyle=a;var b=f.fillStyle;if(f.fillStyle="#fff",f.fillStyle=a,b==f.fillStyle){f.fillRect(0,0,1,1);var c=f.getImageData(0,0,1,1).data;f.clearRect(0,0,1,1);var d=c[3]/255;return[c[0]*d,c[1]*d,c[2]*d,d]}}function d(b,c){return[b,c,function(b){function c(a){return Math.max(0,Math.min(255,a))}if(b[3])for(var d=0;3>d;d++)b[d]=Math.round(c(b[d]/b[3]));return b[3]=a.numberToString(a.clamp(0,1,b[3])),"rgba("+b.join(",")+")"}]}var e=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");e.width=e.height=1;var f=e.getContext("2d");a.addPropertiesHandler(c,d,["background-color","border-bottom-color","border-left-color","border-right-color","border-top-color","color","outline-color","text-decoration-color"]),a.consumeColor=a.consumeParenthesised.bind(null,c),a.mergeColors=d}(d,f),function(a,b){function c(a,b){if(b=b.trim().toLowerCase(),"0"==b&&"px".search(a)>=0)return{px:0};if(/^[^(]*$|^calc/.test(b)){b=b.replace(/calc\(/g,"(");var c={};b=b.replace(a,function(a){return c[a]=null,"U"+a});for(var d="U("+a.source+")",e=b.replace(/[-+]?(\d*\.)?\d+/g,"N").replace(new RegExp("N"+d,"g"),"D").replace(/\s[+-]\s/g,"O").replace(/\s/g,""),f=[/N\*(D)/g,/(N|D)[*\/]N/g,/(N|D)O\1/g,/\((N|D)\)/g],g=0;g<f.length;)f[g].test(e)?(e=e.replace(f[g],"$1"),g=0):g++;if("D"==e){for(var h in c){var i=eval(b.replace(new RegExp("U"+h,"g"),"").replace(new RegExp(d,"g"),"*0"));if(!isFinite(i))return;c[h]=i}return c}}}function d(a,b){return e(a,b,!0)}function e(b,c,d){var e,f=[];for(e in b)f.push(e);for(e in c)f.indexOf(e)<0&&f.push(e);return b=f.map(function(a){return b[a]||0}),c=f.map(function(a){return c[a]||0}),[b,c,function(b){var c=b.map(function(c,e){return 1==b.length&&d&&(c=Math.max(c,0)),a.numberToString(c)+f[e]}).join(" + ");return b.length>1?"calc("+c+")":c}]}var f="px|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc",g=c.bind(null,new RegExp(f,"g")),h=c.bind(null,new RegExp(f+"|%","g")),i=c.bind(null,/deg|rad|grad|turn/g);a.parseLength=g,a.parseLengthOrPercent=h,a.consumeLengthOrPercent=a.consumeParenthesised.bind(null,h),a.parseAngle=i,a.mergeDimensions=e;var j=a.consumeParenthesised.bind(null,g),k=a.consumeRepeated.bind(void 0,j,/^/),l=a.consumeRepeated.bind(void 0,k,/^,/);a.consumeSizePairList=l;var m=function(a){var b=l(a);return b&&""==b[1]?b[0]:void 0},n=a.mergeNestedRepeated.bind(void 0,d," "),o=a.mergeNestedRepeated.bind(void 0,n,",");a.mergeNonNegativeSizePair=n,a.addPropertiesHandler(m,o,["background-size"]),a.addPropertiesHandler(h,d,["border-bottom-width","border-image-width","border-left-width","border-right-width","border-top-width","flex-basis","font-size","height","line-height","max-height","max-width","outline-width","width"]),a.addPropertiesHandler(h,e,["border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","bottom","left","letter-spacing","margin-bottom","margin-left","margin-right","margin-top","min-height","min-width","outline-offset","padding-bottom","padding-left","padding-right","padding-top","perspective","right","shape-margin","text-indent","top","vertical-align","word-spacing"])}(d,f),function(a,b){function c(b){return a.consumeLengthOrPercent(b)||a.consumeToken(/^auto/,b)}function d(b){var d=a.consumeList([a.ignore(a.consumeToken.bind(null,/^rect/)),a.ignore(a.consumeToken.bind(null,/^\(/)),a.consumeRepeated.bind(null,c,/^,/),a.ignore(a.consumeToken.bind(null,/^\)/))],b);return d&&4==d[0].length?d[0]:void 0}function e(b,c){return"auto"==b||"auto"==c?[!0,!1,function(d){var e=d?b:c;if("auto"==e)return"auto";var f=a.mergeDimensions(e,e);return f[2](f[0])}]:a.mergeDimensions(b,c)}function f(a){return"rect("+a+")"}var g=a.mergeWrappedNestedRepeated.bind(null,f,e,", ");a.parseBox=d,a.mergeBoxes=g,a.addPropertiesHandler(d,g,["clip"])}(d,f),function(a,b){function c(a){return function(b){var c=0;return a.map(function(a){return a===k?b[c++]:a})}}function d(a){return a}function e(b){if(b=b.toLowerCase().trim(),"none"==b)return[];for(var c,d=/\s*(\w+)\(([^)]*)\)/g,e=[],f=0;c=d.exec(b);){if(c.index!=f)return;f=c.index+c[0].length;var g=c[1],h=n[g];if(!h)return;var i=c[2].split(","),j=h[0];if(j.length<i.length)return;for(var k=[],o=0;o<j.length;o++){var p,q=i[o],r=j[o];if(p=q?{A:function(b){return"0"==b.trim()?m:a.parseAngle(b)},N:a.parseNumber,T:a.parseLengthOrPercent,L:a.parseLength}[r.toUpperCase()](q):{a:m,n:k[0],t:l}[r],void 0===p)return;k.push(p)}if(e.push({t:g,d:k}),d.lastIndex==b.length)return e}}function f(a){return a.toFixed(6).replace(".000000","")}function g(b,c){if(b.decompositionPair!==c){b.decompositionPair=c;var d=a.makeMatrixDecomposition(b)}if(c.decompositionPair!==b){c.decompositionPair=b;var e=a.makeMatrixDecomposition(c)}return null==d[0]||null==e[0]?[[!1],[!0],function(a){return a?c[0].d:b[0].d}]:(d[0].push(0),e[0].push(1),[d,e,function(b){var c=a.quat(d[0][3],e[0][3],b[5]),g=a.composeMatrix(b[0],b[1],b[2],c,b[4]),h=g.map(f).join(",");return h}])}function h(a){return a.replace(/[xy]/,"")}function i(a){return a.replace(/(x|y|z|3d)?$/,"3d")}function j(b,c){var d=a.makeMatrixDecomposition&&!0,e=!1;if(!b.length||!c.length){b.length||(e=!0,b=c,c=[]);for(var f=0;f<b.length;f++){var j=b[f].t,k=b[f].d,l="scale"==j.substr(0,5)?1:0;c.push({t:j,d:k.map(function(a){if("number"==typeof a)return l;var b={};for(var c in a)b[c]=l;return b})})}}var m=function(a,b){return"perspective"==a&&"perspective"==b||("matrix"==a||"matrix3d"==a)&&("matrix"==b||"matrix3d"==b)},o=[],p=[],q=[];if(b.length!=c.length){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]]}else for(var f=0;f<b.length;f++){var j,s=b[f].t,t=c[f].t,u=b[f].d,v=c[f].d,w=n[s],x=n[t];if(m(s,t)){if(!d)return;var r=g([b[f]],[c[f]]);o.push(r[0]),p.push(r[1]),q.push(["matrix",[r[2]]])}else{if(s==t)j=s;else if(w[2]&&x[2]&&h(s)==h(t))j=h(s),u=w[2](u),v=x[2](v);else{if(!w[1]||!x[1]||i(s)!=i(t)){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]];break}j=i(s),u=w[1](u),v=x[1](v)}for(var y=[],z=[],A=[],B=0;B<u.length;B++){var C="number"==typeof u[B]?a.mergeNumbers:a.mergeDimensions,r=C(u[B],v[B]);y[B]=r[0],z[B]=r[1],A.push(r[2])}o.push(y),p.push(z),q.push([j,A])}}if(e){var D=o;o=p,p=D}return[o,p,function(a){return a.map(function(a,b){var c=a.map(function(a,c){return q[b][1][c](a)}).join(",");return"matrix"==q[b][0]&&16==c.split(",").length&&(q[b][0]="matrix3d"),q[b][0]+"("+c+")"}).join(" ")}]}var k=null,l={px:0},m={deg:0},n={matrix:["NNNNNN",[k,k,0,0,k,k,0,0,0,0,1,0,k,k,0,1],d],matrix3d:["NNNNNNNNNNNNNNNN",d],rotate:["A"],rotatex:["A"],rotatey:["A"],rotatez:["A"],rotate3d:["NNNA"],perspective:["L"],scale:["Nn",c([k,k,1]),d],scalex:["N",c([k,1,1]),c([k,1])],scaley:["N",c([1,k,1]),c([1,k])],scalez:["N",c([1,1,k])],scale3d:["NNN",d],skew:["Aa",null,d],skewx:["A",null,c([k,m])],skewy:["A",null,c([m,k])],translate:["Tt",c([k,k,l]),d],translatex:["T",c([k,l,l]),c([k,l])],translatey:["T",c([l,k,l]),c([l,k])],translatez:["L",c([l,l,k])],translate3d:["TTL",d]};a.addPropertiesHandler(e,j,["transform"])}(d,f),function(a,b){function c(a,b){b.concat([a]).forEach(function(b){b in document.documentElement.style&&(d[a]=b)})}var d={};c("transform",["webkitTransform","msTransform"]),c("transformOrigin",["webkitTransformOrigin"]),c("perspective",["webkitPerspective"]),c("perspectiveOrigin",["webkitPerspectiveOrigin"]),a.propertyName=function(a){return d[a]||a}}(d,f)}(),!function(){if(void 0===document.createElement("div").animate([]).oncancel){var a;if(window.performance&&performance.now)var a=function(){return performance.now()};else var a=function(){return Date.now()};var b=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},c=window.Element.prototype.animate;window.Element.prototype.animate=function(d,e){var f=c.call(this,d,e);f._cancelHandlers=[],f.oncancel=null;var g=f.cancel;f.cancel=function(){g.call(this);var c=new b(this,null,a()),d=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){d.forEach(function(a){a.call(c.target,c)})},0)};var h=f.addEventListener;f.addEventListener=function(a,b){"function"==typeof b&&"cancel"==a?this._cancelHandlers.push(b):h.call(this,a,b)};var i=f.removeEventListener;return f.removeEventListener=function(a,b){if("cancel"==a){var c=this._cancelHandlers.indexOf(b);c>=0&&this._cancelHandlers.splice(c,1)}else i.call(this,a,b)},f}}}(),function(a){var b=document.documentElement,c=null,d=!1;try{var e=getComputedStyle(b).getPropertyValue("opacity"),f="0"==e?"1":"0";c=b.animate({opacity:[f,f]},{duration:1}),c.currentTime=0,d=getComputedStyle(b).getPropertyValue("opacity")==f}catch(g){}finally{c&&c.cancel()}if(!d){var h=window.Element.prototype.animate;window.Element.prototype.animate=function(b,c){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&b[Symbol.iterator]&&(b=Array.from(b)),Array.isArray(b)||null===b||(b=a.convertToArrayForm(b)),h.call(this,b,c)}}}(c),!function(a,b,c){function d(a){var b=window.document.timeline;b.currentTime=a,b._discardAnimations(),0==b._animations.length?f=!1:requestAnimationFrame(d);
+}var e=window.requestAnimationFrame;window.requestAnimationFrame=function(a){return e(function(b){window.document.timeline._updateAnimationsPromises(),a(b),window.document.timeline._updateAnimationsPromises()})},b.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},b.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){b.animationsWithPromises=b.animationsWithPromises.filter(function(a){return a._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(a){return"finished"!=a.playState&&"idle"!=a.playState})},_play:function(a){var c=new b.Animation(a,this);return this._animations.push(c),b.restartWebAnimationsNextTick(),c._updatePromises(),c._animation.play(),c._updatePromises(),c},play:function(a){return a&&a.remove(),this._play(a)}};var f=!1;b.restartWebAnimationsNextTick=function(){f||(f=!0,requestAnimationFrame(d))};var g=new b.AnimationTimeline;b.timeline=g;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return g}})}catch(h){}try{window.document.timeline=g}catch(h){}}(c,e,f),function(a,b,c){b.animationsWithPromises=[],b.Animation=function(b,c){if(this.id="",b&&b._id&&(this.id=b._id),this.effect=b,b&&(b._animation=this),!c)throw new Error("Animation with null timeline is not supported");this._timeline=c,this._sequenceNumber=a.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},b.Animation.prototype={_updatePromises:function(){var a=this._oldPlayState,b=this.playState;return this._readyPromise&&b!==a&&("idle"==b?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==a?this._resolveReadyPromise():"pending"==b&&(this._readyPromise=void 0)),this._finishedPromise&&b!==a&&("idle"==b?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==b?this._resolveFinishedPromise():"finished"==a&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var a,c,d,e,f=!!this._animation;f&&(a=this.playbackRate,c=this._paused,d=this.startTime,e=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=b.newUnderlyingAnimationForKeyframeEffect(this.effect),b.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=b.newUnderlyingAnimationForGroup(this.effect),b.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&b.bindAnimationForCustomEffect(this),f&&(1!=a&&(this.playbackRate=a),null!==d?this.startTime=d:null!==e?this.currentTime=e:null!==this._holdTime&&(this.currentTime=this._holdTime),c&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var a=this.effect._timing.delay;this._childAnimations.forEach(function(c){this._arrangeChildren(c,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c.effect))}.bind(this))}},_setExternalAnimation:function(a){if(this.effect&&this._isGroup)for(var b=0;b<this.effect.children.length;b++)this.effect.children[b]._animation=a,this._childAnimations[b]._setExternalAnimation(a)},_constructChildAnimations:function(){if(this.effect&&this._isGroup){var a=this.effect._timing.delay;this._removeChildAnimations(),this.effect.children.forEach(function(c){var d=window.document.timeline._play(c);this._childAnimations.push(d),d.playbackRate=this.playbackRate,this._paused&&d.pause(),c._animation=this.effect._animation,this._arrangeChildren(d,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c))}.bind(this))}},_arrangeChildren:function(a,b){null===this.startTime?a.currentTime=this.currentTime-b/this.playbackRate:a.startTime!==this.startTime+b/this.playbackRate&&(a.startTime=this.startTime+b/this.playbackRate)},get timeline(){return this._timeline},get playState(){return this._animation?this._animation.playState:"idle"},get finished(){return window.Promise?(this._finishedPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._finishedPromise=new Promise(function(a,b){this._resolveFinishedPromise=function(){a(this)},this._rejectFinishedPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"finished"==this.playState&&this._resolveFinishedPromise()),this._finishedPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get ready(){return window.Promise?(this._readyPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._readyPromise=new Promise(function(a,b){this._resolveReadyPromise=function(){a(this)},this._rejectReadyPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"pending"!==this.playState&&this._resolveReadyPromise()),this._readyPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get onfinish(){return this._animation.onfinish},set onfinish(a){"function"==typeof a?this._animation.onfinish=function(b){b.target=this,a.call(this,b)}.bind(this):this._animation.onfinish=a},get oncancel(){return this._animation.oncancel},set oncancel(a){"function"==typeof a?this._animation.oncancel=function(b){b.target=this,a.call(this,b)}.bind(this):this._animation.oncancel=a},get currentTime(){this._updatePromises();var a=this._animation.currentTime;return this._updatePromises(),a},set currentTime(a){this._updatePromises(),this._animation.currentTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.currentTime=a-c}),this._updatePromises()},get startTime(){return this._animation.startTime},set startTime(a){this._updatePromises(),this._animation.startTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.startTime=a+c}),this._updatePromises()},get playbackRate(){return this._animation.playbackRate},set playbackRate(a){this._updatePromises();var b=this.currentTime;this._animation.playbackRate=a,this._forEachChild(function(b){b.playbackRate=a}),"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!==b&&(this.currentTime=b),this._updatePromises()},play:function(){this._updatePromises(),this._paused=!1,this._animation.play(),-1==this._timeline._animations.indexOf(this)&&this._timeline._animations.push(this),this._register(),b.awaitStartTime(this),this._forEachChild(function(a){var b=a.currentTime;a.play(),a.currentTime=b}),this._updatePromises()},pause:function(){this._updatePromises(),this.currentTime&&(this._holdTime=this.currentTime),this._animation.pause(),this._register(),this._forEachChild(function(a){a.pause()}),this._paused=!0,this._updatePromises()},finish:function(){this._updatePromises(),this._animation.finish(),this._register(),this._updatePromises()},cancel:function(){this._updatePromises(),this._animation.cancel(),this._register(),this._removeChildAnimations(),this._updatePromises()},reverse:function(){this._updatePromises();var a=this.currentTime;this._animation.reverse(),this._forEachChild(function(a){a.reverse()}),null!==a&&(this.currentTime=a),this._updatePromises()},addEventListener:function(a,b){var c=b;"function"==typeof b&&(c=function(a){a.target=this,b.call(this,a)}.bind(this),b._wrapper=c),this._animation.addEventListener(a,c)},removeEventListener:function(a,b){this._animation.removeEventListener(a,b&&b._wrapper||b)},_removeChildAnimations:function(){for(;this._childAnimations.length;)this._childAnimations.pop().cancel()},_forEachChild:function(b){var c=0;if(this.effect.children&&this._childAnimations.length<this.effect.children.length&&this._constructChildAnimations(),this._childAnimations.forEach(function(a){b.call(this,a,c),this.effect instanceof window.SequenceEffect&&(c+=a.effect.activeDuration)}.bind(this)),"pending"!=this.playState){var d=this.effect._timing,e=this.currentTime;null!==e&&(e=a.calculateTimeFraction(a.calculateActiveDuration(d),e,d)),(null==e||isNaN(e))&&this._removeChildAnimations()}}},window.Animation=b.Animation}(c,e,f),function(a,b,c){function d(b){this._frames=a.normalizeKeyframes(b)}function e(){for(var a=!1;i.length;){var b=i.shift();b._updateChildren(),a=!0}return a}var f=function(a){if(a._animation=void 0,a instanceof window.SequenceEffect||a instanceof window.GroupEffect)for(var b=0;b<a.children.length;b++)f(a.children[b])};b.removeMulti=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c];d._parent?(-1==b.indexOf(d._parent)&&b.push(d._parent),d._parent.children.splice(d._parent.children.indexOf(d),1),d._parent=null,f(d)):d._animation&&d._animation.effect==d&&(d._animation.cancel(),d._animation.effect=new KeyframeEffect(null,[]),d._animation._callback&&(d._animation._callback._animation=null),d._animation._rebuildUnderlyingAnimation(),f(d))}for(c=0;c<b.length;c++)b[c]._rebuild()},b.KeyframeEffect=function(b,c,e,f){return this.target=b,this._parent=null,e=a.numericTimingToObject(e),this._timingInput=a.cloneTimingInput(e),this._timing=a.normalizeTimingInput(e),this.timing=a.makeTiming(e,!1,this),this.timing._effect=this,"function"==typeof c?(a.deprecated("Custom KeyframeEffect","2015-06-22","Use KeyframeEffect.onsample instead."),this._normalizedKeyframes=c):this._normalizedKeyframes=new d(c),this._keyframes=c,this.activeDuration=a.calculateActiveDuration(this._timing),this._id=f,this},b.KeyframeEffect.prototype={getFrames:function(){return"function"==typeof this._normalizedKeyframes?this._normalizedKeyframes:this._normalizedKeyframes._frames},set onsample(a){if("function"==typeof this.getFrames())throw new Error("Setting onsample on custom effect KeyframeEffect is not supported.");this._onsample=a,this._animation&&this._animation._rebuildUnderlyingAnimation()},get parent(){return this._parent},clone:function(){if("function"==typeof this.getFrames())throw new Error("Cloning custom effects is not supported.");var b=new KeyframeEffect(this.target,[],a.cloneTimingInput(this._timingInput),this._id);return b._normalizedKeyframes=this._normalizedKeyframes,b._keyframes=this._keyframes,b},remove:function(){b.removeMulti([this])}};var g=Element.prototype.animate;Element.prototype.animate=function(a,c){var d="";return c&&c.id&&(d=c.id),b.timeline._play(new b.KeyframeEffect(this,a,c,d))};var h=document.createElementNS("http://www.w3.org/1999/xhtml","div");b.newUnderlyingAnimationForKeyframeEffect=function(a){if(a){var b=a.target||h,c=a._keyframes;"function"==typeof c&&(c=[]);var d=a._timingInput;d.id=a._id}else var b=h,c=[],d=0;return g.apply(b,[c,d])},b.bindAnimationForKeyframeEffect=function(a){a.effect&&"function"==typeof a.effect._normalizedKeyframes&&b.bindAnimationForCustomEffect(a)};var i=[];b.awaitStartTime=function(a){null===a.startTime&&a._isGroup&&(0==i.length&&requestAnimationFrame(e),i.push(a))};var j=window.getComputedStyle;Object.defineProperty(window,"getComputedStyle",{configurable:!0,enumerable:!0,value:function(){window.document.timeline._updateAnimationsPromises();var a=j.apply(this,arguments);return e()&&(a=j.apply(this,arguments)),window.document.timeline._updateAnimationsPromises(),a}}),window.KeyframeEffect=b.KeyframeEffect,window.Element.prototype.getAnimations=function(){return document.timeline.getAnimations().filter(function(a){return null!==a.effect&&a.effect.target==this}.bind(this))}}(c,e,f),function(a,b,c){function d(a){a._registered||(a._registered=!0,g.push(a),h||(h=!0,requestAnimationFrame(e)))}function e(a){var b=g;g=[],b.sort(function(a,b){return a._sequenceNumber-b._sequenceNumber}),b=b.filter(function(a){a();var b=a._animation?a._animation.playState:"idle";return"running"!=b&&"pending"!=b&&(a._registered=!1),a._registered}),g.push.apply(g,b),g.length?(h=!0,requestAnimationFrame(e)):h=!1}var f=(document.createElementNS("http://www.w3.org/1999/xhtml","div"),0);b.bindAnimationForCustomEffect=function(b){var c,e=b.effect.target,g="function"==typeof b.effect.getFrames();c=g?b.effect.getFrames():b.effect._onsample;var h=b.effect.timing,i=null;h=a.normalizeTimingInput(h);var j=function(){var d=j._animation?j._animation.currentTime:null;null!==d&&(d=a.calculateTimeFraction(a.calculateActiveDuration(h),d,h),isNaN(d)&&(d=null)),d!==i&&(g?c(d,e,b.effect):c(d,b.effect,b.effect._animation)),i=d};j._animation=b,j._registered=!1,j._sequenceNumber=f++,b._callback=j,d(j)};var g=[],h=!1;b.Animation.prototype._register=function(){this._callback&&d(this._callback)}}(c,e,f),function(a,b,c){function d(a){return a._timing.delay+a.activeDuration+a._timing.endDelay}function e(b,c,d){this._id=d,this._parent=null,this.children=b||[],this._reparent(this.children),c=a.numericTimingToObject(c),this._timingInput=a.cloneTimingInput(c),this._timing=a.normalizeTimingInput(c,!0),this.timing=a.makeTiming(c,!0,this),this.timing._effect=this,"auto"===this._timing.duration&&(this._timing.duration=this.activeDuration)}window.SequenceEffect=function(){e.apply(this,arguments)},window.GroupEffect=function(){e.apply(this,arguments)},e.prototype={_isAncestor:function(a){for(var b=this;null!==b;){if(b==a)return!0;b=b._parent}return!1},_rebuild:function(){for(var a=this;a;)"auto"===a.timing.duration&&(a._timing.duration=a.activeDuration),a=a._parent;this._animation&&this._animation._rebuildUnderlyingAnimation()},_reparent:function(a){b.removeMulti(a);for(var c=0;c<a.length;c++)a[c]._parent=this},_putChild:function(a,b){for(var c=b?"Cannot append an ancestor or self":"Cannot prepend an ancestor or self",d=0;d<a.length;d++)if(this._isAncestor(a[d]))throw{type:DOMException.HIERARCHY_REQUEST_ERR,name:"HierarchyRequestError",message:c};for(var d=0;d<a.length;d++)b?this.children.push(a[d]):this.children.unshift(a[d]);this._reparent(a),this._rebuild()},append:function(){this._putChild(arguments,!0)},prepend:function(){this._putChild(arguments,!1)},get parent(){return this._parent},get firstChild(){return this.children.length?this.children[0]:null},get lastChild(){return this.children.length?this.children[this.children.length-1]:null},clone:function(){for(var b=a.cloneTimingInput(this._timingInput),c=[],d=0;d<this.children.length;d++)c.push(this.children[d].clone());return this instanceof GroupEffect?new GroupEffect(c,b):new SequenceEffect(c,b)},remove:function(){b.removeMulti([this])}},window.SequenceEffect.prototype=Object.create(e.prototype),Object.defineProperty(window.SequenceEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a+=d(b)}),Math.max(a,0)}}),window.GroupEffect.prototype=Object.create(e.prototype),Object.defineProperty(window.GroupEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a=Math.max(a,d(b))}),a}}),b.newUnderlyingAnimationForGroup=function(c){var d,e=null,f=function(b){var c=d._wrapper;return c&&"pending"!=c.playState&&c.effect?null==b?void c._removeChildAnimations():0==b&&c.playbackRate<0&&(e||(e=a.normalizeTimingInput(c.effect.timing)),b=a.calculateTimeFraction(a.calculateActiveDuration(e),-1,e),isNaN(b)||null==b)?(c._forEachChild(function(a){a.currentTime=-1}),void c._removeChildAnimations()):void 0:void 0},g=new KeyframeEffect(null,[],c._timing,c._id);return g.onsample=f,d=b.timeline._play(g)},b.bindAnimationForGroup=function(a){a._animation._wrapper=a,a._isGroup=!0,b.awaitStartTime(a),a._constructChildAnimations(),a._setExternalAnimation(a)},b.groupChildDuration=d}(c,e,f),b["true"]=a}({},function(){return this}());
+//# sourceMappingURL=web-animations-next-lite.min.js.map \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js.map b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js.map
new file mode 100644
index 00000000000..0352ea275cb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next-lite.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["src/scope.js","src/timing-utilities.js","src/normalize-keyframes.js","src/deprecation.js","src/keyframe-interpolations.js","src/web-animations-bonus-cancel-events.js","src/web-animations-bonus-object-form-keyframes.js","src/timeline.js","src/web-animations-next-animation.js","src/keyframe-effect-constructor.js","src/effect-callback.js","src/group-constructors.js"],"names":["webAnimationsShared","webAnimations1","webAnimationsNext","webAnimationsTesting","shared","testing","cloneTimingInput","timingInput","clone","m","AnimationEffectTiming","this","_delay","_endDelay","_fill","_iterationStart","_iterations","_duration","_playbackRate","_direction","_easing","_easingFunction","linear","isInvalidTimingDeprecated","isDeprecated","makeTiming","forGroup","effect","timing","fill","duration","isNaN","undefined","Object","getOwnPropertyNames","forEach","property","fills","indexOf","directions","numericTimingToObject","normalizeTimingInput","cubic","a","b","c","d","x","f","start","end","mid","xEst","Math","abs","step","count","pos","stepSize","toTimingFunction","easing","styleForCleaning","document","createElement","style","animationTimingFunction","validatedEasing","TypeError","cubicData","cubicBezierRe","exec","apply","slice","map","Number","stepData","stepRe","Start","middle","Middle","End","preset","presets","calculateActiveDuration","repeatedDuration","playbackRate","iterations","calculatePhase","activeDuration","localTime","PhaseNone","delay","PhaseBefore","PhaseAfter","PhaseActive","calculateActiveTime","fillMode","phase","calculateScaledActiveTime","activeTime","startOffset","calculateIterationTime","iterationDuration","scaledActiveTime","Infinity","iterationStart","calculateCurrentIteration","iterationTime","floor","calculateTransformedTime","currentIteration","currentIterationIsOdd","currentDirectionIsForwards","direction","directedTime","timeFraction","calculateTimeFraction","split","prototype","_setMember","member","value","_effect","_timingInput","_timing","_animation","_rebuildUnderlyingAnimation","endDelay","ease","ease-in","ease-out","ease-in-out","step-start","step-middle","step-end","numberString","RegExp","antiAlias","aliases","expandShorthandAndAntiAlias","result","longProperties","shorthandToLonghand","shorthandExpanderElem","i","longProperty","longhandValue","convertToArrayForm","effectInput","normalizedEffectInput","values","Array","isArray","keyframe","numKeyframes","length","offset","composite","push","sort","normalizeKeyframes","spaceKeyframes","keyframes","previousIndex","previousOffset","j","window","Symbol","iterator","from","originalKeyframe","memberValue","isFinite","type","DOMException","NOT_SUPPORTED_ERR","name","message","everyFrameHasOffset","code","INVALID_MODIFICATION_ERR","filter","background","border","borderBottom","borderColor","borderLeft","borderRadius","borderRight","borderTop","borderWidth","flex","font","margin","outline","padding","createElementNS","borderWidthAliases","thin","medium","thick","borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopWidth","fontSize","xx-small","x-small","small","large","x-large","xx-large","fontWeight","normal","bold","outlineWidth","textShadow","none","boxShadow","silenced","feature","date","advice","plural","auxVerb","today","Date","expiry","setMonth","getMonth","console","warn","toDateString","deprecated","Error","rotate","makePropertySpecificKeyframeGroups","rotate3d","propertySpecificKeyframeGroups","scaley","_","scalez","propertySpecificKeyframe","cast","groupName","group","scope","concat","candidate","makeInterpolations","interpolations","alias","startTime","endTime","startValue","animate","oncancel","now","performance","AnimationCancelEvent","target","currentTime","timelineTime","bubbles","cancelable","currentTarget","defaultPrevented","eventPhase","Event","AT_TARGET","timeStamp","originalElementAnimate","Element","options","animation","call","_cancelHandlers","originalCancel","cancel","event","handlers","setTimeout","handler","originalAddEventListener","addEventListener","originalRemoveEventListener","removeEventListener","index","splice","element","documentElement","animated","originalOpacity","getComputedStyle","getPropertyValue","testOpacity","opacity","error","webAnimationsNextTick","t","timeline","_discardAnimations","_animations","ticking","requestAnimationFrame","originalRequestAnimationFrame","_updateAnimationsPromises","AnimationTimeline","getAnimations","animationsWithPromises","_updatePromises","playState","_play","Animation","restartWebAnimationsNextTick","play","remove","defineProperty","configurable","get","e","id","_id","_timeline","_sequenceNumber","sequenceNumber","_holdTime","_paused","_isGroup","_childAnimations","_callback","_oldPlayState","oldPlayState","newPlayState","_readyPromise","_rejectReadyPromise","_resolveReadyPromise","_finishedPromise","_rejectFinishedPromise","_resolveFinishedPromise","oldPlaybackRate","oldPaused","oldStartTime","oldCurrentTime","hadUnderlying","_wrapper","KeyframeEffect","newUnderlyingAnimationForKeyframeEffect","bindAnimationForKeyframeEffect","SequenceEffect","GroupEffect","newUnderlyingAnimationForGroup","bindAnimationForGroup","_onsample","bindAnimationForCustomEffect","pause","_updateChildren","childAnimation","_arrangeChildren","groupChildDuration","bind","_setExternalAnimation","children","_constructChildAnimations","_removeChildAnimations","child","finished","Promise","resolve","reject","ABORT_ERR","ready","onfinish","v","sign","MAX_VALUE","_register","_forEachChild","awaitStartTime","time","finish","reverse","wrapped","pop","KeyframeList","_frames","updatePendingGroups","updated","pendingGroups","shift","disassociate","removeMulti","effects","oldParents","_parent","_rebuild","_normalizedKeyframes","_keyframes","getFrames","onsample","callback","parent","nullTarget","keyframeEffect","groupAnimation","originalGetComputedStyle","enumerable","arguments","register","_registered","callbacks","tick","updating","left","right","effectFunction","isKeyframeEffect","last","node","constructor","_reparent","_isAncestor","newChildren","_putChild","args","isAppend","HIERARCHY_REQUEST_ERR","unshift","append","prepend","firstChild","lastChild","clonedTiming","clonedChildren","create","total","max","underlyingAnimation","ticker","tf","underlyingEffect","exports"],"mappings":";;;;;;;;;;;;;;CAcA,SAAIA,EAAAA,GAAJ,GAAIA,MACAC,KACAC,KAGEC,EAAuB,MCL7B,SAAUC,EAAQC,GAMhB,QAASC,GAAiBC,GACxB,GAA0B,gBAAfA,GACT,MAAOA,EAET,IAAIC,KACJ,KAAK,GAAIC,KAAKF,GACZC,EAAMC,GAAKF,EAAYE,EAEzB,OAAOD,GAGT,QAASE,KACPC,KAAKC,OAAS,EACdD,KAAKE,UAAY,EACjBF,KAAKG,MAAQ,OACbH,KAAKI,gBAAkB,EACvBJ,KAAKK,YAAc,EACnBL,KAAKM,UAAY,EACjBN,KAAKO,cAAgB,EACrBP,KAAKQ,WAAa,SAClBR,KAAKS,QAAU,SACfT,KAAKU,gBAAkBC,EAGzB,QAASC,KACP,MAAOnB,GAAOoB,aAAa,wBAAyB,aAAc,gDAAA,GA8EpE,QAASC,GAAWlB,EAAamB,EAAUC,GACzC,GAAIC,GAAS,GAAIlB,EA4BjB,OA3BIgB,KACFE,EAAOC,KAAO,OACdD,EAAOE,SAAW,QAEM,gBAAfvB,IAA4BwB,MAAMxB,GAElByB,SAAhBzB,GACT0B,OAAOC,oBAAoB3B,GAAa4B,QAAQ,SAASC,GACvD,GAA6B,QAAzB7B,EAAY6B,GAAqB,CACnC,IAA+B,gBAApBR,GAAOQ,IAAqC,YAAZA,KACL,gBAAzB7B,GAAY6B,IAAyBL,MAAMxB,EAAY6B,KAChE,MAGJ,IAAiB,QAAZA,GAAgE,IAAxCC,EAAMC,QAAQ/B,EAAY6B,IACrD,MAEF,IAAiB,aAAZA,GAA0E,IAA7CG,EAAWD,QAAQ/B,EAAY6B,IAC/D,MAEF,IAAgB,gBAAZA,GAAwD,IAA1B7B,EAAY6B,IAAmBhC,EAAOoB,aAAa,qCAAsC,aAAc,uCACvI,MAEFI,GAAOQ,GAAY7B,EAAY6B,MAlBnCR,EAAOE,SAAWvB,EAsBbqB,EAGT,QAASY,GAAsBjC,GAQ7B,MAP0B,gBAAfA,KAEPA,EADEwB,MAAMxB,IACQuB,SAAU,IAEVA,SAAUvB,IAGvBA,EAGT,QAASkC,GAAqBlC,EAAamB,GAEzC,MADAnB,GAAcH,EAAOoC,sBAAsBjC,GACpCkB,EAAWlB,EAAamB,GAGjC,QAASgB,GAAMC,EAAGC,EAAGC,EAAGC,GACtB,MAAQ,GAAJH,GAASA,EAAI,GAAS,EAAJE,GAASA,EAAI,EAC1BvB,EAEF,SAASyB,GAOZ,QAASC,GAAEL,EAAGC,EAAGnC,GAAK,MAAO,GAAIkC,GAAK,EAAIlC,IAAM,EAAIA,GAAKA,EAAI,EAAImC,GAAK,EAAInC,GAAKA,EAAIA,EAAIA,EAAIA,EAAIA,EANjG,GAAS,GAALsC,GAAe,GAALA,EACZ,MAAOA,EAGT,KADA,GAAIE,GAAQ,EAAGC,EAAM,IACX,CACR,GAAIC,IAAOF,EAAQC,GAAO,EAEtBE,EAAOJ,EAAEL,EAAGE,EAAGM,EACnB,IAAIE,KAAKC,IAAIP,EAAIK,GAAQ,KACvB,MAAOJ,GAAEJ,EAAGE,EAAGK,EAENJ,GAAPK,EACFH,EAAQE,EAERD,EAAMC,IAUd,QAASI,GAAKC,EAAOC,GACnB,MAAO,UAASV,GACd,GAAIA,GAAK,EACP,MAAO,EAET,IAAIW,GAAW,EAAIF,CAEnB,OADAT,IAAKU,EAAMC,EACJX,EAAIA,EAAIW,GAmBnB,QAASC,GAAiBC,GACnBC,IACHA,EAAmBC,SAASC,cAAc,OAAOC,OAEnDH,EAAiBI,wBAA0B,GAC3CJ,EAAiBI,wBAA0BL,CAC3C,IAAIM,GAAkBL,EAAiBI,uBAEvC,IAAuB,IAAnBC,GAAyB3C,IAC3B,KAAM,IAAI4C,WAAUP,EAAS,mCAG/B,IAAIQ,GAAYC,EAAcC,KAAKJ,EACnC,IAAIE,EACF,MAAO1B,GAAM6B,MAAM5D,KAAMyD,EAAUI,MAAM,GAAGC,IAAIC,QAElD,IAAIC,GAAWC,EAAON,KAAKJ,EAC3B,IAAIS,EACF,MAAOpB,GAAKmB,OAAOC,EAAS,KAAM1B,MAAS4B,EAAOC,OAAUC,EAAQ7B,IAAO8B,GAAKL,EAAS,IAE3F,IAAIM,GAASC,EAAQhB,EACrB,OAAIe,GACKA,EAEF3D,EAGT,QAAS6D,GAAwBvD,GAC/B,MAAOyB,MAAKC,IAAI8B,EAAiBxD,GAAUA,EAAOyD,cAGpD,QAASD,GAAiBxD,GACxB,MAAOA,GAAOE,SAAWF,EAAO0D,WAQlC,QAASC,GAAeC,EAAgBC,EAAW7D,GACjD,MAAiB,OAAb6D,EACKC,EAELD,EAAY7D,EAAO+D,MACdC,EAELH,GAAa7D,EAAO+D,MAAQH,EACvBK,EAEFC,EAGT,QAASC,GAAoBP,EAAgBQ,EAAUP,EAAWQ,EAAON,GACvE,OAAQM,GACN,IAAKL,GACH,MAAgB,aAAZI,GAAuC,QAAZA,EACtB,EACF,IACT,KAAKF,GACH,MAAOL,GAAYE,CACrB,KAAKE,GACH,MAAgB,YAAZG,GAAsC,QAAZA,EACrBR,EACF,IACT,KAAKE,GACH,MAAO,OAIb,QAASQ,GAA0BV,EAAgBW,EAAYC,EAAaxE,GAC1E,OAAQA,EAAOyD,aAAe,EAAIc,EAAaX,EAAiBW,GAAcvE,EAAOyD,aAAee,EAGtG,QAASC,GAAuBC,EAAmBlB,EAAkBmB,EAAkBH,EAAaxE,GAClG,MAAI2E,KAAqBC,EAAAA,GAAYD,MAAsBC,EAAAA,IAAaD,EAAmBH,GAAehB,GAAoBxD,EAAO0D,aAAgB1D,EAAO0D,WAAa1D,EAAO6E,gBAAkB,GAAK,EAC9LH,EAGFC,EAAmBD,EAG5B,QAASI,GAA0BJ,EAAmBK,EAAeJ,EAAkB3E,GACrF,MAAyB,KAArB2E,EACK,EAELI,GAAiBL,EACZ1E,EAAO6E,eAAiB7E,EAAO0D,WAAa,EAE9CjC,KAAKuD,MAAML,EAAmBD,GAGvC,QAASO,GAAyBC,EAAkBR,EAAmBK,EAAe/E,GACpF,GAAImF,GAAwBD,EAAmB,GAAK,EAChDE,EAAiD,UAApBpF,EAAOqF,WAAyBrF,EAAOqF,YAAcF,EAAwB,oBAAsB,aAChIG,EAAeF,EAA6BL,EAAgBL,EAAoBK,EAChFQ,EAAeD,EAAeZ,CAClC,OAAOA,GAAoB1E,EAAOP,gBAAgB8F,GAGpD,QAASC,GAAsB5B,EAAgBC,EAAW7D,GACxD,GAAIqE,GAAQV,EAAeC,EAAgBC,EAAW7D,GAClDuE,EAAaJ,EAAoBP,EAAgB5D,EAAOC,KAAM4D,EAAWQ,EAAOrE,EAAO+D,MAC3F,IAAmB,OAAfQ,EACF,MAAO,KACT,IAAuB,IAAnBX,EACF,MAAOS,KAAUL,EAAc,EAAI,CACrC,IAAIQ,GAAcxE,EAAO6E,eAAiB7E,EAAOE,SAC7CyE,EAAmBL,EAA0BV,EAAgBW,EAAYC,EAAaxE,GACtF+E,EAAgBN,EAAuBzE,EAAOE,SAAUsD,EAAiBxD,GAAS2E,EAAkBH,EAAaxE,GACjHkF,EAAmBJ,EAA0B9E,EAAOE,SAAU6E,EAAeJ,EAAkB3E,EACnG,OAAOiF,GAAyBC,EAAkBlF,EAAOE,SAAU6E,EAAe/E,GAAUA,EAAOE,SAjUrG,GAAIO,GAAQ,+BAA+BgF,MAAM,KAC7C9E,EAAa,sCAAsC8E,MAAM,KACzD/F,EAAS,SAASyB,GAAK,MAAOA,GA8BlCrC,GAAsB4G,WACpBC,WAAY,SAASC,EAAQC,GAC3B9G,KAAK,IAAM6G,GAAUC,EACjB9G,KAAK+G,UACP/G,KAAK+G,QAAQC,aAAaH,GAAUC,EACpC9G,KAAK+G,QAAQE,QAAUxH,EAAOqC,qBAAqB9B,KAAK+G,QAAQC,cAChEhH,KAAK+G,QAAQlC,eAAiBpF,EAAO+E,wBAAwBxE,KAAK+G,QAAQE,SACtEjH,KAAK+G,QAAQG,YACflH,KAAK+G,QAAQG,WAAWC,gCAI9BzC,GAAIA,gBACF,MAAO1E,MAAKO,eAEdyE,GAAIA,OAAM8B,GACR9G,KAAK4G,WAAW,QAASE,IAE3B9B,GAAIA,SACF,MAAOhF,MAAKC,QAEdmH,GAAIA,UAASN,GACX9G,KAAK4G,WAAW,WAAYE,IAE9BM,GAAIA,YACF,MAAOpH,MAAKE,WAEdgB,GAAIA,MAAK4F,GACP9G,KAAK4G,WAAW,OAAQE,IAE1B5F,GAAIA,QACF,MAAOlB,MAAKG,OAEd2F,GAAIA,gBAAegB,GACjB,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,2DAA6DvC,OAAO6E,eAE1F9F,MAAK4G,WAAW,iBAAkBE,IAEpChB,GAAIA,kBACF,MAAO9F,MAAKI,iBAEde,GAAIA,UAAS2F,GACX,GAAa,QAATA,IAAoB1F,MAAM0F,IAAkB,EAARA,IAAclG,IACpD,KAAM,IAAI4C,WAAU,oDAAsDsD,EAE5E9G,MAAK4G,WAAW,WAAYE,IAE9B3F,GAAIA,YACF,MAAOnB,MAAKM,WAEdgG,GAAIA,WAAUQ,GACZ9G,KAAK4G,WAAW,YAAaE,IAE/BR,GAAIA,aACF,MAAOtG,MAAKQ,YAEdyC,GAAIA,QAAO6D,GACT9G,KAAKU,gBAAkBsC,EAAiB8D,GACxC9G,KAAK4G,WAAW,SAAUE,IAE5B7D,GAAIA,UACF,MAAOjD,MAAKS,SAEdkE,GAAIA,YAAWmC,GACb,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,8CAAgDsD,EAEtE9G,MAAK4G,WAAW,aAAcE,IAEhCnC,GAAIA,cACF,MAAO3E,MAAKK,aA6EhB,IAAI6D,GAAQ,EACRE,EAAS,GACTC,EAAM,EAaNE,GACF8C,KAAQtF,EAAM,IAAM,GAAK,IAAM,GAC/BuF,UAAWvF,EAAM,IAAM,EAAG,EAAG,GAC7BwF,WAAYxF,EAAM,EAAG,EAAG,IAAM,GAC9ByF,cAAezF,EAAM,IAAM,EAAG,IAAM,GACpC0F,aAAc7E,EAAK,EAAGsB,GACtBwD,cAAe9E,EAAK,EAAGwB,GACvBuD,WAAY/E,EAAK,EAAGyB,IAGlBnB,EAAmB,KACnB0E,EAAe,qCACflE,EAAgB,GAAImE,QAAO,kBAAoBD,EAAe,IAAMA,EAAe,IAAMA,EAAe,IAAMA,EAAe,OAC7H3D,EAAS,gDAqCTc,EAAY,EACZE,EAAc,EACdC,EAAa,EACbC,EAAc,CA4ElB1F,GAAOE,iBAAmBA,EAC1BF,EAAOqB,WAAaA,EACpBrB,EAAOoC,sBAAwBA,EAC/BpC,EAAOqC,qBAAuBA,EAC9BrC,EAAO+E,wBAA0BA,EACjC/E,EAAOgH,sBAAwBA,EAC/BhH,EAAOmF,eAAiBA,EACxBnF,EAAOuD,iBAAmBA,GAkBzB3D,EAAqBG,GC/VxB,SAAUC,EAAQC,GAmIhB,QAASoI,GAAUrG,EAAUqF,GAC3B,MAAIrF,KAAYsG,GACPA,EAAQtG,GAAUqF,IAAUA,EAE9BA,EAIT,QAASkB,GAA4BvG,EAAUqF,EAAOmB,GACpD,GAAIC,GAAiBC,EAAoB1G,EACzC,IAAIyG,EAAgB,CAClBE,EAAsB/E,MAAM5B,GAAYqF,CACxC,KAAK,GAAIuB,KAAKH,GAAgB,CAC5B,GAAII,GAAeJ,EAAeG,GAC9BE,EAAgBH,EAAsB/E,MAAMiF,EAChDL,GAAOK,GAAgBR,EAAUQ,EAAcC,QAGjDN,GAAOxG,GAAYqG,EAAUrG,EAAUqF,GAI3C,QAAS0B,GAAmBC,GAC1B,GAAIC,KAEJ,KAAK,GAAIjH,KAAYgH,GACnB,KAAIhH,KAAa,SAAU,SAAU,cAArC,CAIA,GAAIkH,GAASF,EAAYhH,EACpBmH,OAAMC,QAAQF,KACjBA,GAAUA,GAKZ,KAAK,GAFDG,GACAC,EAAeJ,EAAOK,OACjBX,EAAI,EAAOU,EAAJV,EAAkBA,IAChCS,KAEI,UAAYL,GACdK,EAASG,OAASR,EAAYQ,OACL,GAAhBF,EACTD,EAASG,OAAS,EAElBH,EAASG,OAASZ,GAAKU,EAAe,GAGpC,UAAYN,KACdK,EAAS7F,OAASwF,EAAYxF,QAG5B,aAAewF,KACjBK,EAASI,UAAYT,EAAYS,WAGnCJ,EAASrH,GAAYkH,EAAON,GAE5BK,EAAsBS,KAAKL,GAK/B,MADAJ,GAAsBU,KAAK,SAASpH,EAAGC,GAAK,MAAOD,GAAEiH,OAAShH,EAAEgH,SACzDP,EAGT,QAASW,GAAmBZ,GA+D1B,QAASa,KACP,GAAIN,GAASO,EAAUP,MACa,OAAhCO,EAAUP,EAAS,GAAGC,SACxBM,EAAUP,EAAS,GAAGC,OAAS,GAC7BD,EAAS,GAA4B,MAAvBO,EAAU,GAAGN,SAC7BM,EAAU,GAAGN,OAAS,EAIxB,KAAK,GAFDO,GAAgB,EAChBC,EAAiBF,EAAU,GAAGN,OACzBZ,EAAI,EAAOW,EAAJX,EAAYA,IAAK,CAC/B,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,IAAK,GAAIS,GAAI,EAAOrB,EAAImB,EAARE,EAAuBA,IACrCH,EAAUC,EAAgBE,GAAGT,OAASQ,GAAkBR,EAASQ,GAAkBC,GAAKrB,EAAImB,EAC9FA,GAAgBnB,EAChBoB,EAAiBR,IA7EvB,GAAmB,MAAfR,EACF,QAGEkB,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,KACjBA,EAAcD,EAAmBC,GAgCnC,KAAK,GA7BDc,GAAYd,EAAY3E,IAAI,SAASiG,GACvC,GAAIjB,KACJ,KAAK,GAAIjC,KAAUkD,GAAkB,CACnC,GAAIC,GAAcD,EAAiBlD,EACnC,IAAc,UAAVA,GACF,GAAmB,MAAfmD,IACFA,EAAcjG,OAAOiG,IAChBC,SAASD,IACZ,KAAM,IAAIxG,WAAU,yCAEnB,CAAA,GAAc,aAAVqD,EACT,MACEqD,KAAMC,aAAaC,kBACnBC,KAAM,oBACNC,QAAS,mCAGXN,GAAc,GAAKA,EAErBhC,EAA4BnB,EAAQmD,EAAalB,GAInD,MAFuBzH,SAAnByH,EAASG,SACXH,EAASG,OAAS,MACbH,IAGLyB,GAAAA,EAEAd,IAAkB5D,EAAAA,GACbwC,EAAI,EAAGA,EAAIkB,EAAUP,OAAQX,IAAK,CACzC,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,GAAaQ,EAATR,EACF,MACEuB,KAAML,aAAaM,yBACnBJ,KAAM,2BACNC,QAAS,uEAGbb,GAAiBR,MAEjBsB,IAAAA,EA8BJ,MA1BAhB,GAAYA,EAAUmB,OAAO,SAAS5B,GACpC,MAAOA,GAASG,QAAU,GAAKH,EAASG,QAAU,IAsB/CsB,GACHjB,IAEKC,EAzRT,GAAIpB,IACFwC,YACE,kBACA,qBACA,iBACA,mBACA,uBACA,mBACA,iBACA,mBAEFC,QACE,iBACA,iBACA,iBACA,mBACA,mBACA,mBACA,oBACA,oBACA,oBACA,kBACA,kBACA,mBAEFC,cACE,oBACA,oBACA,qBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,YACE,kBACA,kBACA,mBAEFC,cACE,sBACA,uBACA,0BACA,0BAEFC,aACE,mBACA,mBACA,oBAEFC,WACE,iBACA,iBACA,kBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,MACE,WACA,aACA,aAEFC,MACE,aACA,WACA,YACA,cACA,aACA,cAEFC,QACE,YACA,cACA,eACA,cAEFC,SACE,eACA,eACA,gBAEFC,SACE,aACA,eACA,gBACA,gBAIApD,EAAwBjF,SAASsI,gBAAgB,+BAAgC,OAEjFC,GACFC,KAAM,MACNC,OAAQ,MACRC,MAAO,OAGL9D,GACF+D,kBAAmBJ,EACnBK,gBAAiBL,EACjBM,iBAAkBN,EAClBO,eAAgBP,EAChBQ,UACEC,WAAY,MACZC,UAAW,MACXC,MAAS,MACTT,OAAU,OACVU,MAAS,OACTC,UAAW,OACXC,WAAY,QAEdC,YACEC,OAAQ,MACRC,KAAM,OAERC,aAAclB,EACdmB,YACEC,KAAM,2BAERC,WACED,KAAM,+BA8JVrN,GAAO+I,mBAAqBA,EAC5B/I,EAAO4J,mBAAqBA,GAM3BhK,EAAqBG,GCpSxB,SAAUC,GAER,GAAIuN,KAEJvN,GAAOoB,aAAe,SAASoM,EAASC,EAAMC,EAAQC,GAKpD,GAAIC,GAAUD,EAAS,MAAQ,KAC3BE,EAAQ,GAAIC,MACZC,EAAS,GAAID,MAAKL,EAGtB,OAFAM,GAAOC,SAASD,EAAOE,WAAa,GAExBF,EAARF,GACIL,IAAWD,IACfW,QAAQC,KAAK,mBAAqBX,EAAU,IAAMI,EAAU,wCAA0CG,EAAOK,eAAiB,KAAOV,GAEvIH,EAASC,IAAAA,GAAW,IACb,GAMXxN,EAAOqO,WAAa,SAASb,EAASC,EAAMC,EAAQC,GAClD,GAAIC,GAAUD,EAAS,MAAQ,IAC/B,IAAI3N,EAAOoB,aAAaoM,EAASC,EAAMC,EAAQC,GAC7C,KAAM,IAAIW,OAAMd,EAAU,IAAMI,EAAU,yBAA2BF,KAIxE9N,6noBChCOI,mBAAeC,GA2BvBsO,QAASC,KAAAA,SAAAA,KAAAA,SAAAA,KAAAA,SAAmC1E,KAG1C2E,UAFIC,QAAAA,aAAAA,KAAAA,OAES,KAAO5E,GAAAA,EAAAA,EAAUP,IAAAA,GAAQX,QAC/B,IAAIxB,GAAAA,EAAU0C,EAAAA,IAAAA,GAAUlB,EAC3B,KAAc+F,QAAVvH,IAAAA,GAAgC,EAAAwH,EAAA,IAAVxH,GAAAA,EAAgCwH,KAAAC,QAAVzH,IAAAA,GAC1C0H,EAAAA,EAAAA,KAAAA,SAAAA,MAAAA,GACFtF,MAAQM,KAAAA,KAAUlB,GAAGY,OACrBhG,IAAAA,KAAQsG,GAAAA,EAAUlB,KAAGpF,OACdsG,IAAAA,KAAAA,GAAa1C,EAAAA,KAEtBsH,WAAAA,KAAAA,GAAAA,EAAAA,EAAAA,IAA+BtH,GAAUsH,YAAAA,IAAAA,GAAAA,EAAAA,EAAAA,IAA+BtH,GAAAA,EAAAA,KACxEsH,YAAAA,IAAAA,GAAAA,EAA+BtH,EAAAA,IAAQsC,GAAKoF,EAAAA,KAAAA,YAAAA,IAKlDC,GAASC,EAAAA,EAAAA,KAAaN,aAAAA,MAAAA,GAAAA,GAAAA,qBACRA,EAAAA,GAA+BM,eACjCnP,EAAkBoP,GAAwBzF,SAClD0F,EACEzE,GAAMC,QAAaC,GAAAA,EAAAA,GACbrC,EAAA6G,QAAAvE,IACNC,QAAS,SAAAuE,GAAAA,IAAA1L,UAIRgL,gBAAAA,QAAAA,EAIT9D,GAAAwE,KAASC,GAAAA,KAAmBX,GAAAA,aAAAA,kBACtBY,gBACCC,EAAIP,mBAAaN,0BAEfa,EADDzF,eAAY4E,sBAAAA,EAA+BM,qBAC3BlF,4BACd0F,EAAY1F,aAAaN,SACzBiG,GAAU3F,MAAiBN,GAC3BkG,IAAa5F,IAAazC,EACfyC,OClEvB,WAEE,GAA2DlI,SAAvD8B,SAASC,cAAc,OAAOgM,YAAYC,SAA9C,CAKE,GAAIC,EACC,IAAI3F,OAAO4F,aAAeA,YAAYD,IAC3C,GAAIA,GAAM,WAAa,MAAOC,aAAYD,WAE1C,IAAIA,GAAM,WAAa,MAAO/B,MAAK+B,MAGrC,IAAIE,GAAuB,SAASC,EAAQC,EAAaC,GACvD3P,KAAKyP,OAASA,EACdzP,KAAK0P,YAAcA,EACnB1P,KAAK2P,aAAeA,EAEpB3P,KAAKkK,KAAO,SACZlK,KAAK4P,SAAAA,EACL5P,KAAK6P,YAAAA,EACL7P,KAAK8P,cAAgBL,EACrBzP,KAAK+P,kBAAAA,EACL/P,KAAKgQ,WAAaC,MAAMC,UACxBlQ,KAAKmQ,UAAY5C,KAAK+B,OAGpBc,EAAyBzG,OAAO0G,QAAQ1J,UAAUyI,OACtDzF,QAAO0G,QAAQ1J,UAAUyI,QAAU,SAAS3G,EAAa6H,GACvD,GAAIC,GAAYH,EAAuBI,KAAKxQ,KAAMyI,EAAa6H,EAE/DC,GAAUE,mBACVF,EAAUlB,SAAW,IAErB,IAAIqB,GAAiBH,EAAUI,MAC/BJ,GAAUI,OAAS,WACjBD,EAAeF,KAAKxQ,KACpB,IAAI4Q,GAAQ,GAAIpB,GAAqBxP,KAAM,KAAMsP,KAC7CuB,EAAW7Q,KAAKyQ,gBAAgB7B,OAAO5O,KAAKqP,UAAYrP,KAAKqP,aACjEyB,YAAW,WACTD,EAASrP,QAAQ,SAASuP,GACxBA,EAAQP,KAAKI,EAAMnB,OAAQmB,MAE5B,GAGL,IAAII,GAA2BT,EAAUU,gBACzCV,GAAUU,iBAAmB,SAAS/G,EAAM6G,GACpB,kBAAXA,IAAiC,UAAR7G,EAClClK,KAAKyQ,gBAAgBtH,KAAK4H,GAE1BC,EAAyBR,KAAKxQ,KAAMkK,EAAM6G,GAG9C,IAAIG,GAA8BX,EAAUY,mBAW5C,OAVAZ,GAAUY,oBAAsB,SAASjH,EAAM6G,GAC7C,GAAY,UAAR7G,EAAkB,CACpB,GAAIkH,GAAQpR,KAAKyQ,gBAAgB9O,QAAQoP,EACrCK,IAAS,GACXpR,KAAKyQ,gBAAgBY,OAAOD,EAAO,OAErCF,GAA4BV,KAAKxQ,KAAMkK,EAAM6G,IAI1CR,OClEX,SAAU9Q,GAgBR,GAAI6R,GAAUnO,SAASoO,gBACnBhB,EAAY,KACZiB,GAAAA,CACJ,KACE,GAAIC,GAAkBC,iBAAiBJ,GAASK,iBAAiB,WAC7DC,EAAiC,KAAnBH,EAAyB,IAAM,GACjDlB,GAAYe,EAAQlC,SAASyC,SAAYD,EAAaA,KACjDzQ,SAAU,IACfoP,EAAUb,YAAc,EACxB8B,EAAWE,iBAAiBJ,GAASK,iBAAiB,YAAcC,EACpE,MAAOE,IACP,QACIvB,GACFA,EAAUI,SAEd,IAAIa,EAAJ,CAIA,GAAIpB,GAAyBzG,OAAO0G,QAAQ1J,UAAUyI,OACtDzF,QAAO0G,QAAQ1J,UAAUyI,QAAU,SAAS3G,EAAa6H,GAUvD,MATI3G,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,IAAgC,OAAhBA,IACjCA,EAAchJ,EAAO+I,mBAAmBC,IAGnC2H,EAAuBI,KAAKxQ,KAAMyI,EAAa6H,MAEvDjR,IC/CH,SAAUI,EAAQkP,EAAOjP,GA8DvB,QAASqS,GAAsBC,GAC7B,GAAIC,GAAWtI,OAAOxG,SAAS8O,QAC/BA,GAASvC,YAAcsC,EACvBC,EAASC,qBAC0B,GAA/BD,EAASE,YAAYnJ,OACvBoJ,GAAAA,EAEAC,sBAAsBN;CApE1B,GAAIO,GAAgC3I,OAAO0I,qBAC3C1I,QAAO0I,sBAAwB,SAAShQ,GACtC,MAAOiQ,GAA8B,SAASlQ,GAC5CuH,OAAOxG,SAAS8O,SAASM,4BACzBlQ,EAAED,GACFuH,OAAOxG,SAAS8O,SAASM,+BAI7B5D,EAAM6D,kBAAoB,WACxBxS,KAAKmS,eACLnS,KAAK0P,YAAcrO,QAGrBsN,EAAM6D,kBAAkB7L,WACtB8L,cAAe,WAEb,MADAzS,MAAKkS,qBACElS,KAAKmS,YAAYtO,SAE1B0O,0BAA2B,WACzB5D,EAAM+D,uBAAyB/D,EAAM+D,uBAAuBhI,OAAO,SAAS6F,GAC1E,MAAOA,GAAUoC,qBAGrBT,mBAAoB,WAClBlS,KAAKuS,4BACLvS,KAAKmS,YAAcnS,KAAKmS,YAAYzH,OAAO,SAAS6F,GAClD,MAA8B,YAAvBA,EAAUqC,WAAkD,QAAvBrC,EAAUqC,aAG1DC,MAAO,SAAS7R,GACd,GAAIuP,GAAY,GAAI5B,GAAMmE,UAAU9R,EAAQhB,KAW5C,OAVAA,MAAKmS,YAAYhJ,KAAKoH,GACtB5B,EAAMoE,+BAMNxC,EAAUoC,kBACVpC,EAAUrJ,WAAW8L,OACrBzC,EAAUoC,kBACHpC,GAETyC,KAAM,SAAShS,GAIb,MAHIA,IACFA,EAAOiS,SAEFjT,KAAK6S,MAAM7R,IAItB,IAAIoR,IAAAA,CAEJzD,GAAMoE,6BAA+B,WAC9BX,IACHA,GAAAA,EACAC,sBAAsBN,IAc1B,IAAIE,GAAW,GAAItD,GAAM6D,iBACzB7D,GAAMsD,SAAWA,CAEjB,KACE3Q,OAAO4R,eAAevJ,OAAOxG,SAAU,YACrCgQ,cAAAA,EACAC,IAAK,WAAa,MAAOnB,MAE3B,MAAOoB,IACT,IACE1J,OAAOxG,SAAS8O,SAAWA,EAC3B,MAAOoB,MAERhU,EAAqBE,EAAmBC,GCtF3C,SAAUC,EAAQkP,EAAOjP,GACvBiP,EAAM+D,0BAEN/D,EAAMmE,UAAY,SAAS9R,EAAQiR,GASjC,GARAjS,KAAKsT,GAAK,GACNtS,GAAUA,EAAOuS,MACnBvT,KAAKsT,GAAKtS,EAAOuS,KAEnBvT,KAAKgB,OAASA,EACVA,IACFA,EAAOkG,WAAalH,OAEjBiS,EACH,KAAM,IAAIlE,OAAM,gDAElB/N,MAAKwT,UAAYvB,EACjBjS,KAAKyT,gBAAkBhU,EAAOiU,iBAC9B1T,KAAK2T,UAAY,EACjB3T,KAAK4T,SAAAA,EACL5T,KAAK6T,UAAAA,EACL7T,KAAKkH,WAAa,KAClBlH,KAAK8T,oBACL9T,KAAK+T,UAAY,KACjB/T,KAAKgU,cAAgB,OACrBhU,KAAKmH,8BAELnH,KAAKkH,WAAWyJ,SAChB3Q,KAAK2S,mBAGPhE,EAAMmE,UAAUnM,WACdgM,gBAAiB,WACf,GAAIsB,GAAejU,KAAKgU,cACpBE,EAAelU,KAAK4S,SAsBxB,OArBI5S,MAAKmU,eAAiBD,IAAiBD,IACrB,QAAhBC,GACFlU,KAAKoU,sBACLpU,KAAKmU,cAAgB9S,QACI,WAAhB4S,EACTjU,KAAKqU,uBACoB,WAAhBH,IACTlU,KAAKmU,cAAgB9S,SAGrBrB,KAAKsU,kBAAoBJ,IAAiBD,IACxB,QAAhBC,GACFlU,KAAKuU,yBACLvU,KAAKsU,iBAAmBjT,QACC,YAAhB6S,EACTlU,KAAKwU,0BACoB,YAAhBP,IACTjU,KAAKsU,iBAAmBjT,SAG5BrB,KAAKgU,cAAgBhU,KAAK4S,UAClB5S,KAAKmU,eAAiBnU,KAAKsU,kBAErCnN,4BAA6B,WAC3BnH,KAAK2S,iBACL,IAAI8B,GACAC,EACAC,EACAC,EACAC,IAAgB7U,KAAKkH,UACrB2N,KACFJ,EAAkBzU,KAAK0E,aACvBgQ,EAAY1U,KAAK4T,QACjBe,EAAe3U,KAAKiP,UACpB2F,EAAiB5U,KAAK0P,YACtB1P,KAAKkH,WAAWyJ,SAChB3Q,KAAKkH,WAAW4N,SAAW,KAC3B9U,KAAKkH,WAAa,QAGflH,KAAKgB,QAAUhB,KAAKgB,iBAAkB2I,QAAOoL,kBAChD/U,KAAKkH,WAAayH,EAAMqG,wCAAwChV,KAAKgB,QACrE2N,EAAMsG,+BAA+BjV,QAEnCA,KAAKgB,iBAAkB2I,QAAOuL,gBAAkBlV,KAAKgB,iBAAkB2I,QAAOwL,eAChFnV,KAAKkH,WAAayH,EAAMyG,+BAA+BpV,KAAKgB,QAC5D2N,EAAM0G,sBAAsBrV,OAE1BA,KAAKgB,QAAUhB,KAAKgB,OAAOsU,WAC7B3G,EAAM4G,6BAA6BvV,MAEjC6U,IACqB,GAAnBJ,IACFzU,KAAK0E,aAAe+P,GAED,OAAjBE,EACF3U,KAAKiP,UAAY0F,EACW,OAAnBC,EACT5U,KAAK0P,YAAckF,EACS,OAAnB5U,KAAK2T,YACd3T,KAAK0P,YAAc1P,KAAK2T,WAEtBe,GACF1U,KAAKwV,SAGTxV,KAAK2S,mBAEP8C,gBAAiB,WACf,GAAKzV,KAAKgB,QAA4B,QAAlBhB,KAAK4S,UAAzB,CAGA,GAAI3J,GAASjJ,KAAKgB,OAAOiG,QAAQjC,KACjChF,MAAK8T,iBAAiBtS,QAAQ,SAASkU,GACrC1V,KAAK2V,iBAAiBD,EAAgBzM,GAClCjJ,KAAKgB,iBAAkB2I,QAAOuL,iBAChCjM,GAAU0F,EAAMiH,mBAAmBF,EAAe1U,UACpD6U,KAAK7V,SAET8V,sBAAuB,SAASvF,GAC9B,GAAKvQ,KAAKgB,QAAWhB,KAAK6T,SAE1B,IAAK,GAAIxL,GAAI,EAAGA,EAAIrI,KAAKgB,OAAO+U,SAAS/M,OAAQX,IAC/CrI,KAAKgB,OAAO+U,SAAS1N,GAAGnB,WAAaqJ,EACrCvQ,KAAK8T,iBAAiBzL,GAAGyN,sBAAsBvF,IAGnDyF,0BAA2B,WACzB,GAAKhW,KAAKgB,QAAWhB,KAAK6T,SAA1B,CAEA,GAAI5K,GAASjJ,KAAKgB,OAAOiG,QAAQjC,KACjChF,MAAKiW,yBACLjW,KAAKgB,OAAO+U,SAASvU,QAAQ,SAAS0U,GACpC,GAAIR,GAAiB/L,OAAOxG,SAAS8O,SAASY,MAAMqD,EACpDlW,MAAK8T,iBAAiB3K,KAAKuM,GAC3BA,EAAehR,aAAe1E,KAAK0E,aAC/B1E,KAAK4T,SACP8B,EAAeF,QACjBU,EAAMhP,WAAalH,KAAKgB,OAAOkG,WAE/BlH,KAAK2V,iBAAiBD,EAAgBzM,GAElCjJ,KAAKgB,iBAAkB2I,QAAOuL,iBAChCjM,GAAU0F,EAAMiH,mBAAmBM,KACrCL,KAAK7V,SAET2V,iBAAkB,SAASD,EAAgBzM,GAClB,OAAnBjJ,KAAKiP,UACPyG,EAAehG,YAAc1P,KAAK0P,YAAczG,EAASjJ,KAAK0E,aACrDgR,EAAezG,YAAcjP,KAAKiP,UAAYhG,EAASjJ,KAAK0E,eACrEgR,EAAezG,UAAYjP,KAAKiP,UAAYhG,EAASjJ,KAAK0E,eAG9DuN,GAAIA,YACF,MAAOjS,MAAKwT,WAEdZ,GAAIA,aACF,MAAO5S,MAAKkH,WAAalH,KAAKkH,WAAW0L,UAAY,QAEvDuD,GAAIA,YACF,MAAKxM,QAAOyM,SAIPpW,KAAKsU,mBAC0C,IAA9C3F,EAAM+D,uBAAuB/Q,QAAQ3B,OACvC2O,EAAM+D,uBAAuBvJ,KAAKnJ,MAEpCA,KAAKsU,iBAAmB,GAAI8B,SACxB,SAASC,EAASC,GAChBtW,KAAKwU,wBAA0B,WAC7B6B,EAAQrW,OAEVA,KAAKuU,uBAAyB,WAC5B+B,GAAQpM,KAAMC,aAAaoM,UAAWlM,KAAM,iBAE9CwL,KAAK7V,OACW,YAAlBA,KAAK4S,WACP5S,KAAKwU,2BAGFxU,KAAKsU,mBApBV3G,QAAQC,KAAK,6DACN,OAqBX4I,GAAIA,SACF,MAAK7M,QAAOyM,SAIPpW,KAAKmU,gBAC0C,IAA9CxF,EAAM+D,uBAAuB/Q,QAAQ3B,OACvC2O,EAAM+D,uBAAuBvJ,KAAKnJ,MAEpCA,KAAKmU,cAAgB,GAAIiC,SACrB,SAASC,EAASC,GAChBtW,KAAKqU,qBAAuB,WAC1BgC,EAAQrW,OAEVA,KAAKoU,oBAAsB,WACzBkC,GAAQpM,KAAMC,aAAaoM,UAAWlM,KAAM,iBAE9CwL,KAAK7V,OACY,YAAnBA,KAAK4S,WACP5S,KAAKqU,wBAGFrU,KAAKmU,gBApBVxG,QAAQC,KAAK,6DACN,OAqBX6I,GAAIA,YACF,MAAOzW,MAAKkH,WAAWuP,UAEzBA,GAAIA,UAASC,GACK,kBAALA,GACT1W,KAAKkH,WAAWuP,SAAW,SAAUpD,GACnCA,EAAE5D,OAASzP,KACX0W,EAAElG,KAAKxQ,KAAMqT,IACZwC,KAAK7V,MAERA,KAAKkH,WAAWuP,SAAWC,GAG/BrH,GAAIA,YACF,MAAOrP,MAAKkH,WAAWmI,UAEzBA,GAAIA,UAASqH,GACK,kBAALA,GACT1W,KAAKkH,WAAWmI,SAAW,SAAUgE,GACnCA,EAAE5D,OAASzP,KACX0W,EAAElG,KAAKxQ,KAAMqT,IACZwC,KAAK7V,MAERA,KAAKkH,WAAWmI,SAAWqH,GAG/BhH,GAAIA,eACF1P,KAAK2S,iBACL,IAAIjD,GAAc1P,KAAKkH,WAAWwI,WAElC,OADA1P,MAAK2S,kBACEjD,GAETA,GAAIA,aAAYgH,GACd1W,KAAK2S,kBACL3S,KAAKkH,WAAWwI,YAAczF,SAASyM,GAAKA,EAAIhU,KAAKiU,KAAKD,GAAK3S,OAAO6S,UACtE5W,KAAK6W,YACL7W,KAAK8W,cAAc,SAASZ,EAAOjN,GACjCiN,EAAMxG,YAAcgH,EAAIzN,IAE1BjJ,KAAK2S,mBAEP1D,GAAIA,aACF,MAAOjP,MAAKkH,WAAW+H,WAEzBA,GAAIA,WAAUyH,GACZ1W,KAAK2S,kBACL3S,KAAKkH,WAAW+H,UAAYhF,SAASyM,GAAKA,EAAIhU,KAAKiU,KAAKD,GAAK3S,OAAO6S,UACpE5W,KAAK6W,YACL7W,KAAK8W,cAAc,SAASZ,EAAOjN,GACjCiN,EAAMjH,UAAYyH,EAAIzN,IAExBjJ,KAAK2S,mBAEPjO,GAAIA,gBACF,MAAO1E,MAAKkH,WAAWxC,cAEzBA,GAAIA,cAAaoC,GACf9G,KAAK2S,iBACL,IAAIiC,GAAiB5U,KAAK0P,WAC1B1P,MAAKkH,WAAWxC,aAAeoC,EAC/B9G,KAAK8W,cAAc,SAASpB,GAC1BA,EAAehR,aAAeoC,IAEV,UAAlB9G,KAAK4S,WAA2C,QAAlB5S,KAAK4S,WACrC5S,KAAKgT,OAEgB,OAAnB4B,IACF5U,KAAK0P,YAAckF,GAErB5U,KAAK2S,mBAEPK,KAAM,WACJhT,KAAK2S,kBACL3S,KAAK4T,SAAAA,EACL5T,KAAKkH,WAAW8L,OACgC,IAA5ChT,KAAKwT,UAAUrB,YAAYxQ,QAAQ3B,OACrCA,KAAKwT,UAAUrB,YAAYhJ,KAAKnJ,MAElCA,KAAK6W,YACLlI,EAAMoI,eAAe/W,MACrBA,KAAK8W,cAAc,SAASZ,GAC1B,GAAIc,GAAOd,EAAMxG,WACjBwG,GAAMlD,OACNkD,EAAMxG,YAAcsH,IAEtBhX,KAAK2S,mBAEP6C,MAAO,WACLxV,KAAK2S,kBACD3S,KAAK0P,cACP1P,KAAK2T,UAAY3T,KAAK0P,aAExB1P,KAAKkH,WAAWsO,QAChBxV,KAAK6W,YACL7W,KAAK8W,cAAc,SAASZ,GAC1BA,EAAMV,UAERxV,KAAK4T,SAAAA,EACL5T,KAAK2S,mBAEPsE,OAAQ,WACNjX,KAAK2S,kBACL3S,KAAKkH,WAAW+P,SAChBjX,KAAK6W,YACL7W,KAAK2S,mBAEPhC,OAAQ,WACN3Q,KAAK2S,kBACL3S,KAAKkH,WAAWyJ,SAChB3Q,KAAK6W,YACL7W,KAAKiW,yBACLjW,KAAK2S,mBAEPuE,QAAS,WACPlX,KAAK2S,iBACL,IAAIiC,GAAiB5U,KAAK0P,WAC1B1P,MAAKkH,WAAWgQ,UAChBlX,KAAK8W,cAAc,SAASpB,GAC1BA,EAAewB,YAEM,OAAnBtC,IACF5U,KAAK0P,YAAckF,GAErB5U,KAAK2S,mBAEP1B,iBAAkB,SAAS/G,EAAM6G,GAC/B,GAAIoG,GAAUpG,CACQ,mBAAXA,KACToG,EAAU,SAAU9D,GAClBA,EAAE5D,OAASzP,KACX+Q,EAAQP,KAAKxQ,KAAMqT,IAClBwC,KAAK7V,MACR+Q,EAAQ+D,SAAWqC,GAErBnX,KAAKkH,WAAW+J,iBAAiB/G,EAAMiN,IAEzChG,oBAAqB,SAASjH,EAAM6G,GAClC/Q,KAAKkH,WAAWiK,oBAAoBjH,EAAO6G,GAAWA,EAAQ+D,UAAa/D,IAE7EkF,uBAAwB,WACtB,KAAOjW,KAAK8T,iBAAiB9K,QAC3BhJ,KAAK8T,iBAAiBsD,MAAMzG,UAEhCmG,cAAe,SAASzU,GACtB,GAAI4G,GAAS,CASb,IARIjJ,KAAKgB,OAAO+U,UAAY/V,KAAK8T,iBAAiB9K,OAAShJ,KAAKgB,OAAO+U,SAAS/M,QAC9EhJ,KAAKgW,4BACPhW,KAAK8T,iBAAiBtS,QAAQ,SAAS0U,GACrC7T,EAAEmO,KAAKxQ,KAAMkW,EAAOjN,GAChBjJ,KAAKgB,iBAAkB2I,QAAOuL,iBAChCjM,GAAUiN,EAAMlV,OAAO6D,iBACzBgR,KAAK7V,OAEe,WAAlBA,KAAK4S,UAAT,CAEA,GAAI3R,GAASjB,KAAKgB,OAAOiG,QACrB+K,EAAIhS,KAAK0P,WACH,QAANsC,IACFA,EAAIvS,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS+Q,EAAG/Q,KACrE,MAAL+Q,GAAa5Q,MAAM4Q,KACrBhS,KAAKiW,4BAIXtM,OAAOmJ,UAAYnE,EAAMmE,WAMxBzT,EAAqBE,EAAmBC,GCnX1C,SAASC,EAAQkP,EAAOjP,GAqCvB,QAAS2X,GAAa5O,GACpBzI,KAAKsX,QAAU7X,EAAO4J,mBAAmBZ,GAoG3C,QAAS8O,KAEP,IADA,GAAIC,IAAAA,EACGC,EAAczO,QAAQ,CAC3B,GAAI0F,GAAQ+I,EAAcC,OAC1BhJ,GAAM+G,kBACN+B,GAAAA,EAEF,MAAOA,GA/IT,GAAIG,GAAe,SAAS3W,GAE1B,GADAA,EAAOkG,WAAa7F,OAChBL,YAAkB2I,QAAOuL,gBAAkBlU,YAAkB2I,QAAOwL,YACtE,IAAK,GAAI9M,GAAI,EAAGA,EAAIrH,EAAO+U,SAAS/M,OAAQX,IAC1CsP,EAAa3W,EAAO+U,SAAS1N,IAKnCsG,GAAMiJ,YAAc,SAASC,GAE3B,IAAK,GADDC,MACKzP,EAAI,EAAGA,EAAIwP,EAAQ7O,OAAQX,IAAK,CACvC,GAAIrH,GAAS6W,EAAQxP,EACjBrH,GAAO+W,SACiC,IAAtCD,EAAWnW,QAAQX,EAAO+W,UAC5BD,EAAW3O,KAAKnI,EAAO+W,SAEzB/W,EAAO+W,QAAQhC,SAAS1E,OAAOrQ,EAAO+W,QAAQhC,SAASpU,QAAQX,GAAS,GACxEA,EAAO+W,QAAU,KACjBJ,EAAa3W,IACJA,EAAOkG,YAAelG,EAAOkG,WAAWlG,QAAUA,IAC3DA,EAAOkG,WAAWyJ,SAClB3P,EAAOkG,WAAWlG,OAAS,GAAI+T,gBAAe,SAC1C/T,EAAOkG,WAAW6M,YACpB/S,EAAOkG,WAAW6M,UAAU7M,WAAa,MAE3ClG,EAAOkG,WAAWC,8BAClBwQ,EAAa3W,IAGjB,IAAKqH,EAAI,EAAGA,EAAIyP,EAAW9O,OAAQX,IACjCyP,EAAWzP,GAAG2P,YAQlBrJ,EAAMoG,eAAiB,SAAStF,EAAQhH,EAAa7I,EAAa0T,GAmBhE,MAlBAtT,MAAKyP,OAASA,EACdzP,KAAK+X,QAAU,KAEfnY,EAAcH,EAAOoC,sBAAsBjC,GAC3CI,KAAKgH,aAAevH,EAAOE,iBAAiBC,GAC5CI,KAAKiH,QAAUxH,EAAOqC,qBAAqBlC,GAE3CI,KAAKiB,OAASxB,EAAOqB,WAAWlB,GAAAA,EAAoBI,MACpDA,KAAKiB,OAAO8F,QAAU/G,KACI,kBAAfyI,IACThJ,EAAOqO,WAAW,wBAAyB,aAAc,wCACzD9N,KAAKiY,qBAAuBxP,GAE5BzI,KAAKiY,qBAAuB,GAAIZ,GAAa5O,GAE/CzI,KAAKkY,WAAazP,EAClBzI,KAAK6E,eAAiBpF,EAAO+E,wBAAwBxE,KAAKiH,SAC1DjH,KAAKuT,IAAMD,EACJtT,MAGT2O,EAAMoG,eAAepO,WACnBwR,UAAW,WACT,MAAwC,kBAA7BnY,MAAKiY,qBACPjY,KAAKiY,qBACPjY,KAAKiY,qBAAqBX,SAEnCc,GAAIA,UAASC,GACX,GAA+B,kBAApBrY,MAAKmY,YACd,KAAM,IAAIpK,OAAM,qEAElB/N,MAAKsV,UAAY+C,EACbrY,KAAKkH,YACPlH,KAAKkH,WAAWC,+BAGpBmR,GAAIA,UACF,MAAOtY,MAAK+X,SAEdlY,MAAO,WACL,GAA+B,kBAApBG,MAAKmY,YACd,KAAM,IAAIpK,OAAM,2CAElB,IAAIlO,GAAQ,GAAIkV,gBAAe/U,KAAKyP,UAAYhQ,EAAOE,iBAAiBK,KAAKgH,cAAehH,KAAKuT,IAGjG,OAFA1T,GAAMoY,qBAAuBjY,KAAKiY,qBAClCpY,EAAMqY,WAAalY,KAAKkY,WACjBrY,GAEToT,OAAQ,WACNtE,EAAMiJ,aAAa5X,QAIvB,IAAIoQ,GAAyBC,QAAQ1J,UAAUyI,OAC/CiB,SAAQ1J,UAAUyI,QAAU,SAAS3G,EAAa6H,GAChD,GAAIgD,GAAK,EAIT,OAHIhD,IAAWA,EAAQgD,KACrBA,EAAKhD,EAAQgD,IAER3E,EAAMsD,SAASY,MAAM,GAAIlE,GAAMoG,eAAe/U,KAAMyI,EAAa6H,EAASgD,IAGnF,IAAIiF,GAAapV,SAASsI,gBAAgB,+BAAgC,MAC1EkD,GAAMqG,wCAA0C,SAASwD,GACvD,GAAIA,EAAgB,CAClB,GAAI/I,GAAS+I,EAAe/I,QAAU8I,EAClChP,EAAYiP,EAAeN,UACP,mBAAb3O,KACTA,KAEF,IAAI+G,GAAUkI,EAAexR,YAC7BsJ,GAAQgD,GAAKkF,EAAejF,QAE5B,IAAI9D,GAAS8I,EACThP,KACA+G,EAAU,CAEhB,OAAOF,GAAuBxM,MAAM6L,GAASlG,EAAW+G,KAI1D3B,EAAMsG,+BAAiC,SAAS1E,GAC1CA,EAAUvP,QAA0D,kBAAzCuP,GAAUvP,OAAOiX,sBAC9CtJ,EAAM4G,6BAA6BhF,GAIvC,IAAIkH,KACJ9I,GAAMoI,eAAiB,SAAS0B,GACG,OAA7BA,EAAexJ,WAAuBwJ,EAAe5E,WAE7B,GAAxB4D,EAAczO,QAChBqJ,sBAAsBkF,GAExBE,EAActO,KAAKsP,IAWrB,IAAIC,GAA2B/O,OAAO+H,gBACtCpQ,QAAO4R,eAAevJ,OAAQ,oBAC5BwJ,cAAAA,EACAwF,YAAAA,EACA7R,MAAO,WACL6C,OAAOxG,SAAS8O,SAASM,2BACzB,IAAItK,GAASyQ,EAAyB9U,MAAM5D,KAAM4Y,UAIlD,OAHIrB,OACFtP,EAASyQ,EAAyB9U,MAAM5D,KAAM4Y,YAChDjP,OAAOxG,SAAS8O,SAASM,4BAClBtK,KAIX0B,OAAOoL,eAAiBpG,EAAMoG,eAC9BpL,OAAO0G,QAAQ1J,UAAU8L,cAAgB,WACvC,MAAOtP,UAAS8O,SAASQ,gBAAgB/H,OAAO,SAAS6F,GACvD,MAA4B,QAArBA,EAAUvP,QAAmBuP,EAAUvP,OAAOyO,QAAUzP,MAC/D6V,KAAK7V,SAGTX,EAAqBE,EAAmBC,GCzK1C,SAAUC,EAAQkP,EAAOjP,GA6CvB,QAASmZ,GAASR,GACZA,EAASS,cAEbT,EAASS,aAAAA,EACTC,EAAU5P,KAAKkP,GACVjG,IACHA,GAAAA,EACAC,sBAAsB2G,KAI1B,QAASA,GAAKhH,GACZ,GAAIiH,GAAWF,CACfA,MACAE,EAAS7P,KAAK,SAAS8P,EAAMC,GAC3B,MAAOD,GAAKzF,gBAAkB0F,EAAM1F,kBAEtCwF,EAAWA,EAASvO,OAAO,SAAS2N,GAClCA,GACA,IAAIzF,GAAYyF,EAASnR,WAAamR,EAASnR,WAAW0L,UAAY,MAGtE,OAFiB,WAAbA,GAAuC,WAAbA,IAC5ByF,EAASS,aAAAA,GACJT,EAASS,cAElBC,EAAU5P,KAAKvF,MAAMmV,EAAWE,GAE5BF,EAAU/P,QACZoJ,GAAAA,EACAC,sBAAsB2G,IAEtB5G,GAAAA,EAzEJ,GAEIsB,IAFavQ,SAASsI,gBAAgB,+BAAgC,OAErD,EACrBkD,GAAM4G,6BAA+B,SAAShF,GAC5C,GACI6I,GADA3J,EAASc,EAAUvP,OAAOyO,OAE1B4J,EAA0D,kBAAhC9I,GAAUvP,OAAOmX,WAE7CiB,GADEC,EACe9I,EAAUvP,OAAOmX,YAEjB5H,EAAUvP,OAAOsU,SAEpC,IAAIrU,GAASsP,EAAUvP,OAAOC,OAC1BqY,EAAO,IACXrY,GAASxB,EAAOqC,qBAAqBb,EACrC,IAAIoX,GAAW,WACb,GAAIrG,GAAIqG,EAASnR,WAAamR,EAASnR,WAAWwI,YAAc,IACtD,QAANsC,IACFA,EAAIvS,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS+Q,EAAG/Q,GACxEG,MAAM4Q,KACRA,EAAI,OAIJA,IAAMsH,IACJD,EACFD,EAAepH,EAAGvC,EAAQc,EAAUvP,QAEpCoY,EAAepH,EAAGzB,EAAUvP,OAAQuP,EAAUvP,OAAOkG,aAGzDoS,EAAOtH,EAGTqG,GAASnR,WAAaqJ,EACtB8H,EAASS,aAAAA,EACTT,EAAS5E,gBAAkBC,IAC3BnD,EAAUwD,UAAYsE,EACtBQ,EAASR,GAGX,IAAIU,MACA3G,GAAAA,CAmCJzD,GAAMmE,UAAUnM,UAAUkQ,UAAY,WAChC7W,KAAK+T,WACP8E,EAAS7Y,KAAK+T,aAGjB1U,EAAqBE,EAAmBC,GCnF3C,SAAUC,EAAQkP,EAAOjP,GAEvB,QAASkW,GAAmB2D,GAC1B,MAAOA,GAAKtS,QAAQjC,MAAQuU,EAAK1U,eAAiB0U,EAAKtS,QAAQG,SAGjE,QAASoS,GAAYzD,EAAUnW,EAAa0T,GAC1CtT,KAAKuT,IAAMD,EACXtT,KAAK+X,QAAU,KACf/X,KAAK+V,SAAWA,MAChB/V,KAAKyZ,UAAUzZ,KAAK+V,UACpBnW,EAAcH,EAAOoC,sBAAsBjC,GAC3CI,KAAKgH,aAAevH,EAAOE,iBAAiBC,GAC5CI,KAAKiH,QAAUxH,EAAOqC,qBAAqBlC,GAAAA,GAC3CI,KAAKiB,OAASxB,EAAOqB,WAAWlB,GAAAA,EAAmBI,MACnDA,KAAKiB,OAAO8F,QAAU/G,KAEQ,SAA1BA,KAAKiH,QAAQ9F,WACfnB,KAAKiH,QAAQ9F,SAAWnB,KAAK6E,gBAIjC8E,OAAOuL,eAAiB,WACtBsE,EAAY5V,MAAM5D,KAAM4Y,YAG1BjP,OAAOwL,YAAc,WACnBqE,EAAY5V,MAAM5D,KAAM4Y,YAG1BY,EAAY7S,WACV+S,YAAa,SAAS1Y,GAEpB,IADA,GAAIgB,GAAIhC,KACK,OAANgC,GAAY,CACjB,GAAIA,GAAKhB,EACP,OAAA,CACFgB,GAAIA,EAAE+V,QAER,OAAA,GAEFC,SAAU,WAGR,IADA,GAAIuB,GAAOvZ,KACJuZ,GACwB,SAAzBA,EAAKtY,OAAOE,WACdoY,EAAKtS,QAAQ9F,SAAWoY,EAAK1U,gBAE/B0U,EAAOA,EAAKxB,OAEV/X,MAAKkH,YACPlH,KAAKkH,WAAWC,+BAGpBsS,UAAW,SAASE,GAClBhL,EAAMiJ,YAAY+B,EAClB,KAAK,GAAItR,GAAI,EAAGA,EAAIsR,EAAY3Q,OAAQX,IACtCsR,EAAYtR,GAAG0P,QAAU/X,MAG7B4Z,UAAW,SAASC,EAAMC,GAExB,IAAK,GADDxP,GAAUwP,EAAW,oCAAsC,qCACtDzR,EAAI,EAAGA,EAAIwR,EAAK7Q,OAAQX,IAC/B,GAAIrI,KAAK0Z,YAAYG,EAAKxR,IACxB,MACE6B,KAAMC,aAAa4P,sBACnB1P,KAAM,wBACNC,QAASA,EAKf,KAAK,GAAIjC,GAAI,EAAGA,EAAIwR,EAAK7Q,OAAQX,IAC/ByR,EAAW9Z,KAAK+V,SAAS5M,KAAK0Q,EAAKxR,IAAMrI,KAAK+V,SAASiE,QAAQH,EAAKxR,GAEtErI,MAAKyZ,UAAUI,GACf7Z,KAAKgY,YAEPiC,OAAQ,WACNja,KAAK4Z,UAAUhB,WAAAA,IAEjBsB,QAAS,WACPla,KAAK4Z,UAAUhB,WAAAA,IAEjBN,GAAIA,UACF,MAAOtY,MAAK+X,SAEdoC,GAAIA,cACF,MAAOna,MAAK+V,SAAS/M,OAAShJ,KAAK+V,SAAS,GAAK,MAEnDqE,GAAIA,aACF,MAAOpa,MAAK+V,SAAS/M,OAAShJ,KAAK+V,SAAS/V,KAAK+V,SAAS/M,OAAS,GAAK,MAE1EnJ,MAAO,WAGL,IAAK,GAFDwa,GAAe5a,EAAOE,iBAAiBK,KAAKgH,cAC5CsT,KACKjS,EAAI,EAAGA,EAAIrI,KAAK+V,SAAS/M,OAAQX,IACxCiS,EAAenR,KAAKnJ,KAAK+V,SAAS1N,GAAGxI,QAEvC,OAAQG,gBAAgBmV,aACpB,GAAIA,aAAYmF,EAAgBD,GAChC,GAAInF,gBAAeoF,EAAgBD,IAEzCpH,OAAQ,WACNtE,EAAMiJ,aAAa5X,SAIvB2J,OAAOuL,eAAevO,UAAYrF,OAAOiZ,OAAOf,EAAY7S,WAC5DrF,OAAO4R,eACHvJ,OAAOuL,eAAevO,UACtB,kBAEEyM,IAAK,WACH,GAAIoH,GAAQ,CAIZ,OAHAxa,MAAK+V,SAASvU,QAAQ,SAAS0U,GAC7BsE,GAAS5E,EAAmBM,KAEvBxT,KAAK+X,IAAID,EAAO,MAI/B7Q,OAAOwL,YAAYxO,UAAYrF,OAAOiZ,OAAOf,EAAY7S,WACzDrF,OAAO4R,eACHvJ,OAAOwL,YAAYxO,UACnB,kBAEEyM,IAAK,WACH,GAAIqH,GAAM,CAIV,OAHAza,MAAK+V,SAASvU,QAAQ,SAAS0U,GAC7BuE,EAAM/X,KAAK+X,IAAIA,EAAK7E,EAAmBM,MAElCuE,KAIf9L,EAAMyG,+BAAiC,SAAS1G,GAC9C,GAAIgM,GACAzZ,EAAS,KACT0Z,EAAS,SAASC,GACpB,GAAIrK,GAAYmK,EAAoB5F,QACpC,OAAKvE,IAGsB,WAAvBA,EAAUqC,WAGTrC,EAAUvP,OAGL,MAAN4Z,MACFrK,GAAU0F,yBAQF,GAAN2E,GAAWrK,EAAU7L,aAAe,IACjCzD,IACHA,EAASxB,EAAOqC,qBAAqByO,EAAUvP,OAAOC,SAExD2Z,EAAKnb,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS,GAAIA,GAC1EG,MAAMwZ,IAAa,MAANA,IACfrK,EAAUuG,cAAc,SAASZ,GAC/BA,EAAMxG,YAAc,SAEtBa,GAAU0F,0BATd,OAlBA,QAiCE4E,EAAmB,GAAI9F,gBAAe,QAAUrG,EAAMzH,QAASyH,EAAM6E,IAGzE,OAFAsH,GAAiBzC,SAAWuC,EAC5BD,EAAsB/L,EAAMsD,SAASY,MAAMgI,IAI7ClM,EAAM0G,sBAAwB,SAAS9E,GACrCA,EAAUrJ,WAAW4N,SAAWvE,EAChCA,EAAUsD,UAAAA,EACVlF,EAAMoI,eAAexG,GACrBA,EAAUyF,4BACVzF,EAAUuF,sBAAsBvF,IAGlC5B,EAAMiH,mBAAqBA,GAE1BvW,EAAqBE,EAAmBC,GX3LvCD,EAAAA,QAEJub,MACMtb,WAAAA,MAAuBQ","file":"web-animations-next-lite.min.js"} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js
new file mode 100644
index 00000000000..e61b746f53f
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js
@@ -0,0 +1,17 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+!function(a,b){var c={},d={},e={},f=null;!function(a,b){function c(a){if("number"==typeof a)return a;var b={};for(var c in a)b[c]=a[c];return b}function d(){this._delay=0,this._endDelay=0,this._fill="none",this._iterationStart=0,this._iterations=1,this._duration=0,this._playbackRate=1,this._direction="normal",this._easing="linear",this._easingFunction=w}function e(){return a.isDeprecated("Invalid timing inputs","2016-03-02","TypeError exceptions will be thrown instead.",!0)}function f(b,c,e){var f=new d;return c&&(f.fill="both",f.duration="auto"),"number"!=typeof b||isNaN(b)?void 0!==b&&Object.getOwnPropertyNames(b).forEach(function(c){if("auto"!=b[c]){if(("number"==typeof f[c]||"duration"==c)&&("number"!=typeof b[c]||isNaN(b[c])))return;if("fill"==c&&-1==u.indexOf(b[c]))return;if("direction"==c&&-1==v.indexOf(b[c]))return;if("playbackRate"==c&&1!==b[c]&&a.isDeprecated("AnimationEffectTiming.playbackRate","2014-11-28","Use Animation.playbackRate instead."))return;f[c]=b[c]}}):f.duration=b,f}function g(a){return"number"==typeof a&&(a=isNaN(a)?{duration:0}:{duration:a}),a}function h(b,c){return b=a.numericTimingToObject(b),f(b,c)}function i(a,b,c,d){return 0>a||a>1||0>c||c>1?w:function(e){function f(a,b,c){return 3*a*(1-c)*(1-c)*c+3*b*(1-c)*c*c+c*c*c}if(0==e||1==e)return e;for(var g=0,h=1;;){var i=(g+h)/2,j=f(a,c,i);if(Math.abs(e-j)<1e-4)return f(b,d,i);e>j?g=i:h=i}}}function j(a,b){return function(c){if(c>=1)return 1;var d=1/a;return c+=b*d,c-c%d}}function k(a){B||(B=document.createElement("div").style),B.animationTimingFunction="",B.animationTimingFunction=a;var b=B.animationTimingFunction;if(""==b&&e())throw new TypeError(a+" is not a valid value for easing");var c=D.exec(b);if(c)return i.apply(this,c.slice(1).map(Number));var d=E.exec(b);if(d)return j(Number(d[1]),{start:x,middle:y,end:z}[d[2]]);var f=A[b];return f?f:w}function l(a){return Math.abs(m(a)/a.playbackRate)}function m(a){return a.duration*a.iterations}function n(a,b,c){return null==b?F:b<c.delay?G:b>=c.delay+a?H:I}function o(a,b,c,d,e){switch(d){case G:return"backwards"==b||"both"==b?0:null;case I:return c-e;case H:return"forwards"==b||"both"==b?a:null;case F:return null}}function p(a,b,c,d){return(d.playbackRate<0?b-a:b)*d.playbackRate+c}function q(a,b,c,d,e){return c===1/0||c===-(1/0)||c-d==b&&e.iterations&&(e.iterations+e.iterationStart)%1==0?a:c%a}function r(a,b,c,d){return 0===c?0:b==a?d.iterationStart+d.iterations-1:Math.floor(c/a)}function s(a,b,c,d){var e=a%2>=1,f="normal"==d.direction||d.direction==(e?"alternate-reverse":"alternate"),g=f?c:b-c,h=g/b;return b*d._easingFunction(h)}function t(a,b,c){var d=n(a,b,c),e=o(a,c.fill,b,d,c.delay);if(null===e)return null;if(0===a)return d===G?0:1;var f=c.iterationStart*c.duration,g=p(a,e,f,c),h=q(c.duration,m(c),g,f,c),i=r(c.duration,h,g,c);return s(i,c.duration,h,c)/c.duration}var u="backwards|forwards|both|none".split("|"),v="reverse|alternate|alternate-reverse".split("|"),w=function(a){return a};d.prototype={_setMember:function(b,c){this["_"+b]=c,this._effect&&(this._effect._timingInput[b]=c,this._effect._timing=a.normalizeTimingInput(this._effect._timingInput),this._effect.activeDuration=a.calculateActiveDuration(this._effect._timing),this._effect._animation&&this._effect._animation._rebuildUnderlyingAnimation())},get playbackRate(){return this._playbackRate},set delay(a){this._setMember("delay",a)},get delay(){return this._delay},set endDelay(a){this._setMember("endDelay",a)},get endDelay(){return this._endDelay},set fill(a){this._setMember("fill",a)},get fill(){return this._fill},set iterationStart(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterationStart must be a non-negative number, received: "+timing.iterationStart);this._setMember("iterationStart",a)},get iterationStart(){return this._iterationStart},set duration(a){if("auto"!=a&&(isNaN(a)||0>a)&&e())throw new TypeError("duration must be non-negative or auto, received: "+a);this._setMember("duration",a)},get duration(){return this._duration},set direction(a){this._setMember("direction",a)},get direction(){return this._direction},set easing(a){this._easingFunction=k(a),this._setMember("easing",a)},get easing(){return this._easing},set iterations(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterations must be non-negative, received: "+a);this._setMember("iterations",a)},get iterations(){return this._iterations}};var x=1,y=.5,z=0,A={ease:i(.25,.1,.25,1),"ease-in":i(.42,0,1,1),"ease-out":i(0,0,.58,1),"ease-in-out":i(.42,0,.58,1),"step-start":j(1,x),"step-middle":j(1,y),"step-end":j(1,z)},B=null,C="\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*",D=new RegExp("cubic-bezier\\("+C+","+C+","+C+","+C+"\\)"),E=/steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/,F=0,G=1,H=2,I=3;a.cloneTimingInput=c,a.makeTiming=f,a.numericTimingToObject=g,a.normalizeTimingInput=h,a.calculateActiveDuration=l,a.calculateTimeFraction=t,a.calculatePhase=n,a.toTimingFunction=k}(c,f),function(a,b){function c(a,b){return a in j?j[a][b]||b:b}function d(a,b,d){var e=g[a];if(e){h.style[a]=b;for(var f in e){var i=e[f],j=h.style[i];d[i]=c(i,j)}}else d[a]=c(a,b)}function e(a){var b=[];for(var c in a)if(!(c in["easing","offset","composite"])){var d=a[c];Array.isArray(d)||(d=[d]);for(var e,f=d.length,g=0;f>g;g++)e={},"offset"in a?e.offset=a.offset:1==f?e.offset=1:e.offset=g/(f-1),"easing"in a&&(e.easing=a.easing),"composite"in a&&(e.composite=a.composite),e[c]=d[g],b.push(e)}return b.sort(function(a,b){return a.offset-b.offset}),b}function f(a){function b(){var a=c.length;null==c[a-1].offset&&(c[a-1].offset=1),a>1&&null==c[0].offset&&(c[0].offset=0);for(var b=0,d=c[0].offset,e=1;a>e;e++){var f=c[e].offset;if(null!=f){for(var g=1;e-b>g;g++)c[b+g].offset=d+(f-d)*g/(e-b);b=e,d=f}}}if(null==a)return[];window.Symbol&&Symbol.iterator&&Array.prototype.from&&a[Symbol.iterator]&&(a=Array.from(a)),Array.isArray(a)||(a=e(a));for(var c=a.map(function(a){var b={};for(var c in a){var e=a[c];if("offset"==c){if(null!=e&&(e=Number(e),!isFinite(e)))throw new TypeError("keyframe offsets must be numbers.")}else{if("composite"==c)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"add compositing is not supported"};e=""+e}d(c,e,b)}return void 0==b.offset&&(b.offset=null),b}),f=!0,g=-(1/0),h=0;h<c.length;h++){var i=c[h].offset;if(null!=i){if(g>i)throw{code:DOMException.INVALID_MODIFICATION_ERR,name:"InvalidModificationError",message:"Keyframes are not loosely sorted by offset. Sort or specify offsets."};g=i}else f=!1}return c=c.filter(function(a){return a.offset>=0&&a.offset<=1}),f||b(),c}var g={background:["backgroundImage","backgroundPosition","backgroundSize","backgroundRepeat","backgroundAttachment","backgroundOrigin","backgroundClip","backgroundColor"],border:["borderTopColor","borderTopStyle","borderTopWidth","borderRightColor","borderRightStyle","borderRightWidth","borderBottomColor","borderBottomStyle","borderBottomWidth","borderLeftColor","borderLeftStyle","borderLeftWidth"],borderBottom:["borderBottomWidth","borderBottomStyle","borderBottomColor"],borderColor:["borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],borderLeft:["borderLeftWidth","borderLeftStyle","borderLeftColor"],borderRadius:["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],borderRight:["borderRightWidth","borderRightStyle","borderRightColor"],borderTop:["borderTopWidth","borderTopStyle","borderTopColor"],borderWidth:["borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"],flex:["flexGrow","flexShrink","flexBasis"],font:["fontFamily","fontSize","fontStyle","fontVariant","fontWeight","lineHeight"],margin:["marginTop","marginRight","marginBottom","marginLeft"],outline:["outlineColor","outlineStyle","outlineWidth"],padding:["paddingTop","paddingRight","paddingBottom","paddingLeft"]},h=document.createElementNS("http://www.w3.org/1999/xhtml","div"),i={thin:"1px",medium:"3px",thick:"5px"},j={borderBottomWidth:i,borderLeftWidth:i,borderRightWidth:i,borderTopWidth:i,fontSize:{"xx-small":"60%","x-small":"75%",small:"89%",medium:"100%",large:"120%","x-large":"150%","xx-large":"200%"},fontWeight:{normal:"400",bold:"700"},outlineWidth:i,textShadow:{none:"0px 0px 0px transparent"},boxShadow:{none:"0px 0px 0px 0px transparent"}};a.convertToArrayForm=e,a.normalizeKeyframes=f}(c,f),function(a){var b={};a.isDeprecated=function(a,c,d,e){var f=e?"are":"is",g=new Date,h=new Date(c);return h.setMonth(h.getMonth()+3),h>g?(a in b||console.warn("Web Animations: "+a+" "+f+" deprecated and will stop working on "+h.toDateString()+". "+d),b[a]=!0,!1):!0},a.deprecated=function(b,c,d,e){var f=e?"are":"is";if(a.isDeprecated(b,c,d,e))throw new Error(b+" "+f+" no longer supported. "+d)}}(c),function(){if(document.documentElement.animate){var a=document.documentElement.animate([],0),b=!0;if(a&&(b=!1,"play|currentTime|pause|reverse|playbackRate|cancel|finish|startTime|playState".split("|").forEach(function(c){void 0===a[c]&&(b=!0)})),!b)return}!function(a,b,c){function d(a){for(var b={},c=0;c<a.length;c++)for(var d in a[c])if("offset"!=d&&"easing"!=d&&"composite"!=d){var e={offset:a[c].offset,easing:a[c].easing,value:a[c][d]};b[d]=b[d]||[],b[d].push(e)}for(var f in b){var g=b[f];if(0!=g[0].offset||1!=g[g.length-1].offset)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"Partial keyframes are not supported"}}return b}function e(c){var d=[];for(var e in c)for(var f=c[e],g=0;g<f.length-1;g++){var h=f[g].offset,i=f[g+1].offset,j=f[g].value,k=f[g+1].value,l=f[g].easing;h==i&&(1==i?j=k:k=j),d.push({startTime:h,endTime:i,easing:a.toTimingFunction(l?l:"linear"),property:e,interpolation:b.propertyInterpolation(e,j,k)})}return d.sort(function(a,b){return a.startTime-b.startTime}),d}b.convertEffectInput=function(c){var f=a.normalizeKeyframes(c),g=d(f),h=e(g);return function(a,c){if(null!=c)h.filter(function(a){return 0>=c&&0==a.startTime||c>=1&&1==a.endTime||c>=a.startTime&&c<=a.endTime}).forEach(function(d){var e=c-d.startTime,f=d.endTime-d.startTime,g=0==f?0:d.easing(e/f);b.apply(a,d.property,d.interpolation(g))});else for(var d in g)"offset"!=d&&"easing"!=d&&"composite"!=d&&b.clear(a,d)}}}(c,d,f),function(a,b,c){function d(a){return a.replace(/-(.)/g,function(a,b){return b.toUpperCase()})}function e(a,b,c){h[c]=h[c]||[],h[c].push([a,b])}function f(a,b,c){for(var f=0;f<c.length;f++){var g=c[f];e(a,b,d(g))}}function g(c,e,f){var g=c;/-/.test(c)&&!a.isDeprecated("Hyphenated property names","2016-03-22","Use camelCase instead.",!0)&&(g=d(c)),"initial"!=e&&"initial"!=f||("initial"==e&&(e=i[g]),"initial"==f&&(f=i[g]));for(var j=e==f?[]:h[g],k=0;j&&k<j.length;k++){var l=j[k][0](e),m=j[k][0](f);if(void 0!==l&&void 0!==m){var n=j[k][1](l,m);if(n){var o=b.Interpolation.apply(null,n);return function(a){return 0==a?e:1==a?f:o(a)}}}}return b.Interpolation(!1,!0,function(a){return a?f:e})}var h={};b.addPropertiesHandler=f;var i={backgroundColor:"transparent",backgroundPosition:"0% 0%",borderBottomColor:"currentColor",borderBottomLeftRadius:"0px",borderBottomRightRadius:"0px",borderBottomWidth:"3px",borderLeftColor:"currentColor",borderLeftWidth:"3px",borderRightColor:"currentColor",borderRightWidth:"3px",borderSpacing:"2px",borderTopColor:"currentColor",borderTopLeftRadius:"0px",borderTopRightRadius:"0px",borderTopWidth:"3px",bottom:"auto",clip:"rect(0px, 0px, 0px, 0px)",color:"black",fontSize:"100%",fontWeight:"400",height:"auto",left:"auto",letterSpacing:"normal",lineHeight:"120%",marginBottom:"0px",marginLeft:"0px",marginRight:"0px",marginTop:"0px",maxHeight:"none",maxWidth:"none",minHeight:"0px",minWidth:"0px",opacity:"1.0",outlineColor:"invert",outlineOffset:"0px",outlineWidth:"3px",paddingBottom:"0px",paddingLeft:"0px",paddingRight:"0px",paddingTop:"0px",right:"auto",textIndent:"0px",textShadow:"0px 0px 0px transparent",top:"auto",transform:"",verticalAlign:"0px",visibility:"visible",width:"auto",wordSpacing:"normal",zIndex:"auto"};b.propertyInterpolation=g}(c,d,f),function(a,b,c){function d(b){var c=a.calculateActiveDuration(b),d=function(d){return a.calculateTimeFraction(c,d,b)};return d._totalDuration=b.delay+c+b.endDelay,d._isCurrent=function(d){var e=a.calculatePhase(c,d,b);return e===PhaseActive||e===PhaseBefore},d}b.KeyframeEffect=function(c,e,f,g){var h,i=d(a.normalizeTimingInput(f)),j=b.convertEffectInput(e),k=function(){j(c,h)};return k._update=function(a){return h=i(a),null!==h},k._clear=function(){j(c,null)},k._hasSameTarget=function(a){return c===a},k._isCurrent=i._isCurrent,k._totalDuration=i._totalDuration,k._id=g,k},b.NullEffect=function(a){var b=function(){a&&(a(),a=null)};return b._update=function(){return null},b._totalDuration=0,b._isCurrent=function(){return!1},b._hasSameTarget=function(){return!1},b}}(c,d,f),function(a,b){function c(a,b,c){c.enumerable=!0,c.configurable=!0,Object.defineProperty(a,b,c)}function d(a){this._surrogateStyle=document.createElementNS("http://www.w3.org/1999/xhtml","div").style,this._style=a.style,this._length=0,this._isAnimatedProperty={};for(var b=0;b<this._style.length;b++){var c=this._style[b];this._surrogateStyle[c]=this._style[c]}this._updateIndices()}function e(a){if(!a._webAnimationsPatchedStyle){var b=new d(a);try{c(a,"style",{get:function(){return b}})}catch(e){a.style._set=function(b,c){a.style[b]=c},a.style._clear=function(b){a.style[b]=""}}a._webAnimationsPatchedStyle=a.style}}var f={cssText:1,length:1,parentRule:1},g={getPropertyCSSValue:1,getPropertyPriority:1,getPropertyValue:1,item:1,removeProperty:1,setProperty:1},h={removeProperty:1,setProperty:1};d.prototype={get cssText(){return this._surrogateStyle.cssText},set cssText(a){for(var b={},c=0;c<this._surrogateStyle.length;c++)b[this._surrogateStyle[c]]=!0;this._surrogateStyle.cssText=a,this._updateIndices();for(var c=0;c<this._surrogateStyle.length;c++)b[this._surrogateStyle[c]]=!0;for(var d in b)this._isAnimatedProperty[d]||this._style.setProperty(d,this._surrogateStyle.getPropertyValue(d))},get length(){return this._surrogateStyle.length},get parentRule(){return this._style.parentRule},_updateIndices:function(){for(;this._length<this._surrogateStyle.length;)Object.defineProperty(this,this._length,{configurable:!0,enumerable:!1,get:function(a){return function(){return this._surrogateStyle[a]}}(this._length)}),this._length++;for(;this._length>this._surrogateStyle.length;)this._length--,Object.defineProperty(this,this._length,{configurable:!0,enumerable:!1,value:void 0})},_set:function(a,b){this._style[a]=b,this._isAnimatedProperty[a]=!0},_clear:function(a){this._style[a]=this._surrogateStyle[a],delete this._isAnimatedProperty[a]}};for(var i in g)d.prototype[i]=function(a,b){return function(){var c=this._surrogateStyle[a].apply(this._surrogateStyle,arguments);return b&&(this._isAnimatedProperty[arguments[0]]||this._style[a].apply(this._style,arguments),this._updateIndices()),c}}(i,i in h);for(var j in document.documentElement.style)j in f||j in g||!function(a){c(d.prototype,a,{get:function(){return this._surrogateStyle[a]},set:function(b){this._surrogateStyle[a]=b,this._updateIndices(),this._isAnimatedProperty[a]||(this._style[a]=b)}})}(j);a.apply=function(b,c,d){e(b),b.style._set(a.propertyName(c),d)},a.clear=function(b,c){b._webAnimationsPatchedStyle&&b.style._clear(a.propertyName(c))}}(d,f),function(a){window.Element.prototype.animate=function(b,c){var d="";return c&&c.id&&(d=c.id),a.timeline._play(a.KeyframeEffect(this,b,c,d))}}(d),function(a,b){function c(a,b,d){if("number"==typeof a&&"number"==typeof b)return a*(1-d)+b*d;if("boolean"==typeof a&&"boolean"==typeof b)return.5>d?a:b;if(a.length==b.length){for(var e=[],f=0;f<a.length;f++)e.push(c(a[f],b[f],d));return e}throw"Mismatched interpolation arguments "+a+":"+b}a.Interpolation=function(a,b,d){return function(e){return d(c(a,b,e))}}}(d,f),function(a,b){function c(a,b,c){return Math.max(Math.min(a,c),b)}function d(b,d,e){var f=a.dot(b,d);f=c(f,-1,1);var g=[];if(1===f)g=b;else for(var h=Math.acos(f),i=1*Math.sin(e*h)/Math.sqrt(1-f*f),j=0;4>j;j++)g.push(b[j]*(Math.cos(e*h)-f*i)+d[j]*i);return g}var e=function(){function a(a,b){for(var c=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],d=0;4>d;d++)for(var e=0;4>e;e++)for(var f=0;4>f;f++)c[d][e]+=b[d][f]*a[f][e];return c}function b(a){return 0==a[0][2]&&0==a[0][3]&&0==a[1][2]&&0==a[1][3]&&0==a[2][0]&&0==a[2][1]&&1==a[2][2]&&0==a[2][3]&&0==a[3][2]&&1==a[3][3]}function c(c,d,e,f,g){for(var h=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],i=0;4>i;i++)h[i][3]=g[i];for(var i=0;3>i;i++)for(var j=0;3>j;j++)h[3][i]+=c[j]*h[j][i];var k=f[0],l=f[1],m=f[2],n=f[3],o=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];o[0][0]=1-2*(l*l+m*m),o[0][1]=2*(k*l-m*n),o[0][2]=2*(k*m+l*n),o[1][0]=2*(k*l+m*n),o[1][1]=1-2*(k*k+m*m),o[1][2]=2*(l*m-k*n),o[2][0]=2*(k*m-l*n),o[2][1]=2*(l*m+k*n),o[2][2]=1-2*(k*k+l*l),h=a(h,o);var p=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];e[2]&&(p[2][1]=e[2],h=a(h,p)),e[1]&&(p[2][1]=0,p[2][0]=e[0],h=a(h,p)),e[0]&&(p[2][0]=0,p[1][0]=e[0],h=a(h,p));for(var i=0;3>i;i++)for(var j=0;3>j;j++)h[i][j]*=d[i];return b(h)?[h[0][0],h[0][1],h[1][0],h[1][1],h[3][0],h[3][1]]:h[0].concat(h[1],h[2],h[3])}return c}();a.composeMatrix=e,a.quat=d}(d,f),function(a,b,c){a.sequenceNumber=0;var d=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="finish",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()};b.Animation=function(b){this.id="",b&&b._id&&(this.id=b._id),this._sequenceNumber=a.sequenceNumber++,this._currentTime=0,this._startTime=null,this._paused=!1,this._playbackRate=1,this._inTimeline=!0,this._finishedFlag=!0,this.onfinish=null,this._finishHandlers=[],this._effect=b,this._inEffect=this._effect._update(0),this._idle=!0,this._currentTimePending=!1},b.Animation.prototype={_ensureAlive:function(){this.playbackRate<0&&0===this.currentTime?this._inEffect=this._effect._update(-1):this._inEffect=this._effect._update(this.currentTime),this._inTimeline||!this._inEffect&&this._finishedFlag||(this._inTimeline=!0,b.timeline._animations.push(this))},_tickCurrentTime:function(a,b){a!=this._currentTime&&(this._currentTime=a,this._isFinished&&!b&&(this._currentTime=this._playbackRate>0?this._totalDuration:0),this._ensureAlive())},get currentTime(){return this._idle||this._currentTimePending?null:this._currentTime},set currentTime(a){a=+a,isNaN(a)||(b.restart(),this._paused||null==this._startTime||(this._startTime=this._timeline.currentTime-a/this._playbackRate),this._currentTimePending=!1,this._currentTime!=a&&(this._tickCurrentTime(a,!0),b.invalidateEffects()))},get startTime(){return this._startTime},set startTime(a){a=+a,isNaN(a)||this._paused||this._idle||(this._startTime=a,this._tickCurrentTime((this._timeline.currentTime-this._startTime)*this.playbackRate),b.invalidateEffects())},get playbackRate(){return this._playbackRate},set playbackRate(a){if(a!=this._playbackRate){var b=this.currentTime;this._playbackRate=a,this._startTime=null,"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!=b&&(this.currentTime=b)}},get _isFinished(){return!this._idle&&(this._playbackRate>0&&this._currentTime>=this._totalDuration||this._playbackRate<0&&this._currentTime<=0)},get _totalDuration(){return this._effect._totalDuration},get playState(){return this._idle?"idle":null==this._startTime&&!this._paused&&0!=this.playbackRate||this._currentTimePending?"pending":this._paused?"paused":this._isFinished?"finished":"running"},play:function(){this._paused=!1,(this._isFinished||this._idle)&&(this._currentTime=this._playbackRate>0?0:this._totalDuration,this._startTime=null),this._finishedFlag=!1,this._idle=!1,this._ensureAlive(),b.invalidateEffects()},pause:function(){this._isFinished||this._paused||this._idle||(this._currentTimePending=!0),this._startTime=null,this._paused=!0},finish:function(){this._idle||(this.currentTime=this._playbackRate>0?this._totalDuration:0,this._startTime=this._totalDuration-this.currentTime,this._currentTimePending=!1,b.invalidateEffects())},cancel:function(){this._inEffect&&(this._inEffect=!1,this._idle=!0,this._finishedFlag=!0,this.currentTime=0,this._startTime=null,this._effect._update(null),b.invalidateEffects())},reverse:function(){this.playbackRate*=-1,this.play()},addEventListener:function(a,b){"function"==typeof b&&"finish"==a&&this._finishHandlers.push(b)},removeEventListener:function(a,b){if("finish"==a){var c=this._finishHandlers.indexOf(b);c>=0&&this._finishHandlers.splice(c,1)}},_fireEvents:function(a){if(this._isFinished){if(!this._finishedFlag){var b=new d(this,this._currentTime,a),c=this._finishHandlers.concat(this.onfinish?[this.onfinish]:[]);setTimeout(function(){c.forEach(function(a){a.call(b.target,b)})},0),this._finishedFlag=!0}}else this._finishedFlag=!1},_tick:function(a,b){this._idle||this._paused||(null==this._startTime?b&&(this.startTime=a-this._currentTime/this.playbackRate):this._isFinished||this._tickCurrentTime((a-this._startTime)*this.playbackRate)),b&&(this._currentTimePending=!1,this._fireEvents(a))},get _needsTick(){return this.playState in{pending:1,running:1}||!this._finishedFlag}}}(c,d,f),function(a,b,c){function d(a){var b=j;j=[],a<p.currentTime&&(a=p.currentTime),h(a,!0),b.forEach(function(b){b[1](a)}),g(),l=void 0}function e(a,b){return a._sequenceNumber-b._sequenceNumber}function f(){this._animations=[],this.currentTime=window.performance&&performance.now?performance.now():0}function g(){o.forEach(function(a){a()}),o.length=0}function h(a,c){n=!1;var d=b.timeline;d.currentTime=a,d._animations.sort(e),m=!1;var f=d._animations;d._animations=[];var g=[],h=[];f=f.filter(function(b){b._tick(a,c),b._inEffect?h.push(b._effect):g.push(b._effect),b._needsTick&&(m=!0);var d=b._inEffect||b._needsTick;return b._inTimeline=d,d}),o.push.apply(o,g),o.push.apply(o,h),d._animations.push.apply(d._animations,f),m&&requestAnimationFrame(function(){})}var i=window.requestAnimationFrame,j=[],k=0;window.requestAnimationFrame=function(a){var b=k++;return 0==j.length&&i(d),j.push([b,a]),b},window.cancelAnimationFrame=function(a){j.forEach(function(b){b[0]==a&&(b[1]=function(){})})},f.prototype={_play:function(c){c._timing=a.normalizeTimingInput(c.timing);var d=new b.Animation(c);return d._idle=!1,d._timeline=this,this._animations.push(d),b.restart(),b.invalidateEffects(),d}};var l=void 0,m=!1,n=!1;b.restart=function(){return m||(m=!0,requestAnimationFrame(function(){}),n=!0),n},b.invalidateEffects=function(){h(b.timeline.currentTime,!1),g()};var o=[],p=new f;b.timeline=p}(c,d,f),function(a,b){function c(a,b){for(var c=0,d=0;d<a.length;d++)c+=a[d]*b[d];return c}function d(a,b){return[a[0]*b[0]+a[4]*b[1]+a[8]*b[2]+a[12]*b[3],a[1]*b[0]+a[5]*b[1]+a[9]*b[2]+a[13]*b[3],a[2]*b[0]+a[6]*b[1]+a[10]*b[2]+a[14]*b[3],a[3]*b[0]+a[7]*b[1]+a[11]*b[2]+a[15]*b[3],a[0]*b[4]+a[4]*b[5]+a[8]*b[6]+a[12]*b[7],a[1]*b[4]+a[5]*b[5]+a[9]*b[6]+a[13]*b[7],a[2]*b[4]+a[6]*b[5]+a[10]*b[6]+a[14]*b[7],a[3]*b[4]+a[7]*b[5]+a[11]*b[6]+a[15]*b[7],a[0]*b[8]+a[4]*b[9]+a[8]*b[10]+a[12]*b[11],a[1]*b[8]+a[5]*b[9]+a[9]*b[10]+a[13]*b[11],a[2]*b[8]+a[6]*b[9]+a[10]*b[10]+a[14]*b[11],a[3]*b[8]+a[7]*b[9]+a[11]*b[10]+a[15]*b[11],a[0]*b[12]+a[4]*b[13]+a[8]*b[14]+a[12]*b[15],a[1]*b[12]+a[5]*b[13]+a[9]*b[14]+a[13]*b[15],a[2]*b[12]+a[6]*b[13]+a[10]*b[14]+a[14]*b[15],a[3]*b[12]+a[7]*b[13]+a[11]*b[14]+a[15]*b[15]]}function e(a){var b=a.rad||0,c=a.deg||0,d=a.grad||0,e=a.turn||0,f=(c/360+d/400+e)*(2*Math.PI)+b;return f}function f(a){switch(a.t){case"rotatex":var b=e(a.d[0]);return[1,0,0,0,0,Math.cos(b),Math.sin(b),0,0,-Math.sin(b),Math.cos(b),0,0,0,0,1];case"rotatey":var b=e(a.d[0]);return[Math.cos(b),0,-Math.sin(b),0,0,1,0,0,Math.sin(b),0,Math.cos(b),0,0,0,0,1];case"rotate":case"rotatez":var b=e(a.d[0]);return[Math.cos(b),Math.sin(b),0,0,-Math.sin(b),Math.cos(b),0,0,0,0,1,0,0,0,0,1];case"rotate3d":var c=a.d[0],d=a.d[1],f=a.d[2],b=e(a.d[3]),g=c*c+d*d+f*f;if(0===g)c=1,d=0,f=0;else if(1!==g){var h=Math.sqrt(g);c/=h,d/=h,f/=h}var i=Math.sin(b/2),j=i*Math.cos(b/2),k=i*i;return[1-2*(d*d+f*f)*k,2*(c*d*k+f*j),2*(c*f*k-d*j),0,2*(c*d*k-f*j),1-2*(c*c+f*f)*k,2*(d*f*k+c*j),0,2*(c*f*k+d*j),2*(d*f*k-c*j),1-2*(c*c+d*d)*k,0,0,0,0,1];case"scale":return[a.d[0],0,0,0,0,a.d[1],0,0,0,0,1,0,0,0,0,1];case"scalex":return[a.d[0],0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];case"scaley":return[1,0,0,0,0,a.d[0],0,0,0,0,1,0,0,0,0,1];case"scalez":return[1,0,0,0,0,1,0,0,0,0,a.d[0],0,0,0,0,1];case"scale3d":return[a.d[0],0,0,0,0,a.d[1],0,0,0,0,a.d[2],0,0,0,0,1];case"skew":var l=e(a.d[0]),m=e(a.d[1]);return[1,Math.tan(m),0,0,Math.tan(l),1,0,0,0,0,1,0,0,0,0,1];case"skewx":var b=e(a.d[0]);return[1,0,0,0,Math.tan(b),1,0,0,0,0,1,0,0,0,0,1];case"skewy":var b=e(a.d[0]);return[1,Math.tan(b),0,0,0,1,0,0,0,0,1,0,0,0,0,1];case"translate":var c=a.d[0].px||0,d=a.d[1].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,d,0,1];case"translatex":var c=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,0,0,1];case"translatey":var d=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,0,d,0,1];case"translatez":var f=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,0,0,f,1];case"translate3d":var c=a.d[0].px||0,d=a.d[1].px||0,f=a.d[2].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,d,f,1];case"perspective":var n=a.d[0].px?-1/a.d[0].px:0;return[1,0,0,0,0,1,0,0,0,0,1,n,0,0,0,1];case"matrix":return[a.d[0],a.d[1],0,0,a.d[2],a.d[3],0,0,0,0,1,0,a.d[4],a.d[5],0,1];case"matrix3d":return a.d}}function g(a){return 0===a.length?[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]:a.map(f).reduce(d)}function h(a){return[i(g(a))]}var i=function(){function a(a){return a[0][0]*a[1][1]*a[2][2]+a[1][0]*a[2][1]*a[0][2]+a[2][0]*a[0][1]*a[1][2]-a[0][2]*a[1][1]*a[2][0]-a[1][2]*a[2][1]*a[0][0]-a[2][2]*a[0][1]*a[1][0]}function b(b){for(var c=1/a(b),d=b[0][0],e=b[0][1],f=b[0][2],g=b[1][0],h=b[1][1],i=b[1][2],j=b[2][0],k=b[2][1],l=b[2][2],m=[[(h*l-i*k)*c,(f*k-e*l)*c,(e*i-f*h)*c,0],[(i*j-g*l)*c,(d*l-f*j)*c,(f*g-d*i)*c,0],[(g*k-h*j)*c,(j*e-d*k)*c,(d*h-e*g)*c,0]],n=[],o=0;3>o;o++){for(var p=0,q=0;3>q;q++)p+=b[3][q]*m[q][o];n.push(p)}return n.push(1),m.push(n),m}function d(a){return[[a[0][0],a[1][0],a[2][0],a[3][0]],[a[0][1],a[1][1],a[2][1],a[3][1]],[a[0][2],a[1][2],a[2][2],a[3][2]],[a[0][3],a[1][3],a[2][3],a[3][3]]]}function e(a,b){for(var c=[],d=0;4>d;d++){for(var e=0,f=0;4>f;f++)e+=a[f]*b[f][d];c.push(e)}return c}function f(a){var b=g(a);return[a[0]/b,a[1]/b,a[2]/b]}function g(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])}function h(a,b,c,d){return[c*a[0]+d*b[0],c*a[1]+d*b[1],c*a[2]+d*b[2]]}function i(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]}function j(j){var k=[j.slice(0,4),j.slice(4,8),j.slice(8,12),j.slice(12,16)];if(1!==k[3][3])return null;for(var l=[],m=0;4>m;m++)l.push(k[m].slice());for(var m=0;3>m;m++)l[m][3]=0;if(0===a(l))return!1;var n,o=[];if(k[0][3]||k[1][3]||k[2][3]){o.push(k[0][3]),o.push(k[1][3]),o.push(k[2][3]),o.push(k[3][3]);var p=b(l),q=d(p);n=e(o,q)}else n=[0,0,0,1];var r=k[3].slice(0,3),s=[];s.push(k[0].slice(0,3));var t=[];t.push(g(s[0])),s[0]=f(s[0]);var u=[];s.push(k[1].slice(0,3)),u.push(c(s[0],s[1])),s[1]=h(s[1],s[0],1,-u[0]),t.push(g(s[1])),s[1]=f(s[1]),u[0]/=t[1],s.push(k[2].slice(0,3)),u.push(c(s[0],s[2])),s[2]=h(s[2],s[0],1,-u[1]),u.push(c(s[1],s[2])),s[2]=h(s[2],s[1],1,-u[2]),t.push(g(s[2])),s[2]=f(s[2]),u[1]/=t[2],u[2]/=t[2];var v=i(s[1],s[2]);if(c(s[0],v)<0)for(var m=0;3>m;m++)t[m]*=-1,s[m][0]*=-1,s[m][1]*=-1,s[m][2]*=-1;var w,x,y=s[0][0]+s[1][1]+s[2][2]+1;return y>1e-4?(w=.5/Math.sqrt(y),x=[(s[2][1]-s[1][2])*w,(s[0][2]-s[2][0])*w,(s[1][0]-s[0][1])*w,.25/w]):s[0][0]>s[1][1]&&s[0][0]>s[2][2]?(w=2*Math.sqrt(1+s[0][0]-s[1][1]-s[2][2]),x=[.25*w,(s[0][1]+s[1][0])/w,(s[0][2]+s[2][0])/w,(s[2][1]-s[1][2])/w]):s[1][1]>s[2][2]?(w=2*Math.sqrt(1+s[1][1]-s[0][0]-s[2][2]),x=[(s[0][1]+s[1][0])/w,.25*w,(s[1][2]+s[2][1])/w,(s[0][2]-s[2][0])/w]):(w=2*Math.sqrt(1+s[2][2]-s[0][0]-s[1][1]),x=[(s[0][2]+s[2][0])/w,(s[1][2]+s[2][1])/w,.25*w,(s[1][0]-s[0][1])/w]),[r,t,u,x,n]}return j}();a.dot=c,a.makeMatrixDecomposition=h}(d,f),function(a){function b(a,b){var c=a.exec(b);return c?(c=a.ignoreCase?c[0].toLowerCase():c[0],[c,b.substr(c.length)]):void 0}function c(a,b){b=b.replace(/^\s*/,"");var c=a(b);return c?[c[0],c[1].replace(/^\s*/,"")]:void 0}function d(a,d,e){a=c.bind(null,a);for(var f=[];;){var g=a(e);if(!g)return[f,e];if(f.push(g[0]),e=g[1],g=b(d,e),!g||""==g[1])return[f,e];e=g[1]}}function e(a,b){for(var c=0,d=0;d<b.length&&(!/\s|,/.test(b[d])||0!=c);d++)if("("==b[d])c++;else if(")"==b[d]&&(c--,0==c&&d++,0>=c))break;var e=a(b.substr(0,d));return void 0==e?void 0:[e,b.substr(d)]}function f(a,b){for(var c=a,d=b;c&&d;)c>d?c%=d:d%=c;return c=a*b/(c+d)}function g(a){return function(b){var c=a(b);return c&&(c[0]=void 0),c}}function h(a,b){return function(c){var d=a(c);return d?d:[b,c]}}function i(b,c){for(var d=[],e=0;e<b.length;e++){var f=a.consumeTrimmed(b[e],c);if(!f||""==f[0])return;void 0!==f[0]&&d.push(f[0]),c=f[1]}return""==c?d:void 0}function j(a,b,c,d,e){for(var g=[],h=[],i=[],j=f(d.length,e.length),k=0;j>k;k++){var l=b(d[k%d.length],e[k%e.length]);if(!l)return;g.push(l[0]),h.push(l[1]),i.push(l[2])}return[g,h,function(b){var d=b.map(function(a,b){return i[b](a)}).join(c);return a?a(d):d}]}function k(a,b,c){for(var d=[],e=[],f=[],g=0,h=0;h<c.length;h++)if("function"==typeof c[h]){var i=c[h](a[g],b[g++]);d.push(i[0]),e.push(i[1]),f.push(i[2])}else!function(a){d.push(!1),e.push(!1),f.push(function(){return c[a]})}(h);return[d,e,function(a){for(var b="",c=0;c<a.length;c++)b+=f[c](a[c]);return b}]}a.consumeToken=b,a.consumeTrimmed=c,a.consumeRepeated=d,a.consumeParenthesised=e,a.ignore=g,a.optional=h,a.consumeList=i,a.mergeNestedRepeated=j.bind(null,null),a.mergeWrappedNestedRepeated=j,a.mergeList=k}(d),function(a){function b(b){function c(b){var c=a.consumeToken(/^inset/i,b);if(c)return d.inset=!0,c;var c=a.consumeLengthOrPercent(b);if(c)return d.lengths.push(c[0]),c;var c=a.consumeColor(b);return c?(d.color=c[0],c):void 0}var d={inset:!1,lengths:[],color:null},e=a.consumeRepeated(c,/^/,b);return e&&e[0].length?[d,e[1]]:void 0}function c(c){var d=a.consumeRepeated(b,/^,/,c);return d&&""==d[1]?d[0]:void 0}function d(b,c){for(;b.lengths.length<Math.max(b.lengths.length,c.lengths.length);)b.lengths.push({px:0});for(;c.lengths.length<Math.max(b.lengths.length,c.lengths.length);)c.lengths.push({px:0});if(b.inset==c.inset&&!!b.color==!!c.color){for(var d,e=[],f=[[],0],g=[[],0],h=0;h<b.lengths.length;h++){var i=a.mergeDimensions(b.lengths[h],c.lengths[h],2==h);f[0].push(i[0]),g[0].push(i[1]),e.push(i[2])}if(b.color&&c.color){var j=a.mergeColors(b.color,c.color);f[1]=j[0],g[1]=j[1],d=j[2]}return[f,g,function(a){for(var c=b.inset?"inset ":" ",f=0;f<e.length;f++)c+=e[f](a[0][f])+" ";return d&&(c+=d(a[1])),c}]}}function e(b,c,d,e){function f(a){return{inset:a,color:[0,0,0,0],lengths:[{px:0},{px:0},{px:0},{px:0}]}}for(var g=[],h=[],i=0;i<d.length||i<e.length;i++){var j=d[i]||f(e[i].inset),k=e[i]||f(d[i].inset);g.push(j),h.push(k)}return a.mergeNestedRepeated(b,c,g,h)}var f=e.bind(null,d,", ");a.addPropertiesHandler(c,f,["box-shadow","text-shadow"])}(d),function(a,b){function c(a){return a.toFixed(3).replace(".000","")}function d(a,b,c){return Math.min(b,Math.max(a,c))}function e(a){return/^\s*[-+]?(\d*\.)?\d+\s*$/.test(a)?Number(a):void 0}function f(a,b){return[a,b,c]}function g(a,b){return 0!=a?i(0,1/0)(a,b):void 0}function h(a,b){return[a,b,function(a){return Math.round(d(1,1/0,a))}]}function i(a,b){return function(e,f){return[e,f,function(e){return c(d(a,b,e))}]}}function j(a,b){return[a,b,Math.round]}a.clamp=d,a.addPropertiesHandler(e,i(0,1/0),["border-image-width","line-height"]),a.addPropertiesHandler(e,i(0,1),["opacity","shape-image-threshold"]),a.addPropertiesHandler(e,g,["flex-grow","flex-shrink"]),a.addPropertiesHandler(e,h,["orphans","widows"]),a.addPropertiesHandler(e,j,["z-index"]),a.parseNumber=e,a.mergeNumbers=f,a.numberToString=c}(d,f),function(a,b){function c(a,b){return"visible"==a||"visible"==b?[0,1,function(c){return 0>=c?a:c>=1?b:"visible"}]:void 0}a.addPropertiesHandler(String,c,["visibility"])}(d),function(a,b){function c(a){a=a.trim(),f.fillStyle="#000",
+f.fillStyle=a;var b=f.fillStyle;if(f.fillStyle="#fff",f.fillStyle=a,b==f.fillStyle){f.fillRect(0,0,1,1);var c=f.getImageData(0,0,1,1).data;f.clearRect(0,0,1,1);var d=c[3]/255;return[c[0]*d,c[1]*d,c[2]*d,d]}}function d(b,c){return[b,c,function(b){function c(a){return Math.max(0,Math.min(255,a))}if(b[3])for(var d=0;3>d;d++)b[d]=Math.round(c(b[d]/b[3]));return b[3]=a.numberToString(a.clamp(0,1,b[3])),"rgba("+b.join(",")+")"}]}var e=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");e.width=e.height=1;var f=e.getContext("2d");a.addPropertiesHandler(c,d,["background-color","border-bottom-color","border-left-color","border-right-color","border-top-color","color","outline-color","text-decoration-color"]),a.consumeColor=a.consumeParenthesised.bind(null,c),a.mergeColors=d}(d,f),function(a,b){function c(a,b){if(b=b.trim().toLowerCase(),"0"==b&&"px".search(a)>=0)return{px:0};if(/^[^(]*$|^calc/.test(b)){b=b.replace(/calc\(/g,"(");var c={};b=b.replace(a,function(a){return c[a]=null,"U"+a});for(var d="U("+a.source+")",e=b.replace(/[-+]?(\d*\.)?\d+/g,"N").replace(new RegExp("N"+d,"g"),"D").replace(/\s[+-]\s/g,"O").replace(/\s/g,""),f=[/N\*(D)/g,/(N|D)[*\/]N/g,/(N|D)O\1/g,/\((N|D)\)/g],g=0;g<f.length;)f[g].test(e)?(e=e.replace(f[g],"$1"),g=0):g++;if("D"==e){for(var h in c){var i=eval(b.replace(new RegExp("U"+h,"g"),"").replace(new RegExp(d,"g"),"*0"));if(!isFinite(i))return;c[h]=i}return c}}}function d(a,b){return e(a,b,!0)}function e(b,c,d){var e,f=[];for(e in b)f.push(e);for(e in c)f.indexOf(e)<0&&f.push(e);return b=f.map(function(a){return b[a]||0}),c=f.map(function(a){return c[a]||0}),[b,c,function(b){var c=b.map(function(c,e){return 1==b.length&&d&&(c=Math.max(c,0)),a.numberToString(c)+f[e]}).join(" + ");return b.length>1?"calc("+c+")":c}]}var f="px|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc",g=c.bind(null,new RegExp(f,"g")),h=c.bind(null,new RegExp(f+"|%","g")),i=c.bind(null,/deg|rad|grad|turn/g);a.parseLength=g,a.parseLengthOrPercent=h,a.consumeLengthOrPercent=a.consumeParenthesised.bind(null,h),a.parseAngle=i,a.mergeDimensions=e;var j=a.consumeParenthesised.bind(null,g),k=a.consumeRepeated.bind(void 0,j,/^/),l=a.consumeRepeated.bind(void 0,k,/^,/);a.consumeSizePairList=l;var m=function(a){var b=l(a);return b&&""==b[1]?b[0]:void 0},n=a.mergeNestedRepeated.bind(void 0,d," "),o=a.mergeNestedRepeated.bind(void 0,n,",");a.mergeNonNegativeSizePair=n,a.addPropertiesHandler(m,o,["background-size"]),a.addPropertiesHandler(h,d,["border-bottom-width","border-image-width","border-left-width","border-right-width","border-top-width","flex-basis","font-size","height","line-height","max-height","max-width","outline-width","width"]),a.addPropertiesHandler(h,e,["border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","bottom","left","letter-spacing","margin-bottom","margin-left","margin-right","margin-top","min-height","min-width","outline-offset","padding-bottom","padding-left","padding-right","padding-top","perspective","right","shape-margin","text-indent","top","vertical-align","word-spacing"])}(d,f),function(a,b){function c(b){return a.consumeLengthOrPercent(b)||a.consumeToken(/^auto/,b)}function d(b){var d=a.consumeList([a.ignore(a.consumeToken.bind(null,/^rect/)),a.ignore(a.consumeToken.bind(null,/^\(/)),a.consumeRepeated.bind(null,c,/^,/),a.ignore(a.consumeToken.bind(null,/^\)/))],b);return d&&4==d[0].length?d[0]:void 0}function e(b,c){return"auto"==b||"auto"==c?[!0,!1,function(d){var e=d?b:c;if("auto"==e)return"auto";var f=a.mergeDimensions(e,e);return f[2](f[0])}]:a.mergeDimensions(b,c)}function f(a){return"rect("+a+")"}var g=a.mergeWrappedNestedRepeated.bind(null,f,e,", ");a.parseBox=d,a.mergeBoxes=g,a.addPropertiesHandler(d,g,["clip"])}(d,f),function(a,b){function c(a){return function(b){var c=0;return a.map(function(a){return a===k?b[c++]:a})}}function d(a){return a}function e(b){if(b=b.toLowerCase().trim(),"none"==b)return[];for(var c,d=/\s*(\w+)\(([^)]*)\)/g,e=[],f=0;c=d.exec(b);){if(c.index!=f)return;f=c.index+c[0].length;var g=c[1],h=n[g];if(!h)return;var i=c[2].split(","),j=h[0];if(j.length<i.length)return;for(var k=[],o=0;o<j.length;o++){var p,q=i[o],r=j[o];if(p=q?{A:function(b){return"0"==b.trim()?m:a.parseAngle(b)},N:a.parseNumber,T:a.parseLengthOrPercent,L:a.parseLength}[r.toUpperCase()](q):{a:m,n:k[0],t:l}[r],void 0===p)return;k.push(p)}if(e.push({t:g,d:k}),d.lastIndex==b.length)return e}}function f(a){return a.toFixed(6).replace(".000000","")}function g(b,c){if(b.decompositionPair!==c){b.decompositionPair=c;var d=a.makeMatrixDecomposition(b)}if(c.decompositionPair!==b){c.decompositionPair=b;var e=a.makeMatrixDecomposition(c)}return null==d[0]||null==e[0]?[[!1],[!0],function(a){return a?c[0].d:b[0].d}]:(d[0].push(0),e[0].push(1),[d,e,function(b){var c=a.quat(d[0][3],e[0][3],b[5]),g=a.composeMatrix(b[0],b[1],b[2],c,b[4]),h=g.map(f).join(",");return h}])}function h(a){return a.replace(/[xy]/,"")}function i(a){return a.replace(/(x|y|z|3d)?$/,"3d")}function j(b,c){var d=a.makeMatrixDecomposition&&!0,e=!1;if(!b.length||!c.length){b.length||(e=!0,b=c,c=[]);for(var f=0;f<b.length;f++){var j=b[f].t,k=b[f].d,l="scale"==j.substr(0,5)?1:0;c.push({t:j,d:k.map(function(a){if("number"==typeof a)return l;var b={};for(var c in a)b[c]=l;return b})})}}var m=function(a,b){return"perspective"==a&&"perspective"==b||("matrix"==a||"matrix3d"==a)&&("matrix"==b||"matrix3d"==b)},o=[],p=[],q=[];if(b.length!=c.length){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]]}else for(var f=0;f<b.length;f++){var j,s=b[f].t,t=c[f].t,u=b[f].d,v=c[f].d,w=n[s],x=n[t];if(m(s,t)){if(!d)return;var r=g([b[f]],[c[f]]);o.push(r[0]),p.push(r[1]),q.push(["matrix",[r[2]]])}else{if(s==t)j=s;else if(w[2]&&x[2]&&h(s)==h(t))j=h(s),u=w[2](u),v=x[2](v);else{if(!w[1]||!x[1]||i(s)!=i(t)){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]];break}j=i(s),u=w[1](u),v=x[1](v)}for(var y=[],z=[],A=[],B=0;B<u.length;B++){var C="number"==typeof u[B]?a.mergeNumbers:a.mergeDimensions,r=C(u[B],v[B]);y[B]=r[0],z[B]=r[1],A.push(r[2])}o.push(y),p.push(z),q.push([j,A])}}if(e){var D=o;o=p,p=D}return[o,p,function(a){return a.map(function(a,b){var c=a.map(function(a,c){return q[b][1][c](a)}).join(",");return"matrix"==q[b][0]&&16==c.split(",").length&&(q[b][0]="matrix3d"),q[b][0]+"("+c+")"}).join(" ")}]}var k=null,l={px:0},m={deg:0},n={matrix:["NNNNNN",[k,k,0,0,k,k,0,0,0,0,1,0,k,k,0,1],d],matrix3d:["NNNNNNNNNNNNNNNN",d],rotate:["A"],rotatex:["A"],rotatey:["A"],rotatez:["A"],rotate3d:["NNNA"],perspective:["L"],scale:["Nn",c([k,k,1]),d],scalex:["N",c([k,1,1]),c([k,1])],scaley:["N",c([1,k,1]),c([1,k])],scalez:["N",c([1,1,k])],scale3d:["NNN",d],skew:["Aa",null,d],skewx:["A",null,c([k,m])],skewy:["A",null,c([m,k])],translate:["Tt",c([k,k,l]),d],translatex:["T",c([k,l,l]),c([k,l])],translatey:["T",c([l,k,l]),c([l,k])],translatez:["L",c([l,l,k])],translate3d:["TTL",d]};a.addPropertiesHandler(e,j,["transform"])}(d,f),function(a){function b(a){var b=Number(a);return isNaN(b)||100>b||b>900||b%100!==0?void 0:b}function c(b){return b=100*Math.round(b/100),b=a.clamp(100,900,b),400===b?"normal":700===b?"bold":String(b)}function d(a,b){return[a,b,c]}a.addPropertiesHandler(b,d,["font-weight"])}(d),function(a){function b(a){var b={};for(var c in a)b[c]=-a[c];return b}function c(b){return a.consumeToken(/^(left|center|right|top|bottom)\b/i,b)||a.consumeLengthOrPercent(b)}function d(b,d){var e=a.consumeRepeated(c,/^/,d);if(e&&""==e[1]){var f=e[0];if(f[0]=f[0]||"center",f[1]=f[1]||"center",3==b&&(f[2]=f[2]||{px:0}),f.length==b){if(/top|bottom/.test(f[0])||/left|right/.test(f[1])){var h=f[0];f[0]=f[1],f[1]=h}if(/left|right|center|Object/.test(f[0])&&/top|bottom|center|Object/.test(f[1]))return f.map(function(a){return"object"==typeof a?a:g[a]})}}}function e(d){var e=a.consumeRepeated(c,/^/,d);if(e){for(var f=e[0],h=[{"%":50},{"%":50}],i=0,j=!1,k=0;k<f.length;k++){var l=f[k];"string"==typeof l?(j=/bottom|right/.test(l),i={left:0,right:0,center:i,top:1,bottom:1}[l],h[i]=g[l],"center"==l&&i++):(j&&(l=b(l),l["%"]=(l["%"]||0)+100),h[i]=l,i++,j=!1)}return[h,e[1]]}}function f(b){var c=a.consumeRepeated(e,/^,/,b);return c&&""==c[1]?c[0]:void 0}var g={left:{"%":0},center:{"%":50},right:{"%":100},top:{"%":0},bottom:{"%":100}},h=a.mergeNestedRepeated.bind(null,a.mergeDimensions," ");a.addPropertiesHandler(d.bind(null,3),h,["transform-origin"]),a.addPropertiesHandler(d.bind(null,2),h,["perspective-origin"]),a.consumePosition=e,a.mergeOffsetList=h;var i=a.mergeNestedRepeated.bind(null,h,", ");a.addPropertiesHandler(f,i,["background-position","object-position"])}(d),function(a){function b(b){var c=a.consumeToken(/^circle/,b);if(c&&c[0])return["circle"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),d,a.ignore(a.consumeToken.bind(void 0,/^at/)),a.consumePosition,a.ignore(a.consumeToken.bind(void 0,/^\)/))],c[1]));var f=a.consumeToken(/^ellipse/,b);if(f&&f[0])return["ellipse"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),e,a.ignore(a.consumeToken.bind(void 0,/^at/)),a.consumePosition,a.ignore(a.consumeToken.bind(void 0,/^\)/))],f[1]));var g=a.consumeToken(/^polygon/,b);return g&&g[0]?["polygon"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),a.optional(a.consumeToken.bind(void 0,/^nonzero\s*,|^evenodd\s*,/),"nonzero,"),a.consumeSizePairList,a.ignore(a.consumeToken.bind(void 0,/^\)/))],g[1])):void 0}function c(b,c){return b[0]===c[0]?"circle"==b[0]?a.mergeList(b.slice(1),c.slice(1),["circle(",a.mergeDimensions," at ",a.mergeOffsetList,")"]):"ellipse"==b[0]?a.mergeList(b.slice(1),c.slice(1),["ellipse(",a.mergeNonNegativeSizePair," at ",a.mergeOffsetList,")"]):"polygon"==b[0]&&b[1]==c[1]?a.mergeList(b.slice(2),c.slice(2),["polygon(",b[1],g,")"]):void 0:void 0}var d=a.consumeParenthesised.bind(null,a.parseLengthOrPercent),e=a.consumeRepeated.bind(void 0,d,/^/),f=a.mergeNestedRepeated.bind(void 0,a.mergeDimensions," "),g=a.mergeNestedRepeated.bind(void 0,f,",");a.addPropertiesHandler(b,c,["shape-outside"])}(d),function(a,b){function c(a,b){b.concat([a]).forEach(function(b){b in document.documentElement.style&&(d[a]=b)})}var d={};c("transform",["webkitTransform","msTransform"]),c("transformOrigin",["webkitTransformOrigin"]),c("perspective",["webkitPerspective"]),c("perspectiveOrigin",["webkitPerspectiveOrigin"]),a.propertyName=function(a){return d[a]||a}}(d,f)}(),!function(){if(void 0===document.createElement("div").animate([]).oncancel){var a;if(window.performance&&performance.now)var a=function(){return performance.now()};else var a=function(){return Date.now()};var b=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},c=window.Element.prototype.animate;window.Element.prototype.animate=function(d,e){var f=c.call(this,d,e);f._cancelHandlers=[],f.oncancel=null;var g=f.cancel;f.cancel=function(){g.call(this);var c=new b(this,null,a()),d=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){d.forEach(function(a){a.call(c.target,c)})},0)};var h=f.addEventListener;f.addEventListener=function(a,b){"function"==typeof b&&"cancel"==a?this._cancelHandlers.push(b):h.call(this,a,b)};var i=f.removeEventListener;return f.removeEventListener=function(a,b){if("cancel"==a){var c=this._cancelHandlers.indexOf(b);c>=0&&this._cancelHandlers.splice(c,1)}else i.call(this,a,b)},f}}}(),function(a){var b=document.documentElement,c=null,d=!1;try{var e=getComputedStyle(b).getPropertyValue("opacity"),f="0"==e?"1":"0";c=b.animate({opacity:[f,f]},{duration:1}),c.currentTime=0,d=getComputedStyle(b).getPropertyValue("opacity")==f}catch(g){}finally{c&&c.cancel()}if(!d){var h=window.Element.prototype.animate;window.Element.prototype.animate=function(b,c){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&b[Symbol.iterator]&&(b=Array.from(b)),Array.isArray(b)||null===b||(b=a.convertToArrayForm(b)),h.call(this,b,c)}}}(c),!function(a,b,c){function d(a){var b=window.document.timeline;b.currentTime=a,b._discardAnimations(),0==b._animations.length?f=!1:requestAnimationFrame(d)}var e=window.requestAnimationFrame;window.requestAnimationFrame=function(a){return e(function(b){window.document.timeline._updateAnimationsPromises(),a(b),window.document.timeline._updateAnimationsPromises()})},b.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},b.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){b.animationsWithPromises=b.animationsWithPromises.filter(function(a){return a._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(a){return"finished"!=a.playState&&"idle"!=a.playState})},_play:function(a){var c=new b.Animation(a,this);return this._animations.push(c),b.restartWebAnimationsNextTick(),c._updatePromises(),c._animation.play(),c._updatePromises(),c},play:function(a){return a&&a.remove(),this._play(a)}};var f=!1;b.restartWebAnimationsNextTick=function(){f||(f=!0,requestAnimationFrame(d))};var g=new b.AnimationTimeline;b.timeline=g;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return g}})}catch(h){}try{window.document.timeline=g}catch(h){}}(c,e,f),function(a,b,c){b.animationsWithPromises=[],b.Animation=function(b,c){if(this.id="",b&&b._id&&(this.id=b._id),this.effect=b,b&&(b._animation=this),!c)throw new Error("Animation with null timeline is not supported");this._timeline=c,this._sequenceNumber=a.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},b.Animation.prototype={_updatePromises:function(){var a=this._oldPlayState,b=this.playState;return this._readyPromise&&b!==a&&("idle"==b?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==a?this._resolveReadyPromise():"pending"==b&&(this._readyPromise=void 0)),this._finishedPromise&&b!==a&&("idle"==b?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==b?this._resolveFinishedPromise():"finished"==a&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var a,c,d,e,f=!!this._animation;f&&(a=this.playbackRate,c=this._paused,d=this.startTime,e=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=b.newUnderlyingAnimationForKeyframeEffect(this.effect),b.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=b.newUnderlyingAnimationForGroup(this.effect),b.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&b.bindAnimationForCustomEffect(this),f&&(1!=a&&(this.playbackRate=a),null!==d?this.startTime=d:null!==e?this.currentTime=e:null!==this._holdTime&&(this.currentTime=this._holdTime),c&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var a=this.effect._timing.delay;this._childAnimations.forEach(function(c){this._arrangeChildren(c,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c.effect))}.bind(this))}},_setExternalAnimation:function(a){if(this.effect&&this._isGroup)for(var b=0;b<this.effect.children.length;b++)this.effect.children[b]._animation=a,this._childAnimations[b]._setExternalAnimation(a)},_constructChildAnimations:function(){if(this.effect&&this._isGroup){var a=this.effect._timing.delay;this._removeChildAnimations(),this.effect.children.forEach(function(c){var d=window.document.timeline._play(c);this._childAnimations.push(d),d.playbackRate=this.playbackRate,this._paused&&d.pause(),c._animation=this.effect._animation,this._arrangeChildren(d,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c))}.bind(this))}},_arrangeChildren:function(a,b){null===this.startTime?a.currentTime=this.currentTime-b/this.playbackRate:a.startTime!==this.startTime+b/this.playbackRate&&(a.startTime=this.startTime+b/this.playbackRate)},get timeline(){return this._timeline},get playState(){return this._animation?this._animation.playState:"idle"},get finished(){return window.Promise?(this._finishedPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._finishedPromise=new Promise(function(a,b){this._resolveFinishedPromise=function(){a(this)},this._rejectFinishedPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"finished"==this.playState&&this._resolveFinishedPromise()),this._finishedPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get ready(){return window.Promise?(this._readyPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._readyPromise=new Promise(function(a,b){this._resolveReadyPromise=function(){a(this)},this._rejectReadyPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"pending"!==this.playState&&this._resolveReadyPromise()),this._readyPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get onfinish(){return this._animation.onfinish},set onfinish(a){"function"==typeof a?this._animation.onfinish=function(b){b.target=this,a.call(this,b)}.bind(this):this._animation.onfinish=a},get oncancel(){return this._animation.oncancel},set oncancel(a){"function"==typeof a?this._animation.oncancel=function(b){b.target=this,a.call(this,b)}.bind(this):this._animation.oncancel=a},get currentTime(){this._updatePromises();var a=this._animation.currentTime;return this._updatePromises(),a},set currentTime(a){this._updatePromises(),this._animation.currentTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.currentTime=a-c}),this._updatePromises()},get startTime(){return this._animation.startTime},set startTime(a){this._updatePromises(),this._animation.startTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.startTime=a+c}),this._updatePromises()},get playbackRate(){return this._animation.playbackRate},set playbackRate(a){this._updatePromises();var b=this.currentTime;this._animation.playbackRate=a,this._forEachChild(function(b){b.playbackRate=a}),"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!==b&&(this.currentTime=b),this._updatePromises()},play:function(){this._updatePromises(),this._paused=!1,this._animation.play(),-1==this._timeline._animations.indexOf(this)&&this._timeline._animations.push(this),this._register(),b.awaitStartTime(this),this._forEachChild(function(a){var b=a.currentTime;a.play(),a.currentTime=b}),this._updatePromises()},pause:function(){this._updatePromises(),this.currentTime&&(this._holdTime=this.currentTime),this._animation.pause(),this._register(),this._forEachChild(function(a){a.pause()}),this._paused=!0,this._updatePromises()},finish:function(){this._updatePromises(),this._animation.finish(),this._register(),this._updatePromises()},cancel:function(){this._updatePromises(),this._animation.cancel(),this._register(),this._removeChildAnimations(),this._updatePromises()},reverse:function(){this._updatePromises();var a=this.currentTime;this._animation.reverse(),this._forEachChild(function(a){a.reverse()}),null!==a&&(this.currentTime=a),this._updatePromises()},addEventListener:function(a,b){var c=b;"function"==typeof b&&(c=function(a){a.target=this,b.call(this,a)}.bind(this),b._wrapper=c),this._animation.addEventListener(a,c)},removeEventListener:function(a,b){this._animation.removeEventListener(a,b&&b._wrapper||b)},_removeChildAnimations:function(){for(;this._childAnimations.length;)this._childAnimations.pop().cancel()},_forEachChild:function(b){var c=0;if(this.effect.children&&this._childAnimations.length<this.effect.children.length&&this._constructChildAnimations(),this._childAnimations.forEach(function(a){b.call(this,a,c),this.effect instanceof window.SequenceEffect&&(c+=a.effect.activeDuration)}.bind(this)),"pending"!=this.playState){var d=this.effect._timing,e=this.currentTime;null!==e&&(e=a.calculateTimeFraction(a.calculateActiveDuration(d),e,d)),(null==e||isNaN(e))&&this._removeChildAnimations()}}},window.Animation=b.Animation}(c,e,f),function(a,b,c){function d(b){this._frames=a.normalizeKeyframes(b)}function e(){for(var a=!1;i.length;){var b=i.shift();b._updateChildren(),a=!0}return a}var f=function(a){if(a._animation=void 0,a instanceof window.SequenceEffect||a instanceof window.GroupEffect)for(var b=0;b<a.children.length;b++)f(a.children[b])};b.removeMulti=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c];d._parent?(-1==b.indexOf(d._parent)&&b.push(d._parent),d._parent.children.splice(d._parent.children.indexOf(d),1),d._parent=null,f(d)):d._animation&&d._animation.effect==d&&(d._animation.cancel(),d._animation.effect=new KeyframeEffect(null,[]),d._animation._callback&&(d._animation._callback._animation=null),d._animation._rebuildUnderlyingAnimation(),f(d))}for(c=0;c<b.length;c++)b[c]._rebuild()},b.KeyframeEffect=function(b,c,e,f){return this.target=b,this._parent=null,e=a.numericTimingToObject(e),this._timingInput=a.cloneTimingInput(e),this._timing=a.normalizeTimingInput(e),this.timing=a.makeTiming(e,!1,this),this.timing._effect=this,"function"==typeof c?(a.deprecated("Custom KeyframeEffect","2015-06-22","Use KeyframeEffect.onsample instead."),this._normalizedKeyframes=c):this._normalizedKeyframes=new d(c),this._keyframes=c,this.activeDuration=a.calculateActiveDuration(this._timing),this._id=f,this},b.KeyframeEffect.prototype={getFrames:function(){return"function"==typeof this._normalizedKeyframes?this._normalizedKeyframes:this._normalizedKeyframes._frames},set onsample(a){if("function"==typeof this.getFrames())throw new Error("Setting onsample on custom effect KeyframeEffect is not supported.");this._onsample=a,this._animation&&this._animation._rebuildUnderlyingAnimation()},get parent(){return this._parent},clone:function(){if("function"==typeof this.getFrames())throw new Error("Cloning custom effects is not supported.");var b=new KeyframeEffect(this.target,[],a.cloneTimingInput(this._timingInput),this._id);return b._normalizedKeyframes=this._normalizedKeyframes,b._keyframes=this._keyframes,b},remove:function(){b.removeMulti([this])}};var g=Element.prototype.animate;Element.prototype.animate=function(a,c){var d="";return c&&c.id&&(d=c.id),b.timeline._play(new b.KeyframeEffect(this,a,c,d))};var h=document.createElementNS("http://www.w3.org/1999/xhtml","div");b.newUnderlyingAnimationForKeyframeEffect=function(a){if(a){var b=a.target||h,c=a._keyframes;"function"==typeof c&&(c=[]);var d=a._timingInput;d.id=a._id}else var b=h,c=[],d=0;return g.apply(b,[c,d])},b.bindAnimationForKeyframeEffect=function(a){a.effect&&"function"==typeof a.effect._normalizedKeyframes&&b.bindAnimationForCustomEffect(a)};var i=[];b.awaitStartTime=function(a){null===a.startTime&&a._isGroup&&(0==i.length&&requestAnimationFrame(e),i.push(a))};var j=window.getComputedStyle;Object.defineProperty(window,"getComputedStyle",{configurable:!0,enumerable:!0,value:function(){window.document.timeline._updateAnimationsPromises();var a=j.apply(this,arguments);return e()&&(a=j.apply(this,arguments)),window.document.timeline._updateAnimationsPromises(),a}}),window.KeyframeEffect=b.KeyframeEffect,window.Element.prototype.getAnimations=function(){return document.timeline.getAnimations().filter(function(a){return null!==a.effect&&a.effect.target==this}.bind(this))}}(c,e,f),function(a,b,c){function d(a){a._registered||(a._registered=!0,g.push(a),h||(h=!0,requestAnimationFrame(e)))}function e(a){var b=g;g=[],b.sort(function(a,b){return a._sequenceNumber-b._sequenceNumber}),b=b.filter(function(a){a();var b=a._animation?a._animation.playState:"idle";return"running"!=b&&"pending"!=b&&(a._registered=!1),a._registered}),g.push.apply(g,b),g.length?(h=!0,requestAnimationFrame(e)):h=!1}var f=(document.createElementNS("http://www.w3.org/1999/xhtml","div"),0);b.bindAnimationForCustomEffect=function(b){var c,e=b.effect.target,g="function"==typeof b.effect.getFrames();c=g?b.effect.getFrames():b.effect._onsample;var h=b.effect.timing,i=null;h=a.normalizeTimingInput(h);var j=function(){var d=j._animation?j._animation.currentTime:null;null!==d&&(d=a.calculateTimeFraction(a.calculateActiveDuration(h),d,h),isNaN(d)&&(d=null)),d!==i&&(g?c(d,e,b.effect):c(d,b.effect,b.effect._animation)),i=d};j._animation=b,j._registered=!1,j._sequenceNumber=f++,b._callback=j,d(j)};var g=[],h=!1;b.Animation.prototype._register=function(){this._callback&&d(this._callback)}}(c,e,f),function(a,b,c){function d(a){return a._timing.delay+a.activeDuration+a._timing.endDelay}function e(b,c,d){this._id=d,this._parent=null,this.children=b||[],this._reparent(this.children),c=a.numericTimingToObject(c),this._timingInput=a.cloneTimingInput(c),this._timing=a.normalizeTimingInput(c,!0),this.timing=a.makeTiming(c,!0,this),this.timing._effect=this,"auto"===this._timing.duration&&(this._timing.duration=this.activeDuration)}window.SequenceEffect=function(){e.apply(this,arguments)},window.GroupEffect=function(){e.apply(this,arguments)},e.prototype={_isAncestor:function(a){for(var b=this;null!==b;){if(b==a)return!0;b=b._parent}return!1},_rebuild:function(){for(var a=this;a;)"auto"===a.timing.duration&&(a._timing.duration=a.activeDuration),a=a._parent;this._animation&&this._animation._rebuildUnderlyingAnimation()},_reparent:function(a){b.removeMulti(a);for(var c=0;c<a.length;c++)a[c]._parent=this},_putChild:function(a,b){for(var c=b?"Cannot append an ancestor or self":"Cannot prepend an ancestor or self",d=0;d<a.length;d++)if(this._isAncestor(a[d]))throw{type:DOMException.HIERARCHY_REQUEST_ERR,name:"HierarchyRequestError",message:c};for(var d=0;d<a.length;d++)b?this.children.push(a[d]):this.children.unshift(a[d]);this._reparent(a),this._rebuild()},append:function(){this._putChild(arguments,!0)},prepend:function(){this._putChild(arguments,!1)},get parent(){return this._parent},get firstChild(){return this.children.length?this.children[0]:null},get lastChild(){return this.children.length?this.children[this.children.length-1]:null},clone:function(){for(var b=a.cloneTimingInput(this._timingInput),c=[],d=0;d<this.children.length;d++)c.push(this.children[d].clone());return this instanceof GroupEffect?new GroupEffect(c,b):new SequenceEffect(c,b)},remove:function(){b.removeMulti([this])}},window.SequenceEffect.prototype=Object.create(e.prototype),Object.defineProperty(window.SequenceEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a+=d(b)}),Math.max(a,0)}}),window.GroupEffect.prototype=Object.create(e.prototype),Object.defineProperty(window.GroupEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a=Math.max(a,d(b))}),a}}),b.newUnderlyingAnimationForGroup=function(c){var d,e=null,f=function(b){var c=d._wrapper;return c&&"pending"!=c.playState&&c.effect?null==b?void c._removeChildAnimations():0==b&&c.playbackRate<0&&(e||(e=a.normalizeTimingInput(c.effect.timing)),b=a.calculateTimeFraction(a.calculateActiveDuration(e),-1,e),isNaN(b)||null==b)?(c._forEachChild(function(a){a.currentTime=-1}),void c._removeChildAnimations()):void 0:void 0},g=new KeyframeEffect(null,[],c._timing,c._id);return g.onsample=f,d=b.timeline._play(g)},b.bindAnimationForGroup=function(a){a._animation._wrapper=a,a._isGroup=!0,b.awaitStartTime(a),a._constructChildAnimations(),a._setExternalAnimation(a)},b.groupChildDuration=d}(c,e,f),b["true"]=a}({},function(){return this}());
+//# sourceMappingURL=web-animations-next.min.js.map \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js.map b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js.map
new file mode 100644
index 00000000000..c478544dce2
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations-next.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["src/scope.js","src/timing-utilities.js","src/normalize-keyframes.js","src/deprecation.js","src/keyframe-interpolations.js","src/property-interpolation.js","src/keyframe-effect.js","src/apply-preserving-inline-style.js","src/element-animatable.js","src/interpolation.js","src/matrix-interpolation.js","src/animation.js","src/tick.js","src/web-animations-bonus-cancel-events.js","src/web-animations-bonus-object-form-keyframes.js","src/timeline.js","src/web-animations-next-animation.js","src/keyframe-effect-constructor.js","src/effect-callback.js","src/group-constructors.js"],"names":["webAnimationsShared","webAnimations1","webAnimationsNext","webAnimationsTesting","shared","testing","cloneTimingInput","timingInput","clone","m","AnimationEffectTiming","this","_delay","_endDelay","_fill","_iterationStart","_iterations","_duration","_playbackRate","_direction","_easing","_easingFunction","linear","isInvalidTimingDeprecated","isDeprecated","makeTiming","forGroup","effect","timing","fill","duration","isNaN","undefined","Object","getOwnPropertyNames","forEach","property","fills","indexOf","directions","numericTimingToObject","normalizeTimingInput","cubic","a","b","c","d","x","f","start","end","mid","xEst","Math","abs","step","count","pos","stepSize","toTimingFunction","easing","styleForCleaning","document","createElement","style","animationTimingFunction","validatedEasing","TypeError","cubicData","cubicBezierRe","exec","apply","slice","map","Number","stepData","stepRe","Start","middle","Middle","End","preset","presets","calculateActiveDuration","repeatedDuration","playbackRate","iterations","calculatePhase","activeDuration","localTime","PhaseNone","delay","PhaseBefore","PhaseAfter","PhaseActive","calculateActiveTime","fillMode","phase","calculateScaledActiveTime","activeTime","startOffset","calculateIterationTime","iterationDuration","scaledActiveTime","Infinity","iterationStart","calculateCurrentIteration","iterationTime","floor","calculateTransformedTime","currentIteration","currentIterationIsOdd","currentDirectionIsForwards","direction","directedTime","timeFraction","calculateTimeFraction","split","prototype","_setMember","member","value","_effect","_timingInput","_timing","_animation","_rebuildUnderlyingAnimation","endDelay","ease","ease-in","ease-out","ease-in-out","step-start","step-middle","step-end","numberString","RegExp","antiAlias","aliases","expandShorthandAndAntiAlias","result","longProperties","shorthandToLonghand","shorthandExpanderElem","i","longProperty","longhandValue","convertToArrayForm","effectInput","normalizedEffectInput","values","Array","isArray","keyframe","numKeyframes","length","offset","composite","push","sort","normalizeKeyframes","spaceKeyframes","keyframes","previousIndex","previousOffset","j","window","Symbol","iterator","from","originalKeyframe","memberValue","isFinite","type","DOMException","NOT_SUPPORTED_ERR","name","message","everyFrameHasOffset","code","INVALID_MODIFICATION_ERR","filter","background","border","borderBottom","borderColor","borderLeft","borderRadius","borderRight","borderTop","borderWidth","flex","font","margin","outline","padding","createElementNS","borderWidthAliases","thin","medium","thick","borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopWidth","fontSize","xx-small","x-small","small","large","x-large","xx-large","fontWeight","normal","bold","outlineWidth","textShadow","none","boxShadow","silenced","feature","date","advice","plural","auxVerb","today","Date","expiry","setMonth","getMonth","console","warn","toDateString","deprecated","Error","scope","r","makePropertySpecificKeyframeGroups","leftCopy","propertySpecificKeyframeGroups","bind","addPropertiesHandler","parseShadowList","mergeShadowList","propertySpecificKeyframe","groupName","group","mergeFlex","left","right","round","makeInterpolations","interpolations","startTime","endTime","startValue","endValue","propertyInterpolation","leftInterpolation","rightInterpolation","convertEffectInput","trim","context","target","fraction","interpolation","fillStyle","offsetFraction","localDuration","scaledLocalTime","clamp","join","canvas","toCamelCase","parseColor","toUpperCase","addPropertyHandler","merger","propertyHandlers","parser","properties","ucProperty","test","matchedUnits","string","replace","unitRegExp","initialValues","handlers","parsedRight","parsedLeft","interpolationArgs","interp","Interpolation","t","taggedUnitRegExp","unit","bool","backgroundColor","nonNegative","backgroundPosition","units","borderBottomColor","borderBottomLeftRadius","borderBottomRightRadius","borderLeftColor","borderRightColor","borderSpacing","borderTopColor","borderTopLeftRadius","borderTopRightRadius","numberToString","clip","color","height","marginBottom","marginLeft","marginRight","lengthUnits","marginTop","parseLengthOrPercent","maxWidth","minHeight","minWidth","opacity","parseAngle","outlineColor","outlineOffset","paddingBottom","paddingLeft","transform","verticalAlign","visibility","width","wordSpacing","consumeLength","zIndex","consumeParenthesised","consumeSizePairList","EffectTime","effectTime","_totalDuration","_isCurrent","KeyframeEffect","keyframeEffect","_update","_clear","_hasSameTarget","id","NullEffect","clear","nullEffect","configureProperty","object","descriptor","enumerable","configurable","defineProperty","AnimatedCSSStyleDeclaration","element","_surrogateStyle","ignore","consumeToken","_style","_length","_isAnimatedProperty","_updateIndices","ensureStyleIsPatched","_webAnimationsPatchedStyle","merged","animatedStyle","mergeDimensions","get","mergeWrappedNestedRepeated","_","styleAttributes","cssText","parentRule","styleMethods","getPropertyCSSValue","getPropertyPriority","getPropertyValue","item","removeProperty","setProperty","styleMutatingMethods","text","transformRegExp","isAffectedProperty","functionName","argTypes","s","T","parsedArgs","index","method","modifiesStyle","list","arguments","documentElement","matrixModulesLoaded","set","_set","propertyName","Element","animate","options","mergeMatrices","timeline","interpolate","leftArgs","to","transformFunctions","leftType","leftResult","convertToString","typeTo2D","max","rightArgs","quat","product","dot","fromQ","theta","sqrt","cos","toQ","w","composeMatrix","leftFunctionData","multiply","leftArgsCopy","k","mergeNumbers","merge","rightArgsCopy","translate","skew","perspective","matrix","types","stringConversions","tmp","rightResult","rotMatrix","stringifiedArgs","args","arg","y","z","deg","temp","rotate","rotatez","scale","cast","scaley","scale3d","is2D","concat","translatey","sequenceNumber","AnimationEvent","currentTime","timelineTime","out","bubbles","cancelable","currentTarget","defaultPrevented","eventPhase","Event","AT_TARGET","timeStamp","now","Animation","_id","_sequenceNumber","_currentTime","dimension","_paused","_inTimeline","_finishedFlag","onfinish","consumeOffset","_finishHandlers","_idle","consumeLengthOrPercent","_currentTimePending","_ensureAlive","_inEffect","_animations","_tickCurrentTime","newTime","ignoreLimit","_isFinished","position","restart","_startTime","_timeline","bottomOrRight","invalidateEffects","token","center","oldCurrentTime","mergeNestedRepeated","playState","play","parseOrigin","consumePosition","mergeOffsetList","circle","consumeList","pause","finish","ellipse","cancel","reverse","polygon","addEventListener","handler","_fireEvents","baseTime","event","setTimeout","mergeNonNegativeSizePair","call","_tick","isAnimationFrame","_needsTick","running","mergeSizePair","processRafCallbacks","processing","rafCallbacks","candidate","entry","applyPendingEffects","compareAnimations","rightAnimation","leftAnimation","InternalTimeline","performance","oncancel","AnimationCancelEvent","originalElementAnimate","animation","_cancelHandlers","originalCancel","originalAddEventListener","originalRemoveEventListener","removeEventListener","splice","animated","originalOpacity","getComputedStyle","testOpacity","error","webAnimationsNextTick","_discardAnimations","ticking","requestAnimationFrame","originalRequestAnimationFrame","_updateAnimationsPromises","AnimationTimeline","getAnimations","animationsWithPromises","_updatePromises","_play","restartWebAnimationsNextTick","remove","e","_holdTime","_isGroup","_childAnimations","_callback","_oldPlayState","oldPlayState","newPlayState","_readyPromise","_rejectReadyPromise","_resolveReadyPromise","_finishedPromise","_rejectFinishedPromise","_resolveFinishedPromise","oldPlaybackRate","oldPaused","oldStartTime","hadUnderlying","_wrapper","newUnderlyingAnimationForKeyframeEffect","bindAnimationForKeyframeEffect","SequenceEffect","GroupEffect","newUnderlyingAnimationForGroup","bindAnimationForGroup","_onsample","bindAnimationForCustomEffect","_updateChildren","childAnimation","_arrangeChildren","groupChildDuration","_setExternalAnimation","children","_constructChildAnimations","_removeChildAnimations","child","finished","Promise","resolve","reject","ABORT_ERR","ready","v","sign","MAX_VALUE","_register","_forEachChild","awaitStartTime","time","wrapped","pop","KeyframeList","_frames","updatePendingGroups","updated","pendingGroups","shift","disassociate","removeMulti","effects","oldParents","_parent","_rebuild","_normalizedKeyframes","_keyframes","getFrames","onsample","callback","parent","nullTarget","groupAnimation","originalGetComputedStyle","register","_registered","callbacks","tick","updating","effectFunction","isKeyframeEffect","last","node","constructor","_reparent","_isAncestor","newChildren","_putChild","isAppend","HIERARCHY_REQUEST_ERR","unshift","append","prepend","firstChild","lastChild","clonedTiming","clonedChildren","create","total","underlyingAnimation","ticker","tf","underlyingEffect","exports"],"mappings":";;;;;;;;;;;;;;CAcA,SAAIA,EAAAA,GAAJ,GAAIA,MACAC,KACAC,KAGEC,EAAuB,MCL7B,SAAUC,EAAQC,GAMhB,QAASC,GAAiBC,GACxB,GAA0B,gBAAfA,GACT,MAAOA,EAET,IAAIC,KACJ,KAAK,GAAIC,KAAKF,GACZC,EAAMC,GAAKF,EAAYE,EAEzB,OAAOD,GAGT,QAASE,KACPC,KAAKC,OAAS,EACdD,KAAKE,UAAY,EACjBF,KAAKG,MAAQ,OACbH,KAAKI,gBAAkB,EACvBJ,KAAKK,YAAc,EACnBL,KAAKM,UAAY,EACjBN,KAAKO,cAAgB,EACrBP,KAAKQ,WAAa,SAClBR,KAAKS,QAAU,SACfT,KAAKU,gBAAkBC,EAGzB,QAASC,KACP,MAAOnB,GAAOoB,aAAa,wBAAyB,aAAc,gDAAA,GA8EpE,QAASC,GAAWlB,EAAamB,EAAUC,GACzC,GAAIC,GAAS,GAAIlB,EA4BjB,OA3BIgB,KACFE,EAAOC,KAAO,OACdD,EAAOE,SAAW,QAEM,gBAAfvB,IAA4BwB,MAAMxB,GAElByB,SAAhBzB,GACT0B,OAAOC,oBAAoB3B,GAAa4B,QAAQ,SAASC,GACvD,GAA6B,QAAzB7B,EAAY6B,GAAqB,CACnC,IAA+B,gBAApBR,GAAOQ,IAAqC,YAAZA,KACL,gBAAzB7B,GAAY6B,IAAyBL,MAAMxB,EAAY6B,KAChE,MAGJ,IAAiB,QAAZA,GAAgE,IAAxCC,EAAMC,QAAQ/B,EAAY6B,IACrD,MAEF,IAAiB,aAAZA,GAA0E,IAA7CG,EAAWD,QAAQ/B,EAAY6B,IAC/D,MAEF,IAAgB,gBAAZA,GAAwD,IAA1B7B,EAAY6B,IAAmBhC,EAAOoB,aAAa,qCAAsC,aAAc,uCACvI,MAEFI,GAAOQ,GAAY7B,EAAY6B,MAlBnCR,EAAOE,SAAWvB,EAsBbqB,EAGT,QAASY,GAAsBjC,GAQ7B,MAP0B,gBAAfA,KAEPA,EADEwB,MAAMxB,IACQuB,SAAU,IAEVA,SAAUvB,IAGvBA,EAGT,QAASkC,GAAqBlC,EAAamB,GAEzC,MADAnB,GAAcH,EAAOoC,sBAAsBjC,GACpCkB,EAAWlB,EAAamB,GAGjC,QAASgB,GAAMC,EAAGC,EAAGC,EAAGC,GACtB,MAAQ,GAAJH,GAASA,EAAI,GAAS,EAAJE,GAASA,EAAI,EAC1BvB,EAEF,SAASyB,GAOZ,QAASC,GAAEL,EAAGC,EAAGnC,GAAK,MAAO,GAAIkC,GAAK,EAAIlC,IAAM,EAAIA,GAAKA,EAAI,EAAImC,GAAK,EAAInC,GAAKA,EAAIA,EAAIA,EAAIA,EAAIA,EANjG,GAAS,GAALsC,GAAe,GAALA,EACZ,MAAOA,EAGT,KADA,GAAIE,GAAQ,EAAGC,EAAM,IACX,CACR,GAAIC,IAAOF,EAAQC,GAAO,EAEtBE,EAAOJ,EAAEL,EAAGE,EAAGM,EACnB,IAAIE,KAAKC,IAAIP,EAAIK,GAAQ,KACvB,MAAOJ,GAAEJ,EAAGE,EAAGK,EAENJ,GAAPK,EACFH,EAAQE,EAERD,EAAMC,IAUd,QAASI,GAAKC,EAAOC,GACnB,MAAO,UAASV,GACd,GAAIA,GAAK,EACP,MAAO,EAET,IAAIW,GAAW,EAAIF,CAEnB,OADAT,IAAKU,EAAMC,EACJX,EAAIA,EAAIW,GAmBnB,QAASC,GAAiBC,GACnBC,IACHA,EAAmBC,SAASC,cAAc,OAAOC,OAEnDH,EAAiBI,wBAA0B,GAC3CJ,EAAiBI,wBAA0BL,CAC3C,IAAIM,GAAkBL,EAAiBI,uBAEvC,IAAuB,IAAnBC,GAAyB3C,IAC3B,KAAM,IAAI4C,WAAUP,EAAS,mCAG/B,IAAIQ,GAAYC,EAAcC,KAAKJ,EACnC,IAAIE,EACF,MAAO1B,GAAM6B,MAAM5D,KAAMyD,EAAUI,MAAM,GAAGC,IAAIC,QAElD,IAAIC,GAAWC,EAAON,KAAKJ,EAC3B,IAAIS,EACF,MAAOpB,GAAKmB,OAAOC,EAAS,KAAM1B,MAAS4B,EAAOC,OAAUC,EAAQ7B,IAAO8B,GAAKL,EAAS,IAE3F,IAAIM,GAASC,EAAQhB,EACrB,OAAIe,GACKA,EAEF3D,EAGT,QAAS6D,GAAwBvD,GAC/B,MAAOyB,MAAKC,IAAI8B,EAAiBxD,GAAUA,EAAOyD,cAGpD,QAASD,GAAiBxD,GACxB,MAAOA,GAAOE,SAAWF,EAAO0D,WAQlC,QAASC,GAAeC,EAAgBC,EAAW7D,GACjD,MAAiB,OAAb6D,EACKC,EAELD,EAAY7D,EAAO+D,MACdC,EAELH,GAAa7D,EAAO+D,MAAQH,EACvBK,EAEFC,EAGT,QAASC,GAAoBP,EAAgBQ,EAAUP,EAAWQ,EAAON,GACvE,OAAQM,GACN,IAAKL,GACH,MAAgB,aAAZI,GAAuC,QAAZA,EACtB,EACF,IACT,KAAKF,GACH,MAAOL,GAAYE,CACrB,KAAKE,GACH,MAAgB,YAAZG,GAAsC,QAAZA,EACrBR,EACF,IACT,KAAKE,GACH,MAAO,OAIb,QAASQ,GAA0BV,EAAgBW,EAAYC,EAAaxE,GAC1E,OAAQA,EAAOyD,aAAe,EAAIc,EAAaX,EAAiBW,GAAcvE,EAAOyD,aAAee,EAGtG,QAASC,GAAuBC,EAAmBlB,EAAkBmB,EAAkBH,EAAaxE,GAClG,MAAI2E,KAAqBC,EAAAA,GAAYD,MAAsBC,EAAAA,IAAaD,EAAmBH,GAAehB,GAAoBxD,EAAO0D,aAAgB1D,EAAO0D,WAAa1D,EAAO6E,gBAAkB,GAAK,EAC9LH,EAGFC,EAAmBD,EAG5B,QAASI,GAA0BJ,EAAmBK,EAAeJ,EAAkB3E,GACrF,MAAyB,KAArB2E,EACK,EAELI,GAAiBL,EACZ1E,EAAO6E,eAAiB7E,EAAO0D,WAAa,EAE9CjC,KAAKuD,MAAML,EAAmBD,GAGvC,QAASO,GAAyBC,EAAkBR,EAAmBK,EAAe/E,GACpF,GAAImF,GAAwBD,EAAmB,GAAK,EAChDE,EAAiD,UAApBpF,EAAOqF,WAAyBrF,EAAOqF,YAAcF,EAAwB,oBAAsB,aAChIG,EAAeF,EAA6BL,EAAgBL,EAAoBK,EAChFQ,EAAeD,EAAeZ,CAClC,OAAOA,GAAoB1E,EAAOP,gBAAgB8F,GAGpD,QAASC,GAAsB5B,EAAgBC,EAAW7D,GACxD,GAAIqE,GAAQV,EAAeC,EAAgBC,EAAW7D,GAClDuE,EAAaJ,EAAoBP,EAAgB5D,EAAOC,KAAM4D,EAAWQ,EAAOrE,EAAO+D,MAC3F,IAAmB,OAAfQ,EACF,MAAO,KACT,IAAuB,IAAnBX,EACF,MAAOS,KAAUL,EAAc,EAAI,CACrC,IAAIQ,GAAcxE,EAAO6E,eAAiB7E,EAAOE,SAC7CyE,EAAmBL,EAA0BV,EAAgBW,EAAYC,EAAaxE,GACtF+E,EAAgBN,EAAuBzE,EAAOE,SAAUsD,EAAiBxD,GAAS2E,EAAkBH,EAAaxE,GACjHkF,EAAmBJ,EAA0B9E,EAAOE,SAAU6E,EAAeJ,EAAkB3E,EACnG,OAAOiF,GAAyBC,EAAkBlF,EAAOE,SAAU6E,EAAe/E,GAAUA,EAAOE,SAjUrG,GAAIO,GAAQ,+BAA+BgF,MAAM,KAC7C9E,EAAa,sCAAsC8E,MAAM,KACzD/F,EAAS,SAASyB,GAAK,MAAOA,GA8BlCrC,GAAsB4G,WACpBC,WAAY,SAASC,EAAQC,GAC3B9G,KAAK,IAAM6G,GAAUC,EACjB9G,KAAK+G,UACP/G,KAAK+G,QAAQC,aAAaH,GAAUC,EACpC9G,KAAK+G,QAAQE,QAAUxH,EAAOqC,qBAAqB9B,KAAK+G,QAAQC,cAChEhH,KAAK+G,QAAQlC,eAAiBpF,EAAO+E,wBAAwBxE,KAAK+G,QAAQE,SACtEjH,KAAK+G,QAAQG,YACflH,KAAK+G,QAAQG,WAAWC,gCAI9BzC,GAAIA,gBACF,MAAO1E,MAAKO,eAEdyE,GAAIA,OAAM8B,GACR9G,KAAK4G,WAAW,QAASE,IAE3B9B,GAAIA,SACF,MAAOhF,MAAKC,QAEdmH,GAAIA,UAASN,GACX9G,KAAK4G,WAAW,WAAYE,IAE9BM,GAAIA,YACF,MAAOpH,MAAKE,WAEdgB,GAAIA,MAAK4F,GACP9G,KAAK4G,WAAW,OAAQE,IAE1B5F,GAAIA,QACF,MAAOlB,MAAKG,OAEd2F,GAAIA,gBAAegB,GACjB,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,2DAA6DvC,OAAO6E,eAE1F9F,MAAK4G,WAAW,iBAAkBE,IAEpChB,GAAIA,kBACF,MAAO9F,MAAKI,iBAEde,GAAIA,UAAS2F,GACX,GAAa,QAATA,IAAoB1F,MAAM0F,IAAkB,EAARA,IAAclG,IACpD,KAAM,IAAI4C,WAAU,oDAAsDsD,EAE5E9G,MAAK4G,WAAW,WAAYE,IAE9B3F,GAAIA,YACF,MAAOnB,MAAKM,WAEdgG,GAAIA,WAAUQ,GACZ9G,KAAK4G,WAAW,YAAaE,IAE/BR,GAAIA,aACF,MAAOtG,MAAKQ,YAEdyC,GAAIA,QAAO6D,GACT9G,KAAKU,gBAAkBsC,EAAiB8D,GACxC9G,KAAK4G,WAAW,SAAUE,IAE5B7D,GAAIA,UACF,MAAOjD,MAAKS,SAEdkE,GAAIA,YAAWmC,GACb,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,8CAAgDsD,EAEtE9G,MAAK4G,WAAW,aAAcE,IAEhCnC,GAAIA,cACF,MAAO3E,MAAKK,aA6EhB,IAAI6D,GAAQ,EACRE,EAAS,GACTC,EAAM,EAaNE,GACF8C,KAAQtF,EAAM,IAAM,GAAK,IAAM,GAC/BuF,UAAWvF,EAAM,IAAM,EAAG,EAAG,GAC7BwF,WAAYxF,EAAM,EAAG,EAAG,IAAM,GAC9ByF,cAAezF,EAAM,IAAM,EAAG,IAAM,GACpC0F,aAAc7E,EAAK,EAAGsB,GACtBwD,cAAe9E,EAAK,EAAGwB,GACvBuD,WAAY/E,EAAK,EAAGyB,IAGlBnB,EAAmB,KACnB0E,EAAe,qCACflE,EAAgB,GAAImE,QAAO,kBAAoBD,EAAe,IAAMA,EAAe,IAAMA,EAAe,IAAMA,EAAe,OAC7H3D,EAAS,gDAqCTc,EAAY,EACZE,EAAc,EACdC,EAAa,EACbC,EAAc,CA4ElB1F,GAAOE,iBAAmBA,EAC1BF,EAAOqB,WAAaA,EACpBrB,EAAOoC,sBAAwBA,EAC/BpC,EAAOqC,qBAAuBA,EAC9BrC,EAAO+E,wBAA0BA,EACjC/E,EAAOgH,sBAAwBA,EAC/BhH,EAAOmF,eAAiBA,EACxBnF,EAAOuD,iBAAmBA,GAkBzB3D,EAAqBG,GC/VxB,SAAUC,EAAQC,GAmIhB,QAASoI,GAAUrG,EAAUqF,GAC3B,MAAIrF,KAAYsG,GACPA,EAAQtG,GAAUqF,IAAUA,EAE9BA,EAIT,QAASkB,GAA4BvG,EAAUqF,EAAOmB,GACpD,GAAIC,GAAiBC,EAAoB1G,EACzC,IAAIyG,EAAgB,CAClBE,EAAsB/E,MAAM5B,GAAYqF,CACxC,KAAK,GAAIuB,KAAKH,GAAgB,CAC5B,GAAII,GAAeJ,EAAeG,GAC9BE,EAAgBH,EAAsB/E,MAAMiF,EAChDL,GAAOK,GAAgBR,EAAUQ,EAAcC,QAGjDN,GAAOxG,GAAYqG,EAAUrG,EAAUqF,GAI3C,QAAS0B,GAAmBC,GAC1B,GAAIC,KAEJ,KAAK,GAAIjH,KAAYgH,GACnB,KAAIhH,KAAa,SAAU,SAAU,cAArC,CAIA,GAAIkH,GAASF,EAAYhH,EACpBmH,OAAMC,QAAQF,KACjBA,GAAUA,GAKZ,KAAK,GAFDG,GACAC,EAAeJ,EAAOK,OACjBX,EAAI,EAAOU,EAAJV,EAAkBA,IAChCS,KAEI,UAAYL,GACdK,EAASG,OAASR,EAAYQ,OACL,GAAhBF,EACTD,EAASG,OAAS,EAElBH,EAASG,OAASZ,GAAKU,EAAe,GAGpC,UAAYN,KACdK,EAAS7F,OAASwF,EAAYxF,QAG5B,aAAewF,KACjBK,EAASI,UAAYT,EAAYS,WAGnCJ,EAASrH,GAAYkH,EAAON,GAE5BK,EAAsBS,KAAKL,GAK/B,MADAJ,GAAsBU,KAAK,SAASpH,EAAGC,GAAK,MAAOD,GAAEiH,OAAShH,EAAEgH,SACzDP,EAGT,QAASW,GAAmBZ,GA+D1B,QAASa,KACP,GAAIN,GAASO,EAAUP,MACa,OAAhCO,EAAUP,EAAS,GAAGC,SACxBM,EAAUP,EAAS,GAAGC,OAAS,GAC7BD,EAAS,GAA4B,MAAvBO,EAAU,GAAGN,SAC7BM,EAAU,GAAGN,OAAS,EAIxB,KAAK,GAFDO,GAAgB,EAChBC,EAAiBF,EAAU,GAAGN,OACzBZ,EAAI,EAAOW,EAAJX,EAAYA,IAAK,CAC/B,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,IAAK,GAAIS,GAAI,EAAOrB,EAAImB,EAARE,EAAuBA,IACrCH,EAAUC,EAAgBE,GAAGT,OAASQ,GAAkBR,EAASQ,GAAkBC,GAAKrB,EAAImB,EAC9FA,GAAgBnB,EAChBoB,EAAiBR,IA7EvB,GAAmB,MAAfR,EACF,QAGEkB,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,KACjBA,EAAcD,EAAmBC,GAgCnC,KAAK,GA7BDc,GAAYd,EAAY3E,IAAI,SAASiG,GACvC,GAAIjB,KACJ,KAAK,GAAIjC,KAAUkD,GAAkB,CACnC,GAAIC,GAAcD,EAAiBlD,EACnC,IAAc,UAAVA,GACF,GAAmB,MAAfmD,IACFA,EAAcjG,OAAOiG,IAChBC,SAASD,IACZ,KAAM,IAAIxG,WAAU,yCAEnB,CAAA,GAAc,aAAVqD,EACT,MACEqD,KAAMC,aAAaC,kBACnBC,KAAM,oBACNC,QAAS,mCAGXN,GAAc,GAAKA,EAErBhC,EAA4BnB,EAAQmD,EAAalB,GAInD,MAFuBzH,SAAnByH,EAASG,SACXH,EAASG,OAAS,MACbH,IAGLyB,GAAAA,EAEAd,IAAkB5D,EAAAA,GACbwC,EAAI,EAAGA,EAAIkB,EAAUP,OAAQX,IAAK,CACzC,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,GAAaQ,EAATR,EACF,MACEuB,KAAML,aAAaM,yBACnBJ,KAAM,2BACNC,QAAS,uEAGbb,GAAiBR,MAEjBsB,IAAAA,EA8BJ,MA1BAhB,GAAYA,EAAUmB,OAAO,SAAS5B,GACpC,MAAOA,GAASG,QAAU,GAAKH,EAASG,QAAU,IAsB/CsB,GACHjB,IAEKC,EAzRT,GAAIpB,IACFwC,YACE,kBACA,qBACA,iBACA,mBACA,uBACA,mBACA,iBACA,mBAEFC,QACE,iBACA,iBACA,iBACA,mBACA,mBACA,mBACA,oBACA,oBACA,oBACA,kBACA,kBACA,mBAEFC,cACE,oBACA,oBACA,qBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,YACE,kBACA,kBACA,mBAEFC,cACE,sBACA,uBACA,0BACA,0BAEFC,aACE,mBACA,mBACA,oBAEFC,WACE,iBACA,iBACA,kBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,MACE,WACA,aACA,aAEFC,MACE,aACA,WACA,YACA,cACA,aACA,cAEFC,QACE,YACA,cACA,eACA,cAEFC,SACE,eACA,eACA,gBAEFC,SACE,aACA,eACA,gBACA,gBAIApD,EAAwBjF,SAASsI,gBAAgB,+BAAgC,OAEjFC,GACFC,KAAM,MACNC,OAAQ,MACRC,MAAO,OAGL9D,GACF+D,kBAAmBJ,EACnBK,gBAAiBL,EACjBM,iBAAkBN,EAClBO,eAAgBP,EAChBQ,UACEC,WAAY,MACZC,UAAW,MACXC,MAAS,MACTT,OAAU,OACVU,MAAS,OACTC,UAAW,OACXC,WAAY,QAEdC,YACEC,OAAQ,MACRC,KAAM,OAERC,aAAclB,EACdmB,YACEC,KAAM,2BAERC,WACED,KAAM,+BA8JVrN,GAAO+I,mBAAqBA,EAC5B/I,EAAO4J,mBAAqBA,GAM3BhK,EAAqBG,GCpSxB,SAAUC,GAER,GAAIuN,KAEJvN,GAAOoB,aAAe,SAASoM,EAASC,EAAMC,EAAQC,GAKpD,GAAIC,GAAUD,EAAS,MAAQ,KAC3BE,EAAQ,GAAIC,MACZC,EAAS,GAAID,MAAKL,EAGtB,OAFAM,GAAOC,SAASD,EAAOE,WAAa,GAExBF,EAARF,GACIL,IAAWD,IACfW,QAAQC,KAAK,mBAAqBX,EAAU,IAAMI,EAAU,wCAA0CG,EAAOK,eAAiB,KAAOV,GAEvIH,EAASC,IAAAA,GAAW,IACb,GAMXxN,EAAOqO,WAAa,SAASb,EAASC,EAAMC,EAAQC,GAClD,GAAIC,GAAUD,EAAS,MAAQ,IAC/B,IAAI3N,EAAOoB,aAAaoM,EAASC,EAAMC,EAAQC,GAC7C,KAAM,IAAIW,OAAMd,EAAU,IAAMI,EAAU,yBAA2BF,KAIxE9N,wmrBChCH8J,KAAU1J,GAAQuO,EAAOtO,KA2BvBuO,GAAA,MAASC,GAAAA,oBAAAA,EAAmC3E,EAG1C4E,EAFIC,GAAAA,GAAAA,GAEK/F,EACPgG,KAAK,KAAIxH,EAAU0C,KAAUlB,GACbiG,qBAAsBC,EAAsBC,GAAV3H,aAC1C4H,iBAAAA,GACMlF,SAAaN,EACrBhG,GAAQsG,QAAUlB,GACXkB,GAAAA,MAAUlB,GAAGxB,QAEtBuH,GAAAA,QAAAA,OAAAA,IAAAA,QAAAA,GAA+BvH,EAAUuH,EAAAA,GAAAA,MAAAA,MAAAA,IAAAA,EAAAA,KAA+BvH,IAAAA,EAAAA,IACxEuH,QAAAA,GAAAA,GAA+BvH,MAAAA,2BAAa4H,KAAAA,GAKzCC,OAAAA,GAAaN,OAAAA,QAAAA,GAAAA,EAChBO,GAAQP,OAAAA,EAAAA,EAAAA,GAA+BM,QAC3CE,GAAID,EAAS1F,GAAiD,MAAlC0F,IAAMA,EAAM3F,EACtC,EAAA,EACEkB,GAAAA,EAAMC,GAAAA,OAAaC,QAAAA,GACbyE,EAAAC,GACNxE,OAASuE,EAAAC,EAAA,SAAA1M,GAAA,MAAAM,MAIfqM,MAAOX,EAAAA,EAAAA,EAAAA,EAAAA,MAAAA,QAAAA,GAIAY,EAAAA,GAAAA,MAAmBZ,UAAAA,EAAAA,GAAAA,OAAAA,EACtBa,EAAAA,SAAAA,GACJ,MAASP,GAAaN,EAAAA,EAAAA,EAAAA,OAAAA,QAEpBW,GAAKF,EADDtF,GAAY6E,OAAAA,EAAAA,EAAAA,KAAAA,OAAAA,EAA+BM,MACtCrG,EAAWkB,EAAAA,qBACd2F,EAAY3F,EACZ4F,EAAAA,EAAAA,IAAU5F,qBACV6F,gBAAa7F,EAAUlB,qBACZkB,EAAiBzC,EACnByC,EAAUlB,IAAGpF,UACtBiM,0BACEC,EACFC,qBAEAC,EAAWD,GAGfH,YAAe9F,gBACF+F,EACXC,qBACAlM,EAAeD,GAA0BC,UAAS,WAClDxB,EAAUiN,qBACKV,EAAMsB,GAAAA,YAAsBZ,EAAAA,YAAuBW,EAOxErB,EAHAiB,aAAAA,EAAoBjB,EAASuB,eAAAA,GAAmBC,EACvCD,GAAkBL,SAAYM,EAAAA,GAAmBN,QAAAA,GAEnDD,EAAAA,GArFTjB,MAAMyB,WAAAA,GAAqB,WAAShH,GAAAA,EAAAA,EAClC,SAAIc,GAAAA,MAAY9J,IAAO4J,EAAAA,EAAAA,GAAAA,EAAAA,EAAmBZ,YAAAA,OACtC2F,EAAAA,qBAAiCF,OAAAA,GAAAA,gBAAAA,GACjCe,SAAAA,EAAiBD,GAAAA,QAAmBZ,GAAAA,GAAAA,EAAAA,EACxCsB,OAAOC,EAASC,UAAQC;AACtBF,EAAIE,UACFZ,CAAAA,IAAAA,GAA+Ba,EAC7BC,SAAQF,IAAAA,EAA4CE,UAA3BD,OAAcZ,EAAAA,UAC/BW,EAAiBC,GACjBD,EAAYC,UAAAA,CAAcZ,EAAAA,SAAaW,EAAAA,EAAYC,EAAAA,EAAAA,IAAAA,GAAcX,EACxE3N,aAAiBsO,EAAAA,EAAAA,EAAAA,GAAAA,IAAAA,GACdE,UAAAA,EAAiBH,EAAAA,EAAAA,EAAAA,IAAWC,GAAAA,EAAcZ,GAAAA,GAC1Ce,QAAAA,EAAgBH,GAAAA,EAAcX,EAAUW,GAAAA,EAAAA,EACxCI,GAAAA,EAAAA,IAAmC,QAAjBD,GAAyBH,EAAAA,GAAc7M,OAAO+M,EAAAA,EAAAA,SAAiBC,GAAAA,QACrFjC,GAAMpK,GAAMgM,MAAQE,MAAAA,IAAAA,EAAAA,KAAcrO,IAAAA,IAAUqO,IAAAA,GAAAA,EAAAA,GAAAA,IAAcA,GAAAA,GAAAA,EAAAA,EAAAA,EAAcI,IAAAA,EAAAA,GAAAA,KAAAA,MAAAA,EAG1E9N,EAAKiG,GAAI5G,EAAAA,IAAAA,OAAY2M,GAAAA,GAAAA,EAAAA,eAAAA,EACH+B,MAAA,EAAZ1O,EAAAA,EAAAA,KAAAA,QAAoCW,EAAAgO,KAAZ3O,KAAAA,MAAoC,GAAA4O,GAAZ5O,SAClDuM,gBAAY4B,+BA2ErBvQ,SAAqBC,GAAAA,MAAgBE,EAAAA,OAAAA,CAAAA,IChGxCmQ,GAAUlQ,EAAQuO,WAAOtO,KAIvBsO,GAASsC,qBACPC,EAAO9O,GAAiB,mBAAqBS,sBAClCsO,oBAIJC,qBAA2BC,mBAClCC,QAAAA,gBAAiBlP,0BAA6BA,EAC9CkP,aAAAA,EAAiBlP,qBAAwBiP,KAAAA,KAE3CH,GAASjC,EAAAA,YAAqBsC,GAAgBC,EAC5CrR,GAA+BwJ,SAAQX,EACjC5G,GAAAA,QAAWoP,GAEfJ,EAAmBG,GAAQF,GAAAA,EAAQJ,EAAY7O,OAAAA,cA2D1C6N,KAAAA,GAAAA,KAAAA,OAAsB7N,IAAgBqN,EAAAA,OACzCgC,GAAAA,EAAAA,IAAAA,gBACIC,KAAKtP,GAAAA,CAAAA,EAAchC,EAAOoB,QAAa,UAAA,IAAA,IAAAmQ,KAA6BC,GAAcA,EAAAC,QAAAC,EAA0B,SAClHL,GAAaR,MAAAA,GAAY7O,GAEf,KAAA,IAARoN,GAA8B,KAAA,GAATC,GACnBD,KAAAA,EACKuC,OAAAA,IAAcN,EAAAA,EACVI,QAATpC,oBACMsC,KAAAA,QAAcN,GAAAA,QAGrB,IADDO,EAAmBvC,KAAAA,KAAa6B,QAAAA,YAAiBG,KAAAA,QACrCO,MAAAA,IAAgBA,GAASrI,UACvC,eAAiBqI,YAAY,cACzBC,EAAAA,EAAAA,EAAcD,EAAYrI,QAAG8F,EACdzN,GAAfkQ,KAAAA,IAA4ClQ,EAAhBiQ,EAC1BE,QAAAA,EAAoBH,GAAAA,MAAShJ,EAAAA,GAAGA,GAAGkJ,IAAAA,KAAYD,EAAAA,CAAAA,IACnD,GAAIE,KAAAA,GACEC,CAAAA,GAAAA,GAAeC,KAAAA,EAAAA,QAAoB,GAAA7J,QAAM2J,IAAAA,EAAAA,KAC7C,IAAAN,QAAO,GAASS,QACdC,EACmB9C,KAAAA,MACZ2C,KAAOE,SAKf3D,GAAM0D,MAAAA,GAA2BG,GAAA5J,EAAS6J,MACxCA,KAAejD,QAvGtB8B,GAmBErC,EAAAA,GAAAA,MAAuBA,GAAAA,EAE7BQ,GAAIsC,GAAAA,QACFW,GAAiBlD,EAAAC,EAAAkD,GACjBC,GAAAA,GAAoBC,IACpBC,KAAAA,IAAAA,GAAmBD,EAAA/I,KAAA0I,EACnBO,KAAAA,IAAAA,GAAAA,EAAwBzQ,QACxB0Q,GAAAA,GAAAA,EAAAA,KAAyBR,EACzB/F,OAAAA,GAAAA,EAAmBhI,IAAA,SACnBwO,GAAAA,MAAiBzD,GAAAgD,IACjB9F,IAAAA,EAAAA,EAAiBjI,IACjByO,SAAAA,GAAAA,MAAkBzD,GAAA+C,IAClB7F,KAAAA,EAAAA,EAAkB,SAElBwG,GAAAA,GAAevK,GACfwK,EAAAA,IAAgB,SAAA3L,EAChB4L,GAAAA,MAAAA,IAAAA,EAAqB1J,QACrB2J,IAAAA,EAAsBjQ,KACtBuJ,IAAAA,EAAAA,IAAAA,EAAgB2G,eAEhBC,GAAMX,EAAA7J,KAAA+H,KAAA,MAAA,OACN0C,GAAO9J,OACPkD,EAAAA,QAAUjE,EACVwE,IAAAA,IACAsG,GAAAA,GACAlE,iDAGAmE,EAAAA,EACAC,KAAY,KACZC,GAAAA,QAAaC,EACbC,MAAWC,EAEXC,EAAUjF,KACVkF,KAAAA,GAAW1L,QACX2L,EACAC,KAAAA,MAASC,EACTC,EACAC,KAAAA,KAAAA,qBACc5F,GACd6F,YAAAA,EACAC,EAAAA,qBACcT,EACFrF,EACZc,uBACYd,EACZnB,qBAAYwB,KAAA,KAAAgF,GAEZU,EACAC,WAAAA,EACAC,EAAAA,gBACAC,CACAC,IAAaC,GACbC,EAAQC,qBAkCJhF,KAAAA,KAAAA,GAAwBA,EAE7BjQ,EAAAA,gBAAqBC,KAAAA,OAAgBE,EAAAA,KC9GxC+U,EAAkBvG,EAAOtO,gBAEd8U,KAAAA,OAAWvT,EAEd4D,KAAAA,GAAiBpF,oBAAO+E,CACxBiQ,IAAAA,GAAsB3P,SACjBrF,GAAAA,GAAOgH,GAAAA,EAAsB5B,EAAgBC,OAAAA,IAAW7D,IAOjEgH,EALAwM,GAAAA,EAAAA,GAAWC,QAAAA,EAAgC7P,EAAAA,oBAC3C4P,KAAAA,OAAWE,EAAsB7P,KAC3BQ,EAA8BT,EAAAA,oBAA2B5D,KAC7D,OAAOqE,EAAyBA,IAAUL,GAAAA,yBAKxC2P,EAA0BhF,EAAQnH,qBAAa7I,EAG/C4G,GAFwB/G,oBAAOqC,EAAqBlC,qBACpDqP,EAAuBQ,GAEvBoF,sBAEF5F,qBAAeW,oBAgBjB,qBAbekF,mBAAmBhQ,aAChC0B,YAAAA,SAAeiO,cACS,aAAjBjO,YAETqO,gBAAeE,UAAS/G,EACtBiB,qBAAuBoE,EAEV2B,GAAiB,4BACvBpF,6BAETiF,yBAA4BJ,0BAC5BI,SAAeH,OAAAA,iBAA4BA,gBAC3CG,cAAqBI,eACdJ,aAGHK,aAAa,YACjB,iBAAiB,iBAEbC,eACQ,gBAGZC,cAAWN,cACT,QAAO,eAEEJ,cAAiB,MAC5BU,iBAAWT,kBACTrV,EAES0V,GAAiB,SAC1BhH,EAEKoH,GAAAA,QAQR/V,GAAqBC,GAAgBE,MAAAA,GAAAA,uBClEvBE,IAsBfsO,EAASqH,aAAAA,QAAkBC,GAAQ7T,QAAU8T,GAC3CA,GAAWC,GAAAA,GAAAA,EACXD,aAAWE,EAAAA,OACXnU,EAAOoU,aAAAA,KAAeJ,KAAQ7T,UAAU8T,EAAAA,OAG1CvH,EAAS2H,aAAAA,KAAAA,KAAAA,QAA4BC,EAOnC5V,gBAAK6V,KAAkB1S,KAAAA,EAAyB,MAAA6K,EAAA8H,OAAA9H,EAAgC+H,aAChF/V,KAAKgW,KAASJ,SAAQvS,EACtBrD,OAAKiW,IACLjW,GAAKkW,EAAAA,GAAAA,OAAAA,EAGL,GAAK,OAAW7N,QAAS2N,GAAe3N,EAClC5G,GAAAA,MAAWzB,QAAKgW,GACpBhW,QAAK6V,IAAAA,GAAAA,EAAgBpU,SAAYzB,GAAAA,GAAKgW,GAAOvU,EAAAA,EAE/CzB,CAAKmW,IAAAA,QAAAA,EA+FP,MAASC,MAAAA,IAAAA,GAAAA,EAAqBR,gBACxBA,EAAQS,EAAAA,OAAAA,GAAAA,GAGZC,EAAIC,MAAAA,EAAgBC,gBAAIb,EAAAA,GAAAA,QAA4BC,GACpD3N,GACEoN,MAAAA,QAAkBO,EAAS,IAAA,GAAWa,GAAKzI,EAAa0I,2BACjDC,KAGPf,KAAAA,EAAQvS,EAAa,KAAS5B,GAAUqF,SACtC8O,EAAQvS,EAAM5B,WAAYqF,EAEpBzD,EAAM0R,qBAAkBtT,EAC9BmU,GAAcnU,UAKlBmU,EAAQS,GAA6BT,SAAQvS,EA7J/C3D,GAAIkX,QAAAA,GACFC,GACA7N,MACA8N,UAAAA,GAGEC,GAAAA,GAAAA,CACFC,OAAAA,GAAAA,IAAAA,SACAC,GAAAA,MAAAA,KAAqBN,EACrBO,EAAAA,KAAAA,KACAC,QACAC,GAAAA,GAAAA,MAAgBhV,GAChBiV,QAAAA,GAGEC,GAAAA,GAAAA,EACFF,EAAAA,cACAC,OA6BF1B,QAAAA,EAAAA,QAAAA,KAA4BhP,GAAAA,GAC1BkQ,EACE,uBAAYhB,KAAgBgB,EAElBU,EAAAA,EAEVC,EADIC,KAAAA,IACS,CAAA,GAAOzX,EAAK6V,OAAAA,EAAgB7M,MACvCyO,GAAAA,EAAmBzX,MAAK6V,EAAAA,GAAAA,MAAgBxN,IAE1CrI,GAAK6V,EAAAA,GAAgBgB,EACrB7W,EACA0X,EAAgBrP,KAAIrI,EAAK6V,MAAgB7M,IAAAA,GACvCyO,EAAAA,GAAAA,MAAAA,KAAmBzX,EAAK6V,EAAgBxN,EAAM,IAEhDsP,EAASlW,OAAAA,EAAYgW,OAAAA,MAAAA,KACdzX,GAAKkW,MAAAA,EAAAA,EAAAA,EAAoBzU,EAAAA,OACvBuU,IAAAA,CAAAA,GAAOqB,GAAY5V,EAAAA,EAAUzB,GAAAA,EAAK6V,EAAAA,EAAAA,IAAgBqB,EAAAA,GAAiBzV,EAAAA,SAAAA,GAI9EuH,MAAIA,KACF4O,EAAAlI,OAAO1P,EAAK6V,EAAAA,WAAgB7M,IAAAA,EAE9B8N,EAAIA,YACFe,EAAA7J,EAAOhO,qBAGTmW,EAAAA,EAAAA,aAAgBjM,EACdsG,eAAYyF,IAAUjW,EAAK6V,EAAAA,EAAAA,EAAgB7M,GAAAA,EAAAA,GACzC1H,GAAOoU,SAAAA,EAAqB1V,MAAKiW,GAC/BR,KAAAA,GACAD,GAAAA,EACAiB,MAAK9E,EAAA+F,EACHvV,EAAA2V,IAAoBN,EAAY3B,WAAAA,EAAgBkC,OAC/C/X,MAAKiW,IAEVjW,QAAKiW,GAEKA,GAAUjW,MAAK6V,GAAAA,QAAAA,GAAgB7M,QACzChJ,UAAKiW,IAAAA,QACEP,GAAe1V,EAAMA,GAAKiW,GAAAA,EAC/BR,oBACAD,EAAAA,CAAY3G,EACZ/H,kBAIAgI,CAAA,IAASrN,GAAUqF,EACvB9G,wBAAwB8G,GACxB9G,GAAKkW,EAAAA,oBAAoBzU,EAAY,CAAAqN,EAEvCiG,kBAAiBtT,CACfzB,IAAKgW,GAAOvU,EAAAA,wBAAiCA,GAAAA,MACtCzB,OAAKkW,EAAAA,IAAAA,MAAAA,EAAoBzU,MAKpC,KAASuW,GAAAA,SAAUjB,GAAAA,MAAAA,GACjBpB,EAAAA,GAAAA,EAAAA,EAAAA,GAAAA,KAAAA,EAA4BhP,GAAAA,KAAUqR,GAAAA,EAAoBA,GAAAA,KAAQC,IAAAA,EAAAA,EACzD,SACLC,GAAIjQ,GAAAA,GAASjI,EAAK6V,KAAAA,EAAgBmC,GAAAA,GAAQpU,EAAWiS,GAAAA,GAAAA,EAAAA,IAAAA,EAAiBsC,EAAAA,cAClEF,EAAAA,GAAAA,EACGjY,GAAKkW,EAAAA,GAAAA,EAAAA,EAAAA,IAAoBiC,EAC5BnY,EAAKgW,IAAAA,GAA0BA,KAAAA,IAAQmC,OAAAA,MACpChC,QAEAlO,GAER+P,GAAQA,MAAUV,GAAAA,QAAAA,OAAAA,IAIvB,QAAS7V,GAAY0B,GAAAA,MAASiV,GAAAA,QAAgB/U,eACxC5B,MAAYmV,QAAAA,GAA+BG,EAAAA,GAAAA,GAG/CsB,GACEhD,EAAAA,0BAAkBM,EAAAA,GAA4BhP,CAAAA,KAAAA,EAAWlF,SACvDgV,EAAKzN,OACH,CAAA6F,EAAO7O,SAAK6V,GAAgBpU,EAAAA,EAAAA,EAE9B6W,KAAcxR,KAAAA,GACZ9G,GAAAA,EAAK6V,EAAAA,EAAAA,OAAAA,IAAgBpU,CAAAA,GAAAA,GAAYqF,EACjC9G,GAAAA,EAAKmW,EAAAA,EAAAA,GAAAA,EAAAA,EACKD,SAAAA,EAAoBzU,OAAAA,EAAAA,GAC5BzB,EAAAA,CAAKgW,GAAAA,MAAOvU,EAAAA,EAAYqF,EAAAA,EAAAA,IAG7BrF,SAyBLuM,GAAMpK,GAAAA,gBAAiBgS,GAASnU,MAAAA,EAC9B2U,IAAAA,KAAAA,KAAqBR,GAAAA,KACrBA,GAAQvS,EAAMkV,GAAKvK,CAAMwK,OAAa/W,QAAWqF,GAGnDkH,GAAuB4H,SAASnU,EAAAA,GAC1BmU,MAAAA,eAAQS,GAAAA,eACVT,IAAQvS,UAAM0R,GAAO/G,YAAMwK,KAAa/W,UAAAA,GAO3CnC,YAAgBE,IAAAA,KAAAA,KChLTwO,IACRrE,IAAO8O,EAAAA,QAAQ9R,EAAU+R,OAAU,CAAA,IAAAL,EAAsBM,MACnD1D,IAAKqB,GAITsC,EAHeD,EAAAA,EACb1D,IAAaA,EAERjH,IAAM6K,GAAe7K,EAAM4G,IAAAA,IAAAA,UAAqBnM,EAAAA,UAAsBwM,KAAAA,GAE9E3V,GAAAA,EAAAA,EAAAA,EAAAA,OCRH+I,IAAU2F,CAAAA,GAAAA,GAAOtO,EAEfmP,EAASiK,GAAAA,EAAAA,EAAYhP,EAAUzH,GAC7BsP,EAAoBoH,EAAAlK,EAAAxG,GAARyB,EAAAA,EAAmCgF,EAAAzG,GAAAlG,EAAN6W,EACxBC,EAEGC,GAARpP,EAAoCmP,EACvC5W,EAOT,IAAIyH,EAA0BoP,EACxBjL,GACgBnE,CAAAA,IAAKd,EAChB8P,MAAAA,IAAYhP,GAASkP,GAE9BnK,EAEFxG,KAAMyG,EAAAzG,IAAA8Q,GAAAhQ,KAAAmN,EAAA,IAAwCxM,EAGhDkE,KAAM0D,EAAAA,IAAAA,EAAgBvI,MAASW,UAAUsP,EAAAA,UACvC,CAAA,GAAOF,GAAS7W,EACP+W,EAAAA,MAAgBN,IAAAA,EAAsBzW,IAQhD/C,EAAgBE,IAAAA,EAAAA,IClCnB6Z,EAAUrL,GAyFR9D,EAAAmP,EAAejX,GAAQkX,EACd5W,EAAkBN,GAAGkX,GAG9BC,EAASC,EACP,GAAIC,OAAgBC,CAAAA,IAAIC,EACdxJ,KAAMsJ,EAEZD,IAAAA,EACYN,IACdM,EAAOG,GAKF,CAAA,IAHDC,EAAkBH,MACd/W,IAAAA,GAAakX,EAAkBC,EAASJ,EAAAA,IAEnCnD,EAAUjO,IACrBmR,GAAUG,EAAYjX,IAAKoX,IAAQF,UAASH,EAClCM,KAASC,OAGvB9P,EAAOsP,EA5GLS,GAAAA,EAAgBC,EACTC,GAAAA,GAEPZ,EADItR,EAA4B,GAAMsR,GAAc,IAAK,GAAMa,MACxC/R,KACEqB,KACE2Q,EAAAA,EACrBpS,EAAAA,EAAUyB,OAAW2Q,IAAKrY,CAAEqY,GAAG3Q,GAIrC,gBAGFqP,GAAcjZ,GACZkO,EACesM,aACAtM,EAANwI,gBAEMF,EAATiE,EACSxB,EAANrP,GACM6P,EAAN7P,GACL5J,GACAA,GAAEwW,EACS,GAATkE,EACA9Q,GAAG4M,EAGX,GAAS2D,EAAcQ,KAAAA,EAAkBC,IAAAA,EAAYC,KAAAA,GAC/CC,EAAoBzR,KAAKqR,GAAuBK,EAAQ1R,MAAMe,EAErD4Q,KACD,GAAKH,EAGjB,CAAA,GAAKI,GAAI1S,CAAcA,GACR2S,EACXJ,EAAgBH,EAAAA,OAAU/Q,EAAYA,EAIlC8P,SAAaA,GAAK,MAAQA,GAASQ,IAAIR,SAE3CyB,EAAAA,GAAc,GAAMC,GAAsBC,EAAMrX,IAAG,SAAcsX,EAErEH,GAAAA,MAAUJ,GAAYxS,GAAKgT,GAAIA,GAAQC,KACvCL,KAAAA,IAAa,OAAU7Y,UACvB6Y,EAAAA,GAAU,IAAG,IAAU7Y,EACvB6Y,MAAa,KAAKjS,SAAiBgR,EACnCiB,GAAAA,GAAU,YAAqB7Y,EAAQkZ,GACvCL,GAAAA,IAAAA,EAAmCjB,MACnCiB,KAAAA,OAAa,GAAU7Y,GAAIkZ,KAAQtB,GACnCiB,GAAAA,GAAAA,GAAaM,IAAUF,GAAIC,GACdV,QAAcxY,UAE3BwY,EAAAA,EAAAA,EAAST,EAAAA,EAAAA,EAAAA,EAASS,EAAAA,EAAAA,EAAAA,EAAQK,EAAAA,EAAAA,EAAAA,EAAAA,GAE1BhG,GAAIuG,UAAe,mBAAyBvG,GAAMwG,QAAW,KACzDf,SAAK,KACPc,SAAad,KAAKgB,SACTvB,KAAAA,UAAiBqB,QAGxBd,aACFc,KAAQG,OACRH,KAAQI,GAAKlB,EAAK/D,EAAA,IAClBiE,GAAST,QAAAA,IAASS,GAAQY,EAAAA,EAAAA,IAGxBd,GAAK/D,EACP6E,KAAKK,QACLL,IAAKI,GAAQlB,EAAAA,EAAAA,IACbE,GAAAA,EAAST,KAAAA,QAASS,IAAQY,GAG5B,EAAA,EAAK7E,KAAQmF,SAAUzT,MAChB4M,GAAIvL,MAAOA,KACdkR,KAAAA,GAAOvS,OAASsT,IAAMtT,KAI1BuT,GAAIG,EAAAA,KAAKnB,OACCA,IAAO,KAAOA,GAAAA,EAAUjE,KAAIiE,WAAcA,KAAAA,GAAUjE,EAAIiE,EAAAA,IAAO3F,GAAO2F,YAAU,IAEnFA,GAAOjE,EAAGqF,EAAAA,IAAOpB,GAAOjE,EAAIiE,KAAOqB,YAAW,IAEvDL,GAAO3B,EAAAA,EAAAA,IAAAA,GA0BTjM,EAAMiM,KAAAA,YAAgBA,IAAAA,GACtBjM,EAAAA,EAAMwL,KAAOA,aAEZla,MAAgBE,GAAAA,GAAAA,qBCnHTC,EAAeC,GAEhBwc,eAEP5c,EAAI6c,GAAkCC,SAAaC,GAAAA,QACjDrc,GAAK4P,GAASA,GACd5P,GAAKoc,OAAAA,EAAcA,OAAAA,OACnBpc,IAAKqc,IAAAA,GAAeA,EAAAA,KAAAA,EAEpBrc,MAAKkK,EAHckS,OAGPE,EACZtc,QAAKuc,GACLvc,GAAKwc,MAAAA,GACLxc,IAAKyc,KAAAA,MAAAA,EAAgB7M,KACrB5P,EAAK0c,EAAAA,MAAAA,IAAmB,IACxB1c,GAAK2c,MAAAA,EAAaC,SAAMC,MACxB7c,EAAK8c,OAAYvP,OAAKwP,GAGxB/O,QAAMgP,GAAYnO,EAAAC,GAAS9N,OACpBiU,EAAKnG,EACN9N,GAAUA,EAAOic,qBACFA,EAEnBjd,GAAKkd,iBAAyBhB,GAAAA,SACzBiB,GAAAA,QACLnd,GAAkBod,GACbC,GAAUpV,KACV1H,KAAAA,GAAAA,KACLP,GAAKsd,EAAAA,IACLtd,EAAKud,EAAAA,OAAgBtV,GAChBuV,QAAWC,GACXC,GAAAA,MACL1d,GAAK+G,aACL/G,qCAAsCiR,IACjC0M,EAAQC,uBACRC,GAGP7P,QAAMgP,GAAUrW,EACdmX,GAAAA,GAAc7V,GAAA+F,EAIRhO,gBAAoByd,EAAUrB,IAAAA,EAChCpc,IAAK+d,GAAAA,IAAY/d,EAAK+G,GAAAA,CAAQ+N,GAAAA,GAAQ7M,EAEjC8V,EAAAA,IAAAA,EAAY/d,GAAK+G,EAAQ+N,IAAAA,SAAasH,EAAAA,GAAAA,EAEnCkB,IAAAA,SAAAA,GAAgBtd,IAAK+d,EAAc/d,GAAAA,EAAKud,KAAAA,GAAAA,IAChDvd,EAAKsd,QAAAA,EACLtP,CAAAA,GAAM6K,aAASmF,KAAAA,EAAiBhe,KAAAA,aAGpCie,KAAAA,EAAkB,IAASC,CAAAA,GAAAA,GAASC,EAAAA,EAAAA,GAC9BD,GAAAA,EAAgBf,GAAAA,EAAAA,GAAAA,EAClBnd,GAAKmd,2BACIiB,KAAAA,EAAgBD,KAAAA,2BACHne,KAAKO,EAAAA,IAAAA,MAAoBP,GAAK0U,IAAAA,SAAiB2J,GAChEP,MAAAA,gBAGL1B,GACFiC,EAAIre,EAAcA,OAAK6d,QAAAA,GAEXV,GAAAA,GAEVf,GAAAA,EAAY8B,gBACdA,EACI9c,IAAM8c,EAAAA,IAEVlQ,EAAMsQ,CAAAA,IAAAA,GACDte,GAAKqd,EAA8B,GAAAf,IAAdiC,IAAAA,KAAAA,IACxBve,KAAKue,EAAAA,EAAAA,GAAkBC,EAAAA,EAAAA,EAAUpC,EAAAA,EAAAA,OAAc8B,IAAUle,CAAAA,GAAKO,GAAAA,EAAAA,EAEhEP,iBAAK6d,IAAsBY,EAClBtB,eAAgBe,KAEzBle,GAAKie,GAAAA,KAAAA,EAAiBC,MAAAA,EAAAA,OACtBlQ,EAAM0Q,IAAAA,EAAAA,OAAAA,GAAAA,GAERxP,EAAIA,GAAAA,EACFyP,GAAO3e,UAAKue,GAEVrP,MAAAA,IACFgP,EAAWA,EACDA,GAENle,EAAKqd,MAAAA,EAAgBM,MAAAA,GAEzB3d,KAAKue,EAAAA,GAAAA,EAAaL,IAClBle,GAAKie,GAAAA,OAAuBO,EAAAA,EAAUpC,KAAAA,QAAcpc,GAAmBA,GAAK0E,GAAAA,GAC5EsJ,EAAM0Q,gBAAAA,EAEJha,KACFuM,EAAOjR,OAAKO,IAAAA,IAEdmE,EAAIA,GAAAA,EAAaoC,GAAAA,OACXA,GAAAA,IAAcvG,MAAAA,IAAAA,GAGlBqe,QAAIC,IAAAA,IAAAA,OAAsBzC,IAAAA,KAAAA,KAC1Bpc,IAAKO,GAAAA,QAAAA,IAAgBuG,MACrB9G,EAAkBgO,EACI8Q,oBAAbC,KAA2C,KAAA/Q,EAAb+Q,gBAChCC,IAAAA,GAEe1Q,qBACpBtO,EAAKoc,KAAcyC,KAAAA,GAAAA,GAGnBT,qBACWT,EAAAA,qBAA+BsB,EAAU9B,KAAAA,KAAgBnd,GAAAA,GAAK0U,uBAC7C1U,EAAKmd,gBAAgB+B,EAEjDxK,EAAmByK,gBAAYpY,CAAQ2N,IAC3CqK,GACE/Q,EAAIhO,oBAEoBqO,KAAnBrO,KAAKue,EAA4BlB,KAAAA,GAAWrd,qBAA2BA,EAAK6d,GAE7E7d,sBAEAA,qBACKV,GAGX0f,SAAMhR,GACJhO,QAAKqd,GACIe,GAAAA,GAAAA,GAAoBT,EAAAA,aACtBR,UAAend,EAAKO,IAAAA,GAAgB6e,EAAQpf,GAAK0U,OAAAA,UACtD1U,OAAKue,EAAac,aAEf9B,EAAAA,OAAgBvP,EAChB2P,aACL3d,KAAK8d,OAAAA,QACL9P,EAEFsR,EAAOxJ,OAAA9H,EACAhO,aAAKoe,KAAgBpe,OAAKqd,QAAYrd,EAAK2d,gBACzCE,EAAAA,OAAAA,EAEP7d,aAAKue,KAAa,OACblB,SAAU+B,EAEjBG,IAAQ,IAAAC,GACFxf,EAAK2d,aAEJvB,WAAcpc,EAAKO,IAAAA,GAAoBP,EAAK0U,GAAAA,OAAiB,WAC7D6J,OAAave,EAAK0U,aAAAA,EAAsB0H,OAAAA,EAC7Cpc,aAAK6d,KAAAA,OAAsB,QACrBa,EAERe,EAAQ3J,OACD9V,EAAK+d,aAEV/d,KAAK+d,OAAAA,QACL/d,EAAK2d,gBACAJ,EAAAA,OACLvd,EAAKoc,aACLpc,KAAKue,OAAAA,SACLve,EAAK+G,IAAQ+N,IAAAA,GAGb9G,EAAM0Q,aAAAA,WAERgB,EAAS,OAAAC,IACFjb,EAAAA,IAAgB,WAChBsa,OAEPY,EAAAA,aAAkB5R,EAAS9D,OAAM2V,EACT9J,aAAA1H,KAAXwR,OAAAA,QAAiC7R,EAAR9D,SAClClK,EAAK0d,aAAgBvU,KAAK0W,OAAAA,6BAET,YAAeA,EACtBtL,oBAERwD,EAAQ/X,OAAK0d,EAAAA,aAAgB/b,KAAQke,OACrC9H,SAAS4H,EACNjC,KAAAA,OAAAA,QAAuB3F,GAEhC+H,EAAAA,GAAa,MAAAjR,GAASkR,KAAAA,EAChB/f,GAAKoe,UAAAA,EACP,GAAKpe,EAAKud,UAAAA,EACR1Z,MAAImc,GAAQlR,EAAIqN,MAAAA,IAAAA,UAAqBnc,EAAKmd,gBAAc4C,OACpD1O,EAAWrR,gBAAK0d,MAAgB1B,WAAYwB,EAAAA,GAAAA,EAAiBA,UAAAA,EACjEyC,MAAAA,GAAAA,EAAWpc,MACTwN,IAAAA,WAAS7P,EAAQ0e,yBACPC,OAAKH,EAAMpQ,gBAGvB5P,MAAKud,WAAAA,EAAgB,IAGvBvd,EAAAA,IAAKud,EAAAA,GAAAA,EAGT6C,UAAOvR,EAASwN,MAAAA,GAAAA,EAAcgE,MAAAA,IAAAA,WAClB1C,EAAAA,GAAU3d,EACK,MAAnBA,OAAKue,OACH8B,GAAAA,GACGnR,EAAYmN,qBAAoBc,KAAAA,KAAend,EAAK0E,sBAE5C0Z,EACVH,EAAkB5B,gBAAoBkC,KAAAA,OAAcve,EAIzDqgB,KAAAA,EACFrgB,EAAK6d,oBACL7d,KAAK8f,OAAAA,EAAYzD,gBAGrBiE,KAAIA,EACMtgB,EAAK+e,oBAAyB1Q,KAAGkS,OAAWC,EAAajD,IAAAA,GAQpEle,qBAAqBC,EAAAA,GAAgBE,mBC5NxCF,GAAyBI,SAqBvBsO,EAASyS,GAAAA,QAAAA,GACPpW,EAAIqW,GAAAA,EAAaC,QACjBA,IAAAA,QACIhP,SAAIkH,GAASuD,IACXvD,UAASuD,gBACP/Y,QACRqd,EAAWlf,GAAQof,KAASC,GAASA,KACrCC,GAAAA,aAAAA,kBAIF,gBAASC,EAAAA,mBAAiCC,0BACjCC,EAAAA,eAAc/D,sBAAiCA,EAAAA,qBAG/CgE,4BACFlD,EAELhe,aAAKoc,SAAczS,GAAOwX,MAAeA,GAAAA,IAAkBA,IAAYpE,EA8ChE+D,OCtFX,WAEE,GAA2Dzf,SAAvD8B,SAASC,cAAc,OAAOsV,YAAY0I,SAA9C,CAKE,GAAIrE,EACC,IAAIpT,OAAOwX,aAAeA,YAAYpE,IAC3C,GAAIA,GAAM,WAAa,MAAOoE,aAAYpE,WAE1C,IAAIA,GAAM,WAAa,MAAOxP,MAAKwP,MAGrC,IAAIsE,GAAuB,SAASzR,EAAQwM,EAAaC,GACvDrc,KAAK4P,OAASA,EACd5P,KAAKoc,YAAcA,EACnBpc,KAAKqc,aAAeA,EAEpBrc,KAAKkK,KAAO,SACZlK,KAAKuc,SAAAA,EACLvc,KAAKwc,YAAAA,EACLxc,KAAKyc,cAAgB7M,EACrB5P,KAAK0c,kBAAAA,EACL1c,KAAK2c,WAAaC,MAAMC,UACxB7c,KAAK8c,UAAYvP,KAAKwP,OAGpBuE,EAAyB3X,OAAO8O,QAAQ9R,UAAU+R,OACtD/O,QAAO8O,QAAQ9R,UAAU+R,QAAU,SAASjQ,EAAakQ,GACvD,GAAI4I,GAAYD,EAAuBnB,KAAKngB,KAAMyI,EAAakQ,EAE/D4I,GAAUC,mBACVD,EAAUH,SAAW,IAErB,IAAIK,GAAiBF,EAAU9B,MAC/B8B,GAAU9B,OAAS,WACjBgC,EAAetB,KAAKngB,KACpB,IAAIggB,GAAQ,GAAIqB,GAAqBrhB,KAAM,KAAM+c,KAC7C1L,EAAWrR,KAAKwhB,gBAAgBxF,OAAOhc,KAAKohB,UAAYphB,KAAKohB,aACjEnB,YAAW,WACT5O,EAAS7P,QAAQ,SAASqe,GACxBA,EAAQM,KAAKH,EAAMpQ,OAAQoQ,MAE5B,GAGL,IAAI0B,GAA2BH,EAAU3B,gBACzC2B,GAAU3B,iBAAmB,SAAS1V,EAAM2V,GACpB,kBAAXA,IAAiC,UAAR3V,EAClClK,KAAKwhB,gBAAgBrY,KAAK0W,GAE1B6B,EAAyBvB,KAAKngB,KAAMkK,EAAM2V,GAG9C,IAAI8B,GAA8BJ,EAAUK,mBAW5C,OAVAL,GAAUK,oBAAsB,SAAS1X,EAAM2V,GAC7C,GAAY,UAAR3V,EAAkB,CACpB,GAAI6N,GAAQ/X,KAAKwhB,gBAAgB7f,QAAQke,EACrC9H,IAAS,GACX/X,KAAKwhB,gBAAgBK,OAAO9J,EAAO,OAErC4J,GAA4BxB,KAAKngB,KAAMkK,EAAM2V,IAI1C0B,OClEX,SAAU9hB,GAgBR,GAAImW,GAAUzS,SAASiV,gBACnBmJ,EAAY,KACZO,GAAAA,CACJ,KACE,GAAIC,GAAkBC,iBAAiBpM,GAASsB,iBAAiB,WAC7D+K,EAAiC,KAAnBF,EAAyB,IAAM,GACjDR,GAAY3L,EAAQ8C,SAASjF,SAAYwO,EAAaA,KACjD9gB,SAAU,IACfogB,EAAUnF,YAAc,EACxB0F,EAAWE,iBAAiBpM,GAASsB,iBAAiB,YAAc+K,EACpE,MAAOC,IACP,QACIX,GACFA,EAAU9B,SAEd,IAAIqC,EAAJ,CAIA,GAAIR,GAAyB3X,OAAO8O,QAAQ9R,UAAU+R,OACtD/O,QAAO8O,QAAQ9R,UAAU+R,QAAU,SAASjQ,EAAakQ,GAUvD,MATIhP,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,IAAgC,OAAhBA,IACjCA,EAAchJ,EAAO+I,mBAAmBC,IAGnC6Y,EAAuBnB,KAAKngB,KAAMyI,EAAakQ,MAEvDtZ,IC/CH,SAAUI,EAAQuO,EAAOtO,GA8DvB,QAASyiB,GAAsBxQ,GAC7B,GAAIkH,GAAWlP,OAAOxG,SAAS0V,QAC/BA,GAASuD,YAAczK,EACvBkH,EAASuJ,qBAC0B,GAA/BvJ,EAASmF,YAAYhV,OACvBqZ,GAAAA,EAEAC,sBAAsBH,GApE1B,GAAII,GAAgC5Y,OAAO2Y,qBAC3C3Y,QAAO2Y,sBAAwB,SAASjgB,GACtC,MAAOkgB,GAA8B,SAASngB,GAC5CuH,OAAOxG,SAAS0V,SAAS2J,4BACzBngB,EAAED,GACFuH,OAAOxG,SAAS0V,SAAS2J,+BAI7BxU,EAAMyU,kBAAoB,WACxBziB,KAAKge,eACLhe,KAAKoc,YAAc/a,QAGrB2M,EAAMyU,kBAAkB9b,WACtB+b,cAAe,WAEb,MADA1iB,MAAKoiB,qBACEpiB,KAAKge,YAAYna,SAE1B2e,0BAA2B,WACzBxU,EAAM2U,uBAAyB3U,EAAM2U,uBAAuBjY,OAAO,SAAS6W,GAC1E,MAAOA,GAAUqB,qBAGrBR,mBAAoB,WAClBpiB,KAAKwiB,4BACLxiB,KAAKge,YAAche,KAAKge,YAAYtT,OAAO,SAAS6W,GAClD,MAA8B,YAAvBA,EAAUxC,WAAkD,QAAvBwC,EAAUxC,aAG1D8D,MAAO,SAAS7hB,GACd,GAAIugB,GAAY,GAAIvT,GAAMgP,UAAUhc,EAAQhB,KAW5C,OAVAA,MAAKge,YAAY7U,KAAKoY,GACtBvT,EAAM8U,+BAMNvB,EAAUqB,kBACVrB,EAAUra,WAAW8X,OACrBuC,EAAUqB,kBACHrB,GAETvC,KAAM,SAAShe,GAIb,MAHIA,IACFA,EAAO+hB,SAEF/iB,KAAK6iB,MAAM7hB,IAItB,IAAIqhB,IAAAA,CAEJrU,GAAM8U,6BAA+B,WAC9BT,IACHA,GAAAA,EACAC,sBAAsBH,IAc1B,IAAItJ,GAAW,GAAI7K,GAAMyU,iBACzBzU,GAAM6K,SAAWA,CAEjB,KACEvX,OAAOoU,eAAe/L,OAAOxG,SAAU,YACrCsS,cAAAA,EACAgB,IAAK,WAAa,MAAOoC,MAE3B,MAAOmK,IACT,IACErZ,OAAOxG,SAAS0V,SAAWA,EAC3B,MAAOmK,MAER3jB,EAAqBE,EAAmBC,GCtF3C,SAAUC,EAAQuO,EAAOtO,GACvBsO,EAAM2U,0BAEN3U,EAAMgP,UAAY,SAAShc,EAAQ6X,GASjC,GARA7Y,KAAKiV,GAAK,GACNjU,GAAUA,EAAOic,MACnBjd,KAAKiV,GAAKjU,EAAOic,KAEnBjd,KAAKgB,OAASA,EACVA,IACFA,EAAOkG,WAAalH,OAEjB6Y,EACH,KAAM,IAAI9K,OAAM,gDAElB/N,MAAKwe,UAAY3F,EACjB7Y,KAAKkd,gBAAkBzd,EAAOyc,iBAC9Blc,KAAKijB,UAAY,EACjBjjB,KAAKqd,SAAAA,EACLrd,KAAKkjB,UAAAA,EACLljB,KAAKkH,WAAa,KAClBlH,KAAKmjB,oBACLnjB,KAAKojB,UAAY,KACjBpjB,KAAKqjB,cAAgB,OACrBrjB,KAAKmH,8BAELnH,KAAKkH,WAAWuY,SAChBzf,KAAK4iB,mBAGP5U,EAAMgP,UAAUrW,WACdic,gBAAiB,WACf,GAAIU,GAAetjB,KAAKqjB,cACpBE,EAAevjB,KAAK+e,SAsBxB,OArBI/e,MAAKwjB,eAAiBD,IAAiBD,IACrB,QAAhBC,GACFvjB,KAAKyjB,sBACLzjB,KAAKwjB,cAAgBniB,QACI,WAAhBiiB,EACTtjB,KAAK0jB,uBACoB,WAAhBH,IACTvjB,KAAKwjB,cAAgBniB,SAGrBrB,KAAK2jB,kBAAoBJ,IAAiBD,IACxB,QAAhBC,GACFvjB,KAAK4jB,yBACL5jB,KAAK2jB,iBAAmBtiB,QACC,YAAhBkiB,EACTvjB,KAAK6jB,0BACoB,YAAhBP,IACTtjB,KAAK2jB,iBAAmBtiB,SAG5BrB,KAAKqjB,cAAgBrjB,KAAK+e,UAClB/e,KAAKwjB,eAAiBxjB,KAAK2jB,kBAErCxc,4BAA6B,WAC3BnH,KAAK4iB,iBACL,IAAIkB,GACAC,EACAC,EACAnF,EACAoF,IAAgBjkB,KAAKkH,UACrB+c,KACFH,EAAkB9jB,KAAK0E,aACvBqf,EAAY/jB,KAAKqd,QACjB2G,EAAehkB,KAAKkP,UACpB2P,EAAiB7e,KAAKoc,YACtBpc,KAAKkH,WAAWuY,SAChBzf,KAAKkH,WAAWgd,SAAW,KAC3BlkB,KAAKkH,WAAa,QAGflH,KAAKgB,QAAUhB,KAAKgB,iBAAkB2I,QAAOiL,kBAChD5U,KAAKkH,WAAa8G,EAAMmW,wCAAwCnkB,KAAKgB,QACrEgN,EAAMoW,+BAA+BpkB,QAEnCA,KAAKgB,iBAAkB2I,QAAO0a,gBAAkBrkB,KAAKgB,iBAAkB2I,QAAO2a,eAChFtkB,KAAKkH,WAAa8G,EAAMuW,+BAA+BvkB,KAAKgB,QAC5DgN,EAAMwW,sBAAsBxkB,OAE1BA,KAAKgB,QAAUhB,KAAKgB,OAAOyjB,WAC7BzW,EAAM0W,6BAA6B1kB,MAEjCikB,IACqB,GAAnBH,IACF9jB,KAAK0E,aAAeof,GAED,OAAjBE,EACFhkB,KAAKkP,UAAY8U,EACW,OAAnBnF,EACT7e,KAAKoc,YAAcyC,EACS,OAAnB7e,KAAKijB,YACdjjB,KAAKoc,YAAcpc,KAAKijB,WAEtBc,GACF/jB,KAAKsf,SAGTtf,KAAK4iB,mBAEP+B,gBAAiB,WACf,GAAK3kB,KAAKgB,QAA4B,QAAlBhB,KAAK+e,UAAzB,CAGA,GAAI9V,GAASjJ,KAAKgB,OAAOiG,QAAQjC,KACjChF,MAAKmjB,iBAAiB3hB,QAAQ,SAASojB,GACrC5kB,KAAK6kB,iBAAiBD,EAAgB3b,GAClCjJ,KAAKgB,iBAAkB2I,QAAO0a,iBAChCpb,GAAU+E,EAAM8W,mBAAmBF,EAAe5jB,UACpDqN,KAAKrO,SAET+kB,sBAAuB,SAASxD,GAC9B,GAAKvhB,KAAKgB,QAAWhB,KAAKkjB,SAE1B,IAAK,GAAI7a,GAAI,EAAGA,EAAIrI,KAAKgB,OAAOgkB,SAAShc,OAAQX,IAC/CrI,KAAKgB,OAAOgkB,SAAS3c,GAAGnB,WAAaqa,EACrCvhB,KAAKmjB,iBAAiB9a,GAAG0c,sBAAsBxD,IAGnD0D,0BAA2B,WACzB,GAAKjlB,KAAKgB,QAAWhB,KAAKkjB,SAA1B,CAEA,GAAIja,GAASjJ,KAAKgB,OAAOiG,QAAQjC,KACjChF,MAAKklB,yBACLllB,KAAKgB,OAAOgkB,SAASxjB,QAAQ,SAAS2jB,GACpC,GAAIP,GAAiBjb,OAAOxG,SAAS0V,SAASgK,MAAMsC,EACpDnlB,MAAKmjB,iBAAiBha,KAAKyb,GAC3BA,EAAelgB,aAAe1E,KAAK0E,aAC/B1E,KAAKqd,SACPuH,EAAetF,QACjB6F,EAAMje,WAAalH,KAAKgB,OAAOkG,WAE/BlH,KAAK6kB,iBAAiBD,EAAgB3b,GAElCjJ,KAAKgB,iBAAkB2I,QAAO0a,iBAChCpb,GAAU+E,EAAM8W,mBAAmBK,KACrC9W,KAAKrO,SAET6kB,iBAAkB,SAASD,EAAgB3b,GAClB,OAAnBjJ,KAAKkP,UACP0V,EAAexI,YAAcpc,KAAKoc,YAAcnT,EAASjJ,KAAK0E,aACrDkgB,EAAe1V,YAAclP,KAAKkP,UAAYjG,EAASjJ,KAAK0E,eACrEkgB,EAAe1V,UAAYlP,KAAKkP,UAAYjG,EAASjJ,KAAK0E,eAG9DmU,GAAIA,YACF,MAAO7Y,MAAKwe,WAEdO,GAAIA,aACF,MAAO/e,MAAKkH,WAAalH,KAAKkH,WAAW6X,UAAY,QAEvDqG,GAAIA,YACF,MAAKzb,QAAO0b,SAIPrlB,KAAK2jB,mBAC0C,IAA9C3V,EAAM2U,uBAAuBhhB,QAAQ3B,OACvCgO,EAAM2U,uBAAuBxZ,KAAKnJ,MAEpCA,KAAK2jB,iBAAmB,GAAI0B,SACxB,SAASC,EAASC,GAChBvlB,KAAK6jB,wBAA0B,WAC7ByB,EAAQtlB,OAEVA,KAAK4jB,uBAAyB,WAC5B2B,GAAQrb,KAAMC,aAAaqb,UAAWnb,KAAM,iBAE9CgE,KAAKrO,OACW,YAAlBA,KAAK+e,WACP/e,KAAK6jB,2BAGF7jB,KAAK2jB,mBApBVhW,QAAQC,KAAK,6DACN,OAqBX6X,GAAIA,SACF,MAAK9b,QAAO0b,SAIPrlB,KAAKwjB,gBAC0C,IAA9CxV,EAAM2U,uBAAuBhhB,QAAQ3B,OACvCgO,EAAM2U,uBAAuBxZ,KAAKnJ,MAEpCA,KAAKwjB,cAAgB,GAAI6B,SACrB,SAASC,EAASC,GAChBvlB,KAAK0jB,qBAAuB,WAC1B4B,EAAQtlB,OAEVA,KAAKyjB,oBAAsB,WACzB8B,GAAQrb,KAAMC,aAAaqb,UAAWnb,KAAM,iBAE9CgE,KAAKrO,OACY,YAAnBA,KAAK+e,WACP/e,KAAK0jB,wBAGF1jB,KAAKwjB,gBApBV7V,QAAQC,KAAK,6DACN,OAqBX4P,GAAIA,YACF,MAAOxd,MAAKkH,WAAWsW,UAEzBA,GAAIA,UAASkI,GACK,kBAALA,GACT1lB,KAAKkH,WAAWsW,SAAW,SAAUwF,GACnCA,EAAEpT,OAAS5P,KACX0lB,EAAEvF,KAAKngB,KAAMgjB,IACZ3U,KAAKrO,MAERA,KAAKkH,WAAWsW,SAAWkI,GAG/BtE,GAAIA,YACF,MAAOphB,MAAKkH,WAAWka,UAEzBA,GAAIA,UAASsE,GACK,kBAALA,GACT1lB,KAAKkH,WAAWka,SAAW,SAAU4B,GACnCA,EAAEpT,OAAS5P,KACX0lB,EAAEvF,KAAKngB,KAAMgjB,IACZ3U,KAAKrO,MAERA,KAAKkH,WAAWka,SAAWsE,GAG/BtJ,GAAIA,eACFpc,KAAK4iB,iBACL,IAAIxG,GAAcpc,KAAKkH,WAAWkV,WAElC,OADApc,MAAK4iB,kBACExG,GAETA,GAAIA,aAAYsJ,GACd1lB,KAAK4iB,kBACL5iB,KAAKkH,WAAWkV,YAAcnS,SAASyb,GAAKA,EAAIhjB,KAAKijB,KAAKD,GAAK3hB,OAAO6hB,UACtE5lB,KAAK6lB,YACL7lB,KAAK8lB,cAAc,SAASX,EAAOlc,GACjCkc,EAAM/I,YAAcsJ,EAAIzc,IAE1BjJ,KAAK4iB,mBAEP1T,GAAIA,aACF,MAAOlP,MAAKkH,WAAWgI,WAEzBA,GAAIA,WAAUwW,GACZ1lB,KAAK4iB,kBACL5iB,KAAKkH,WAAWgI,UAAYjF,SAASyb,GAAKA,EAAIhjB,KAAKijB,KAAKD,GAAK3hB,OAAO6hB,UACpE5lB,KAAK6lB,YACL7lB,KAAK8lB,cAAc,SAASX,EAAOlc,GACjCkc,EAAMjW,UAAYwW,EAAIzc,IAExBjJ,KAAK4iB,mBAEPle,GAAIA,gBACF,MAAO1E,MAAKkH,WAAWxC,cAEzBA,GAAIA,cAAaoC,GACf9G,KAAK4iB,iBACL,IAAI/D,GAAiB7e,KAAKoc,WAC1Bpc,MAAKkH,WAAWxC,aAAeoC,EAC/B9G,KAAK8lB,cAAc,SAASlB,GAC1BA,EAAelgB,aAAeoC,IAEV,UAAlB9G,KAAK+e,WAA2C,QAAlB/e,KAAK+e,WACrC/e,KAAKgf,OAEgB,OAAnBH,IACF7e,KAAKoc,YAAcyC,GAErB7e,KAAK4iB,mBAEP5D,KAAM,WACJhf,KAAK4iB,kBACL5iB,KAAKqd,SAAAA,EACLrd,KAAKkH,WAAW8X,OACgC,IAA5Chf,KAAKwe,UAAUR,YAAYrc,QAAQ3B,OACrCA,KAAKwe,UAAUR,YAAY7U,KAAKnJ,MAElCA,KAAK6lB,YACL7X,EAAM+X,eAAe/lB,MACrBA,KAAK8lB,cAAc,SAASX,GAC1B,GAAIa,GAAOb,EAAM/I,WACjB+I,GAAMnG,OACNmG,EAAM/I,YAAc4J,IAEtBhmB,KAAK4iB,mBAEPtD,MAAO,WACLtf,KAAK4iB,kBACD5iB,KAAKoc,cACPpc,KAAKijB,UAAYjjB,KAAKoc,aAExBpc,KAAKkH,WAAWoY,QAChBtf,KAAK6lB,YACL7lB,KAAK8lB,cAAc,SAASX,GAC1BA,EAAM7F,UAERtf,KAAKqd,SAAAA,EACLrd,KAAK4iB,mBAEPrD,OAAQ,WACNvf,KAAK4iB,kBACL5iB,KAAKkH,WAAWqY,SAChBvf,KAAK6lB,YACL7lB,KAAK4iB,mBAEPnD,OAAQ,WACNzf,KAAK4iB,kBACL5iB,KAAKkH,WAAWuY,SAChBzf,KAAK6lB,YACL7lB,KAAKklB,yBACLllB,KAAK4iB,mBAEPlD,QAAS,WACP1f,KAAK4iB,iBACL,IAAI/D,GAAiB7e,KAAKoc,WAC1Bpc,MAAKkH,WAAWwY,UAChB1f,KAAK8lB,cAAc,SAASlB,GAC1BA,EAAelF,YAEM,OAAnBb,IACF7e,KAAKoc,YAAcyC,GAErB7e,KAAK4iB,mBAEPhD,iBAAkB,SAAS1V,EAAM2V,GAC/B,GAAIoG,GAAUpG,CACQ,mBAAXA,KACToG,EAAU,SAAUjD,GAClBA,EAAEpT,OAAS5P,KACX6f,EAAQM,KAAKngB,KAAMgjB,IAClB3U,KAAKrO,MACR6f,EAAQqE,SAAW+B,GAErBjmB,KAAKkH,WAAW0Y,iBAAiB1V,EAAM+b,IAEzCrE,oBAAqB,SAAS1X,EAAM2V,GAClC7f,KAAKkH,WAAW0a,oBAAoB1X,EAAO2V,GAAWA,EAAQqE,UAAarE,IAE7EqF,uBAAwB,WACtB,KAAOllB,KAAKmjB,iBAAiBna,QAC3BhJ,KAAKmjB,iBAAiB+C,MAAMzG,UAEhCqG,cAAe,SAASzjB,GACtB,GAAI4G,GAAS,CASb,IARIjJ,KAAKgB,OAAOgkB,UAAYhlB,KAAKmjB,iBAAiBna,OAAShJ,KAAKgB,OAAOgkB,SAAShc,QAC9EhJ,KAAKilB,4BACPjlB,KAAKmjB,iBAAiB3hB,QAAQ,SAAS2jB,GACrC9iB,EAAE8d,KAAKngB,KAAMmlB,EAAOlc,GAChBjJ,KAAKgB,iBAAkB2I,QAAO0a,iBAChCpb,GAAUkc,EAAMnkB,OAAO6D,iBACzBwJ,KAAKrO,OAEe,WAAlBA,KAAK+e,UAAT,CAEA,GAAI9d,GAASjB,KAAKgB,OAAOiG,QACrB0K,EAAI3R,KAAKoc,WACH,QAANzK,IACFA,EAAIlS,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS0Q,EAAG1Q,KACrE,MAAL0Q,GAAavQ,MAAMuQ,KACrB3R,KAAKklB,4BAIXvb,OAAOqT,UAAYhP,EAAMgP,WAMxB3d,EAAqBE,EAAmBC,GCnX1C,SAASC,EAAQuO,EAAOtO,GAqCvB,QAASymB,GAAa1d,GACpBzI,KAAKomB,QAAU3mB,EAAO4J,mBAAmBZ,GAoG3C,QAAS4d,KAEP,IADA,GAAIC,IAAAA,EACGC,EAAcvd,QAAQ,CAC3B,GAAI2F,GAAQ4X,EAAcC,OAC1B7X,GAAMgW,kBACN2B,GAAAA,EAEF,MAAOA,GA/IT,GAAIG,GAAe,SAASzlB,GAE1B,GADAA,EAAOkG,WAAa7F,OAChBL,YAAkB2I,QAAO0a,gBAAkBrjB,YAAkB2I,QAAO2a,YACtE,IAAK,GAAIjc,GAAI,EAAGA,EAAIrH,EAAOgkB,SAAShc,OAAQX,IAC1Coe,EAAazlB,EAAOgkB,SAAS3c,IAKnC2F,GAAM0Y,YAAc,SAASC,GAE3B,IAAK,GADDC,MACKve,EAAI,EAAGA,EAAIse,EAAQ3d,OAAQX,IAAK,CACvC,GAAIrH,GAAS2lB,EAAQte,EACjBrH,GAAO6lB,SACiC,IAAtCD,EAAWjlB,QAAQX,EAAO6lB,UAC5BD,EAAWzd,KAAKnI,EAAO6lB,SAEzB7lB,EAAO6lB,QAAQ7B,SAASnD,OAAO7gB,EAAO6lB,QAAQ7B,SAASrjB,QAAQX,GAAS,GACxEA,EAAO6lB,QAAU,KACjBJ,EAAazlB,IACJA,EAAOkG,YAAelG,EAAOkG,WAAWlG,QAAUA,IAC3DA,EAAOkG,WAAWuY,SAClBze,EAAOkG,WAAWlG,OAAS,GAAI4T,gBAAe,SAC1C5T,EAAOkG,WAAWkc,YACpBpiB,EAAOkG,WAAWkc,UAAUlc,WAAa,MAE3ClG,EAAOkG,WAAWC,8BAClBsf,EAAazlB,IAGjB,IAAKqH,EAAI,EAAGA,EAAIue,EAAW5d,OAAQX,IACjCue,EAAWve,GAAGye,YAQlB9Y,EAAM4G,eAAiB,SAAShF,EAAQnH,EAAa7I,EAAaqV,GAmBhE,MAlBAjV,MAAK4P,OAASA,EACd5P,KAAK6mB,QAAU,KAEfjnB,EAAcH,EAAOoC,sBAAsBjC,GAC3CI,KAAKgH,aAAevH,EAAOE,iBAAiBC,GAC5CI,KAAKiH,QAAUxH,EAAOqC,qBAAqBlC,GAE3CI,KAAKiB,OAASxB,EAAOqB,WAAWlB,GAAAA,EAAoBI,MACpDA,KAAKiB,OAAO8F,QAAU/G,KACI,kBAAfyI,IACThJ,EAAOqO,WAAW,wBAAyB,aAAc,wCACzD9N,KAAK+mB,qBAAuBte,GAE5BzI,KAAK+mB,qBAAuB,GAAIZ,GAAa1d,GAE/CzI,KAAKgnB,WAAave,EAClBzI,KAAK6E,eAAiBpF,EAAO+E,wBAAwBxE,KAAKiH,SAC1DjH,KAAKid,IAAMhI,EACJjV,MAGTgO,EAAM4G,eAAejO,WACnBsgB,UAAW,WACT,MAAwC,kBAA7BjnB,MAAK+mB,qBACP/mB,KAAK+mB,qBACP/mB,KAAK+mB,qBAAqBX,SAEnCc,GAAIA,UAASC,GACX,GAA+B,kBAApBnnB,MAAKinB,YACd,KAAM,IAAIlZ,OAAM,qEAElB/N,MAAKykB,UAAY0C,EACbnnB,KAAKkH,YACPlH,KAAKkH,WAAWC,+BAGpBigB,GAAIA,UACF,MAAOpnB,MAAK6mB,SAEdhnB,MAAO,WACL,GAA+B,kBAApBG,MAAKinB,YACd,KAAM,IAAIlZ,OAAM,2CAElB,IAAIlO,GAAQ,GAAI+U,gBAAe5U,KAAK4P,UAAYnQ,EAAOE,iBAAiBK,KAAKgH,cAAehH,KAAKid,IAGjG,OAFApd,GAAMknB,qBAAuB/mB,KAAK+mB,qBAClClnB,EAAMmnB,WAAahnB,KAAKgnB,WACjBnnB,GAETkjB,OAAQ,WACN/U,EAAM0Y,aAAa1mB,QAIvB,IAAIshB,GAAyB7I,QAAQ9R,UAAU+R,OAC/CD,SAAQ9R,UAAU+R,QAAU,SAASjQ,EAAakQ,GAChD,GAAI1D,GAAK,EAIT,OAHI0D,IAAWA,EAAQ1D,KACrBA,EAAK0D,EAAQ1D,IAERjH,EAAM6K,SAASgK,MAAM,GAAI7U,GAAM4G,eAAe5U,KAAMyI,EAAakQ,EAAS1D,IAGnF,IAAIoS,GAAalkB,SAASsI,gBAAgB,+BAAgC,MAC1EuC,GAAMmW,wCAA0C,SAAStP,GACvD,GAAIA,EAAgB,CAClB,GAAIjF,GAASiF,EAAejF,QAAUyX,EAClC9d,EAAYsL,EAAemS,UACP,mBAAbzd,KACTA,KAEF,IAAIoP,GAAU9D,EAAe7N,YAC7B2R,GAAQ1D,GAAKJ,EAAeoI,QAE5B,IAAIrN,GAASyX,EACT9d,KACAoP,EAAU,CAEhB,OAAO2I,GAAuB1d,MAAMgM,GAASrG,EAAWoP,KAI1D3K,EAAMoW,+BAAiC,SAAS7C,GAC1CA,EAAUvgB,QAA0D,kBAAzCugB,GAAUvgB,OAAO+lB,sBAC9C/Y,EAAM0W,6BAA6BnD,GAIvC,IAAIgF,KACJvY,GAAM+X,eAAiB,SAASuB,GACG,OAA7BA,EAAepY,WAAuBoY,EAAepE,WAE7B,GAAxBqD,EAAcvd,QAChBsZ,sBAAsB+D,GAExBE,EAAcpd,KAAKme,IAWrB,IAAIC,GAA2B5d,OAAOqY,gBACtC1gB,QAAOoU,eAAe/L,OAAQ,oBAC5B8L,cAAAA,EACAD,YAAAA,EACA1O,MAAO,WACL6C,OAAOxG,SAAS0V,SAAS2J,2BACzB,IAAIva,GAASsf,EAAyB3jB,MAAM5D,KAAMmY,UAIlD,OAHIkO,OACFpe,EAASsf,EAAyB3jB,MAAM5D,KAAMmY,YAChDxO,OAAOxG,SAAS0V,SAAS2J,4BAClBva,KAIX0B,OAAOiL,eAAiB5G,EAAM4G,eAC9BjL,OAAO8O,QAAQ9R,UAAU+b,cAAgB,WACvC,MAAOvf,UAAS0V,SAAS6J,gBAAgBhY,OAAO,SAAS6W,GACvD,MAA4B,QAArBA,EAAUvgB,QAAmBugB,EAAUvgB,OAAO4O,QAAU5P,MAC/DqO,KAAKrO,SAGTX,EAAqBE,EAAmBC,GCzK1C,SAAUC,EAAQuO,EAAOtO,GA6CvB,QAAS8nB,GAASL,GACZA,EAASM,cAEbN,EAASM,aAAAA,EACTC,EAAUve,KAAKge,GACV9E,IACHA,GAAAA,EACAC,sBAAsBqF,KAI1B,QAASA,GAAKhW,GACZ,GAAIiW,GAAWF,CACfA,MACAE,EAASxe,KAAK,SAASyF,EAAMC,GAC3B,MAAOD,GAAKqO,gBAAkBpO,EAAMoO,kBAEtC0K,EAAWA,EAASld,OAAO,SAASyc,GAClCA,GACA,IAAIpI,GAAYoI,EAASjgB,WAAaigB,EAASjgB,WAAW6X,UAAY,MAGtE,OAFiB,WAAbA,GAAuC,WAAbA,IAC5BoI,EAASM,aAAAA,GACJN,EAASM,cAElBC,EAAUve,KAAKvF,MAAM8jB,EAAWE,GAE5BF,EAAU1e,QACZqZ,GAAAA,EACAC,sBAAsBqF,IAEtBtF,GAAAA,EAzEJ,GAEInG,IAFa/Y,SAASsI,gBAAgB,+BAAgC,OAErD,EACrBuC,GAAM0W,6BAA+B,SAASnD,GAC5C,GACIsG,GADAjY,EAAS2R,EAAUvgB,OAAO4O,OAE1BkY,EAA0D,kBAAhCvG,GAAUvgB,OAAOimB,WAE7CY,GADEC,EACevG,EAAUvgB,OAAOimB,YAEjB1F,EAAUvgB,OAAOyjB,SAEpC,IAAIxjB,GAASsgB,EAAUvgB,OAAOC,OAC1B8mB,EAAO,IACX9mB,GAASxB,EAAOqC,qBAAqBb,EACrC,IAAIkmB,GAAW,WACb,GAAIxV,GAAIwV,EAASjgB,WAAaigB,EAASjgB,WAAWkV,YAAc,IACtD,QAANzK,IACFA,EAAIlS,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS0Q,EAAG1Q,GACxEG,MAAMuQ,KACRA,EAAI,OAIJA,IAAMoW,IACJD,EACFD,EAAelW,EAAG/B,EAAQ2R,EAAUvgB,QAEpC6mB,EAAelW,EAAG4P,EAAUvgB,OAAQugB,EAAUvgB,OAAOkG,aAGzD6gB,EAAOpW,EAGTwV,GAASjgB,WAAaqa,EACtB4F,EAASM,aAAAA,EACTN,EAASjK,gBAAkBhB,IAC3BqF,EAAU6B,UAAY+D,EACtBK,EAASL,GAGX,IAAIO,MACArF,GAAAA,CAmCJrU,GAAMgP,UAAUrW,UAAUkf,UAAY,WAChC7lB,KAAKojB,WACPoE,EAASxnB,KAAKojB,aAGjB/jB,EAAqBE,EAAmBC,GCnF3C,SAAUC,EAAQuO,EAAOtO,GAEvB,QAASolB,GAAmBkD,GAC1B,MAAOA,GAAK/gB,QAAQjC,MAAQgjB,EAAKnjB,eAAiBmjB,EAAK/gB,QAAQG,SAGjE,QAAS6gB,GAAYjD,EAAUplB,EAAaqV,GAC1CjV,KAAKid,IAAMhI,EACXjV,KAAK6mB,QAAU,KACf7mB,KAAKglB,SAAWA,MAChBhlB,KAAKkoB,UAAUloB,KAAKglB,UACpBplB,EAAcH,EAAOoC,sBAAsBjC,GAC3CI,KAAKgH,aAAevH,EAAOE,iBAAiBC,GAC5CI,KAAKiH,QAAUxH,EAAOqC,qBAAqBlC,GAAAA,GAC3CI,KAAKiB,OAASxB,EAAOqB,WAAWlB,GAAAA,EAAmBI,MACnDA,KAAKiB,OAAO8F,QAAU/G,KAEQ,SAA1BA,KAAKiH,QAAQ9F,WACfnB,KAAKiH,QAAQ9F,SAAWnB,KAAK6E,gBAIjC8E,OAAO0a,eAAiB,WACtB4D,EAAYrkB,MAAM5D,KAAMmY,YAG1BxO,OAAO2a,YAAc,WACnB2D,EAAYrkB,MAAM5D,KAAMmY,YAG1B8P,EAAYthB,WACVwhB,YAAa,SAASnnB,GAEpB,IADA,GAAIgB,GAAIhC,KACK,OAANgC,GAAY,CACjB,GAAIA,GAAKhB,EACP,OAAA,CACFgB,GAAIA,EAAE6kB,QAER,OAAA,GAEFC,SAAU,WAGR,IADA,GAAIkB,GAAOhoB,KACJgoB,GACwB,SAAzBA,EAAK/mB,OAAOE,WACd6mB,EAAK/gB,QAAQ9F,SAAW6mB,EAAKnjB,gBAE/BmjB,EAAOA,EAAKnB,OAEV7mB,MAAKkH,YACPlH,KAAKkH,WAAWC,+BAGpB+gB,UAAW,SAASE,GAClBpa,EAAM0Y,YAAY0B,EAClB,KAAK,GAAI/f,GAAI,EAAGA,EAAI+f,EAAYpf,OAAQX,IACtC+f,EAAY/f,GAAGwe,QAAU7mB,MAG7BqoB,UAAW,SAASlN,EAAMmN,GAExB,IAAK,GADDhe,GAAUge,EAAW,oCAAsC,qCACtDjgB,EAAI,EAAGA,EAAI8S,EAAKnS,OAAQX,IAC/B,GAAIrI,KAAKmoB,YAAYhN,EAAK9S,IACxB,MACE6B,KAAMC,aAAaoe,sBACnBle,KAAM,wBACNC,QAASA,EAKf,KAAK,GAAIjC,GAAI,EAAGA,EAAI8S,EAAKnS,OAAQX,IAC/BigB,EAAWtoB,KAAKglB,SAAS7b,KAAKgS,EAAK9S,IAAMrI,KAAKglB,SAASwD,QAAQrN,EAAK9S,GAEtErI,MAAKkoB,UAAU/M,GACfnb,KAAK8mB,YAEP2B,OAAQ,WACNzoB,KAAKqoB,UAAUlQ,WAAAA,IAEjBuQ,QAAS,WACP1oB,KAAKqoB,UAAUlQ,WAAAA,IAEjBiP,GAAIA,UACF,MAAOpnB,MAAK6mB,SAEd8B,GAAIA,cACF,MAAO3oB,MAAKglB,SAAShc,OAAShJ,KAAKglB,SAAS,GAAK,MAEnD4D,GAAIA,aACF,MAAO5oB,MAAKglB,SAAShc,OAAShJ,KAAKglB,SAAShlB,KAAKglB,SAAShc,OAAS,GAAK,MAE1EnJ,MAAO,WAGL,IAAK,GAFDgpB,GAAeppB,EAAOE,iBAAiBK,KAAKgH,cAC5C8hB,KACKzgB,EAAI,EAAGA,EAAIrI,KAAKglB,SAAShc,OAAQX,IACxCygB,EAAe3f,KAAKnJ,KAAKglB,SAAS3c,GAAGxI,QAEvC,OAAQG,gBAAgBskB,aACpB,GAAIA,aAAYwE,EAAgBD,GAChC,GAAIxE,gBAAeyE,EAAgBD,IAEzC9F,OAAQ,WACN/U,EAAM0Y,aAAa1mB,SAIvB2J,OAAO0a,eAAe1d,UAAYrF,OAAOynB,OAAOd,EAAYthB,WAC5DrF,OAAOoU,eACH/L,OAAO0a,eAAe1d,UACtB,kBAEE8P,IAAK,WACH,GAAIuS,GAAQ,CAIZ,OAHAhpB,MAAKglB,SAASxjB,QAAQ,SAAS2jB,GAC7B6D,GAASlE,EAAmBK,KAEvBziB,KAAK4W,IAAI0P,EAAO,MAI/Brf,OAAO2a,YAAY3d,UAAYrF,OAAOynB,OAAOd,EAAYthB,WACzDrF,OAAOoU,eACH/L,OAAO2a,YAAY3d,UACnB,kBAEE8P,IAAK,WACH,GAAI6C,GAAM,CAIV,OAHAtZ,MAAKglB,SAASxjB,QAAQ,SAAS2jB,GAC7B7L,EAAM5W,KAAK4W,IAAIA,EAAKwL,EAAmBK,MAElC7L,KAIftL,EAAMuW,+BAAiC,SAAS5V,GAC9C,GAAIsa,GACAhoB,EAAS,KACTioB,EAAS,SAASC,GACpB,GAAI5H,GAAY0H,EAAoB/E,QACpC,OAAK3C,IAGsB,WAAvBA,EAAUxC,WAGTwC,EAAUvgB,OAGL,MAANmoB,MACF5H,GAAU2D,yBAQF,GAANiE,GAAW5H,EAAU7c,aAAe,IACjCzD,IACHA,EAASxB,EAAOqC,qBAAqByf,EAAUvgB,OAAOC,SAExDkoB,EAAK1pB,EAAOgH,sBAAsBhH,EAAO+E,wBAAwBvD,GAAS,GAAIA,GAC1EG,MAAM+nB,IAAa,MAANA,IACf5H,EAAUuE,cAAc,SAASX,GAC/BA,EAAM/I,YAAc,SAEtBmF,GAAU2D,0BATd,OAlBA,QAiCEkE,EAAmB,GAAIxU,gBAAe,QAAUjG,EAAM1H,QAAS0H,EAAMsO,IAGzE,OAFAmM,GAAiBlC,SAAWgC,EAC5BD,EAAsBjb,EAAM6K,SAASgK,MAAMuG,IAI7Cpb,EAAMwW,sBAAwB,SAASjD,GACrCA,EAAUra,WAAWgd,SAAW3C,EAChCA,EAAU2B,UAAAA,EACVlV,EAAM+X,eAAexE,GACrBA,EAAU0D,4BACV1D,EAAUwD,sBAAsBxD,IAGlCvT,EAAM8W,mBAAqBA,GAE1BzlB,EAAqBE,EAAmBC,GnB3LvCD,EAAAA,QAEJ8pB,MACM7pB,WAAAA,MAAuBQ","file":"web-animations-next.min.js"} \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.html b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.html
new file mode 100644
index 00000000000..b5de36c855e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.html
@@ -0,0 +1,50 @@
+<!--
+ Copyright 2014 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- WARNING: This file is DEPRECATED, for development purposes use
+ web-animations*.dev.html instead or depend on
+ web-animations*.min.js in the web-animations-js
+ repository -->
+
+<script src="src/dev.js"></script>
+<script src="src/scope.js"></script>
+<script src="src/deprecation.js"></script>
+<script src="src/timing-utilities.js"></script>
+<script src="src/normalize-keyframes.js"></script>
+<script src="src/animation-node.js"></script>
+<script src="src/effect.js"></script>
+<script src="src/property-interpolation.js"></script>
+<script src="src/animation.js"></script>
+<script src="src/apply.js"></script>
+<script src="src/element-animatable.js"></script>
+<script src="src/interpolation.js"></script>
+<script src="src/player.js"></script>
+<script src="src/tick.js"></script>
+<script src="src/handler-utils.js"></script>
+<script src="src/shadow-handler.js"></script>
+<script src="src/number-handler.js"></script>
+<script src="src/visibility-handler.js"></script>
+<script src="src/color-handler.js"></script>
+<script src="src/dimension-handler.js"></script>
+<script src="src/box-handler.js"></script>
+<script src="src/transform-handler.js"></script>
+<script src="src/property-names.js"></script>
+<script src="src/timeline.js"></script>
+<script src="src/maxifill-player.js"></script>
+<script src="src/animation-constructor.js"></script>
+<script src="src/effect-callback.js"></script>
+<script src="src/group-constructors.js"></script>
+
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js
new file mode 100644
index 00000000000..796b50dbcc0
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js
@@ -0,0 +1,17 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+!function(a,b){var c={},d={},e={},f=null;!function(a,b){function c(a){if("number"==typeof a)return a;var b={};for(var c in a)b[c]=a[c];return b}function d(){this._delay=0,this._endDelay=0,this._fill="none",this._iterationStart=0,this._iterations=1,this._duration=0,this._playbackRate=1,this._direction="normal",this._easing="linear",this._easingFunction=w}function e(){return a.isDeprecated("Invalid timing inputs","2016-03-02","TypeError exceptions will be thrown instead.",!0)}function f(b,c,e){var f=new d;return c&&(f.fill="both",f.duration="auto"),"number"!=typeof b||isNaN(b)?void 0!==b&&Object.getOwnPropertyNames(b).forEach(function(c){if("auto"!=b[c]){if(("number"==typeof f[c]||"duration"==c)&&("number"!=typeof b[c]||isNaN(b[c])))return;if("fill"==c&&-1==u.indexOf(b[c]))return;if("direction"==c&&-1==v.indexOf(b[c]))return;if("playbackRate"==c&&1!==b[c]&&a.isDeprecated("AnimationEffectTiming.playbackRate","2014-11-28","Use Animation.playbackRate instead."))return;f[c]=b[c]}}):f.duration=b,f}function g(a){return"number"==typeof a&&(a=isNaN(a)?{duration:0}:{duration:a}),a}function h(b,c){return b=a.numericTimingToObject(b),f(b,c)}function i(a,b,c,d){return 0>a||a>1||0>c||c>1?w:function(e){function f(a,b,c){return 3*a*(1-c)*(1-c)*c+3*b*(1-c)*c*c+c*c*c}if(0==e||1==e)return e;for(var g=0,h=1;;){var i=(g+h)/2,j=f(a,c,i);if(Math.abs(e-j)<1e-4)return f(b,d,i);e>j?g=i:h=i}}}function j(a,b){return function(c){if(c>=1)return 1;var d=1/a;return c+=b*d,c-c%d}}function k(a){B||(B=document.createElement("div").style),B.animationTimingFunction="",B.animationTimingFunction=a;var b=B.animationTimingFunction;if(""==b&&e())throw new TypeError(a+" is not a valid value for easing");var c=D.exec(b);if(c)return i.apply(this,c.slice(1).map(Number));var d=E.exec(b);if(d)return j(Number(d[1]),{start:x,middle:y,end:z}[d[2]]);var f=A[b];return f?f:w}function l(a){return Math.abs(m(a)/a.playbackRate)}function m(a){return a.duration*a.iterations}function n(a,b,c){return null==b?F:b<c.delay?G:b>=c.delay+a?H:I}function o(a,b,c,d,e){switch(d){case G:return"backwards"==b||"both"==b?0:null;case I:return c-e;case H:return"forwards"==b||"both"==b?a:null;case F:return null}}function p(a,b,c,d){return(d.playbackRate<0?b-a:b)*d.playbackRate+c}function q(a,b,c,d,e){return c===1/0||c===-(1/0)||c-d==b&&e.iterations&&(e.iterations+e.iterationStart)%1==0?a:c%a}function r(a,b,c,d){return 0===c?0:b==a?d.iterationStart+d.iterations-1:Math.floor(c/a)}function s(a,b,c,d){var e=a%2>=1,f="normal"==d.direction||d.direction==(e?"alternate-reverse":"alternate"),g=f?c:b-c,h=g/b;return b*d._easingFunction(h)}function t(a,b,c){var d=n(a,b,c),e=o(a,c.fill,b,d,c.delay);if(null===e)return null;if(0===a)return d===G?0:1;var f=c.iterationStart*c.duration,g=p(a,e,f,c),h=q(c.duration,m(c),g,f,c),i=r(c.duration,h,g,c);return s(i,c.duration,h,c)/c.duration}var u="backwards|forwards|both|none".split("|"),v="reverse|alternate|alternate-reverse".split("|"),w=function(a){return a};d.prototype={_setMember:function(b,c){this["_"+b]=c,this._effect&&(this._effect._timingInput[b]=c,this._effect._timing=a.normalizeTimingInput(this._effect._timingInput),this._effect.activeDuration=a.calculateActiveDuration(this._effect._timing),this._effect._animation&&this._effect._animation._rebuildUnderlyingAnimation())},get playbackRate(){return this._playbackRate},set delay(a){this._setMember("delay",a)},get delay(){return this._delay},set endDelay(a){this._setMember("endDelay",a)},get endDelay(){return this._endDelay},set fill(a){this._setMember("fill",a)},get fill(){return this._fill},set iterationStart(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterationStart must be a non-negative number, received: "+timing.iterationStart);this._setMember("iterationStart",a)},get iterationStart(){return this._iterationStart},set duration(a){if("auto"!=a&&(isNaN(a)||0>a)&&e())throw new TypeError("duration must be non-negative or auto, received: "+a);this._setMember("duration",a)},get duration(){return this._duration},set direction(a){this._setMember("direction",a)},get direction(){return this._direction},set easing(a){this._easingFunction=k(a),this._setMember("easing",a)},get easing(){return this._easing},set iterations(a){if((isNaN(a)||0>a)&&e())throw new TypeError("iterations must be non-negative, received: "+a);this._setMember("iterations",a)},get iterations(){return this._iterations}};var x=1,y=.5,z=0,A={ease:i(.25,.1,.25,1),"ease-in":i(.42,0,1,1),"ease-out":i(0,0,.58,1),"ease-in-out":i(.42,0,.58,1),"step-start":j(1,x),"step-middle":j(1,y),"step-end":j(1,z)},B=null,C="\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*",D=new RegExp("cubic-bezier\\("+C+","+C+","+C+","+C+"\\)"),E=/steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/,F=0,G=1,H=2,I=3;a.cloneTimingInput=c,a.makeTiming=f,a.numericTimingToObject=g,a.normalizeTimingInput=h,a.calculateActiveDuration=l,a.calculateTimeFraction=t,a.calculatePhase=n,a.toTimingFunction=k}(c,f),function(a,b){function c(a,b){return a in j?j[a][b]||b:b}function d(a,b,d){var e=g[a];if(e){h.style[a]=b;for(var f in e){var i=e[f],j=h.style[i];d[i]=c(i,j)}}else d[a]=c(a,b)}function e(a){var b=[];for(var c in a)if(!(c in["easing","offset","composite"])){var d=a[c];Array.isArray(d)||(d=[d]);for(var e,f=d.length,g=0;f>g;g++)e={},"offset"in a?e.offset=a.offset:1==f?e.offset=1:e.offset=g/(f-1),"easing"in a&&(e.easing=a.easing),"composite"in a&&(e.composite=a.composite),e[c]=d[g],b.push(e)}return b.sort(function(a,b){return a.offset-b.offset}),b}function f(a){function b(){var a=c.length;null==c[a-1].offset&&(c[a-1].offset=1),a>1&&null==c[0].offset&&(c[0].offset=0);for(var b=0,d=c[0].offset,e=1;a>e;e++){var f=c[e].offset;if(null!=f){for(var g=1;e-b>g;g++)c[b+g].offset=d+(f-d)*g/(e-b);b=e,d=f}}}if(null==a)return[];window.Symbol&&Symbol.iterator&&Array.prototype.from&&a[Symbol.iterator]&&(a=Array.from(a)),Array.isArray(a)||(a=e(a));for(var c=a.map(function(a){var b={};for(var c in a){var e=a[c];if("offset"==c){if(null!=e&&(e=Number(e),!isFinite(e)))throw new TypeError("keyframe offsets must be numbers.")}else{if("composite"==c)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"add compositing is not supported"};e=""+e}d(c,e,b)}return void 0==b.offset&&(b.offset=null),b}),f=!0,g=-(1/0),h=0;h<c.length;h++){var i=c[h].offset;if(null!=i){if(g>i)throw{code:DOMException.INVALID_MODIFICATION_ERR,name:"InvalidModificationError",message:"Keyframes are not loosely sorted by offset. Sort or specify offsets."};g=i}else f=!1}return c=c.filter(function(a){return a.offset>=0&&a.offset<=1}),f||b(),c}var g={background:["backgroundImage","backgroundPosition","backgroundSize","backgroundRepeat","backgroundAttachment","backgroundOrigin","backgroundClip","backgroundColor"],border:["borderTopColor","borderTopStyle","borderTopWidth","borderRightColor","borderRightStyle","borderRightWidth","borderBottomColor","borderBottomStyle","borderBottomWidth","borderLeftColor","borderLeftStyle","borderLeftWidth"],borderBottom:["borderBottomWidth","borderBottomStyle","borderBottomColor"],borderColor:["borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],borderLeft:["borderLeftWidth","borderLeftStyle","borderLeftColor"],borderRadius:["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],borderRight:["borderRightWidth","borderRightStyle","borderRightColor"],borderTop:["borderTopWidth","borderTopStyle","borderTopColor"],borderWidth:["borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"],flex:["flexGrow","flexShrink","flexBasis"],font:["fontFamily","fontSize","fontStyle","fontVariant","fontWeight","lineHeight"],margin:["marginTop","marginRight","marginBottom","marginLeft"],outline:["outlineColor","outlineStyle","outlineWidth"],padding:["paddingTop","paddingRight","paddingBottom","paddingLeft"]},h=document.createElementNS("http://www.w3.org/1999/xhtml","div"),i={thin:"1px",medium:"3px",thick:"5px"},j={borderBottomWidth:i,borderLeftWidth:i,borderRightWidth:i,borderTopWidth:i,fontSize:{"xx-small":"60%","x-small":"75%",small:"89%",medium:"100%",large:"120%","x-large":"150%","xx-large":"200%"},fontWeight:{normal:"400",bold:"700"},outlineWidth:i,textShadow:{none:"0px 0px 0px transparent"},boxShadow:{none:"0px 0px 0px 0px transparent"}};a.convertToArrayForm=e,a.normalizeKeyframes=f}(c,f),function(a){var b={};a.isDeprecated=function(a,c,d,e){var f=e?"are":"is",g=new Date,h=new Date(c);return h.setMonth(h.getMonth()+3),h>g?(a in b||console.warn("Web Animations: "+a+" "+f+" deprecated and will stop working on "+h.toDateString()+". "+d),b[a]=!0,!1):!0},a.deprecated=function(b,c,d,e){var f=e?"are":"is";if(a.isDeprecated(b,c,d,e))throw new Error(b+" "+f+" no longer supported. "+d)}}(c),function(){if(document.documentElement.animate){var a=document.documentElement.animate([],0),b=!0;if(a&&(b=!1,"play|currentTime|pause|reverse|playbackRate|cancel|finish|startTime|playState".split("|").forEach(function(c){void 0===a[c]&&(b=!0)})),!b)return}!function(a,b,c){function d(a){for(var b={},c=0;c<a.length;c++)for(var d in a[c])if("offset"!=d&&"easing"!=d&&"composite"!=d){var e={offset:a[c].offset,easing:a[c].easing,value:a[c][d]};b[d]=b[d]||[],b[d].push(e)}for(var f in b){var g=b[f];if(0!=g[0].offset||1!=g[g.length-1].offset)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"Partial keyframes are not supported"}}return b}function e(c){var d=[];for(var e in c)for(var f=c[e],g=0;g<f.length-1;g++){var h=f[g].offset,i=f[g+1].offset,j=f[g].value,k=f[g+1].value,l=f[g].easing;h==i&&(1==i?j=k:k=j),d.push({startTime:h,endTime:i,easing:a.toTimingFunction(l?l:"linear"),property:e,interpolation:b.propertyInterpolation(e,j,k)})}return d.sort(function(a,b){return a.startTime-b.startTime}),d}b.convertEffectInput=function(c){var f=a.normalizeKeyframes(c),g=d(f),h=e(g);return function(a,c){if(null!=c)h.filter(function(a){return 0>=c&&0==a.startTime||c>=1&&1==a.endTime||c>=a.startTime&&c<=a.endTime}).forEach(function(d){var e=c-d.startTime,f=d.endTime-d.startTime,g=0==f?0:d.easing(e/f);b.apply(a,d.property,d.interpolation(g))});else for(var d in g)"offset"!=d&&"easing"!=d&&"composite"!=d&&b.clear(a,d)}}}(c,d,f),function(a,b,c){function d(a){return a.replace(/-(.)/g,function(a,b){return b.toUpperCase()})}function e(a,b,c){h[c]=h[c]||[],h[c].push([a,b])}function f(a,b,c){for(var f=0;f<c.length;f++){var g=c[f];e(a,b,d(g))}}function g(c,e,f){var g=c;/-/.test(c)&&!a.isDeprecated("Hyphenated property names","2016-03-22","Use camelCase instead.",!0)&&(g=d(c)),"initial"!=e&&"initial"!=f||("initial"==e&&(e=i[g]),"initial"==f&&(f=i[g]));for(var j=e==f?[]:h[g],k=0;j&&k<j.length;k++){var l=j[k][0](e),m=j[k][0](f);if(void 0!==l&&void 0!==m){var n=j[k][1](l,m);if(n){var o=b.Interpolation.apply(null,n);return function(a){return 0==a?e:1==a?f:o(a)}}}}return b.Interpolation(!1,!0,function(a){return a?f:e})}var h={};b.addPropertiesHandler=f;var i={backgroundColor:"transparent",backgroundPosition:"0% 0%",borderBottomColor:"currentColor",borderBottomLeftRadius:"0px",borderBottomRightRadius:"0px",borderBottomWidth:"3px",borderLeftColor:"currentColor",borderLeftWidth:"3px",borderRightColor:"currentColor",borderRightWidth:"3px",borderSpacing:"2px",borderTopColor:"currentColor",borderTopLeftRadius:"0px",borderTopRightRadius:"0px",borderTopWidth:"3px",bottom:"auto",clip:"rect(0px, 0px, 0px, 0px)",color:"black",fontSize:"100%",fontWeight:"400",height:"auto",left:"auto",letterSpacing:"normal",lineHeight:"120%",marginBottom:"0px",marginLeft:"0px",marginRight:"0px",marginTop:"0px",maxHeight:"none",maxWidth:"none",minHeight:"0px",minWidth:"0px",opacity:"1.0",outlineColor:"invert",outlineOffset:"0px",outlineWidth:"3px",paddingBottom:"0px",paddingLeft:"0px",paddingRight:"0px",paddingTop:"0px",right:"auto",textIndent:"0px",textShadow:"0px 0px 0px transparent",top:"auto",transform:"",verticalAlign:"0px",visibility:"visible",width:"auto",wordSpacing:"normal",zIndex:"auto"};b.propertyInterpolation=g}(c,d,f),function(a,b,c){function d(b){var c=a.calculateActiveDuration(b),d=function(d){return a.calculateTimeFraction(c,d,b)};return d._totalDuration=b.delay+c+b.endDelay,d._isCurrent=function(d){var e=a.calculatePhase(c,d,b);return e===PhaseActive||e===PhaseBefore},d}b.KeyframeEffect=function(c,e,f,g){var h,i=d(a.normalizeTimingInput(f)),j=b.convertEffectInput(e),k=function(){j(c,h)};return k._update=function(a){return h=i(a),null!==h},k._clear=function(){j(c,null)},k._hasSameTarget=function(a){return c===a},k._isCurrent=i._isCurrent,k._totalDuration=i._totalDuration,k._id=g,k},b.NullEffect=function(a){var b=function(){a&&(a(),a=null)};return b._update=function(){return null},b._totalDuration=0,b._isCurrent=function(){return!1},b._hasSameTarget=function(){return!1},b}}(c,d,f),function(a,b){function c(a,b,c){c.enumerable=!0,c.configurable=!0,Object.defineProperty(a,b,c)}function d(a){this._surrogateStyle=document.createElementNS("http://www.w3.org/1999/xhtml","div").style,this._style=a.style,this._length=0,this._isAnimatedProperty={};for(var b=0;b<this._style.length;b++){var c=this._style[b];this._surrogateStyle[c]=this._style[c]}this._updateIndices()}function e(a){if(!a._webAnimationsPatchedStyle){var b=new d(a);try{c(a,"style",{get:function(){return b}})}catch(e){a.style._set=function(b,c){a.style[b]=c},a.style._clear=function(b){a.style[b]=""}}a._webAnimationsPatchedStyle=a.style}}var f={cssText:1,length:1,parentRule:1},g={getPropertyCSSValue:1,getPropertyPriority:1,getPropertyValue:1,item:1,removeProperty:1,setProperty:1},h={removeProperty:1,setProperty:1};d.prototype={get cssText(){return this._surrogateStyle.cssText},set cssText(a){for(var b={},c=0;c<this._surrogateStyle.length;c++)b[this._surrogateStyle[c]]=!0;this._surrogateStyle.cssText=a,this._updateIndices();for(var c=0;c<this._surrogateStyle.length;c++)b[this._surrogateStyle[c]]=!0;for(var d in b)this._isAnimatedProperty[d]||this._style.setProperty(d,this._surrogateStyle.getPropertyValue(d))},get length(){return this._surrogateStyle.length},get parentRule(){return this._style.parentRule},_updateIndices:function(){for(;this._length<this._surrogateStyle.length;)Object.defineProperty(this,this._length,{configurable:!0,enumerable:!1,get:function(a){return function(){return this._surrogateStyle[a]}}(this._length)}),this._length++;for(;this._length>this._surrogateStyle.length;)this._length--,Object.defineProperty(this,this._length,{configurable:!0,enumerable:!1,value:void 0})},_set:function(a,b){this._style[a]=b,this._isAnimatedProperty[a]=!0},_clear:function(a){this._style[a]=this._surrogateStyle[a],delete this._isAnimatedProperty[a]}};for(var i in g)d.prototype[i]=function(a,b){return function(){var c=this._surrogateStyle[a].apply(this._surrogateStyle,arguments);return b&&(this._isAnimatedProperty[arguments[0]]||this._style[a].apply(this._style,arguments),this._updateIndices()),c}}(i,i in h);for(var j in document.documentElement.style)j in f||j in g||!function(a){c(d.prototype,a,{get:function(){return this._surrogateStyle[a]},set:function(b){this._surrogateStyle[a]=b,this._updateIndices(),this._isAnimatedProperty[a]||(this._style[a]=b)}})}(j);a.apply=function(b,c,d){e(b),b.style._set(a.propertyName(c),d)},a.clear=function(b,c){b._webAnimationsPatchedStyle&&b.style._clear(a.propertyName(c))}}(d,f),function(a){window.Element.prototype.animate=function(b,c){var d="";return c&&c.id&&(d=c.id),a.timeline._play(a.KeyframeEffect(this,b,c,d))}}(d),function(a,b){function c(a,b,d){if("number"==typeof a&&"number"==typeof b)return a*(1-d)+b*d;if("boolean"==typeof a&&"boolean"==typeof b)return.5>d?a:b;if(a.length==b.length){for(var e=[],f=0;f<a.length;f++)e.push(c(a[f],b[f],d));return e}throw"Mismatched interpolation arguments "+a+":"+b}a.Interpolation=function(a,b,d){return function(e){return d(c(a,b,e))}}}(d,f),function(a,b){function c(a,b,c){return Math.max(Math.min(a,c),b)}function d(b,d,e){var f=a.dot(b,d);f=c(f,-1,1);var g=[];if(1===f)g=b;else for(var h=Math.acos(f),i=1*Math.sin(e*h)/Math.sqrt(1-f*f),j=0;4>j;j++)g.push(b[j]*(Math.cos(e*h)-f*i)+d[j]*i);return g}var e=function(){function a(a,b){for(var c=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],d=0;4>d;d++)for(var e=0;4>e;e++)for(var f=0;4>f;f++)c[d][e]+=b[d][f]*a[f][e];return c}function b(a){return 0==a[0][2]&&0==a[0][3]&&0==a[1][2]&&0==a[1][3]&&0==a[2][0]&&0==a[2][1]&&1==a[2][2]&&0==a[2][3]&&0==a[3][2]&&1==a[3][3]}function c(c,d,e,f,g){for(var h=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],i=0;4>i;i++)h[i][3]=g[i];for(var i=0;3>i;i++)for(var j=0;3>j;j++)h[3][i]+=c[j]*h[j][i];var k=f[0],l=f[1],m=f[2],n=f[3],o=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];o[0][0]=1-2*(l*l+m*m),o[0][1]=2*(k*l-m*n),o[0][2]=2*(k*m+l*n),o[1][0]=2*(k*l+m*n),o[1][1]=1-2*(k*k+m*m),o[1][2]=2*(l*m-k*n),o[2][0]=2*(k*m-l*n),o[2][1]=2*(l*m+k*n),o[2][2]=1-2*(k*k+l*l),h=a(h,o);var p=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];e[2]&&(p[2][1]=e[2],h=a(h,p)),e[1]&&(p[2][1]=0,p[2][0]=e[0],h=a(h,p)),e[0]&&(p[2][0]=0,p[1][0]=e[0],h=a(h,p));for(var i=0;3>i;i++)for(var j=0;3>j;j++)h[i][j]*=d[i];return b(h)?[h[0][0],h[0][1],h[1][0],h[1][1],h[3][0],h[3][1]]:h[0].concat(h[1],h[2],h[3])}return c}();a.composeMatrix=e,a.quat=d}(d,f),function(a,b,c){a.sequenceNumber=0;var d=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="finish",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()};b.Animation=function(b){this.id="",b&&b._id&&(this.id=b._id),this._sequenceNumber=a.sequenceNumber++,this._currentTime=0,this._startTime=null,this._paused=!1,this._playbackRate=1,this._inTimeline=!0,this._finishedFlag=!0,this.onfinish=null,this._finishHandlers=[],this._effect=b,this._inEffect=this._effect._update(0),this._idle=!0,this._currentTimePending=!1},b.Animation.prototype={_ensureAlive:function(){this.playbackRate<0&&0===this.currentTime?this._inEffect=this._effect._update(-1):this._inEffect=this._effect._update(this.currentTime),this._inTimeline||!this._inEffect&&this._finishedFlag||(this._inTimeline=!0,b.timeline._animations.push(this))},_tickCurrentTime:function(a,b){a!=this._currentTime&&(this._currentTime=a,this._isFinished&&!b&&(this._currentTime=this._playbackRate>0?this._totalDuration:0),this._ensureAlive())},get currentTime(){return this._idle||this._currentTimePending?null:this._currentTime},set currentTime(a){a=+a,isNaN(a)||(b.restart(),this._paused||null==this._startTime||(this._startTime=this._timeline.currentTime-a/this._playbackRate),this._currentTimePending=!1,this._currentTime!=a&&(this._tickCurrentTime(a,!0),b.invalidateEffects()))},get startTime(){return this._startTime},set startTime(a){a=+a,isNaN(a)||this._paused||this._idle||(this._startTime=a,this._tickCurrentTime((this._timeline.currentTime-this._startTime)*this.playbackRate),b.invalidateEffects())},get playbackRate(){return this._playbackRate},set playbackRate(a){if(a!=this._playbackRate){var b=this.currentTime;this._playbackRate=a,this._startTime=null,"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!=b&&(this.currentTime=b)}},get _isFinished(){return!this._idle&&(this._playbackRate>0&&this._currentTime>=this._totalDuration||this._playbackRate<0&&this._currentTime<=0)},get _totalDuration(){return this._effect._totalDuration},get playState(){return this._idle?"idle":null==this._startTime&&!this._paused&&0!=this.playbackRate||this._currentTimePending?"pending":this._paused?"paused":this._isFinished?"finished":"running"},play:function(){this._paused=!1,(this._isFinished||this._idle)&&(this._currentTime=this._playbackRate>0?0:this._totalDuration,this._startTime=null),this._finishedFlag=!1,this._idle=!1,this._ensureAlive(),b.invalidateEffects()},pause:function(){this._isFinished||this._paused||this._idle||(this._currentTimePending=!0),this._startTime=null,this._paused=!0},finish:function(){this._idle||(this.currentTime=this._playbackRate>0?this._totalDuration:0,this._startTime=this._totalDuration-this.currentTime,this._currentTimePending=!1,b.invalidateEffects())},cancel:function(){this._inEffect&&(this._inEffect=!1,this._idle=!0,this._finishedFlag=!0,this.currentTime=0,this._startTime=null,this._effect._update(null),b.invalidateEffects())},reverse:function(){this.playbackRate*=-1,this.play()},addEventListener:function(a,b){"function"==typeof b&&"finish"==a&&this._finishHandlers.push(b)},removeEventListener:function(a,b){if("finish"==a){var c=this._finishHandlers.indexOf(b);c>=0&&this._finishHandlers.splice(c,1)}},_fireEvents:function(a){if(this._isFinished){if(!this._finishedFlag){var b=new d(this,this._currentTime,a),c=this._finishHandlers.concat(this.onfinish?[this.onfinish]:[]);setTimeout(function(){c.forEach(function(a){a.call(b.target,b)})},0),this._finishedFlag=!0}}else this._finishedFlag=!1},_tick:function(a,b){this._idle||this._paused||(null==this._startTime?b&&(this.startTime=a-this._currentTime/this.playbackRate):this._isFinished||this._tickCurrentTime((a-this._startTime)*this.playbackRate)),b&&(this._currentTimePending=!1,this._fireEvents(a))},get _needsTick(){return this.playState in{pending:1,running:1}||!this._finishedFlag}}}(c,d,f),function(a,b,c){function d(a){var b=j;j=[],a<p.currentTime&&(a=p.currentTime),h(a,!0),b.forEach(function(b){b[1](a)}),g(),l=void 0}function e(a,b){return a._sequenceNumber-b._sequenceNumber}function f(){this._animations=[],this.currentTime=window.performance&&performance.now?performance.now():0}function g(){o.forEach(function(a){a()}),o.length=0}function h(a,c){n=!1;var d=b.timeline;d.currentTime=a,d._animations.sort(e),m=!1;var f=d._animations;d._animations=[];var g=[],h=[];f=f.filter(function(b){b._tick(a,c),b._inEffect?h.push(b._effect):g.push(b._effect),b._needsTick&&(m=!0);var d=b._inEffect||b._needsTick;return b._inTimeline=d,d}),o.push.apply(o,g),o.push.apply(o,h),d._animations.push.apply(d._animations,f),m&&requestAnimationFrame(function(){})}var i=window.requestAnimationFrame,j=[],k=0;window.requestAnimationFrame=function(a){var b=k++;return 0==j.length&&i(d),j.push([b,a]),b},window.cancelAnimationFrame=function(a){j.forEach(function(b){b[0]==a&&(b[1]=function(){})})},f.prototype={_play:function(c){c._timing=a.normalizeTimingInput(c.timing);var d=new b.Animation(c);return d._idle=!1,d._timeline=this,this._animations.push(d),b.restart(),b.invalidateEffects(),d}};var l=void 0,m=!1,n=!1;b.restart=function(){return m||(m=!0,requestAnimationFrame(function(){}),n=!0),n},b.invalidateEffects=function(){h(b.timeline.currentTime,!1),g()};var o=[],p=new f;b.timeline=p}(c,d,f),function(a,b){function c(a,b){for(var c=0,d=0;d<a.length;d++)c+=a[d]*b[d];return c}function d(a,b){return[a[0]*b[0]+a[4]*b[1]+a[8]*b[2]+a[12]*b[3],a[1]*b[0]+a[5]*b[1]+a[9]*b[2]+a[13]*b[3],a[2]*b[0]+a[6]*b[1]+a[10]*b[2]+a[14]*b[3],a[3]*b[0]+a[7]*b[1]+a[11]*b[2]+a[15]*b[3],a[0]*b[4]+a[4]*b[5]+a[8]*b[6]+a[12]*b[7],a[1]*b[4]+a[5]*b[5]+a[9]*b[6]+a[13]*b[7],a[2]*b[4]+a[6]*b[5]+a[10]*b[6]+a[14]*b[7],a[3]*b[4]+a[7]*b[5]+a[11]*b[6]+a[15]*b[7],a[0]*b[8]+a[4]*b[9]+a[8]*b[10]+a[12]*b[11],a[1]*b[8]+a[5]*b[9]+a[9]*b[10]+a[13]*b[11],a[2]*b[8]+a[6]*b[9]+a[10]*b[10]+a[14]*b[11],a[3]*b[8]+a[7]*b[9]+a[11]*b[10]+a[15]*b[11],a[0]*b[12]+a[4]*b[13]+a[8]*b[14]+a[12]*b[15],a[1]*b[12]+a[5]*b[13]+a[9]*b[14]+a[13]*b[15],a[2]*b[12]+a[6]*b[13]+a[10]*b[14]+a[14]*b[15],a[3]*b[12]+a[7]*b[13]+a[11]*b[14]+a[15]*b[15]]}function e(a){var b=a.rad||0,c=a.deg||0,d=a.grad||0,e=a.turn||0,f=(c/360+d/400+e)*(2*Math.PI)+b;return f}function f(a){switch(a.t){case"rotatex":var b=e(a.d[0]);return[1,0,0,0,0,Math.cos(b),Math.sin(b),0,0,-Math.sin(b),Math.cos(b),0,0,0,0,1];case"rotatey":var b=e(a.d[0]);return[Math.cos(b),0,-Math.sin(b),0,0,1,0,0,Math.sin(b),0,Math.cos(b),0,0,0,0,1];case"rotate":case"rotatez":var b=e(a.d[0]);return[Math.cos(b),Math.sin(b),0,0,-Math.sin(b),Math.cos(b),0,0,0,0,1,0,0,0,0,1];case"rotate3d":var c=a.d[0],d=a.d[1],f=a.d[2],b=e(a.d[3]),g=c*c+d*d+f*f;if(0===g)c=1,d=0,f=0;else if(1!==g){var h=Math.sqrt(g);c/=h,d/=h,f/=h}var i=Math.sin(b/2),j=i*Math.cos(b/2),k=i*i;return[1-2*(d*d+f*f)*k,2*(c*d*k+f*j),2*(c*f*k-d*j),0,2*(c*d*k-f*j),1-2*(c*c+f*f)*k,2*(d*f*k+c*j),0,2*(c*f*k+d*j),2*(d*f*k-c*j),1-2*(c*c+d*d)*k,0,0,0,0,1];case"scale":return[a.d[0],0,0,0,0,a.d[1],0,0,0,0,1,0,0,0,0,1];case"scalex":return[a.d[0],0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];case"scaley":return[1,0,0,0,0,a.d[0],0,0,0,0,1,0,0,0,0,1];case"scalez":return[1,0,0,0,0,1,0,0,0,0,a.d[0],0,0,0,0,1];case"scale3d":return[a.d[0],0,0,0,0,a.d[1],0,0,0,0,a.d[2],0,0,0,0,1];case"skew":var l=e(a.d[0]),m=e(a.d[1]);return[1,Math.tan(m),0,0,Math.tan(l),1,0,0,0,0,1,0,0,0,0,1];case"skewx":var b=e(a.d[0]);return[1,0,0,0,Math.tan(b),1,0,0,0,0,1,0,0,0,0,1];case"skewy":var b=e(a.d[0]);return[1,Math.tan(b),0,0,0,1,0,0,0,0,1,0,0,0,0,1];case"translate":var c=a.d[0].px||0,d=a.d[1].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,d,0,1];case"translatex":var c=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,0,0,1];case"translatey":var d=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,0,d,0,1];case"translatez":var f=a.d[0].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,0,0,f,1];case"translate3d":var c=a.d[0].px||0,d=a.d[1].px||0,f=a.d[2].px||0;return[1,0,0,0,0,1,0,0,0,0,1,0,c,d,f,1];case"perspective":var n=a.d[0].px?-1/a.d[0].px:0;return[1,0,0,0,0,1,0,0,0,0,1,n,0,0,0,1];case"matrix":return[a.d[0],a.d[1],0,0,a.d[2],a.d[3],0,0,0,0,1,0,a.d[4],a.d[5],0,1];case"matrix3d":return a.d}}function g(a){return 0===a.length?[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]:a.map(f).reduce(d)}function h(a){return[i(g(a))]}var i=function(){function a(a){return a[0][0]*a[1][1]*a[2][2]+a[1][0]*a[2][1]*a[0][2]+a[2][0]*a[0][1]*a[1][2]-a[0][2]*a[1][1]*a[2][0]-a[1][2]*a[2][1]*a[0][0]-a[2][2]*a[0][1]*a[1][0]}function b(b){for(var c=1/a(b),d=b[0][0],e=b[0][1],f=b[0][2],g=b[1][0],h=b[1][1],i=b[1][2],j=b[2][0],k=b[2][1],l=b[2][2],m=[[(h*l-i*k)*c,(f*k-e*l)*c,(e*i-f*h)*c,0],[(i*j-g*l)*c,(d*l-f*j)*c,(f*g-d*i)*c,0],[(g*k-h*j)*c,(j*e-d*k)*c,(d*h-e*g)*c,0]],n=[],o=0;3>o;o++){for(var p=0,q=0;3>q;q++)p+=b[3][q]*m[q][o];n.push(p)}return n.push(1),m.push(n),m}function d(a){return[[a[0][0],a[1][0],a[2][0],a[3][0]],[a[0][1],a[1][1],a[2][1],a[3][1]],[a[0][2],a[1][2],a[2][2],a[3][2]],[a[0][3],a[1][3],a[2][3],a[3][3]]]}function e(a,b){for(var c=[],d=0;4>d;d++){for(var e=0,f=0;4>f;f++)e+=a[f]*b[f][d];c.push(e)}return c}function f(a){var b=g(a);return[a[0]/b,a[1]/b,a[2]/b]}function g(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])}function h(a,b,c,d){return[c*a[0]+d*b[0],c*a[1]+d*b[1],c*a[2]+d*b[2]]}function i(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]}function j(j){var k=[j.slice(0,4),j.slice(4,8),j.slice(8,12),j.slice(12,16)];if(1!==k[3][3])return null;for(var l=[],m=0;4>m;m++)l.push(k[m].slice());for(var m=0;3>m;m++)l[m][3]=0;if(0===a(l))return!1;var n,o=[];if(k[0][3]||k[1][3]||k[2][3]){o.push(k[0][3]),o.push(k[1][3]),o.push(k[2][3]),o.push(k[3][3]);var p=b(l),q=d(p);n=e(o,q)}else n=[0,0,0,1];var r=k[3].slice(0,3),s=[];s.push(k[0].slice(0,3));var t=[];t.push(g(s[0])),s[0]=f(s[0]);var u=[];s.push(k[1].slice(0,3)),u.push(c(s[0],s[1])),s[1]=h(s[1],s[0],1,-u[0]),t.push(g(s[1])),s[1]=f(s[1]),u[0]/=t[1],s.push(k[2].slice(0,3)),u.push(c(s[0],s[2])),s[2]=h(s[2],s[0],1,-u[1]),u.push(c(s[1],s[2])),s[2]=h(s[2],s[1],1,-u[2]),t.push(g(s[2])),s[2]=f(s[2]),u[1]/=t[2],u[2]/=t[2];var v=i(s[1],s[2]);if(c(s[0],v)<0)for(var m=0;3>m;m++)t[m]*=-1,s[m][0]*=-1,s[m][1]*=-1,s[m][2]*=-1;var w,x,y=s[0][0]+s[1][1]+s[2][2]+1;return y>1e-4?(w=.5/Math.sqrt(y),x=[(s[2][1]-s[1][2])*w,(s[0][2]-s[2][0])*w,(s[1][0]-s[0][1])*w,.25/w]):s[0][0]>s[1][1]&&s[0][0]>s[2][2]?(w=2*Math.sqrt(1+s[0][0]-s[1][1]-s[2][2]),x=[.25*w,(s[0][1]+s[1][0])/w,(s[0][2]+s[2][0])/w,(s[2][1]-s[1][2])/w]):s[1][1]>s[2][2]?(w=2*Math.sqrt(1+s[1][1]-s[0][0]-s[2][2]),x=[(s[0][1]+s[1][0])/w,.25*w,(s[1][2]+s[2][1])/w,(s[0][2]-s[2][0])/w]):(w=2*Math.sqrt(1+s[2][2]-s[0][0]-s[1][1]),x=[(s[0][2]+s[2][0])/w,(s[1][2]+s[2][1])/w,.25*w,(s[1][0]-s[0][1])/w]),[r,t,u,x,n]}return j}();a.dot=c,a.makeMatrixDecomposition=h}(d,f),function(a){function b(a,b){var c=a.exec(b);return c?(c=a.ignoreCase?c[0].toLowerCase():c[0],[c,b.substr(c.length)]):void 0}function c(a,b){b=b.replace(/^\s*/,"");var c=a(b);return c?[c[0],c[1].replace(/^\s*/,"")]:void 0}function d(a,d,e){a=c.bind(null,a);for(var f=[];;){var g=a(e);if(!g)return[f,e];if(f.push(g[0]),e=g[1],g=b(d,e),!g||""==g[1])return[f,e];e=g[1]}}function e(a,b){for(var c=0,d=0;d<b.length&&(!/\s|,/.test(b[d])||0!=c);d++)if("("==b[d])c++;else if(")"==b[d]&&(c--,0==c&&d++,0>=c))break;var e=a(b.substr(0,d));return void 0==e?void 0:[e,b.substr(d)]}function f(a,b){for(var c=a,d=b;c&&d;)c>d?c%=d:d%=c;return c=a*b/(c+d)}function g(a){return function(b){var c=a(b);return c&&(c[0]=void 0),c}}function h(a,b){return function(c){var d=a(c);return d?d:[b,c]}}function i(b,c){for(var d=[],e=0;e<b.length;e++){var f=a.consumeTrimmed(b[e],c);if(!f||""==f[0])return;void 0!==f[0]&&d.push(f[0]),c=f[1]}return""==c?d:void 0}function j(a,b,c,d,e){for(var g=[],h=[],i=[],j=f(d.length,e.length),k=0;j>k;k++){var l=b(d[k%d.length],e[k%e.length]);if(!l)return;g.push(l[0]),h.push(l[1]),i.push(l[2])}return[g,h,function(b){var d=b.map(function(a,b){return i[b](a)}).join(c);return a?a(d):d}]}function k(a,b,c){for(var d=[],e=[],f=[],g=0,h=0;h<c.length;h++)if("function"==typeof c[h]){var i=c[h](a[g],b[g++]);d.push(i[0]),e.push(i[1]),f.push(i[2])}else!function(a){d.push(!1),e.push(!1),f.push(function(){return c[a]})}(h);return[d,e,function(a){for(var b="",c=0;c<a.length;c++)b+=f[c](a[c]);return b}]}a.consumeToken=b,a.consumeTrimmed=c,a.consumeRepeated=d,a.consumeParenthesised=e,a.ignore=g,a.optional=h,a.consumeList=i,a.mergeNestedRepeated=j.bind(null,null),a.mergeWrappedNestedRepeated=j,a.mergeList=k}(d),function(a){function b(b){function c(b){var c=a.consumeToken(/^inset/i,b);if(c)return d.inset=!0,c;var c=a.consumeLengthOrPercent(b);if(c)return d.lengths.push(c[0]),c;var c=a.consumeColor(b);return c?(d.color=c[0],c):void 0}var d={inset:!1,lengths:[],color:null},e=a.consumeRepeated(c,/^/,b);return e&&e[0].length?[d,e[1]]:void 0}function c(c){var d=a.consumeRepeated(b,/^,/,c);return d&&""==d[1]?d[0]:void 0}function d(b,c){for(;b.lengths.length<Math.max(b.lengths.length,c.lengths.length);)b.lengths.push({px:0});for(;c.lengths.length<Math.max(b.lengths.length,c.lengths.length);)c.lengths.push({px:0});if(b.inset==c.inset&&!!b.color==!!c.color){for(var d,e=[],f=[[],0],g=[[],0],h=0;h<b.lengths.length;h++){var i=a.mergeDimensions(b.lengths[h],c.lengths[h],2==h);f[0].push(i[0]),g[0].push(i[1]),e.push(i[2])}if(b.color&&c.color){var j=a.mergeColors(b.color,c.color);f[1]=j[0],g[1]=j[1],d=j[2]}return[f,g,function(a){for(var c=b.inset?"inset ":" ",f=0;f<e.length;f++)c+=e[f](a[0][f])+" ";return d&&(c+=d(a[1])),c}]}}function e(b,c,d,e){function f(a){return{inset:a,color:[0,0,0,0],lengths:[{px:0},{px:0},{px:0},{px:0}]}}for(var g=[],h=[],i=0;i<d.length||i<e.length;i++){var j=d[i]||f(e[i].inset),k=e[i]||f(d[i].inset);g.push(j),h.push(k)}return a.mergeNestedRepeated(b,c,g,h)}var f=e.bind(null,d,", ");a.addPropertiesHandler(c,f,["box-shadow","text-shadow"])}(d),function(a,b){function c(a){return a.toFixed(3).replace(".000","")}function d(a,b,c){return Math.min(b,Math.max(a,c))}function e(a){return/^\s*[-+]?(\d*\.)?\d+\s*$/.test(a)?Number(a):void 0}function f(a,b){return[a,b,c]}function g(a,b){return 0!=a?i(0,1/0)(a,b):void 0}function h(a,b){return[a,b,function(a){return Math.round(d(1,1/0,a))}]}function i(a,b){return function(e,f){return[e,f,function(e){return c(d(a,b,e))}]}}function j(a,b){return[a,b,Math.round]}a.clamp=d,a.addPropertiesHandler(e,i(0,1/0),["border-image-width","line-height"]),a.addPropertiesHandler(e,i(0,1),["opacity","shape-image-threshold"]),a.addPropertiesHandler(e,g,["flex-grow","flex-shrink"]),a.addPropertiesHandler(e,h,["orphans","widows"]),a.addPropertiesHandler(e,j,["z-index"]),a.parseNumber=e,a.mergeNumbers=f,a.numberToString=c}(d,f),function(a,b){function c(a,b){return"visible"==a||"visible"==b?[0,1,function(c){return 0>=c?a:c>=1?b:"visible"}]:void 0}a.addPropertiesHandler(String,c,["visibility"])}(d),function(a,b){function c(a){a=a.trim(),f.fillStyle="#000",
+f.fillStyle=a;var b=f.fillStyle;if(f.fillStyle="#fff",f.fillStyle=a,b==f.fillStyle){f.fillRect(0,0,1,1);var c=f.getImageData(0,0,1,1).data;f.clearRect(0,0,1,1);var d=c[3]/255;return[c[0]*d,c[1]*d,c[2]*d,d]}}function d(b,c){return[b,c,function(b){function c(a){return Math.max(0,Math.min(255,a))}if(b[3])for(var d=0;3>d;d++)b[d]=Math.round(c(b[d]/b[3]));return b[3]=a.numberToString(a.clamp(0,1,b[3])),"rgba("+b.join(",")+")"}]}var e=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");e.width=e.height=1;var f=e.getContext("2d");a.addPropertiesHandler(c,d,["background-color","border-bottom-color","border-left-color","border-right-color","border-top-color","color","outline-color","text-decoration-color"]),a.consumeColor=a.consumeParenthesised.bind(null,c),a.mergeColors=d}(d,f),function(a,b){function c(a,b){if(b=b.trim().toLowerCase(),"0"==b&&"px".search(a)>=0)return{px:0};if(/^[^(]*$|^calc/.test(b)){b=b.replace(/calc\(/g,"(");var c={};b=b.replace(a,function(a){return c[a]=null,"U"+a});for(var d="U("+a.source+")",e=b.replace(/[-+]?(\d*\.)?\d+/g,"N").replace(new RegExp("N"+d,"g"),"D").replace(/\s[+-]\s/g,"O").replace(/\s/g,""),f=[/N\*(D)/g,/(N|D)[*\/]N/g,/(N|D)O\1/g,/\((N|D)\)/g],g=0;g<f.length;)f[g].test(e)?(e=e.replace(f[g],"$1"),g=0):g++;if("D"==e){for(var h in c){var i=eval(b.replace(new RegExp("U"+h,"g"),"").replace(new RegExp(d,"g"),"*0"));if(!isFinite(i))return;c[h]=i}return c}}}function d(a,b){return e(a,b,!0)}function e(b,c,d){var e,f=[];for(e in b)f.push(e);for(e in c)f.indexOf(e)<0&&f.push(e);return b=f.map(function(a){return b[a]||0}),c=f.map(function(a){return c[a]||0}),[b,c,function(b){var c=b.map(function(c,e){return 1==b.length&&d&&(c=Math.max(c,0)),a.numberToString(c)+f[e]}).join(" + ");return b.length>1?"calc("+c+")":c}]}var f="px|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc",g=c.bind(null,new RegExp(f,"g")),h=c.bind(null,new RegExp(f+"|%","g")),i=c.bind(null,/deg|rad|grad|turn/g);a.parseLength=g,a.parseLengthOrPercent=h,a.consumeLengthOrPercent=a.consumeParenthesised.bind(null,h),a.parseAngle=i,a.mergeDimensions=e;var j=a.consumeParenthesised.bind(null,g),k=a.consumeRepeated.bind(void 0,j,/^/),l=a.consumeRepeated.bind(void 0,k,/^,/);a.consumeSizePairList=l;var m=function(a){var b=l(a);return b&&""==b[1]?b[0]:void 0},n=a.mergeNestedRepeated.bind(void 0,d," "),o=a.mergeNestedRepeated.bind(void 0,n,",");a.mergeNonNegativeSizePair=n,a.addPropertiesHandler(m,o,["background-size"]),a.addPropertiesHandler(h,d,["border-bottom-width","border-image-width","border-left-width","border-right-width","border-top-width","flex-basis","font-size","height","line-height","max-height","max-width","outline-width","width"]),a.addPropertiesHandler(h,e,["border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","bottom","left","letter-spacing","margin-bottom","margin-left","margin-right","margin-top","min-height","min-width","outline-offset","padding-bottom","padding-left","padding-right","padding-top","perspective","right","shape-margin","text-indent","top","vertical-align","word-spacing"])}(d,f),function(a,b){function c(b){return a.consumeLengthOrPercent(b)||a.consumeToken(/^auto/,b)}function d(b){var d=a.consumeList([a.ignore(a.consumeToken.bind(null,/^rect/)),a.ignore(a.consumeToken.bind(null,/^\(/)),a.consumeRepeated.bind(null,c,/^,/),a.ignore(a.consumeToken.bind(null,/^\)/))],b);return d&&4==d[0].length?d[0]:void 0}function e(b,c){return"auto"==b||"auto"==c?[!0,!1,function(d){var e=d?b:c;if("auto"==e)return"auto";var f=a.mergeDimensions(e,e);return f[2](f[0])}]:a.mergeDimensions(b,c)}function f(a){return"rect("+a+")"}var g=a.mergeWrappedNestedRepeated.bind(null,f,e,", ");a.parseBox=d,a.mergeBoxes=g,a.addPropertiesHandler(d,g,["clip"])}(d,f),function(a,b){function c(a){return function(b){var c=0;return a.map(function(a){return a===k?b[c++]:a})}}function d(a){return a}function e(b){if(b=b.toLowerCase().trim(),"none"==b)return[];for(var c,d=/\s*(\w+)\(([^)]*)\)/g,e=[],f=0;c=d.exec(b);){if(c.index!=f)return;f=c.index+c[0].length;var g=c[1],h=n[g];if(!h)return;var i=c[2].split(","),j=h[0];if(j.length<i.length)return;for(var k=[],o=0;o<j.length;o++){var p,q=i[o],r=j[o];if(p=q?{A:function(b){return"0"==b.trim()?m:a.parseAngle(b)},N:a.parseNumber,T:a.parseLengthOrPercent,L:a.parseLength}[r.toUpperCase()](q):{a:m,n:k[0],t:l}[r],void 0===p)return;k.push(p)}if(e.push({t:g,d:k}),d.lastIndex==b.length)return e}}function f(a){return a.toFixed(6).replace(".000000","")}function g(b,c){if(b.decompositionPair!==c){b.decompositionPair=c;var d=a.makeMatrixDecomposition(b)}if(c.decompositionPair!==b){c.decompositionPair=b;var e=a.makeMatrixDecomposition(c)}return null==d[0]||null==e[0]?[[!1],[!0],function(a){return a?c[0].d:b[0].d}]:(d[0].push(0),e[0].push(1),[d,e,function(b){var c=a.quat(d[0][3],e[0][3],b[5]),g=a.composeMatrix(b[0],b[1],b[2],c,b[4]),h=g.map(f).join(",");return h}])}function h(a){return a.replace(/[xy]/,"")}function i(a){return a.replace(/(x|y|z|3d)?$/,"3d")}function j(b,c){var d=a.makeMatrixDecomposition&&!0,e=!1;if(!b.length||!c.length){b.length||(e=!0,b=c,c=[]);for(var f=0;f<b.length;f++){var j=b[f].t,k=b[f].d,l="scale"==j.substr(0,5)?1:0;c.push({t:j,d:k.map(function(a){if("number"==typeof a)return l;var b={};for(var c in a)b[c]=l;return b})})}}var m=function(a,b){return"perspective"==a&&"perspective"==b||("matrix"==a||"matrix3d"==a)&&("matrix"==b||"matrix3d"==b)},o=[],p=[],q=[];if(b.length!=c.length){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]]}else for(var f=0;f<b.length;f++){var j,s=b[f].t,t=c[f].t,u=b[f].d,v=c[f].d,w=n[s],x=n[t];if(m(s,t)){if(!d)return;var r=g([b[f]],[c[f]]);o.push(r[0]),p.push(r[1]),q.push(["matrix",[r[2]]])}else{if(s==t)j=s;else if(w[2]&&x[2]&&h(s)==h(t))j=h(s),u=w[2](u),v=x[2](v);else{if(!w[1]||!x[1]||i(s)!=i(t)){if(!d)return;var r=g(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]];break}j=i(s),u=w[1](u),v=x[1](v)}for(var y=[],z=[],A=[],B=0;B<u.length;B++){var C="number"==typeof u[B]?a.mergeNumbers:a.mergeDimensions,r=C(u[B],v[B]);y[B]=r[0],z[B]=r[1],A.push(r[2])}o.push(y),p.push(z),q.push([j,A])}}if(e){var D=o;o=p,p=D}return[o,p,function(a){return a.map(function(a,b){var c=a.map(function(a,c){return q[b][1][c](a)}).join(",");return"matrix"==q[b][0]&&16==c.split(",").length&&(q[b][0]="matrix3d"),q[b][0]+"("+c+")"}).join(" ")}]}var k=null,l={px:0},m={deg:0},n={matrix:["NNNNNN",[k,k,0,0,k,k,0,0,0,0,1,0,k,k,0,1],d],matrix3d:["NNNNNNNNNNNNNNNN",d],rotate:["A"],rotatex:["A"],rotatey:["A"],rotatez:["A"],rotate3d:["NNNA"],perspective:["L"],scale:["Nn",c([k,k,1]),d],scalex:["N",c([k,1,1]),c([k,1])],scaley:["N",c([1,k,1]),c([1,k])],scalez:["N",c([1,1,k])],scale3d:["NNN",d],skew:["Aa",null,d],skewx:["A",null,c([k,m])],skewy:["A",null,c([m,k])],translate:["Tt",c([k,k,l]),d],translatex:["T",c([k,l,l]),c([k,l])],translatey:["T",c([l,k,l]),c([l,k])],translatez:["L",c([l,l,k])],translate3d:["TTL",d]};a.addPropertiesHandler(e,j,["transform"])}(d,f),function(a){function b(a){var b=Number(a);return isNaN(b)||100>b||b>900||b%100!==0?void 0:b}function c(b){return b=100*Math.round(b/100),b=a.clamp(100,900,b),400===b?"normal":700===b?"bold":String(b)}function d(a,b){return[a,b,c]}a.addPropertiesHandler(b,d,["font-weight"])}(d),function(a){function b(a){var b={};for(var c in a)b[c]=-a[c];return b}function c(b){return a.consumeToken(/^(left|center|right|top|bottom)\b/i,b)||a.consumeLengthOrPercent(b)}function d(b,d){var e=a.consumeRepeated(c,/^/,d);if(e&&""==e[1]){var f=e[0];if(f[0]=f[0]||"center",f[1]=f[1]||"center",3==b&&(f[2]=f[2]||{px:0}),f.length==b){if(/top|bottom/.test(f[0])||/left|right/.test(f[1])){var h=f[0];f[0]=f[1],f[1]=h}if(/left|right|center|Object/.test(f[0])&&/top|bottom|center|Object/.test(f[1]))return f.map(function(a){return"object"==typeof a?a:g[a]})}}}function e(d){var e=a.consumeRepeated(c,/^/,d);if(e){for(var f=e[0],h=[{"%":50},{"%":50}],i=0,j=!1,k=0;k<f.length;k++){var l=f[k];"string"==typeof l?(j=/bottom|right/.test(l),i={left:0,right:0,center:i,top:1,bottom:1}[l],h[i]=g[l],"center"==l&&i++):(j&&(l=b(l),l["%"]=(l["%"]||0)+100),h[i]=l,i++,j=!1)}return[h,e[1]]}}function f(b){var c=a.consumeRepeated(e,/^,/,b);return c&&""==c[1]?c[0]:void 0}var g={left:{"%":0},center:{"%":50},right:{"%":100},top:{"%":0},bottom:{"%":100}},h=a.mergeNestedRepeated.bind(null,a.mergeDimensions," ");a.addPropertiesHandler(d.bind(null,3),h,["transform-origin"]),a.addPropertiesHandler(d.bind(null,2),h,["perspective-origin"]),a.consumePosition=e,a.mergeOffsetList=h;var i=a.mergeNestedRepeated.bind(null,h,", ");a.addPropertiesHandler(f,i,["background-position","object-position"])}(d),function(a){function b(b){var c=a.consumeToken(/^circle/,b);if(c&&c[0])return["circle"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),d,a.ignore(a.consumeToken.bind(void 0,/^at/)),a.consumePosition,a.ignore(a.consumeToken.bind(void 0,/^\)/))],c[1]));var f=a.consumeToken(/^ellipse/,b);if(f&&f[0])return["ellipse"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),e,a.ignore(a.consumeToken.bind(void 0,/^at/)),a.consumePosition,a.ignore(a.consumeToken.bind(void 0,/^\)/))],f[1]));var g=a.consumeToken(/^polygon/,b);return g&&g[0]?["polygon"].concat(a.consumeList([a.ignore(a.consumeToken.bind(void 0,/^\(/)),a.optional(a.consumeToken.bind(void 0,/^nonzero\s*,|^evenodd\s*,/),"nonzero,"),a.consumeSizePairList,a.ignore(a.consumeToken.bind(void 0,/^\)/))],g[1])):void 0}function c(b,c){return b[0]===c[0]?"circle"==b[0]?a.mergeList(b.slice(1),c.slice(1),["circle(",a.mergeDimensions," at ",a.mergeOffsetList,")"]):"ellipse"==b[0]?a.mergeList(b.slice(1),c.slice(1),["ellipse(",a.mergeNonNegativeSizePair," at ",a.mergeOffsetList,")"]):"polygon"==b[0]&&b[1]==c[1]?a.mergeList(b.slice(2),c.slice(2),["polygon(",b[1],g,")"]):void 0:void 0}var d=a.consumeParenthesised.bind(null,a.parseLengthOrPercent),e=a.consumeRepeated.bind(void 0,d,/^/),f=a.mergeNestedRepeated.bind(void 0,a.mergeDimensions," "),g=a.mergeNestedRepeated.bind(void 0,f,",");a.addPropertiesHandler(b,c,["shape-outside"])}(d),function(a,b){function c(a,b){b.concat([a]).forEach(function(b){b in document.documentElement.style&&(d[a]=b)})}var d={};c("transform",["webkitTransform","msTransform"]),c("transformOrigin",["webkitTransformOrigin"]),c("perspective",["webkitPerspective"]),c("perspectiveOrigin",["webkitPerspectiveOrigin"]),a.propertyName=function(a){return d[a]||a}}(d,f)}(),!function(){if(void 0===document.createElement("div").animate([]).oncancel){var a;if(window.performance&&performance.now)var a=function(){return performance.now()};else var a=function(){return Date.now()};var b=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},c=window.Element.prototype.animate;window.Element.prototype.animate=function(d,e){var f=c.call(this,d,e);f._cancelHandlers=[],f.oncancel=null;var g=f.cancel;f.cancel=function(){g.call(this);var c=new b(this,null,a()),d=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){d.forEach(function(a){a.call(c.target,c)})},0)};var h=f.addEventListener;f.addEventListener=function(a,b){"function"==typeof b&&"cancel"==a?this._cancelHandlers.push(b):h.call(this,a,b)};var i=f.removeEventListener;return f.removeEventListener=function(a,b){if("cancel"==a){var c=this._cancelHandlers.indexOf(b);c>=0&&this._cancelHandlers.splice(c,1)}else i.call(this,a,b)},f}}}(),function(a){var b=document.documentElement,c=null,d=!1;try{var e=getComputedStyle(b).getPropertyValue("opacity"),f="0"==e?"1":"0";c=b.animate({opacity:[f,f]},{duration:1}),c.currentTime=0,d=getComputedStyle(b).getPropertyValue("opacity")==f}catch(g){}finally{c&&c.cancel()}if(!d){var h=window.Element.prototype.animate;window.Element.prototype.animate=function(b,c){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&b[Symbol.iterator]&&(b=Array.from(b)),Array.isArray(b)||null===b||(b=a.convertToArrayForm(b)),h.call(this,b,c)}}}(c),b["true"]=a}({},function(){return this}());
+//# sourceMappingURL=web-animations.min.js.map \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js.map b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js.map
new file mode 100644
index 00000000000..8c6d3075feb
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/web-animations-js/web-animations.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["src/scope.js","src/timing-utilities.js","src/normalize-keyframes.js","src/deprecation.js","src/keyframe-interpolations.js","src/property-interpolation.js","src/keyframe-effect.js","src/apply-preserving-inline-style.js","src/element-animatable.js","src/interpolation.js","src/matrix-interpolation.js","src/animation.js","src/tick.js","src/web-animations-bonus-cancel-events.js","src/web-animations-bonus-object-form-keyframes.js"],"names":["webAnimationsShared","webAnimations1","webAnimationsNext","webAnimationsTesting","shared","testing","cloneTimingInput","timingInput","clone","m","AnimationEffectTiming","this","_delay","_endDelay","_fill","_iterationStart","_iterations","_duration","_playbackRate","_direction","_easing","_easingFunction","linear","isInvalidTimingDeprecated","isDeprecated","makeTiming","forGroup","effect","timing","fill","duration","isNaN","undefined","Object","getOwnPropertyNames","forEach","property","fills","indexOf","directions","numericTimingToObject","normalizeTimingInput","cubic","a","b","c","d","x","f","start","end","mid","xEst","Math","abs","step","count","pos","stepSize","toTimingFunction","easing","styleForCleaning","document","createElement","style","animationTimingFunction","validatedEasing","TypeError","cubicData","cubicBezierRe","exec","apply","slice","map","Number","stepData","stepRe","Start","middle","Middle","End","preset","presets","calculateActiveDuration","repeatedDuration","playbackRate","iterations","calculatePhase","activeDuration","localTime","PhaseNone","delay","PhaseBefore","PhaseAfter","PhaseActive","calculateActiveTime","fillMode","phase","calculateScaledActiveTime","activeTime","startOffset","calculateIterationTime","iterationDuration","scaledActiveTime","Infinity","iterationStart","calculateCurrentIteration","iterationTime","floor","calculateTransformedTime","currentIteration","currentIterationIsOdd","currentDirectionIsForwards","direction","directedTime","timeFraction","calculateTimeFraction","split","prototype","_setMember","member","value","_effect","_timingInput","_timing","_animation","_rebuildUnderlyingAnimation","endDelay","ease","ease-in","ease-out","ease-in-out","step-start","step-middle","step-end","numberString","RegExp","antiAlias","aliases","expandShorthandAndAntiAlias","result","longProperties","shorthandToLonghand","shorthandExpanderElem","i","longProperty","longhandValue","convertToArrayForm","effectInput","normalizedEffectInput","values","Array","isArray","keyframe","numKeyframes","length","offset","composite","push","sort","normalizeKeyframes","spaceKeyframes","keyframes","previousIndex","previousOffset","j","window","Symbol","iterator","from","originalKeyframe","memberValue","isFinite","type","DOMException","NOT_SUPPORTED_ERR","name","message","everyFrameHasOffset","code","INVALID_MODIFICATION_ERR","filter","background","border","borderBottom","borderColor","borderLeft","borderRadius","borderRight","borderTop","borderWidth","flex","font","margin","outline","padding","createElementNS","borderWidthAliases","thin","medium","thick","borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopWidth","fontSize","xx-small","x-small","small","large","x-large","xx-large","fontWeight","normal","bold","outlineWidth","textShadow","none","boxShadow","silenced","feature","date","advice","plural","auxVerb","today","Date","expiry","setMonth","getMonth","console","warn","toDateString","deprecated","Error","scope","r","makePropertySpecificKeyframeGroups","leftCopy","propertySpecificKeyframeGroups","bind","addPropertiesHandler","parseShadowList","mergeShadowList","propertySpecificKeyframe","groupName","group","mergeFlex","left","right","round","makeInterpolations","interpolations","startTime","endTime","startValue","endValue","propertyInterpolation","leftInterpolation","rightInterpolation","convertEffectInput","trim","context","target","fraction","interpolation","fillStyle","offsetFraction","localDuration","scaledLocalTime","clamp","join","canvas","toCamelCase","parseColor","toUpperCase","addPropertyHandler","merger","propertyHandlers","parser","properties","ucProperty","test","matchedUnits","string","replace","unitRegExp","initialValues","handlers","parsedRight","parsedLeft","interpolationArgs","interp","Interpolation","t","taggedUnitRegExp","unit","bool","backgroundColor","nonNegative","backgroundPosition","units","borderBottomColor","borderBottomLeftRadius","borderBottomRightRadius","borderLeftColor","borderRightColor","borderSpacing","borderTopColor","borderTopLeftRadius","borderTopRightRadius","numberToString","clip","color","height","marginBottom","marginLeft","marginRight","lengthUnits","marginTop","parseLengthOrPercent","maxWidth","minHeight","minWidth","opacity","parseAngle","outlineColor","outlineOffset","paddingBottom","paddingLeft","transform","verticalAlign","visibility","width","wordSpacing","consumeLength","zIndex","consumeParenthesised","consumeSizePairList","EffectTime","effectTime","_totalDuration","_isCurrent","KeyframeEffect","keyframeEffect","_update","_clear","_hasSameTarget","id","NullEffect","clear","nullEffect","configureProperty","object","descriptor","enumerable","configurable","defineProperty","AnimatedCSSStyleDeclaration","element","_surrogateStyle","ignore","consumeToken","_style","_length","_isAnimatedProperty","_updateIndices","ensureStyleIsPatched","_webAnimationsPatchedStyle","merged","animatedStyle","mergeDimensions","get","mergeWrappedNestedRepeated","_","styleAttributes","cssText","parentRule","styleMethods","getPropertyCSSValue","getPropertyPriority","getPropertyValue","item","removeProperty","setProperty","styleMutatingMethods","text","transformRegExp","isAffectedProperty","functionName","argTypes","s","T","parsedArgs","index","method","modifiesStyle","list","arguments","documentElement","matrixModulesLoaded","set","_set","propertyName","Element","animate","options","mergeMatrices","timeline","interpolate","leftArgs","to","transformFunctions","leftType","leftResult","convertToString","typeTo2D","max","rightArgs","quat","product","dot","fromQ","theta","sqrt","cos","toQ","w","composeMatrix","leftFunctionData","multiply","leftArgsCopy","k","mergeNumbers","merge","rightArgsCopy","translate","skew","perspective","matrix","types","stringConversions","tmp","rightResult","rotMatrix","stringifiedArgs","args","arg","y","z","deg","temp","rotate","rotatez","scale","cast","scaley","scale3d","is2D","concat","translatey","sequenceNumber","AnimationEvent","currentTime","timelineTime","out","bubbles","cancelable","currentTarget","defaultPrevented","eventPhase","Event","AT_TARGET","timeStamp","now","Animation","_id","_sequenceNumber","_currentTime","dimension","_paused","_inTimeline","_finishedFlag","onfinish","consumeOffset","_finishHandlers","_idle","consumeLengthOrPercent","_currentTimePending","_ensureAlive","_inEffect","_animations","_tickCurrentTime","newTime","ignoreLimit","_isFinished","position","restart","_startTime","_timeline","bottomOrRight","invalidateEffects","token","center","oldCurrentTime","mergeNestedRepeated","playState","play","parseOrigin","consumePosition","mergeOffsetList","circle","consumeList","pause","finish","ellipse","cancel","reverse","polygon","addEventListener","handler","_fireEvents","baseTime","event","setTimeout","mergeNonNegativeSizePair","call","_tick","isAnimationFrame","_needsTick","running","mergeSizePair","processRafCallbacks","processing","rafCallbacks","candidate","entry","applyPendingEffects","compareAnimations","rightAnimation","leftAnimation","InternalTimeline","performance","oncancel","AnimationCancelEvent","originalElementAnimate","animation","_cancelHandlers","originalCancel","originalAddEventListener","originalRemoveEventListener","removeEventListener","splice","animated","originalOpacity","getComputedStyle","testOpacity","error","exports"],"mappings":";;;;;;;;;;;;;;CAcA,SAAIA,EAAAA,GAAJ,GAAIA,MACAC,KACAC,KAGEC,EAAuB,MCL7B,SAAUC,EAAQC,GAMhB,QAASC,GAAiBC,GACxB,GAA0B,gBAAfA,GACT,MAAOA,EAET,IAAIC,KACJ,KAAK,GAAIC,KAAKF,GACZC,EAAMC,GAAKF,EAAYE,EAEzB,OAAOD,GAGT,QAASE,KACPC,KAAKC,OAAS,EACdD,KAAKE,UAAY,EACjBF,KAAKG,MAAQ,OACbH,KAAKI,gBAAkB,EACvBJ,KAAKK,YAAc,EACnBL,KAAKM,UAAY,EACjBN,KAAKO,cAAgB,EACrBP,KAAKQ,WAAa,SAClBR,KAAKS,QAAU,SACfT,KAAKU,gBAAkBC,EAGzB,QAASC,KACP,MAAOnB,GAAOoB,aAAa,wBAAyB,aAAc,gDAAA,GA8EpE,QAASC,GAAWlB,EAAamB,EAAUC,GACzC,GAAIC,GAAS,GAAIlB,EA4BjB,OA3BIgB,KACFE,EAAOC,KAAO,OACdD,EAAOE,SAAW,QAEM,gBAAfvB,IAA4BwB,MAAMxB,GAElByB,SAAhBzB,GACT0B,OAAOC,oBAAoB3B,GAAa4B,QAAQ,SAASC,GACvD,GAA6B,QAAzB7B,EAAY6B,GAAqB,CACnC,IAA+B,gBAApBR,GAAOQ,IAAqC,YAAZA,KACL,gBAAzB7B,GAAY6B,IAAyBL,MAAMxB,EAAY6B,KAChE,MAGJ,IAAiB,QAAZA,GAAgE,IAAxCC,EAAMC,QAAQ/B,EAAY6B,IACrD,MAEF,IAAiB,aAAZA,GAA0E,IAA7CG,EAAWD,QAAQ/B,EAAY6B,IAC/D,MAEF,IAAgB,gBAAZA,GAAwD,IAA1B7B,EAAY6B,IAAmBhC,EAAOoB,aAAa,qCAAsC,aAAc,uCACvI,MAEFI,GAAOQ,GAAY7B,EAAY6B,MAlBnCR,EAAOE,SAAWvB,EAsBbqB,EAGT,QAASY,GAAsBjC,GAQ7B,MAP0B,gBAAfA,KAEPA,EADEwB,MAAMxB,IACQuB,SAAU,IAEVA,SAAUvB,IAGvBA,EAGT,QAASkC,GAAqBlC,EAAamB,GAEzC,MADAnB,GAAcH,EAAOoC,sBAAsBjC,GACpCkB,EAAWlB,EAAamB,GAGjC,QAASgB,GAAMC,EAAGC,EAAGC,EAAGC,GACtB,MAAQ,GAAJH,GAASA,EAAI,GAAS,EAAJE,GAASA,EAAI,EAC1BvB,EAEF,SAASyB,GAOZ,QAASC,GAAEL,EAAGC,EAAGnC,GAAK,MAAO,GAAIkC,GAAK,EAAIlC,IAAM,EAAIA,GAAKA,EAAI,EAAImC,GAAK,EAAInC,GAAKA,EAAIA,EAAIA,EAAIA,EAAIA,EANjG,GAAS,GAALsC,GAAe,GAALA,EACZ,MAAOA,EAGT,KADA,GAAIE,GAAQ,EAAGC,EAAM,IACX,CACR,GAAIC,IAAOF,EAAQC,GAAO,EAEtBE,EAAOJ,EAAEL,EAAGE,EAAGM,EACnB,IAAIE,KAAKC,IAAIP,EAAIK,GAAQ,KACvB,MAAOJ,GAAEJ,EAAGE,EAAGK,EAENJ,GAAPK,EACFH,EAAQE,EAERD,EAAMC,IAUd,QAASI,GAAKC,EAAOC,GACnB,MAAO,UAASV,GACd,GAAIA,GAAK,EACP,MAAO,EAET,IAAIW,GAAW,EAAIF,CAEnB,OADAT,IAAKU,EAAMC,EACJX,EAAIA,EAAIW,GAmBnB,QAASC,GAAiBC,GACnBC,IACHA,EAAmBC,SAASC,cAAc,OAAOC,OAEnDH,EAAiBI,wBAA0B,GAC3CJ,EAAiBI,wBAA0BL,CAC3C,IAAIM,GAAkBL,EAAiBI,uBAEvC,IAAuB,IAAnBC,GAAyB3C,IAC3B,KAAM,IAAI4C,WAAUP,EAAS,mCAG/B,IAAIQ,GAAYC,EAAcC,KAAKJ,EACnC,IAAIE,EACF,MAAO1B,GAAM6B,MAAM5D,KAAMyD,EAAUI,MAAM,GAAGC,IAAIC,QAElD,IAAIC,GAAWC,EAAON,KAAKJ,EAC3B,IAAIS,EACF,MAAOpB,GAAKmB,OAAOC,EAAS,KAAM1B,MAAS4B,EAAOC,OAAUC,EAAQ7B,IAAO8B,GAAKL,EAAS,IAE3F,IAAIM,GAASC,EAAQhB,EACrB,OAAIe,GACKA,EAEF3D,EAGT,QAAS6D,GAAwBvD,GAC/B,MAAOyB,MAAKC,IAAI8B,EAAiBxD,GAAUA,EAAOyD,cAGpD,QAASD,GAAiBxD,GACxB,MAAOA,GAAOE,SAAWF,EAAO0D,WAQlC,QAASC,GAAeC,EAAgBC,EAAW7D,GACjD,MAAiB,OAAb6D,EACKC,EAELD,EAAY7D,EAAO+D,MACdC,EAELH,GAAa7D,EAAO+D,MAAQH,EACvBK,EAEFC,EAGT,QAASC,GAAoBP,EAAgBQ,EAAUP,EAAWQ,EAAON,GACvE,OAAQM,GACN,IAAKL,GACH,MAAgB,aAAZI,GAAuC,QAAZA,EACtB,EACF,IACT,KAAKF,GACH,MAAOL,GAAYE,CACrB,KAAKE,GACH,MAAgB,YAAZG,GAAsC,QAAZA,EACrBR,EACF,IACT,KAAKE,GACH,MAAO,OAIb,QAASQ,GAA0BV,EAAgBW,EAAYC,EAAaxE,GAC1E,OAAQA,EAAOyD,aAAe,EAAIc,EAAaX,EAAiBW,GAAcvE,EAAOyD,aAAee,EAGtG,QAASC,GAAuBC,EAAmBlB,EAAkBmB,EAAkBH,EAAaxE,GAClG,MAAI2E,KAAqBC,EAAAA,GAAYD,MAAsBC,EAAAA,IAAaD,EAAmBH,GAAehB,GAAoBxD,EAAO0D,aAAgB1D,EAAO0D,WAAa1D,EAAO6E,gBAAkB,GAAK,EAC9LH,EAGFC,EAAmBD,EAG5B,QAASI,GAA0BJ,EAAmBK,EAAeJ,EAAkB3E,GACrF,MAAyB,KAArB2E,EACK,EAELI,GAAiBL,EACZ1E,EAAO6E,eAAiB7E,EAAO0D,WAAa,EAE9CjC,KAAKuD,MAAML,EAAmBD,GAGvC,QAASO,GAAyBC,EAAkBR,EAAmBK,EAAe/E,GACpF,GAAImF,GAAwBD,EAAmB,GAAK,EAChDE,EAAiD,UAApBpF,EAAOqF,WAAyBrF,EAAOqF,YAAcF,EAAwB,oBAAsB,aAChIG,EAAeF,EAA6BL,EAAgBL,EAAoBK,EAChFQ,EAAeD,EAAeZ,CAClC,OAAOA,GAAoB1E,EAAOP,gBAAgB8F,GAGpD,QAASC,GAAsB5B,EAAgBC,EAAW7D,GACxD,GAAIqE,GAAQV,EAAeC,EAAgBC,EAAW7D,GAClDuE,EAAaJ,EAAoBP,EAAgB5D,EAAOC,KAAM4D,EAAWQ,EAAOrE,EAAO+D,MAC3F,IAAmB,OAAfQ,EACF,MAAO,KACT,IAAuB,IAAnBX,EACF,MAAOS,KAAUL,EAAc,EAAI,CACrC,IAAIQ,GAAcxE,EAAO6E,eAAiB7E,EAAOE,SAC7CyE,EAAmBL,EAA0BV,EAAgBW,EAAYC,EAAaxE,GACtF+E,EAAgBN,EAAuBzE,EAAOE,SAAUsD,EAAiBxD,GAAS2E,EAAkBH,EAAaxE,GACjHkF,EAAmBJ,EAA0B9E,EAAOE,SAAU6E,EAAeJ,EAAkB3E,EACnG,OAAOiF,GAAyBC,EAAkBlF,EAAOE,SAAU6E,EAAe/E,GAAUA,EAAOE,SAjUrG,GAAIO,GAAQ,+BAA+BgF,MAAM,KAC7C9E,EAAa,sCAAsC8E,MAAM,KACzD/F,EAAS,SAASyB,GAAK,MAAOA,GA8BlCrC,GAAsB4G,WACpBC,WAAY,SAASC,EAAQC,GAC3B9G,KAAK,IAAM6G,GAAUC,EACjB9G,KAAK+G,UACP/G,KAAK+G,QAAQC,aAAaH,GAAUC,EACpC9G,KAAK+G,QAAQE,QAAUxH,EAAOqC,qBAAqB9B,KAAK+G,QAAQC,cAChEhH,KAAK+G,QAAQlC,eAAiBpF,EAAO+E,wBAAwBxE,KAAK+G,QAAQE,SACtEjH,KAAK+G,QAAQG,YACflH,KAAK+G,QAAQG,WAAWC,gCAI9BzC,GAAIA,gBACF,MAAO1E,MAAKO,eAEdyE,GAAIA,OAAM8B,GACR9G,KAAK4G,WAAW,QAASE,IAE3B9B,GAAIA,SACF,MAAOhF,MAAKC,QAEdmH,GAAIA,UAASN,GACX9G,KAAK4G,WAAW,WAAYE,IAE9BM,GAAIA,YACF,MAAOpH,MAAKE,WAEdgB,GAAIA,MAAK4F,GACP9G,KAAK4G,WAAW,OAAQE,IAE1B5F,GAAIA,QACF,MAAOlB,MAAKG,OAEd2F,GAAIA,gBAAegB,GACjB,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,2DAA6DvC,OAAO6E,eAE1F9F,MAAK4G,WAAW,iBAAkBE,IAEpChB,GAAIA,kBACF,MAAO9F,MAAKI,iBAEde,GAAIA,UAAS2F,GACX,GAAa,QAATA,IAAoB1F,MAAM0F,IAAkB,EAARA,IAAclG,IACpD,KAAM,IAAI4C,WAAU,oDAAsDsD,EAE5E9G,MAAK4G,WAAW,WAAYE,IAE9B3F,GAAIA,YACF,MAAOnB,MAAKM,WAEdgG,GAAIA,WAAUQ,GACZ9G,KAAK4G,WAAW,YAAaE,IAE/BR,GAAIA,aACF,MAAOtG,MAAKQ,YAEdyC,GAAIA,QAAO6D,GACT9G,KAAKU,gBAAkBsC,EAAiB8D,GACxC9G,KAAK4G,WAAW,SAAUE,IAE5B7D,GAAIA,UACF,MAAOjD,MAAKS,SAEdkE,GAAIA,YAAWmC,GACb,IAAK1F,MAAM0F,IAAkB,EAARA,IAAclG,IACjC,KAAM,IAAI4C,WAAU,8CAAgDsD,EAEtE9G,MAAK4G,WAAW,aAAcE,IAEhCnC,GAAIA,cACF,MAAO3E,MAAKK,aA6EhB,IAAI6D,GAAQ,EACRE,EAAS,GACTC,EAAM,EAaNE,GACF8C,KAAQtF,EAAM,IAAM,GAAK,IAAM,GAC/BuF,UAAWvF,EAAM,IAAM,EAAG,EAAG,GAC7BwF,WAAYxF,EAAM,EAAG,EAAG,IAAM,GAC9ByF,cAAezF,EAAM,IAAM,EAAG,IAAM,GACpC0F,aAAc7E,EAAK,EAAGsB,GACtBwD,cAAe9E,EAAK,EAAGwB,GACvBuD,WAAY/E,EAAK,EAAGyB,IAGlBnB,EAAmB,KACnB0E,EAAe,qCACflE,EAAgB,GAAImE,QAAO,kBAAoBD,EAAe,IAAMA,EAAe,IAAMA,EAAe,IAAMA,EAAe,OAC7H3D,EAAS,gDAqCTc,EAAY,EACZE,EAAc,EACdC,EAAa,EACbC,EAAc,CA4ElB1F,GAAOE,iBAAmBA,EAC1BF,EAAOqB,WAAaA,EACpBrB,EAAOoC,sBAAwBA,EAC/BpC,EAAOqC,qBAAuBA,EAC9BrC,EAAO+E,wBAA0BA,EACjC/E,EAAOgH,sBAAwBA,EAC/BhH,EAAOmF,eAAiBA,EACxBnF,EAAOuD,iBAAmBA,GAkBzB3D,EAAqBG,GC/VxB,SAAUC,EAAQC,GAmIhB,QAASoI,GAAUrG,EAAUqF,GAC3B,MAAIrF,KAAYsG,GACPA,EAAQtG,GAAUqF,IAAUA,EAE9BA,EAIT,QAASkB,GAA4BvG,EAAUqF,EAAOmB,GACpD,GAAIC,GAAiBC,EAAoB1G,EACzC,IAAIyG,EAAgB,CAClBE,EAAsB/E,MAAM5B,GAAYqF,CACxC,KAAK,GAAIuB,KAAKH,GAAgB,CAC5B,GAAII,GAAeJ,EAAeG,GAC9BE,EAAgBH,EAAsB/E,MAAMiF,EAChDL,GAAOK,GAAgBR,EAAUQ,EAAcC,QAGjDN,GAAOxG,GAAYqG,EAAUrG,EAAUqF,GAI3C,QAAS0B,GAAmBC,GAC1B,GAAIC,KAEJ,KAAK,GAAIjH,KAAYgH,GACnB,KAAIhH,KAAa,SAAU,SAAU,cAArC,CAIA,GAAIkH,GAASF,EAAYhH,EACpBmH,OAAMC,QAAQF,KACjBA,GAAUA,GAKZ,KAAK,GAFDG,GACAC,EAAeJ,EAAOK,OACjBX,EAAI,EAAOU,EAAJV,EAAkBA,IAChCS,KAEI,UAAYL,GACdK,EAASG,OAASR,EAAYQ,OACL,GAAhBF,EACTD,EAASG,OAAS,EAElBH,EAASG,OAASZ,GAAKU,EAAe,GAGpC,UAAYN,KACdK,EAAS7F,OAASwF,EAAYxF,QAG5B,aAAewF,KACjBK,EAASI,UAAYT,EAAYS,WAGnCJ,EAASrH,GAAYkH,EAAON,GAE5BK,EAAsBS,KAAKL,GAK/B,MADAJ,GAAsBU,KAAK,SAASpH,EAAGC,GAAK,MAAOD,GAAEiH,OAAShH,EAAEgH,SACzDP,EAGT,QAASW,GAAmBZ,GA+D1B,QAASa,KACP,GAAIN,GAASO,EAAUP,MACa,OAAhCO,EAAUP,EAAS,GAAGC,SACxBM,EAAUP,EAAS,GAAGC,OAAS,GAC7BD,EAAS,GAA4B,MAAvBO,EAAU,GAAGN,SAC7BM,EAAU,GAAGN,OAAS,EAIxB,KAAK,GAFDO,GAAgB,EAChBC,EAAiBF,EAAU,GAAGN,OACzBZ,EAAI,EAAOW,EAAJX,EAAYA,IAAK,CAC/B,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,IAAK,GAAIS,GAAI,EAAOrB,EAAImB,EAARE,EAAuBA,IACrCH,EAAUC,EAAgBE,GAAGT,OAASQ,GAAkBR,EAASQ,GAAkBC,GAAKrB,EAAImB,EAC9FA,GAAgBnB,EAChBoB,EAAiBR,IA7EvB,GAAmB,MAAfR,EACF,QAGEkB,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,KACjBA,EAAcD,EAAmBC,GAgCnC,KAAK,GA7BDc,GAAYd,EAAY3E,IAAI,SAASiG,GACvC,GAAIjB,KACJ,KAAK,GAAIjC,KAAUkD,GAAkB,CACnC,GAAIC,GAAcD,EAAiBlD,EACnC,IAAc,UAAVA,GACF,GAAmB,MAAfmD,IACFA,EAAcjG,OAAOiG,IAChBC,SAASD,IACZ,KAAM,IAAIxG,WAAU,yCAEnB,CAAA,GAAc,aAAVqD,EACT,MACEqD,KAAMC,aAAaC,kBACnBC,KAAM,oBACNC,QAAS,mCAGXN,GAAc,GAAKA,EAErBhC,EAA4BnB,EAAQmD,EAAalB,GAInD,MAFuBzH,SAAnByH,EAASG,SACXH,EAASG,OAAS,MACbH,IAGLyB,GAAAA,EAEAd,IAAkB5D,EAAAA,GACbwC,EAAI,EAAGA,EAAIkB,EAAUP,OAAQX,IAAK,CACzC,GAAIY,GAASM,EAAUlB,GAAGY,MAC1B,IAAc,MAAVA,EAAgB,CAClB,GAAaQ,EAATR,EACF,MACEuB,KAAML,aAAaM,yBACnBJ,KAAM,2BACNC,QAAS,uEAGbb,GAAiBR,MAEjBsB,IAAAA,EA8BJ,MA1BAhB,GAAYA,EAAUmB,OAAO,SAAS5B,GACpC,MAAOA,GAASG,QAAU,GAAKH,EAASG,QAAU,IAsB/CsB,GACHjB,IAEKC,EAzRT,GAAIpB,IACFwC,YACE,kBACA,qBACA,iBACA,mBACA,uBACA,mBACA,iBACA,mBAEFC,QACE,iBACA,iBACA,iBACA,mBACA,mBACA,mBACA,oBACA,oBACA,oBACA,kBACA,kBACA,mBAEFC,cACE,oBACA,oBACA,qBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,YACE,kBACA,kBACA,mBAEFC,cACE,sBACA,uBACA,0BACA,0BAEFC,aACE,mBACA,mBACA,oBAEFC,WACE,iBACA,iBACA,kBAEFC,aACE,iBACA,mBACA,oBACA,mBAEFC,MACE,WACA,aACA,aAEFC,MACE,aACA,WACA,YACA,cACA,aACA,cAEFC,QACE,YACA,cACA,eACA,cAEFC,SACE,eACA,eACA,gBAEFC,SACE,aACA,eACA,gBACA,gBAIApD,EAAwBjF,SAASsI,gBAAgB,+BAAgC,OAEjFC,GACFC,KAAM,MACNC,OAAQ,MACRC,MAAO,OAGL9D,GACF+D,kBAAmBJ,EACnBK,gBAAiBL,EACjBM,iBAAkBN,EAClBO,eAAgBP,EAChBQ,UACEC,WAAY,MACZC,UAAW,MACXC,MAAS,MACTT,OAAU,OACVU,MAAS,OACTC,UAAW,OACXC,WAAY,QAEdC,YACEC,OAAQ,MACRC,KAAM,OAERC,aAAclB,EACdmB,YACEC,KAAM,2BAERC,WACED,KAAM,+BA8JVrN,GAAO+I,mBAAqBA,EAC5B/I,EAAO4J,mBAAqBA,GAM3BhK,EAAqBG,GCpSxB,SAAUC,GAER,GAAIuN,KAEJvN,GAAOoB,aAAe,SAASoM,EAASC,EAAMC,EAAQC,GAKpD,GAAIC,GAAUD,EAAS,MAAQ,KAC3BE,EAAQ,GAAIC,MACZC,EAAS,GAAID,MAAKL,EAGtB,OAFAM,GAAOC,SAASD,EAAOE,WAAa,GAExBF,EAARF,GACIL,IAAWD,IACfW,QAAQC,KAAK,mBAAqBX,EAAU,IAAMI,EAAU,wCAA0CG,EAAOK,eAAiB,KAAOV,GAEvIH,EAASC,IAAAA,GAAW,IACb,GAMXxN,EAAOqO,WAAa,SAASb,EAASC,EAAMC,EAAQC,GAClD,GAAIC,GAAUD,EAAS,MAAQ,IAC/B,IAAI3N,EAAOoB,aAAaoM,EAASC,EAAMC,EAAQC,GAC7C,KAAM,IAAIW,OAAMd,EAAU,IAAMI,EAAU,yBAA2BF,KAIxE9N,wmrBChCH8J,KAAU1J,GAAQuO,EAAOtO,KA2BvBuO,GAAA,MAASC,GAAAA,oBAAAA,EAAmC3E,EAG1C4E,EAFIC,GAAAA,GAAAA,GAEK/F,EACPgG,KAAK,KAAIxH,EAAU0C,KAAUlB,GACbiG,qBAAsBC,EAAsBC,GAAV3H,aAC1C4H,iBAAAA,GACMlF,SAAaN,EACrBhG,GAAQsG,QAAUlB,GACXkB,GAAAA,MAAUlB,GAAGxB,QAEtBuH,GAAAA,QAAAA,OAAAA,IAAAA,QAAAA,GAA+BvH,EAAUuH,EAAAA,GAAAA,MAAAA,MAAAA,IAAAA,EAAAA,KAA+BvH,IAAAA,EAAAA,IACxEuH,QAAAA,GAAAA,GAA+BvH,MAAAA,2BAAa4H,KAAAA,GAKzCC,OAAAA,GAAaN,OAAAA,QAAAA,GAAAA,EAChBO,GAAQP,OAAAA,EAAAA,EAAAA,GAA+BM,QAC3CE,GAAID,EAAS1F,GAAiD,MAAlC0F,IAAMA,EAAM3F,EACtC,EAAA,EACEkB,GAAAA,EAAMC,GAAAA,OAAaC,QAAAA,GACbyE,EAAAC,GACNxE,OAASuE,EAAAC,EAAA,SAAA1M,GAAA,MAAAM,MAIfqM,MAAOX,EAAAA,EAAAA,EAAAA,EAAAA,MAAAA,QAAAA,GAIAY,EAAAA,GAAAA,MAAmBZ,UAAAA,EAAAA,GAAAA,OAAAA,EACtBa,EAAAA,SAAAA,GACJ,MAASP,GAAaN,EAAAA,EAAAA,EAAAA,OAAAA,QAEpBW,GAAKF,EADDtF,GAAY6E,OAAAA,EAAAA,EAAAA,KAAAA,OAAAA,EAA+BM,MACtCrG,EAAWkB,EAAAA,qBACd2F,EAAY3F,EACZ4F,EAAAA,EAAAA,IAAU5F,qBACV6F,gBAAa7F,EAAUlB,qBACZkB,EAAiBzC,EACnByC,EAAUlB,IAAGpF,UACtBiM,0BACEC,EACFC,qBAEAC,EAAWD,GAGfH,YAAe9F,gBACF+F,EACXC,qBACAlM,EAAeD,GAA0BC,UAAS,WAClDxB,EAAUiN,qBACKV,EAAMsB,GAAAA,YAAsBZ,EAAAA,YAAuBW,EAOxErB,EAHAiB,aAAAA,EAAoBjB,EAASuB,eAAAA,GAAmBC,EACvCD,GAAkBL,SAAYM,EAAAA,GAAmBN,QAAAA,GAEnDD,EAAAA,GArFTjB,MAAMyB,WAAAA,GAAqB,WAAShH,GAAAA,EAAAA,EAClC,SAAIc,GAAAA,MAAY9J,IAAO4J,EAAAA,EAAAA,GAAAA,EAAAA,EAAmBZ,YAAAA,OACtC2F,EAAAA,qBAAiCF,OAAAA,GAAAA,gBAAAA,GACjCe,SAAAA,EAAiBD,GAAAA,QAAmBZ,GAAAA,GAAAA,EAAAA,EACxCsB,OAAOC,EAASC,UAAQC;AACtBF,EAAIE,UACFZ,CAAAA,IAAAA,GAA+Ba,EAC7BC,SAAQF,IAAAA,EAA4CE,UAA3BD,OAAcZ,EAAAA,UAC/BW,EAAiBC,GACjBD,EAAYC,UAAAA,CAAcZ,EAAAA,SAAaW,EAAAA,EAAYC,EAAAA,EAAAA,IAAAA,GAAcX,EACxE3N,aAAiBsO,EAAAA,EAAAA,EAAAA,GAAAA,IAAAA,GACdE,UAAAA,EAAiBH,EAAAA,EAAAA,EAAAA,IAAWC,GAAAA,EAAcZ,GAAAA,GAC1Ce,QAAAA,EAAgBH,GAAAA,EAAcX,EAAUW,GAAAA,EAAAA,EACxCI,GAAAA,EAAAA,IAAmC,QAAjBD,GAAyBH,EAAAA,GAAc7M,OAAO+M,EAAAA,EAAAA,SAAiBC,GAAAA,QACrFjC,GAAMpK,GAAMgM,MAAQE,MAAAA,IAAAA,EAAAA,KAAcrO,IAAAA,IAAUqO,IAAAA,GAAAA,EAAAA,GAAAA,IAAcA,GAAAA,GAAAA,EAAAA,EAAAA,EAAcI,IAAAA,EAAAA,GAAAA,KAAAA,MAAAA,EAG1E9N,EAAKiG,GAAI5G,EAAAA,IAAAA,OAAY2M,GAAAA,GAAAA,EAAAA,eAAAA,EACH+B,MAAA,EAAZ1O,EAAAA,EAAAA,KAAAA,QAAoCW,EAAAgO,KAAZ3O,KAAAA,MAAoC,GAAA4O,GAAZ5O,SAClDuM,gBAAY4B,+BA2ErBvQ,SAAqBC,GAAAA,MAAgBE,EAAAA,OAAAA,CAAAA,IChGxCmQ,GAAUlQ,EAAQuO,WAAOtO,KAIvBsO,GAASsC,qBACPC,EAAO9O,GAAiB,mBAAqBS,sBAClCsO,oBAIJC,qBAA2BC,mBAClCC,QAAAA,gBAAiBlP,0BAA6BA,EAC9CkP,aAAAA,EAAiBlP,qBAAwBiP,KAAAA,KAE3CH,GAASjC,EAAAA,YAAqBsC,GAAgBC,EAC5CrR,GAA+BwJ,SAAQX,EACjC5G,GAAAA,QAAWoP,GAEfJ,EAAmBG,GAAQF,GAAAA,EAAQJ,EAAY7O,OAAAA,cA2D1C6N,KAAAA,GAAAA,KAAAA,OAAsB7N,IAAgBqN,EAAAA,OACzCgC,GAAAA,EAAAA,IAAAA,gBACIC,KAAKtP,GAAAA,CAAAA,EAAchC,EAAOoB,QAAa,UAAA,IAAA,IAAAmQ,KAA6BC,GAAcA,EAAAC,QAAAC,EAA0B,SAClHL,GAAaR,MAAAA,GAAY7O,GAEf,KAAA,IAARoN,GAA8B,KAAA,GAATC,GACnBD,KAAAA,EACKuC,OAAAA,IAAcN,EAAAA,EACVI,QAATpC,oBACMsC,KAAAA,QAAcN,GAAAA,QAGrB,IADDO,EAAmBvC,KAAAA,KAAa6B,QAAAA,YAAiBG,KAAAA,QACrCO,MAAAA,IAAgBA,GAASrI,UACvC,eAAiBqI,YAAY,cACzBC,EAAAA,EAAAA,EAAcD,EAAYrI,QAAG8F,EACdzN,GAAfkQ,KAAAA,IAA4ClQ,EAAhBiQ,EAC1BE,QAAAA,EAAoBH,GAAAA,MAAShJ,EAAAA,GAAGA,GAAGkJ,IAAAA,KAAYD,EAAAA,CAAAA,IACnD,GAAIE,KAAAA,GACEC,CAAAA,GAAAA,GAAeC,KAAAA,EAAAA,QAAoB,GAAA7J,QAAM2J,IAAAA,EAAAA,KAC7C,IAAAN,QAAO,GAASS,QACdC,EACmB9C,KAAAA,MACZ2C,KAAOE,SAKf3D,GAAM0D,MAAAA,GAA2BG,GAAA5J,EAAS6J,MACxCA,KAAejD,QAvGtB8B,GAmBErC,EAAAA,GAAAA,MAAuBA,GAAAA,EAE7BQ,GAAIsC,GAAAA,QACFW,GAAiBlD,EAAAC,EAAAkD,GACjBC,GAAAA,GAAoBC,IACpBC,KAAAA,IAAAA,GAAmBD,EAAA/I,KAAA0I,EACnBO,KAAAA,IAAAA,GAAAA,EAAwBzQ,QACxB0Q,GAAAA,GAAAA,EAAAA,KAAyBR,EACzB/F,OAAAA,GAAAA,EAAmBhI,IAAA,SACnBwO,GAAAA,MAAiBzD,GAAAgD,IACjB9F,IAAAA,EAAAA,EAAiBjI,IACjByO,SAAAA,GAAAA,MAAkBzD,GAAA+C,IAClB7F,KAAAA,EAAAA,EAAkB,SAElBwG,GAAAA,GAAevK,GACfwK,EAAAA,IAAgB,SAAA3L,EAChB4L,GAAAA,MAAAA,IAAAA,EAAqB1J,QACrB2J,IAAAA,EAAsBjQ,KACtBuJ,IAAAA,EAAAA,IAAAA,EAAgB2G,eAEhBC,GAAMX,EAAA7J,KAAA+H,KAAA,MAAA,OACN0C,GAAO9J,OACPkD,EAAAA,QAAUjE,EACVwE,IAAAA,IACAsG,GAAAA,GACAlE,iDAGAmE,EAAAA,EACAC,KAAY,KACZC,GAAAA,QAAaC,EACbC,MAAWC,EAEXC,EAAUjF,KACVkF,KAAAA,GAAW1L,QACX2L,EACAC,KAAAA,MAASC,EACTC,EACAC,KAAAA,KAAAA,qBACc5F,GACd6F,YAAAA,EACAC,EAAAA,qBACcT,EACFrF,EACZc,uBACYd,EACZnB,qBAAYwB,KAAA,KAAAgF,GAEZU,EACAC,WAAAA,EACAC,EAAAA,gBACAC,CACAC,IAAaC,GACbC,EAAQC,qBAkCJhF,KAAAA,KAAAA,GAAwBA,EAE7BjQ,EAAAA,gBAAqBC,KAAAA,OAAgBE,EAAAA,KC9GxC+U,EAAkBvG,EAAOtO,gBAEd8U,KAAAA,OAAWvT,EAEd4D,KAAAA,GAAiBpF,oBAAO+E,CACxBiQ,IAAAA,GAAsB3P,SACjBrF,GAAAA,GAAOgH,GAAAA,EAAsB5B,EAAgBC,OAAAA,IAAW7D,IAOjEgH,EALAwM,GAAAA,EAAAA,GAAWC,QAAAA,EAAgC7P,EAAAA,oBAC3C4P,KAAAA,OAAWE,EAAsB7P,KAC3BQ,EAA8BT,EAAAA,oBAA2B5D,KAC7D,OAAOqE,EAAyBA,IAAUL,GAAAA,yBAKxC2P,EAA0BhF,EAAQnH,qBAAa7I,EAG/C4G,GAFwB/G,oBAAOqC,EAAqBlC,qBACpDqP,EAAuBQ,GAEvBoF,sBAEF5F,qBAAeW,oBAgBjB,qBAbekF,mBAAmBhQ,aAChC0B,YAAAA,SAAeiO,cACS,aAAjBjO,YAETqO,gBAAeE,UAAS/G,EACtBiB,qBAAuBoE,EAEV2B,GAAiB,4BACvBpF,6BAETiF,yBAA4BJ,0BAC5BI,SAAeH,OAAAA,iBAA4BA,gBAC3CG,cAAqBI,eACdJ,aAGHK,aAAa,YACjB,iBAAiB,iBAEbC,eACQ,gBAGZC,cAAWN,cACT,QAAO,eAEEJ,cAAiB,MAC5BU,iBAAWT,kBACTrV,EAES0V,GAAiB,SAC1BhH,EAEKoH,GAAAA,QAQR/V,GAAqBC,GAAgBE,MAAAA,GAAAA,uBClEvBE,IAsBfsO,EAASqH,aAAAA,QAAkBC,GAAQ7T,QAAU8T,GAC3CA,GAAWC,GAAAA,GAAAA,EACXD,aAAWE,EAAAA,OACXnU,EAAOoU,aAAAA,KAAeJ,KAAQ7T,UAAU8T,EAAAA,OAG1CvH,EAAS2H,aAAAA,KAAAA,KAAAA,QAA4BC,EAOnC5V,gBAAK6V,KAAkB1S,KAAAA,EAAyB,MAAA6K,EAAA8H,OAAA9H,EAAgC+H,aAChF/V,KAAKgW,KAASJ,SAAQvS,EACtBrD,OAAKiW,IACLjW,GAAKkW,EAAAA,GAAAA,OAAAA,EAGL,GAAK,OAAW7N,QAAS2N,GAAe3N,EAClC5G,GAAAA,MAAWzB,QAAKgW,GACpBhW,QAAK6V,IAAAA,GAAAA,EAAgBpU,SAAYzB,GAAAA,GAAKgW,GAAOvU,EAAAA,EAE/CzB,CAAKmW,IAAAA,QAAAA,EA+FP,MAASC,MAAAA,IAAAA,GAAAA,EAAqBR,gBACxBA,EAAQS,EAAAA,OAAAA,GAAAA,GAGZC,EAAIC,MAAAA,EAAgBC,gBAAIb,EAAAA,GAAAA,QAA4BC,GACpD3N,GACEoN,MAAAA,QAAkBO,EAAS,IAAA,GAAWa,GAAKzI,EAAa0I,2BACjDC,KAGPf,KAAAA,EAAQvS,EAAa,KAAS5B,GAAUqF,SACtC8O,EAAQvS,EAAM5B,WAAYqF,EAEpBzD,EAAM0R,qBAAkBtT,EAC9BmU,GAAcnU,UAKlBmU,EAAQS,GAA6BT,SAAQvS,EA7J/C3D,GAAIkX,QAAAA,GACFC,GACA7N,MACA8N,UAAAA,GAGEC,GAAAA,GAAAA,CACFC,OAAAA,GAAAA,IAAAA,SACAC,GAAAA,MAAAA,KAAqBN,EACrBO,EAAAA,KAAAA,KACAC,QACAC,GAAAA,GAAAA,MAAgBhV,GAChBiV,QAAAA,GAGEC,GAAAA,GAAAA,EACFF,EAAAA,cACAC,OA6BF1B,QAAAA,EAAAA,QAAAA,KAA4BhP,GAAAA,GAC1BkQ,EACE,uBAAYhB,KAAgBgB,EAElBU,EAAAA,EAEVC,EADIC,KAAAA,IACS,CAAA,GAAOzX,EAAK6V,OAAAA,EAAgB7M,MACvCyO,GAAAA,EAAmBzX,MAAK6V,EAAAA,GAAAA,MAAgBxN,IAE1CrI,GAAK6V,EAAAA,GAAgBgB,EACrB7W,EACA0X,EAAgBrP,KAAIrI,EAAK6V,MAAgB7M,IAAAA,GACvCyO,EAAAA,GAAAA,MAAAA,KAAmBzX,EAAK6V,EAAgBxN,EAAM,IAEhDsP,EAASlW,OAAAA,EAAYgW,OAAAA,MAAAA,KACdzX,GAAKkW,MAAAA,EAAAA,EAAAA,EAAoBzU,EAAAA,OACvBuU,IAAAA,CAAAA,GAAOqB,GAAY5V,EAAAA,EAAUzB,GAAAA,EAAK6V,EAAAA,EAAAA,IAAgBqB,EAAAA,GAAiBzV,EAAAA,SAAAA,GAI9EuH,MAAIA,KACF4O,EAAAlI,OAAO1P,EAAK6V,EAAAA,WAAgB7M,IAAAA,EAE9B8N,EAAIA,YACFe,EAAA7J,EAAOhO,qBAGTmW,EAAAA,EAAAA,aAAgBjM,EACdsG,eAAYyF,IAAUjW,EAAK6V,EAAAA,EAAAA,EAAgB7M,GAAAA,EAAAA,GACzC1H,GAAOoU,SAAAA,EAAqB1V,MAAKiW,GAC/BR,KAAAA,GACAD,GAAAA,EACAiB,MAAK9E,EAAA+F,EACHvV,EAAA2V,IAAoBN,EAAY3B,WAAAA,EAAgBkC,OAC/C/X,MAAKiW,IAEVjW,QAAKiW,GAEKA,GAAUjW,MAAK6V,GAAAA,QAAAA,GAAgB7M,QACzChJ,UAAKiW,IAAAA,QACEP,GAAe1V,EAAMA,GAAKiW,GAAAA,EAC/BR,oBACAD,EAAAA,CAAY3G,EACZ/H,kBAIAgI,CAAA,IAASrN,GAAUqF,EACvB9G,wBAAwB8G,GACxB9G,GAAKkW,EAAAA,oBAAoBzU,EAAY,CAAAqN,EAEvCiG,kBAAiBtT,CACfzB,IAAKgW,GAAOvU,EAAAA,wBAAiCA,GAAAA,MACtCzB,OAAKkW,EAAAA,IAAAA,MAAAA,EAAoBzU,MAKpC,KAASuW,GAAAA,SAAUjB,GAAAA,MAAAA,GACjBpB,EAAAA,GAAAA,EAAAA,EAAAA,GAAAA,KAAAA,EAA4BhP,GAAAA,KAAUqR,GAAAA,EAAoBA,GAAAA,KAAQC,IAAAA,EAAAA,EACzD,SACLC,GAAIjQ,GAAAA,GAASjI,EAAK6V,KAAAA,EAAgBmC,GAAAA,GAAQpU,EAAWiS,GAAAA,GAAAA,EAAAA,IAAAA,EAAiBsC,EAAAA,cAClEF,EAAAA,GAAAA,EACGjY,GAAKkW,EAAAA,GAAAA,EAAAA,EAAAA,IAAoBiC,EAC5BnY,EAAKgW,IAAAA,GAA0BA,KAAAA,IAAQmC,OAAAA,MACpChC,QAEAlO,GAER+P,GAAQA,MAAUV,GAAAA,QAAAA,OAAAA,IAIvB,QAAS7V,GAAY0B,GAAAA,MAASiV,GAAAA,QAAgB/U,eACxC5B,MAAYmV,QAAAA,GAA+BG,EAAAA,GAAAA,GAG/CsB,GACEhD,EAAAA,0BAAkBM,EAAAA,GAA4BhP,CAAAA,KAAAA,EAAWlF,SACvDgV,EAAKzN,OACH,CAAA6F,EAAO7O,SAAK6V,GAAgBpU,EAAAA,EAAAA,EAE9B6W,KAAcxR,KAAAA,GACZ9G,GAAAA,EAAK6V,EAAAA,EAAAA,OAAAA,IAAgBpU,CAAAA,GAAAA,GAAYqF,EACjC9G,GAAAA,EAAKmW,EAAAA,EAAAA,GAAAA,EAAAA,EACKD,SAAAA,EAAoBzU,OAAAA,EAAAA,GAC5BzB,EAAAA,CAAKgW,GAAAA,MAAOvU,EAAAA,EAAYqF,EAAAA,EAAAA,IAG7BrF,SAyBLuM,GAAMpK,GAAAA,gBAAiBgS,GAASnU,MAAAA,EAC9B2U,IAAAA,KAAAA,KAAqBR,GAAAA,KACrBA,GAAQvS,EAAMkV,GAAKvK,CAAMwK,OAAa/W,QAAWqF,GAGnDkH,GAAuB4H,SAASnU,EAAAA,GAC1BmU,MAAAA,eAAQS,GAAAA,eACVT,IAAQvS,UAAM0R,GAAO/G,YAAMwK,KAAa/W,UAAAA,GAO3CnC,YAAgBE,IAAAA,KAAAA,KChLTwO,IACRrE,IAAO8O,EAAAA,QAAQ9R,EAAU+R,OAAU,CAAA,IAAAL,EAAsBM,MACnD1D,IAAKqB,GAITsC,EAHeD,EAAAA,EACb1D,IAAaA,EAERjH,IAAM6K,GAAe7K,EAAM4G,IAAAA,IAAAA,UAAqBnM,EAAAA,UAAsBwM,KAAAA,GAE9E3V,GAAAA,EAAAA,EAAAA,EAAAA,OCRH+I,IAAU2F,CAAAA,GAAAA,GAAOtO,EAEfmP,EAASiK,GAAAA,EAAAA,EAAYhP,EAAUzH,GAC7BsP,EAAoBoH,EAAAlK,EAAAxG,GAARyB,EAAAA,EAAmCgF,EAAAzG,GAAAlG,EAAN6W,EACxBC,EAEGC,GAARpP,EAAoCmP,EACvC5W,EAOT,IAAIyH,EAA0BoP,EACxBjL,GACgBnE,CAAAA,IAAKd,EAChB8P,MAAAA,IAAYhP,GAASkP,GAE9BnK,EAEFxG,KAAMyG,EAAAzG,IAAA8Q,GAAAhQ,KAAAmN,EAAA,IAAwCxM,EAGhDkE,KAAM0D,EAAAA,IAAAA,EAAgBvI,MAASW,UAAUsP,EAAAA,UACvC,CAAA,GAAOF,GAAS7W,EACP+W,EAAAA,MAAgBN,IAAAA,EAAsBzW,IAQhD/C,EAAgBE,IAAAA,EAAAA,IClCnB6Z,EAAUrL,GAyFR9D,EAAAmP,EAAejX,GAAQkX,EACd5W,EAAkBN,GAAGkX,GAG9BC,EAASC,EACP,GAAIC,OAAgBC,CAAAA,IAAIC,EACdxJ,KAAMsJ,EAEZD,IAAAA,EACYN,IACdM,EAAOG,GAKF,CAAA,IAHDC,EAAkBH,MACd/W,IAAAA,GAAakX,EAAkBC,EAASJ,EAAAA,IAEnCnD,EAAUjO,IACrBmR,GAAUG,EAAYjX,IAAKoX,IAAQF,UAASH,EAClCM,KAASC,OAGvB9P,EAAOsP,EA5GLS,GAAAA,EAAgBC,EACTC,GAAAA,GAEPZ,EADItR,EAA4B,GAAMsR,GAAc,IAAK,GAAMa,MACxC/R,KACEqB,KACE2Q,EAAAA,EACrBpS,EAAAA,EAAUyB,OAAW2Q,IAAKrY,CAAEqY,GAAG3Q,GAIrC,gBAGFqP,GAAcjZ,GACZkO,EACesM,aACAtM,EAANwI,gBAEMF,EAATiE,EACSxB,EAANrP,GACM6P,EAAN7P,GACL5J,GACAA,GAAEwW,EACS,GAATkE,EACA9Q,GAAG4M,EAGX,GAAS2D,EAAcQ,KAAAA,EAAkBC,IAAAA,EAAYC,KAAAA,GAC/CC,EAAoBzR,KAAKqR,GAAuBK,EAAQ1R,MAAMe,EAErD4Q,KACD,GAAKH,EAGjB,CAAA,GAAKI,GAAI1S,CAAcA,GACR2S,EACXJ,EAAgBH,EAAAA,OAAU/Q,EAAYA,EAIlC8P,SAAaA,GAAK,MAAQA,GAASQ,IAAIR,SAE3CyB,EAAAA,GAAc,GAAMC,GAAsBC,EAAMrX,IAAG,SAAcsX,EAErEH,GAAAA,MAAUJ,GAAYxS,GAAKgT,GAAIA,GAAQC,KACvCL,KAAAA,IAAa,OAAU7Y,UACvB6Y,EAAAA,GAAU,IAAG,IAAU7Y,EACvB6Y,MAAa,KAAKjS,SAAiBgR,EACnCiB,GAAAA,GAAU,YAAqB7Y,EAAQkZ,GACvCL,GAAAA,IAAAA,EAAmCjB,MACnCiB,KAAAA,OAAa,GAAU7Y,GAAIkZ,KAAQtB,GACnCiB,GAAAA,GAAAA,GAAaM,IAAUF,GAAIC,GACdV,QAAcxY,UAE3BwY,EAAAA,EAAAA,EAAST,EAAAA,EAAAA,EAAAA,EAASS,EAAAA,EAAAA,EAAAA,EAAQK,EAAAA,EAAAA,EAAAA,EAAAA,GAE1BhG,GAAIuG,UAAe,mBAAyBvG,GAAMwG,QAAW,KACzDf,SAAK,KACPc,SAAad,KAAKgB,SACTvB,KAAAA,UAAiBqB,QAGxBd,aACFc,KAAQG,OACRH,KAAQI,GAAKlB,EAAK/D,EAAA,IAClBiE,GAAST,QAAAA,IAASS,GAAQY,EAAAA,EAAAA,IAGxBd,GAAK/D,EACP6E,KAAKK,QACLL,IAAKI,GAAQlB,EAAAA,EAAAA,IACbE,GAAAA,EAAST,KAAAA,QAASS,IAAQY,GAG5B,EAAA,EAAK7E,KAAQmF,SAAUzT,MAChB4M,GAAIvL,MAAOA,KACdkR,KAAAA,GAAOvS,OAASsT,IAAMtT,KAI1BuT,GAAIG,EAAAA,KAAKnB,OACCA,IAAO,KAAOA,GAAAA,EAAUjE,KAAIiE,WAAcA,KAAAA,GAAUjE,EAAIiE,EAAAA,IAAO3F,GAAO2F,YAAU,IAEnFA,GAAOjE,EAAGqF,EAAAA,IAAOpB,GAAOjE,EAAIiE,KAAOqB,YAAW,IAEvDL,GAAO3B,EAAAA,EAAAA,IAAAA,GA0BTjM,EAAMiM,KAAAA,YAAgBA,IAAAA,GACtBjM,EAAAA,EAAMwL,KAAOA,aAEZla,MAAgBE,GAAAA,GAAAA,qBCnHTC,EAAeC,GAEhBwc,eAEP5c,EAAI6c,GAAkCC,SAAaC,GAAAA,QACjDrc,GAAK4P,GAASA,GACd5P,GAAKoc,OAAAA,EAAcA,OAAAA,OACnBpc,IAAKqc,IAAAA,GAAeA,EAAAA,KAAAA,EAEpBrc,MAAKkK,EAHckS,OAGPE,EACZtc,QAAKuc,GACLvc,GAAKwc,MAAAA,GACLxc,IAAKyc,KAAAA,MAAAA,EAAgB7M,KACrB5P,EAAK0c,EAAAA,MAAAA,IAAmB,IACxB1c,GAAK2c,MAAAA,EAAaC,SAAMC,MACxB7c,EAAK8c,OAAYvP,OAAKwP,GAGxB/O,QAAMgP,GAAYnO,EAAAC,GAAS9N,OACpBiU,EAAKnG,EACN9N,GAAUA,EAAOic,qBACFA,EAEnBjd,GAAKkd,iBAAyBhB,GAAAA,SACzBiB,GAAAA,QACLnd,GAAkBod,GACbC,GAAUpV,KACV1H,KAAAA,GAAAA,KACLP,GAAKsd,EAAAA,IACLtd,EAAKud,EAAAA,OAAgBtV,GAChBuV,QAAWC,GACXC,GAAAA,MACL1d,GAAK+G,aACL/G,qCAAsCiR,IACjC0M,EAAQC,uBACRC,GAGP7P,QAAMgP,GAAUrW,EACdmX,GAAAA,GAAc7V,GAAA+F,EAIRhO,gBAAoByd,EAAUrB,IAAAA,EAChCpc,IAAK+d,GAAAA,IAAY/d,EAAK+G,GAAAA,CAAQ+N,GAAAA,GAAQ7M,EAEjC8V,EAAAA,IAAAA,EAAY/d,GAAK+G,EAAQ+N,IAAAA,SAAasH,EAAAA,GAAAA,EAEnCkB,IAAAA,SAAAA,GAAgBtd,IAAK+d,EAAc/d,GAAAA,EAAKud,KAAAA,GAAAA,IAChDvd,EAAKsd,QAAAA,EACLtP,CAAAA,GAAM6K,aAASmF,KAAAA,EAAiBhe,KAAAA,aAGpCie,KAAAA,EAAkB,IAASC,CAAAA,GAAAA,GAASC,EAAAA,EAAAA,GAC9BD,GAAAA,EAAgBf,GAAAA,EAAAA,GAAAA,EAClBnd,GAAKmd,2BACIiB,KAAAA,EAAgBD,KAAAA,2BACHne,KAAKO,EAAAA,IAAAA,MAAoBP,GAAK0U,IAAAA,SAAiB2J,GAChEP,MAAAA,gBAGL1B,GACFiC,EAAIre,EAAcA,OAAK6d,QAAAA,GAEXV,GAAAA,GAEVf,GAAAA,EAAY8B,gBACdA,EACI9c,IAAM8c,EAAAA,IAEVlQ,EAAMsQ,CAAAA,IAAAA,GACDte,GAAKqd,EAA8B,GAAAf,IAAdiC,IAAAA,KAAAA,IACxBve,KAAKue,EAAAA,EAAAA,GAAkBC,EAAAA,EAAAA,EAAUpC,EAAAA,EAAAA,OAAc8B,IAAUle,CAAAA,GAAKO,GAAAA,EAAAA,EAEhEP,iBAAK6d,IAAsBY,EAClBtB,eAAgBe,KAEzBle,GAAKie,GAAAA,KAAAA,EAAiBC,MAAAA,EAAAA,OACtBlQ,EAAM0Q,IAAAA,EAAAA,OAAAA,GAAAA,GAERxP,EAAIA,GAAAA,EACFyP,GAAO3e,UAAKue,GAEVrP,MAAAA,IACFgP,EAAWA,EACDA,GAENle,EAAKqd,MAAAA,EAAgBM,MAAAA,GAEzB3d,KAAKue,EAAAA,GAAAA,EAAaL,IAClBle,GAAKie,GAAAA,OAAuBO,EAAAA,EAAUpC,KAAAA,QAAcpc,GAAmBA,GAAK0E,GAAAA,GAC5EsJ,EAAM0Q,gBAAAA,EAEJha,KACFuM,EAAOjR,OAAKO,IAAAA,IAEdmE,EAAIA,GAAAA,EAAaoC,GAAAA,OACXA,GAAAA,IAAcvG,MAAAA,IAAAA,GAGlBqe,QAAIC,IAAAA,IAAAA,OAAsBzC,IAAAA,KAAAA,KAC1Bpc,IAAKO,GAAAA,QAAAA,IAAgBuG,MACrB9G,EAAkBgO,EACI8Q,oBAAbC,KAA2C,KAAA/Q,EAAb+Q,gBAChCC,IAAAA,GAEe1Q,qBACpBtO,EAAKoc,KAAcyC,KAAAA,GAAAA,GAGnBT,qBACWT,EAAAA,qBAA+BsB,EAAU9B,KAAAA,KAAgBnd,GAAAA,GAAK0U,uBAC7C1U,EAAKmd,gBAAgB+B,EAEjDxK,EAAmByK,gBAAYpY,CAAQ2N,IAC3CqK,GACE/Q,EAAIhO,oBAEoBqO,KAAnBrO,KAAKue,EAA4BlB,KAAAA,GAAWrd,qBAA2BA,EAAK6d,GAE7E7d,sBAEAA,qBACKV,GAGX0f,SAAMhR,GACJhO,QAAKqd,GACIe,GAAAA,GAAAA,GAAoBT,EAAAA,aACtBR,UAAend,EAAKO,IAAAA,GAAgB6e,EAAQpf,GAAK0U,OAAAA,UACtD1U,OAAKue,EAAac,aAEf9B,EAAAA,OAAgBvP,EAChB2P,aACL3d,KAAK8d,OAAAA,QACL9P,EAEFsR,EAAOxJ,OAAA9H,EACAhO,aAAKoe,KAAgBpe,OAAKqd,QAAYrd,EAAK2d,gBACzCE,EAAAA,OAAAA,EAEP7d,aAAKue,KAAa,OACblB,SAAU+B,EAEjBG,IAAQ,IAAAC,GACFxf,EAAK2d,aAEJvB,WAAcpc,EAAKO,IAAAA,GAAoBP,EAAK0U,GAAAA,OAAiB,WAC7D6J,OAAave,EAAK0U,aAAAA,EAAsB0H,OAAAA,EAC7Cpc,aAAK6d,KAAAA,OAAsB,QACrBa,EAERe,EAAQ3J,OACD9V,EAAK+d,aAEV/d,KAAK+d,OAAAA,QACL/d,EAAK2d,gBACAJ,EAAAA,OACLvd,EAAKoc,aACLpc,KAAKue,OAAAA,SACLve,EAAK+G,IAAQ+N,IAAAA,GAGb9G,EAAM0Q,aAAAA,WAERgB,EAAS,OAAAC,IACFjb,EAAAA,IAAgB,WAChBsa,OAEPY,EAAAA,aAAkB5R,EAAS9D,OAAM2V,EACT9J,aAAA1H,KAAXwR,OAAAA,QAAiC7R,EAAR9D,SAClClK,EAAK0d,aAAgBvU,KAAK0W,OAAAA,6BAET,YAAeA,EACtBtL,oBAERwD,EAAQ/X,OAAK0d,EAAAA,aAAgB/b,KAAQke,OACrC9H,SAAS4H,EACNjC,KAAAA,OAAAA,QAAuB3F,GAEhC+H,EAAAA,GAAa,MAAAjR,GAASkR,KAAAA,EAChB/f,GAAKoe,UAAAA,EACP,GAAKpe,EAAKud,UAAAA,EACR1Z,MAAImc,GAAQlR,EAAIqN,MAAAA,IAAAA,UAAqBnc,EAAKmd,gBAAc4C,OACpD1O,EAAWrR,gBAAK0d,MAAgB1B,WAAYwB,EAAAA,GAAAA,EAAiBA,UAAAA,EACjEyC,MAAAA,GAAAA,EAAWpc,MACTwN,IAAAA,WAAS7P,EAAQ0e,yBACPC,OAAKH,EAAMpQ,gBAGvB5P,MAAKud,WAAAA,EAAgB,IAGvBvd,EAAAA,IAAKud,EAAAA,GAAAA,EAGT6C,UAAOvR,EAASwN,MAAAA,GAAAA,EAAcgE,MAAAA,IAAAA,WAClB1C,EAAAA,GAAU3d,EACK,MAAnBA,OAAKue,OACH8B,GAAAA,GACGnR,EAAYmN,qBAAoBc,KAAAA,KAAend,EAAK0E,sBAE5C0Z,EACVH,EAAkB5B,gBAAoBkC,KAAAA,OAAcve,EAIzDqgB,KAAAA,EACFrgB,EAAK6d,oBACL7d,KAAK8f,OAAAA,EAAYzD,gBAGrBiE,KAAIA,EACMtgB,EAAK+e,oBAAyB1Q,KAAGkS,OAAWC,EAAajD,IAAAA,GAQpEle,qBAAqBC,EAAAA,GAAgBE,mBC5NxCF,GAAyBI,SAqBvBsO,EAASyS,GAAAA,QAAAA,GACPpW,EAAIqW,GAAAA,EAAaC,QACjBA,IAAAA,QACIhP,SAAIkH,GAASuD,IACXvD,UAASuD,gBACP/Y,QACRqd,EAAWlf,GAAQof,KAASC,GAASA,KACrCC,GAAAA,aAAAA,kBAIF,gBAASC,EAAAA,mBAAiCC,0BACjCC,EAAAA,eAAc/D,sBAAiCA,EAAAA,qBAG/CgE,4BACFlD,EAELhe,aAAKoc,SAAczS,GAAOwX,MAAeA,GAAAA,IAAkBA,IAAYpE,EA8ChE+D,OCtFX,WAEE,GAA2Dzf,SAAvD8B,SAASC,cAAc,OAAOsV,YAAY0I,SAA9C,CAKE,GAAIrE,EACC,IAAIpT,OAAOwX,aAAeA,YAAYpE,IAC3C,GAAIA,GAAM,WAAa,MAAOoE,aAAYpE,WAE1C,IAAIA,GAAM,WAAa,MAAOxP,MAAKwP,MAGrC,IAAIsE,GAAuB,SAASzR,EAAQwM,EAAaC,GACvDrc,KAAK4P,OAASA,EACd5P,KAAKoc,YAAcA,EACnBpc,KAAKqc,aAAeA,EAEpBrc,KAAKkK,KAAO,SACZlK,KAAKuc,SAAAA,EACLvc,KAAKwc,YAAAA,EACLxc,KAAKyc,cAAgB7M,EACrB5P,KAAK0c,kBAAAA,EACL1c,KAAK2c,WAAaC,MAAMC,UACxB7c,KAAK8c,UAAYvP,KAAKwP,OAGpBuE,EAAyB3X,OAAO8O,QAAQ9R,UAAU+R,OACtD/O,QAAO8O,QAAQ9R,UAAU+R,QAAU,SAASjQ,EAAakQ,GACvD,GAAI4I,GAAYD,EAAuBnB,KAAKngB,KAAMyI,EAAakQ,EAE/D4I,GAAUC,mBACVD,EAAUH,SAAW,IAErB,IAAIK,GAAiBF,EAAU9B,MAC/B8B,GAAU9B,OAAS,WACjBgC,EAAetB,KAAKngB,KACpB,IAAIggB,GAAQ,GAAIqB,GAAqBrhB,KAAM,KAAM+c,KAC7C1L,EAAWrR,KAAKwhB,gBAAgBxF,OAAOhc,KAAKohB,UAAYphB,KAAKohB,aACjEnB,YAAW,WACT5O,EAAS7P,QAAQ,SAASqe,GACxBA,EAAQM,KAAKH,EAAMpQ,OAAQoQ,MAE5B,GAGL,IAAI0B,GAA2BH,EAAU3B,gBACzC2B,GAAU3B,iBAAmB,SAAS1V,EAAM2V,GACpB,kBAAXA,IAAiC,UAAR3V,EAClClK,KAAKwhB,gBAAgBrY,KAAK0W,GAE1B6B,EAAyBvB,KAAKngB,KAAMkK,EAAM2V,GAG9C,IAAI8B,GAA8BJ,EAAUK,mBAW5C,OAVAL,GAAUK,oBAAsB,SAAS1X,EAAM2V,GAC7C,GAAY,UAAR3V,EAAkB,CACpB,GAAI6N,GAAQ/X,KAAKwhB,gBAAgB7f,QAAQke,EACrC9H,IAAS,GACX/X,KAAKwhB,gBAAgBK,OAAO9J,EAAO,OAErC4J,GAA4BxB,KAAKngB,KAAMkK,EAAM2V,IAI1C0B,OClEX,SAAU9hB,GAgBR,GAAImW,GAAUzS,SAASiV,gBACnBmJ,EAAY,KACZO,GAAAA,CACJ,KACE,GAAIC,GAAkBC,iBAAiBpM,GAASsB,iBAAiB,WAC7D+K,EAAiC,KAAnBF,EAAyB,IAAM,GACjDR,GAAY3L,EAAQ8C,SAASjF,SAAYwO,EAAaA,KACjD9gB,SAAU,IACfogB,EAAUnF,YAAc,EACxB0F,EAAWE,iBAAiBpM,GAASsB,iBAAiB,YAAc+K,EACpE,MAAOC,IACP,QACIX,GACFA,EAAU9B,SAEd,IAAIqC,EAAJ,CAIA,GAAIR,GAAyB3X,OAAO8O,QAAQ9R,UAAU+R,OACtD/O,QAAO8O,QAAQ9R,UAAU+R,QAAU,SAASjQ,EAAakQ,GAUvD,MATIhP,QAAOC,QAAUA,OAAOC,UAAYjB,MAAMjC,UAAUmD,MAAQrB,EAAYmB,OAAOC,YAEjFpB,EAAcG,MAAMkB,KAAKrB,IAGtBG,MAAMC,QAAQJ,IAAgC,OAAhBA,IACjCA,EAAchJ,EAAO+I,mBAAmBC,IAGnC6Y,EAAuBnB,KAAKngB,KAAMyI,EAAakQ,MAEvDtZ,Gd9CCE,EAAAA,QAEJ4iB,MACM3iB,WAAAA,MAAuBQ","file":"web-animations.min.js"} \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/.bower.json b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/.bower.json
index e763b61c2da..42cf72a37ef 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/.bower.json
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/.bower.json
@@ -1,7 +1,7 @@
{
"name": "webcomponentsjs",
"main": "webcomponents.js",
- "version": "0.5.5",
+ "version": "0.6.3",
"homepage": "http://webcomponents.org",
"authors": [
"The Polymer Authors"
@@ -11,13 +11,13 @@
],
"license": "BSD",
"ignore": [],
- "_release": "0.5.5",
+ "_release": "0.6.3",
"_resolution": {
"type": "version",
- "tag": "0.5.5",
- "commit": "46f8f2665f7b91e3f248bc9bdb20a29b91f921b5"
+ "tag": "v0.6.3",
+ "commit": "2a1003f895dc55510015898809deefc419899011"
},
- "_source": "git://github.com/Polymer/webcomponentsjs.git",
- "_target": "^0.5",
- "_originalSource": "Polymer/webcomponentsjs"
+ "_source": "https://github.com/Polymer/webcomponentsjs.git",
+ "_target": "^0.6.0",
+ "_originalSource": "webcomponentsjs"
} \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.js
index 8ec15f6b8c2..71731bdbb94 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.js
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.js
@@ -7,7 +7,7 @@
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
-// @version 0.5.5
+// @version 0.6.1
if (typeof WeakMap === "undefined") {
(function() {
var defineProperty = Object.defineProperty;
@@ -44,6 +44,305 @@ if (typeof WeakMap === "undefined") {
})();
}
+(function(global) {
+ var registrationsTable = new WeakMap();
+ var setImmediate;
+ if (/Trident|Edge/.test(navigator.userAgent)) {
+ setImmediate = setTimeout;
+ } else if (window.setImmediate) {
+ setImmediate = window.setImmediate;
+ } else {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener("message", function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, "*");
+ };
+ }
+ var isScheduled = false;
+ var scheduledObservers = [];
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
+ }
+ function dispatchCallbacks() {
+ isScheduled = false;
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+ var queue = observer.takeRecords();
+ removeTransientObserversFor(observer);
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+ if (anyNonEmpty) dispatchCallbacks();
+ }
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations) return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer) registration.removeTransientObservers();
+ });
+ });
+ }
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+ if (node !== target && !options.subtree) continue;
+ var record = callback(options);
+ if (record) registration.enqueue(record);
+ }
+ }
+ }
+ }
+ var uidCounter = 0;
+ function JsMutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+ JsMutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+ if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
+ throw new SyntaxError();
+ }
+ var registrations = registrationsTable.get(target);
+ if (!registrations) registrationsTable.set(target, registrations = []);
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+ registration.addListeners();
+ },
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ }
+ var currentRecord, recordWithOldValue;
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue) return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord) return lastRecord;
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
+ return null;
+ }
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+ records[length] = record;
+ },
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
+ },
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
+ },
+ addTransientObserver: function(node) {
+ if (node === this.target) return;
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations) registrationsTable.set(node, registrations = []);
+ registrations.push(this);
+ },
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+ transientObservedNodes.forEach(function(node) {
+ this.removeListeners_(node);
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ },
+ handleEvent: function(e) {
+ e.stopImmediatePropagation();
+ switch (e.type) {
+ case "DOMAttrModified":
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+ var record = new getRecord("attributes", target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+ var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.attributes) return;
+ if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMCharacterDataModified":
+ var target = e.target;
+ var record = getRecord("characterData", target);
+ var oldValue = e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.characterData) return;
+ if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMNodeRemoved":
+ this.addTransientObserver(e.target);
+
+ case "DOMNodeInserted":
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === "DOMNodeInserted") {
+ addedNodes = [ changedNode ];
+ removedNodes = [];
+ } else {
+ addedNodes = [];
+ removedNodes = [ changedNode ];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+ var record = getRecord("childList", e.target.parentNode);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+ forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
+ if (!options.childList) return;
+ return record;
+ });
+ }
+ clearRecords();
+ }
+ };
+ global.JsMutationObserver = JsMutationObserver;
+ if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;
+})(this);
+
window.CustomElements = window.CustomElements || {
flags: {}
};
@@ -99,13 +398,10 @@ CustomElements.addModule(function(scope) {
root = root.olderShadowRoot;
}
}
- var processingDocuments;
function forDocumentTree(doc, cb) {
- processingDocuments = [];
- _forDocumentTree(doc, cb);
- processingDocuments = null;
+ _forDocumentTree(doc, cb, []);
}
- function _forDocumentTree(doc, cb) {
+ function _forDocumentTree(doc, cb, processingDocuments) {
doc = wrap(doc);
if (processingDocuments.indexOf(doc) >= 0) {
return;
@@ -114,7 +410,7 @@ CustomElements.addModule(function(scope) {
var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
if (n.import) {
- _forDocumentTree(n.import, cb);
+ _forDocumentTree(n.import, cb, processingDocuments);
}
}
cb(doc);
@@ -221,7 +517,7 @@ CustomElements.addModule(function(scope) {
if (p == doc) {
return true;
}
- p = p.parentNode || p.host;
+ p = p.parentNode || p.nodeType === Node.DOCUMENT_FRAGMENT_NODE && p.host;
}
}
function watchShadow(node) {
@@ -380,8 +676,9 @@ CustomElements.addModule(function(scope) {
});
CustomElements.addModule(function(scope) {
+ var isIE11OrOlder = scope.isIE11OrOlder;
var upgradeDocumentTree = scope.upgradeDocumentTree;
- var upgrade = scope.upgrade;
+ var upgradeAll = scope.upgradeAll;
var upgradeWithDefinition = scope.upgradeWithDefinition;
var implementPrototype = scope.implementPrototype;
var useNative = scope.useNative;
@@ -531,14 +828,8 @@ CustomElements.addModule(function(scope) {
}
return element;
}
- function cloneNode(deep) {
- var n = domCloneNode.call(this, deep);
- upgrade(n);
- return n;
- }
var domCreateElement = document.createElement.bind(document);
var domCreateElementNS = document.createElementNS.bind(document);
- var domCloneNode = Node.prototype.cloneNode;
var isInstance;
if (!Object.__proto__ && !useNative) {
isInstance = function(obj, ctor) {
@@ -556,10 +847,34 @@ CustomElements.addModule(function(scope) {
return obj instanceof base;
};
}
+ function wrapDomMethodToForceUpgrade(obj, methodName) {
+ var orig = obj[methodName];
+ obj[methodName] = function() {
+ var n = orig.apply(this, arguments);
+ upgradeAll(n);
+ return n;
+ };
+ }
+ wrapDomMethodToForceUpgrade(Node.prototype, "cloneNode");
+ wrapDomMethodToForceUpgrade(document, "importNode");
+ if (isIE11OrOlder) {
+ (function() {
+ var importNode = document.importNode;
+ document.importNode = function() {
+ var n = importNode.apply(document, arguments);
+ if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
+ var f = document.createDocumentFragment();
+ f.appendChild(n);
+ return f;
+ } else {
+ return n;
+ }
+ };
+ })();
+ }
document.registerElement = register;
document.createElement = createElement;
document.createElementNS = createElementNS;
- Node.prototype.cloneNode = cloneNode;
scope.registry = registry;
scope.instanceof = isInstance;
scope.reservedTagList = reservedTagList;
@@ -631,4 +946,5 @@ CustomElements.addModule(function(scope) {
var loadEvent = window.HTMLImports && !HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
window.addEventListener(loadEvent, bootstrap);
}
+ scope.isIE11OrOlder = isIE11OrOlder;
})(window.CustomElements); \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.min.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.min.js
new file mode 100644
index 00000000000..5b1b5387baa
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/CustomElements.min.js
@@ -0,0 +1,11 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.6.1
+"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,r=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};r.prototype={set:function(t,r){var n=t[this.name];return n&&n[0]===t?n[1]=r:e(t,this.name,{value:[t,r],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=r}(),function(e){function t(e){_.push(e),b||(b=!0,h(n))}function r(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function n(){b=!1;var e=_;_=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var r=e.takeRecords();o(e),r.length&&(e.callback_(r,e),t=!0)}),t&&n()}function o(e){e.nodes_.forEach(function(t){var r=v.get(t);r&&r.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var r=e;r;r=r.parentNode){var n=v.get(r);if(n)for(var o=0;o<n.length;o++){var i=n[o],a=i.options;if(r===e||a.subtree){var s=t(a);s&&i.enqueue(s)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++E}function s(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function d(e){var t=new s(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function u(e,t){return y=new s(e,t)}function c(e){return N?N:(N=d(y),N.oldValue=e,N)}function l(){y=N=void 0}function f(e){return e===N||e===y}function p(e,t){return e===t?e:N&&f(e)?N:null}function m(e,t,r){this.observer=e,this.target=t,this.options=r,this.transientObservedNodes=[]}var h,v=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))h=setTimeout;else if(window.setImmediate)h=window.setImmediate;else{var w=[],g=String(Math.random());window.addEventListener("message",function(e){if(e.data===g){var t=w;w=[],t.forEach(function(e){e()})}}),h=function(e){w.push(e),window.postMessage(g,"*")}}var b=!1,_=[],E=0;a.prototype={observe:function(e,t){if(e=r(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var n=v.get(e);n||v.set(e,n=[]);for(var o,i=0;i<n.length;i++)if(n[i].observer===this){o=n[i],o.removeListeners(),o.options=t;break}o||(o=new m(this,e,t),n.push(o),this.nodes_.push(e)),o.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=v.get(e),r=0;r<t.length;r++){var n=t[r];if(n.observer===this){n.removeListeners(),t.splice(r,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var y,N;m.prototype={enqueue:function(e){var r=this.observer.records_,n=r.length;if(r.length>0){var o=r[n-1],i=p(o,e);if(i)return void(r[n-1]=i)}else t(this.observer);r[n]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),r=0;r<t.length;r++)if(t[r]===this){t.splice(r,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,r=e.relatedNode.namespaceURI,n=e.target,o=new u("attributes",n);o.attributeName=t,o.attributeNamespace=r;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(n,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(r)?void 0:e.attributeOldValue?c(a):o});break;case"DOMCharacterDataModified":var n=e.target,o=u("characterData",n),a=e.prevValue;i(n,function(e){return e.characterData?e.characterDataOldValue?c(a):o:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var s,d,f=e.target;"DOMNodeInserted"===e.type?(s=[f],d=[]):(s=[],d=[f]);var p=f.previousSibling,m=f.nextSibling,o=u("childList",e.target.parentNode);o.addedNodes=s,o.removedNodes=d,o.previousSibling=p,o.nextSibling=m,i(e.relatedNode,function(e){return e.childList?o:void 0})}l()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a)}(this),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,r=[],n=function(e){r.push(e)},o=function(){r.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){r(e,function(e){return t(e)?!0:void n(e,t)}),n(e,t)}function r(e,t,n){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,n)!==!0&&r(o,t,n),o=o.nextElementSibling;return null}function n(e,r){for(var n=e.shadowRoot;n;)t(n,r),n=n.olderShadowRoot}function o(e,t){i(e,t,[])}function i(e,t,r){if(e=wrap(e),!(r.indexOf(e)>=0)){r.push(e);for(var n,o=e.querySelectorAll("link[rel="+a+"]"),s=0,d=o.length;d>s&&(n=o[s]);s++)n["import"]&&i(n["import"],t,r);t(e)}}var a=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return r(e)||n(e)}function r(t){return e.upgrade(t)?!0:void s(t)}function n(e){_(e,function(e){return r(e)?!0:void 0})}function o(e){s(e),f(e)&&_(e,function(e){s(e)})}function i(e){M.push(e),N||(N=!0,setTimeout(a))}function a(){N=!1;for(var e,t=M,r=0,n=t.length;n>r&&(e=t[r]);r++)e();M=[]}function s(e){y?i(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&f(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function u(e){c(e),_(e,function(e){c(e)})}function c(e){y?i(function(){l(e)}):l(e)}function l(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!f(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function f(e){for(var t=e,r=wrap(document);t;){if(t==r)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function p(e){if(e.shadowRoot&&!e.shadowRoot.__watched){b.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)v(t),t=t.olderShadowRoot}}function m(e){if(b.dom){var r=e[0];if(r&&"childList"===r.type&&r.addedNodes&&r.addedNodes){for(var n=r.addedNodes[0];n&&n!==document&&!n.host;)n=n.parentNode;var o=n&&(n.URL||n._URL||n.host&&n.host.localName)||"";o=o.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,o||"")}e.forEach(function(e){"childList"===e.type&&(O(e.addedNodes,function(e){e.localName&&t(e)}),O(e.removedNodes,function(e){e.localName&&u(e)}))}),b.dom&&console.groupEnd()}function h(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(m(t.takeRecords()),a())}function v(e){if(!e.__observer){var t=new MutationObserver(m);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function w(e){e=wrap(e),b.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),v(e),b.dom&&console.groupEnd()}function g(e){E(e,w)}var b=e.flags,_=e.forSubtree,E=e.forDocumentTree,y=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=y;var N=!1,M=[],O=Array.prototype.forEach.call.bind(Array.prototype.forEach),L=Element.prototype.createShadowRoot;L&&(Element.prototype.createShadowRoot=function(){var e=L.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=p,e.upgradeDocumentTree=g,e.upgradeSubtree=n,e.upgradeAll=t,e.attachedNode=o,e.takeRecords=h}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var n=t.getAttribute("is"),o=e.getRegisteredDefinition(n||t.localName);if(o){if(n&&o.tag==t.localName)return r(t,o);if(!n&&!o["extends"])return r(t,o)}}}function r(t,r){return a.upgrade&&console.group("upgrade:",t.localName),r.is&&t.setAttribute("is",r.is),n(t,r),t.__upgraded__=!0,i(t),e.attachedNode(t),e.upgradeSubtree(t),a.upgrade&&console.groupEnd(),t}function n(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,r){for(var n={},o=t;o!==r&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)n[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),n[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=r,e.implementPrototype=n}),CustomElements.addModule(function(e){function t(t,n){var d=n||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(u(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return d.prototype||(d.prototype=Object.create(HTMLElement.prototype)),d.__name=t.toLowerCase(),d.lifecycle=d.lifecycle||{},d.ancestry=i(d["extends"]),a(d),s(d),r(d.prototype),c(d.__name,d),d.ctor=l(d),d.ctor.prototype=d.prototype,d.prototype.constructor=d.ctor,e.ready&&w(document),d.ctor}function r(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,r){n.call(this,e,r,t)};var r=e.removeAttribute;e.removeAttribute=function(e){n.call(this,e,null,r)},e.setAttribute._polyfilled=!0}}function n(e,t,r){e=e.toLowerCase();var n=this.getAttribute(e);r.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==n&&this.attributeChangedCallback(e,n,o)}function o(e){for(var t=0;t<y.length;t++)if(e===y[t])return!0}function i(e){var t=u(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,r=e["extends"],n=0;t=e.ancestry[n];n++)r=t.is&&t.tag;e.tag=r||e.__name,r&&(e.is=e.__name)}function s(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var r=document.createElement(e.tag),n=Object.getPrototypeOf(r);n===e.prototype&&(t=n)}for(var o,i=e.prototype;i&&i!==t;)o=Object.getPrototypeOf(i),i.__proto__=o,i=o;e["native"]=t}}function d(e){return b(O(e.tag),e)}function u(e){return e?N[e.toLowerCase()]:void 0}function c(e,t){N[e]=t}function l(e){return function(){return d(e)}}function f(e,t,r){return e===M?p(t,r):L(e,t)}function p(e,t){var r=u(t||e);if(r){if(e==r.tag&&t==r.is)return new r.ctor;if(!t&&!r.is)return new r.ctor}var n;return t?(n=p(e),n.setAttribute("is",t),n):(n=O(e),e.indexOf("-")>=0&&_(n,HTMLElement),n)}function m(e,t){var r=e[t];e[t]=function(){var e=r.apply(this,arguments);return g(e),e}}var h,v=e.isIE11OrOlder,w=e.upgradeDocumentTree,g=e.upgradeAll,b=e.upgradeWithDefinition,_=e.implementPrototype,E=e.useNative,y=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],N={},M="http://www.w3.org/1999/xhtml",O=document.createElement.bind(document),L=document.createElementNS.bind(document);h=Object.__proto__||E?function(e,t){return e instanceof t}:function(e,t){for(var r=e;r;){if(r===t.prototype)return!0;r=r.__proto__}return!1},m(Node.prototype,"cloneNode"),m(document,"importNode"),v&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType==t.DOCUMENT_FRAGMENT_NODE){var r=document.createDocumentFragment();return r.appendChild(t),r}return t}}(),document.registerElement=t,document.createElement=p,document.createElementNS=f,e.registry=N,e["instanceof"]=h,e.reservedTagList=y,e.getRegisteredDefinition=u,document.register=document.registerElement}),function(e){function t(){a(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){a(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var r=e.useNative,n=e.initializeModules,o=/Trident/.test(navigator.userAgent);if(r){var i=function(){};e.watchShadow=i,e.upgrade=i,e.upgradeAll=i,e.upgradeDocumentTree=i,e.upgradeSubtree=i,e.takeRecords=i,e["instanceof"]=function(e,t){return e instanceof t}}else n();var a=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),o&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var r=document.createEvent("CustomEvent");return r.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),r},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t();e.isIE11OrOlder=o}(window.CustomElements); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.js
index 9a194e14457..90613da7d2c 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.js
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.js
@@ -7,7 +7,7 @@
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
-// @version 0.5.5
+// @version 0.6.1
if (typeof WeakMap === "undefined") {
(function() {
var defineProperty = Object.defineProperty;
@@ -44,6 +44,305 @@ if (typeof WeakMap === "undefined") {
})();
}
+(function(global) {
+ var registrationsTable = new WeakMap();
+ var setImmediate;
+ if (/Trident|Edge/.test(navigator.userAgent)) {
+ setImmediate = setTimeout;
+ } else if (window.setImmediate) {
+ setImmediate = window.setImmediate;
+ } else {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener("message", function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, "*");
+ };
+ }
+ var isScheduled = false;
+ var scheduledObservers = [];
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
+ }
+ function dispatchCallbacks() {
+ isScheduled = false;
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+ var queue = observer.takeRecords();
+ removeTransientObserversFor(observer);
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+ if (anyNonEmpty) dispatchCallbacks();
+ }
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations) return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer) registration.removeTransientObservers();
+ });
+ });
+ }
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+ if (node !== target && !options.subtree) continue;
+ var record = callback(options);
+ if (record) registration.enqueue(record);
+ }
+ }
+ }
+ }
+ var uidCounter = 0;
+ function JsMutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+ JsMutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+ if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
+ throw new SyntaxError();
+ }
+ var registrations = registrationsTable.get(target);
+ if (!registrations) registrationsTable.set(target, registrations = []);
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+ registration.addListeners();
+ },
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ }
+ var currentRecord, recordWithOldValue;
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue) return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord) return lastRecord;
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
+ return null;
+ }
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+ records[length] = record;
+ },
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
+ },
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
+ },
+ addTransientObserver: function(node) {
+ if (node === this.target) return;
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations) registrationsTable.set(node, registrations = []);
+ registrations.push(this);
+ },
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+ transientObservedNodes.forEach(function(node) {
+ this.removeListeners_(node);
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ },
+ handleEvent: function(e) {
+ e.stopImmediatePropagation();
+ switch (e.type) {
+ case "DOMAttrModified":
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+ var record = new getRecord("attributes", target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+ var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.attributes) return;
+ if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMCharacterDataModified":
+ var target = e.target;
+ var record = getRecord("characterData", target);
+ var oldValue = e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.characterData) return;
+ if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMNodeRemoved":
+ this.addTransientObserver(e.target);
+
+ case "DOMNodeInserted":
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === "DOMNodeInserted") {
+ addedNodes = [ changedNode ];
+ removedNodes = [];
+ } else {
+ addedNodes = [];
+ removedNodes = [ changedNode ];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+ var record = getRecord("childList", e.target.parentNode);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+ forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
+ if (!options.childList) return;
+ return record;
+ });
+ }
+ clearRecords();
+ }
+ };
+ global.JsMutationObserver = JsMutationObserver;
+ if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;
+})(this);
+
window.HTMLImports = window.HTMLImports || {
flags: {}
};
@@ -95,26 +394,35 @@ window.HTMLImports = window.HTMLImports || {
}
function watchImportsLoad(callback, doc) {
var imports = doc.querySelectorAll("link[rel=import]");
- var loaded = 0, l = imports.length;
- function checkDone(d) {
- if (loaded == l && callback) {
- callback();
+ var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];
+ function checkDone() {
+ if (parsedCount == importCount && callback) {
+ callback({
+ allImports: imports,
+ loadedImports: newImports,
+ errorImports: errorImports
+ });
}
}
function loadedImport(e) {
markTargetLoaded(e);
- loaded++;
+ newImports.push(this);
+ parsedCount++;
+ checkDone();
+ }
+ function errorLoadingImport(e) {
+ errorImports.push(this);
+ parsedCount++;
checkDone();
}
- if (l) {
- for (var i = 0, imp; i < l && (imp = imports[i]); i++) {
+ if (importCount) {
+ for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) {
if (isImportLoaded(imp)) {
- loadedImport.call(imp, {
- target: imp
- });
+ parsedCount++;
+ checkDone();
} else {
imp.addEventListener("load", loadedImport);
- imp.addEventListener("error", loadedImport);
+ imp.addEventListener("error", errorLoadingImport);
}
}
} else {
@@ -164,11 +472,11 @@ window.HTMLImports = window.HTMLImports || {
}
})();
}
- whenReady(function() {
+ whenReady(function(detail) {
HTMLImports.ready = true;
HTMLImports.readyTime = new Date().getTime();
var evt = rootDocument.createEvent("CustomEvent");
- evt.initCustomEvent("HTMLImportsLoaded", true, true, {});
+ evt.initCustomEvent("HTMLImportsLoaded", true, true, detail);
rootDocument.dispatchEvent(evt);
});
scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
@@ -196,20 +504,23 @@ HTMLImports.addModule(function(scope) {
var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
var path = {
- resolveUrlsInStyle: function(style) {
+ resolveUrlsInStyle: function(style, linkUrl) {
var doc = style.ownerDocument;
var resolver = doc.createElement("a");
- style.textContent = this.resolveUrlsInCssText(style.textContent, resolver);
+ style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver);
return style;
},
- resolveUrlsInCssText: function(cssText, urlObj) {
- var r = this.replaceUrls(cssText, urlObj, CSS_URL_REGEXP);
- r = this.replaceUrls(r, urlObj, CSS_IMPORT_REGEXP);
+ resolveUrlsInCssText: function(cssText, linkUrl, urlObj) {
+ var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP);
+ r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP);
return r;
},
- replaceUrls: function(text, urlObj, regexp) {
+ replaceUrls: function(text, urlObj, linkUrl, regexp) {
return text.replace(regexp, function(m, pre, url, post) {
var urlPath = url.replace(/["']/g, "");
+ if (linkUrl) {
+ urlPath = new URL(urlPath, linkUrl).href;
+ }
urlObj.href = urlPath;
urlPath = urlObj.href;
return pre + "'" + urlPath + "'" + post;
@@ -477,6 +788,7 @@ HTMLImports.addModule(function(scope) {
parseStyle: function(elt) {
var src = elt;
elt = cloneStyle(elt);
+ src.__appliedElement = elt;
elt.__importElement = src;
this.parseGeneric(elt);
},
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.min.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.min.js
new file mode 100644
index 00000000000..b30d76b3a29
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/HTMLImports.min.js
@@ -0,0 +1,11 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.6.1
+"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,r=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};r.prototype={set:function(t,r){var n=t[this.name];return n&&n[0]===t?n[1]=r:e(t,this.name,{value:[t,r],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=r}(),function(e){function t(e){E.push(e),_||(_=!0,f(n))}function r(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function n(){_=!1;var e=E;E=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var r=e.takeRecords();o(e),r.length&&(e.callback_(r,e),t=!0)}),t&&n()}function o(e){e.nodes_.forEach(function(t){var r=v.get(t);r&&r.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var r=e;r;r=r.parentNode){var n=v.get(r);if(n)for(var o=0;o<n.length;o++){var i=n[o],a=i.options;if(r===e||a.subtree){var s=t(a);s&&i.enqueue(s)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++L}function s(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function d(e){var t=new s(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function c(e,t){return y=new s(e,t)}function u(e){return M?M:(M=d(y),M.oldValue=e,M)}function l(){y=M=void 0}function h(e){return e===M||e===y}function m(e,t){return e===t?e:M&&h(e)?M:null}function p(e,t,r){this.observer=e,this.target=t,this.options=r,this.transientObservedNodes=[]}var f,v=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))f=setTimeout;else if(window.setImmediate)f=window.setImmediate;else{var b=[],g=String(Math.random());window.addEventListener("message",function(e){if(e.data===g){var t=b;b=[],t.forEach(function(e){e()})}}),f=function(e){b.push(e),window.postMessage(g,"*")}}var _=!1,E=[],L=0;a.prototype={observe:function(e,t){if(e=r(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var n=v.get(e);n||v.set(e,n=[]);for(var o,i=0;i<n.length;i++)if(n[i].observer===this){o=n[i],o.removeListeners(),o.options=t;break}o||(o=new p(this,e,t),n.push(o),this.nodes_.push(e)),o.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=v.get(e),r=0;r<t.length;r++){var n=t[r];if(n.observer===this){n.removeListeners(),t.splice(r,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var y,M;p.prototype={enqueue:function(e){var r=this.observer.records_,n=r.length;if(r.length>0){var o=r[n-1],i=m(o,e);if(i)return void(r[n-1]=i)}else t(this.observer);r[n]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),r=0;r<t.length;r++)if(t[r]===this){t.splice(r,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,r=e.relatedNode.namespaceURI,n=e.target,o=new c("attributes",n);o.attributeName=t,o.attributeNamespace=r;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(n,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(r)?void 0:e.attributeOldValue?u(a):o});break;case"DOMCharacterDataModified":var n=e.target,o=c("characterData",n),a=e.prevValue;i(n,function(e){return e.characterData?e.characterDataOldValue?u(a):o:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var s,d,h=e.target;"DOMNodeInserted"===e.type?(s=[h],d=[]):(s=[],d=[h]);var m=h.previousSibling,p=h.nextSibling,o=c("childList",e.target.parentNode);o.addedNodes=s,o.removedNodes=d,o.previousSibling=m,o.nextSibling=p,i(e.relatedNode,function(e){return e.childList?o:void 0})}l()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a)}(this),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,n(function(){i(e,t)},t)}function r(e){return"complete"===e.readyState||e.readyState===b}function n(e,t){if(r(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===b)&&(t.removeEventListener(g,o),n(e,t))};t.addEventListener(g,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function r(){d==c&&e&&e({allImports:s,loadedImports:u,errorImports:l})}function n(e){o(e),u.push(this),d++,r()}function i(e){l.push(this),d++,r()}var s=t.querySelectorAll("link[rel=import]"),d=0,c=s.length,u=[],l=[];if(c)for(var h,m=0;c>m&&(h=s[m]);m++)a(h)?(d++,r()):(h.addEventListener("load",n),h.addEventListener("error",i));else r()}function a(e){return l?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,r=0,n=e.length;n>r&&(t=e[r]);r++)d(t)&&c(t)}function d(e){return"link"===e.localName&&"import"===e.rel}function c(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var u="import",l=Boolean(u in document.createElement("link")),h=Boolean(window.ShadowDOMPolyfill),m=function(e){return h?ShadowDOMPolyfill.wrapIfNeeded(e):e},p=m(document),f={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return m(e)},configurable:!0};Object.defineProperty(document,"_currentScript",f),Object.defineProperty(p,"_currentScript",f);var v=/Trident|Edge/.test(navigator.userAgent),b=v?"complete":"interactive",g="readystatechange";l&&(new MutationObserver(function(e){for(var t,r=0,n=e.length;n>r&&(t=e[r]);r++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),r=0,n=t.length;n>r&&(e=t[r]);r++)c(e)}()),t(function(e){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var t=p.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),p.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=u,e.useNative=l,e.rootDocument=p,e.whenReady=t,e.isIE=v}(HTMLImports),function(e){var t=[],r=function(e){t.push(e)},n=function(){t.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=n}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,r=/(@import[\s]+(?!url\())([^;]*)(;)/g,n={resolveUrlsInStyle:function(e,t){var r=e.ownerDocument,n=r.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,n),e},resolveUrlsInCssText:function(e,n,o){var i=this.replaceUrls(e,o,n,t);return i=this.replaceUrls(i,o,n,r)},replaceUrls:function(e,t,r,n){return e.replace(n,function(e,n,o,i){var a=o.replace(/["']/g,"");return r&&(a=new URL(a,r).href),t.href=a,a=t.href,n+"'"+a+"'"+i})}};e.path=n}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(r,n,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(r+="?"+Math.random()),i.open("GET",r,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var r=i.getResponseHeader("Location"),a=null;if(r)var a="/"===r.substr(0,1)?location.origin+r:r;n.call(o,!t.ok(i)&&i,i.response||i.responseText,a)}}),i.send(),i},loadDocument:function(e,t,r){this.load(e,t,r).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,r=e.flags,n=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};n.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,r=0,n=e.length;n>r&&(t=e[r]);r++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,n){if(r.load&&console.log("fetch",e,n),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,n,null,a)}.bind(this),0)}else{var s=function(t,r,o){this.receive(e,n,t,r,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,n,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,r,n,o){this.cache[e]=n;for(var i,a=this.pending[e],s=0,d=a.length;d>s&&(i=a[s]);s++)this.onload(e,i,n,r,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=n}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,r=0,n=e.length;n>r&&(t=e[r]);r++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,r=0,n=e.length;n>r&&(t=e[r]);r++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function r(e){var t=n(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function n(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var r=e.ownerDocument.baseURI,n=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+r+n+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,d=e.flags,c=e.isIE,u=e.IMPORT_LINK_TYPE,l="link[rel="+u+"]",h={documentSelectors:l,importsSelectors:[l,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(d.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){d.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,d.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var r=this,n=function(n){t&&t(n),r.markParsingComplete(e),r.parseNext()};if(e.addEventListener("load",n),e.addEventListener("error",n),c&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,d=0;s>d&&(i=a[d]);d++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var n=document.createElement("script");n.__importElement=t,n.src=t.src?t.src:r(t),e.currentScript=t,this.trackElement(n,function(t){n.parentNode.removeChild(n),e.currentScript=null}),this.addElementToDocument(n)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,r){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var n,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(n=o[i]);i++)if(!this.isParsed(n))return this.hasResource(n)?t(n)?this.nextToParseInDoc(n["import"],n):n:void 0}return r},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=h,e.IMPORT_SELECTOR=l}),HTMLImports.addModule(function(e){function t(e){return r(e,a)}function r(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function n(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var r=document.implementation.createHTMLDocument(a);r._URL=t;var o=r.createElement("base");o.setAttribute("href",t),r.baseURI||n(r)||Object.defineProperty(r,"baseURI",{value:t});var i=r.createElement("meta");return i.setAttribute("charset","utf-8"),r.head.appendChild(i),r.head.appendChild(o),r.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(r),r}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,d=e.rootDocument,c=e.Loader,u=e.Observer,l=e.parser,h={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){m.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);m.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===d?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,r,n,a,s){if(i.load&&console.log("loaded",e,r),r.__resource=n,r.__error=a,t(r)){var d=this.documents[e];void 0===d&&(d=a?null:o(n,s||e),d&&(d.__importLink=r,this.bootDocument(d)),this.documents[e]=d),r["import"]=d}l.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),l.parseNext()},loadedAll:function(){l.parseNext()}},m=new c(h.loaded.bind(h),h.loadedAll.bind(h));if(h.observer=new u,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(d,"baseURI",p)}e.importer=h,e.importLoader=m}),HTMLImports.addModule(function(e){var t=e.parser,r=e.importer,n={added:function(e){for(var n,o,i,a,s=0,d=e.length;d>s&&(a=e[s]);s++)n||(n=a.ownerDocument,o=t.isParsed(n)),i=this.shouldLoadNode(a),i&&r.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,r.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};r.observer.addCallback=n.added.bind(n);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(o)}var r=e.initializeModules,n=e.isIE;if(!e.useNative){n&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var r=document.createEvent("CustomEvent");return r.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),r},window.CustomEvent.prototype=window.Event.prototype),r();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/README.md b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/README.md
index 49ed2b64f30..442af182e5c 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/README.md
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/README.md
@@ -71,3 +71,38 @@ Everything in this repository is BSD style license unless otherwise specified.
Copyright (c) 2015 The Polymer Authors. All rights reserved.
+## Known Issues
+
+ * [Custom element's constructor property is unreliable](#constructor)
+ * [Contenteditable elements do not trigger MutationObserver](#contentedit)
+ * [ShadowCSS: :host-context(...):host(...) doesn't work](#hostcontext)
+ * [execCommand isn't supported under Shadow DOM](#execcommand)
+
+### Custom element's constructor property is unreliable <a id="constructor"></a>
+See [#215](https://github.com/webcomponents/webcomponentsjs/issues/215) for background.
+
+In Safari and IE, instances of Custom Elements have a `constructor` property of `HTMLUnknownElementConstructor` and `HTMLUnknownElement`, respectively. It's unsafe to rely on this property for checking element types.
+
+It's worth noting that `customElement.__proto__.__proto__.constructor` is `HTMLElementPrototype` and that the prototype chain isn't modified by the polyfills(onto `ElementPrototype`, etc.)
+
+### Contenteditable elements do not trigger MutationObserver <a id="contentedit"></a>
+Using the MutationObserver polyfill, it isn't possible to monitor mutations of an element marked `contenteditable`.
+See [the mailing list](https://groups.google.com/forum/#!msg/polymer-dev/LHdtRVXXVsA/v1sGoiTYWUkJ)
+
+### ShadowCSS: :host-context(...):host(...) doesn't work <a id="hostcontext"></a>
+See [#16](https://github.com/webcomponents/webcomponentsjs/issues/16) for background.
+
+Under the shadow DOM polyfill, rules like:
+```
+:host-context(.foo):host(.bar) {...}
+```
+don't work, despite working under native Shadow DOM. The solution is to use `polyfill-next-selector` like:
+
+```
+polyfill-next-selector { content: '.foo :host.bar, :host.foo.bar'; }
+```
+
+### execCommand and contenteditable isn't supported under Shadow DOM <a id="execcommand"></a>
+See [#212](https://github.com/webcomponents/webcomponentsjs/issues/212)
+
+`execCommand`, and `contenteditable` aren't supported under the ShadowDOM polyfill, with commands that insert or remove nodes being especially prone to failure.
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.js
index fb5c08f3463..96647356a00 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.js
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.js
@@ -7,7 +7,7 @@
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
-// @version 0.5.5
+// @version 0.6.1
if (typeof WeakMap === "undefined") {
(function() {
var defineProperty = Object.defineProperty;
@@ -146,7 +146,7 @@ window.ShadowDOMPolyfill = {};
return /^on[a-z]+$/.test(name);
}
function isIdentifierName(name) {
- return /^\w[a-zA-Z_0-9]*$/.test(name);
+ return /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(name);
}
function getGetter(name) {
return hasEval && isIdentifierName(name) ? new Function("return this.__impl4cf1e782hg__." + name) : function() {
@@ -302,6 +302,7 @@ window.ShadowDOMPolyfill = {};
scope.defineGetter = defineGetter;
scope.defineWrapGetter = defineWrapGetter;
scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
+ scope.isIdentifierName = isIdentifierName;
scope.isWrapper = isWrapper;
scope.isWrapperFor = isWrapperFor;
scope.mixin = mixin;
@@ -1731,6 +1732,7 @@ window.ShadowDOMPolyfill = {};
var OriginalDocumentFragment = window.DocumentFragment;
var originalAppendChild = OriginalNode.prototype.appendChild;
var originalCompareDocumentPosition = OriginalNode.prototype.compareDocumentPosition;
+ var originalIsEqualNode = OriginalNode.prototype.isEqualNode;
var originalInsertBefore = OriginalNode.prototype.insertBefore;
var originalRemoveChild = OriginalNode.prototype.removeChild;
var originalReplaceChild = OriginalNode.prototype.replaceChild;
@@ -1959,6 +1961,9 @@ window.ShadowDOMPolyfill = {};
compareDocumentPosition: function(otherNode) {
return originalCompareDocumentPosition.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));
},
+ isEqualNode: function(otherNode) {
+ return originalIsEqualNode.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));
+ },
normalize: function() {
var nodes = snapshotNodeList(this.childNodes);
var remNodes = [];
@@ -2036,10 +2041,10 @@ window.ShadowDOMPolyfill = {};
return index;
}
function shimSelector(selector) {
- return String(selector).replace(/\/deep\/|::shadow/g, " ");
+ return String(selector).replace(/\/deep\/|::shadow|>>>/g, " ");
}
function shimMatchesSelector(selector) {
- return String(selector).replace(/:host\(([^\s]+)\)/g, "$1").replace(/([^\s]):host/g, "$1").replace(":host", "*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content/g, " ");
+ return String(selector).replace(/:host\(([^\s]+)\)/g, "$1").replace(/([^\s]):host/g, "$1").replace(":host", "*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content|>>>/g, " ");
}
function findOne(node, selector) {
var m, el = node.firstElementChild;
@@ -2262,6 +2267,12 @@ window.ShadowDOMPolyfill = {};
}
CharacterData.prototype = Object.create(Node.prototype);
mixin(CharacterData.prototype, {
+ get nodeValue() {
+ return this.data;
+ },
+ set nodeValue(data) {
+ this.data = data;
+ },
get textContent() {
return this.data;
},
@@ -3265,30 +3276,131 @@ window.ShadowDOMPolyfill = {};
(function(scope) {
"use strict";
+ var GetElementsByInterface = scope.GetElementsByInterface;
+ var ParentNodeInterface = scope.ParentNodeInterface;
+ var SelectorsInterface = scope.SelectorsInterface;
+ var mixin = scope.mixin;
+ var registerObject = scope.registerObject;
+ var DocumentFragment = registerObject(document.createDocumentFragment());
+ mixin(DocumentFragment.prototype, ParentNodeInterface);
+ mixin(DocumentFragment.prototype, SelectorsInterface);
+ mixin(DocumentFragment.prototype, GetElementsByInterface);
+ var Comment = registerObject(document.createComment(""));
+ scope.wrappers.Comment = Comment;
+ scope.wrappers.DocumentFragment = DocumentFragment;
+})(window.ShadowDOMPolyfill);
+
+(function(scope) {
+ "use strict";
+ var DocumentFragment = scope.wrappers.DocumentFragment;
+ var TreeScope = scope.TreeScope;
+ var elementFromPoint = scope.elementFromPoint;
+ var getInnerHTML = scope.getInnerHTML;
+ var getTreeScope = scope.getTreeScope;
+ var mixin = scope.mixin;
+ var rewrap = scope.rewrap;
+ var setInnerHTML = scope.setInnerHTML;
+ var unsafeUnwrap = scope.unsafeUnwrap;
+ var unwrap = scope.unwrap;
+ var shadowHostTable = new WeakMap();
+ var nextOlderShadowTreeTable = new WeakMap();
+ var spaceCharRe = /[ \t\n\r\f]/;
+ function ShadowRoot(hostWrapper) {
+ var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment());
+ DocumentFragment.call(this, node);
+ rewrap(node, this);
+ var oldShadowRoot = hostWrapper.shadowRoot;
+ nextOlderShadowTreeTable.set(this, oldShadowRoot);
+ this.treeScope_ = new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
+ shadowHostTable.set(this, hostWrapper);
+ }
+ ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
+ mixin(ShadowRoot.prototype, {
+ constructor: ShadowRoot,
+ get innerHTML() {
+ return getInnerHTML(this);
+ },
+ set innerHTML(value) {
+ setInnerHTML(this, value);
+ this.invalidateShadowRenderer();
+ },
+ get olderShadowRoot() {
+ return nextOlderShadowTreeTable.get(this) || null;
+ },
+ get host() {
+ return shadowHostTable.get(this) || null;
+ },
+ invalidateShadowRenderer: function() {
+ return shadowHostTable.get(this).invalidateShadowRenderer();
+ },
+ elementFromPoint: function(x, y) {
+ return elementFromPoint(this, this.ownerDocument, x, y);
+ },
+ getElementById: function(id) {
+ if (spaceCharRe.test(id)) return null;
+ return this.querySelector('[id="' + id + '"]');
+ }
+ });
+ scope.wrappers.ShadowRoot = ShadowRoot;
+})(window.ShadowDOMPolyfill);
+
+(function(scope) {
+ "use strict";
var registerWrapper = scope.registerWrapper;
var setWrapper = scope.setWrapper;
var unsafeUnwrap = scope.unsafeUnwrap;
var unwrap = scope.unwrap;
var unwrapIfNeeded = scope.unwrapIfNeeded;
var wrap = scope.wrap;
+ var getTreeScope = scope.getTreeScope;
var OriginalRange = window.Range;
+ var ShadowRoot = scope.wrappers.ShadowRoot;
+ function getHost(node) {
+ var root = getTreeScope(node).root;
+ if (root instanceof ShadowRoot) {
+ return root.host;
+ }
+ return null;
+ }
+ function hostNodeToShadowNode(refNode, offset) {
+ if (refNode.shadowRoot) {
+ offset = Math.min(refNode.childNodes.length - 1, offset);
+ var child = refNode.childNodes[offset];
+ if (child) {
+ var insertionPoint = scope.getDestinationInsertionPoints(child);
+ if (insertionPoint.length > 0) {
+ var parentNode = insertionPoint[0].parentNode;
+ if (parentNode.nodeType == Node.ELEMENT_NODE) {
+ refNode = parentNode;
+ }
+ }
+ }
+ }
+ return refNode;
+ }
+ function shadowNodeToHostNode(node) {
+ node = wrap(node);
+ return getHost(node) || node;
+ }
function Range(impl) {
setWrapper(impl, this);
}
Range.prototype = {
get startContainer() {
- return wrap(unsafeUnwrap(this).startContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).startContainer);
},
get endContainer() {
- return wrap(unsafeUnwrap(this).endContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).endContainer);
},
get commonAncestorContainer() {
- return wrap(unsafeUnwrap(this).commonAncestorContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).commonAncestorContainer);
},
setStart: function(refNode, offset) {
+ refNode = hostNodeToShadowNode(refNode, offset);
unsafeUnwrap(this).setStart(unwrapIfNeeded(refNode), offset);
},
setEnd: function(refNode, offset) {
+ refNode = hostNodeToShadowNode(refNode, offset);
unsafeUnwrap(this).setEnd(unwrapIfNeeded(refNode), offset);
},
setStartBefore: function(refNode) {
@@ -3351,76 +3463,6 @@ window.ShadowDOMPolyfill = {};
(function(scope) {
"use strict";
- var GetElementsByInterface = scope.GetElementsByInterface;
- var ParentNodeInterface = scope.ParentNodeInterface;
- var SelectorsInterface = scope.SelectorsInterface;
- var mixin = scope.mixin;
- var registerObject = scope.registerObject;
- var DocumentFragment = registerObject(document.createDocumentFragment());
- mixin(DocumentFragment.prototype, ParentNodeInterface);
- mixin(DocumentFragment.prototype, SelectorsInterface);
- mixin(DocumentFragment.prototype, GetElementsByInterface);
- var Comment = registerObject(document.createComment(""));
- scope.wrappers.Comment = Comment;
- scope.wrappers.DocumentFragment = DocumentFragment;
-})(window.ShadowDOMPolyfill);
-
-(function(scope) {
- "use strict";
- var DocumentFragment = scope.wrappers.DocumentFragment;
- var TreeScope = scope.TreeScope;
- var elementFromPoint = scope.elementFromPoint;
- var getInnerHTML = scope.getInnerHTML;
- var getTreeScope = scope.getTreeScope;
- var mixin = scope.mixin;
- var rewrap = scope.rewrap;
- var setInnerHTML = scope.setInnerHTML;
- var unsafeUnwrap = scope.unsafeUnwrap;
- var unwrap = scope.unwrap;
- var shadowHostTable = new WeakMap();
- var nextOlderShadowTreeTable = new WeakMap();
- var spaceCharRe = /[ \t\n\r\f]/;
- function ShadowRoot(hostWrapper) {
- var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment());
- DocumentFragment.call(this, node);
- rewrap(node, this);
- var oldShadowRoot = hostWrapper.shadowRoot;
- nextOlderShadowTreeTable.set(this, oldShadowRoot);
- this.treeScope_ = new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
- shadowHostTable.set(this, hostWrapper);
- }
- ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
- mixin(ShadowRoot.prototype, {
- constructor: ShadowRoot,
- get innerHTML() {
- return getInnerHTML(this);
- },
- set innerHTML(value) {
- setInnerHTML(this, value);
- this.invalidateShadowRenderer();
- },
- get olderShadowRoot() {
- return nextOlderShadowTreeTable.get(this) || null;
- },
- get host() {
- return shadowHostTable.get(this) || null;
- },
- invalidateShadowRenderer: function() {
- return shadowHostTable.get(this).invalidateShadowRenderer();
- },
- elementFromPoint: function(x, y) {
- return elementFromPoint(this, this.ownerDocument, x, y);
- },
- getElementById: function(id) {
- if (spaceCharRe.test(id)) return null;
- return this.querySelector('[id="' + id + '"]');
- }
- });
- scope.wrappers.ShadowRoot = ShadowRoot;
-})(window.ShadowDOMPolyfill);
-
-(function(scope) {
- "use strict";
var Element = scope.wrappers.Element;
var HTMLContentElement = scope.wrappers.HTMLContentElement;
var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
@@ -3873,7 +3915,7 @@ window.ShadowDOMPolyfill = {};
return wrap(unsafeUnwrap(this).focusNode);
},
addRange: function(range) {
- unsafeUnwrap(this).addRange(unwrap(range));
+ unsafeUnwrap(this).addRange(unwrapIfNeeded(range));
},
collapse: function(node, index) {
unsafeUnwrap(this).collapse(unwrapIfNeeded(node), index);
@@ -3881,9 +3923,6 @@ window.ShadowDOMPolyfill = {};
containsNode: function(node, allowPartial) {
return unsafeUnwrap(this).containsNode(unwrapIfNeeded(node), allowPartial);
},
- extend: function(node, offset) {
- unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);
- },
getRangeAt: function(index) {
return wrap(unsafeUnwrap(this).getRangeAt(index));
},
@@ -3897,12 +3936,64 @@ window.ShadowDOMPolyfill = {};
return unsafeUnwrap(this).toString();
}
};
+ if (OriginalSelection.prototype.extend) {
+ Selection.prototype.extend = function(node, offset) {
+ unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);
+ };
+ }
registerWrapper(window.Selection, Selection, window.getSelection());
scope.wrappers.Selection = Selection;
})(window.ShadowDOMPolyfill);
(function(scope) {
"use strict";
+ var registerWrapper = scope.registerWrapper;
+ var setWrapper = scope.setWrapper;
+ var unsafeUnwrap = scope.unsafeUnwrap;
+ var unwrapIfNeeded = scope.unwrapIfNeeded;
+ var wrap = scope.wrap;
+ var OriginalTreeWalker = window.TreeWalker;
+ function TreeWalker(impl) {
+ setWrapper(impl, this);
+ }
+ TreeWalker.prototype = {
+ get root() {
+ return wrap(unsafeUnwrap(this).root);
+ },
+ get currentNode() {
+ return wrap(unsafeUnwrap(this).currentNode);
+ },
+ set currentNode(node) {
+ unsafeUnwrap(this).currentNode = unwrapIfNeeded(node);
+ },
+ get filter() {
+ return unsafeUnwrap(this).filter;
+ },
+ parentNode: function() {
+ return wrap(unsafeUnwrap(this).parentNode());
+ },
+ firstChild: function() {
+ return wrap(unsafeUnwrap(this).firstChild());
+ },
+ lastChild: function() {
+ return wrap(unsafeUnwrap(this).lastChild());
+ },
+ previousSibling: function() {
+ return wrap(unsafeUnwrap(this).previousSibling());
+ },
+ previousNode: function() {
+ return wrap(unsafeUnwrap(this).previousNode());
+ },
+ nextNode: function() {
+ return wrap(unsafeUnwrap(this).nextNode());
+ }
+ };
+ registerWrapper(OriginalTreeWalker, TreeWalker);
+ scope.wrappers.TreeWalker = TreeWalker;
+})(window.ShadowDOMPolyfill);
+
+(function(scope) {
+ "use strict";
var GetElementsByInterface = scope.GetElementsByInterface;
var Node = scope.wrappers.Node;
var ParentNodeInterface = scope.ParentNodeInterface;
@@ -3978,6 +4069,25 @@ window.ShadowDOMPolyfill = {};
return SelectorsInterface.querySelectorAll.call(this, "[name=" + JSON.stringify(String(name)) + "]");
}
});
+ var originalCreateTreeWalker = document.createTreeWalker;
+ var TreeWalkerWrapper = scope.wrappers.TreeWalker;
+ Document.prototype.createTreeWalker = function(root, whatToShow, filter, expandEntityReferences) {
+ var newFilter = null;
+ if (filter) {
+ if (filter.acceptNode && typeof filter.acceptNode === "function") {
+ newFilter = {
+ acceptNode: function(node) {
+ return filter.acceptNode(wrap(node));
+ }
+ };
+ } else if (typeof filter === "function") {
+ newFilter = function(node) {
+ return filter(wrap(node));
+ };
+ }
+ }
+ return new TreeWalkerWrapper(originalCreateTreeWalker.call(unwrap(this), unwrap(root), whatToShow, newFilter, expandEntityReferences));
+ };
if (document.registerElement) {
var originalRegisterElement = document.registerElement;
Document.prototype.registerElement = function(tagName, object) {
@@ -4041,7 +4151,7 @@ window.ShadowDOMPolyfill = {};
}
forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLDocument || window.Document, window.HTMLHeadElement, window.HTMLHtmlElement ], [ "appendChild", "compareDocumentPosition", "contains", "getElementsByClassName", "getElementsByTagName", "getElementsByTagNameNS", "insertBefore", "querySelector", "querySelectorAll", "removeChild", "replaceChild" ]);
forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLHeadElement, window.HTMLHtmlElement ], matchesNames);
- forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ "adoptNode", "importNode", "contains", "createComment", "createDocumentFragment", "createElement", "createElementNS", "createEvent", "createEventNS", "createRange", "createTextNode", "elementFromPoint", "getElementById", "getElementsByName", "getSelection" ]);
+ forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ "adoptNode", "importNode", "contains", "createComment", "createDocumentFragment", "createElement", "createElementNS", "createEvent", "createEventNS", "createRange", "createTextNode", "createTreeWalker", "elementFromPoint", "getElementById", "getElementsByName", "getSelection" ]);
mixin(Document.prototype, GetElementsByInterface);
mixin(Document.prototype, ParentNodeInterface);
mixin(Document.prototype, SelectorsInterface);
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.min.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.min.js
new file mode 100644
index 00000000000..df384534403
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/ShadowDOM.min.js
@@ -0,0 +1,14 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.6.1
+"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.ShadowDOMPolyfill={},function(e){"use strict";function t(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if(navigator.getDeviceStorage)return!1;try{var e=new Function("return true;");return e()}catch(t){return!1}}function n(e){if(!e)throw new Error("Assertion failed")}function r(e,t){for(var n=k(t),r=0;r<n.length;r++){var o=n[r];I(e,o,F(t,o))}return e}function o(e,t){for(var n=k(t),r=0;r<n.length;r++){var o=n[r];switch(o){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":continue}I(e,o,F(t,o))}return e}function i(e,t){for(var n=0;n<t.length;n++)if(t[n]in e)return t[n]}function a(e,t,n){B.value=n,I(e,t,B)}function s(e){var t=e.__proto__||Object.getPrototypeOf(e);if(U)try{k(t)}catch(n){t=t.__proto__}var r=R.get(t);if(r)return r;var o=s(t),i=E(o);return v(t,i,e),i}function c(e,t){m(e,t,!0)}function u(e,t){m(t,e,!1)}function l(e){return/^on[a-z]+$/.test(e)}function p(e){return/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(e)}function d(e){return A&&p(e)?new Function("return this.__impl4cf1e782hg__."+e):function(){return this.__impl4cf1e782hg__[e]}}function f(e){return A&&p(e)?new Function("v","this.__impl4cf1e782hg__."+e+" = v"):function(t){this.__impl4cf1e782hg__[e]=t}}function h(e){return A&&p(e)?new Function("return this.__impl4cf1e782hg__."+e+".apply(this.__impl4cf1e782hg__, arguments)"):function(){return this.__impl4cf1e782hg__[e].apply(this.__impl4cf1e782hg__,arguments)}}function w(e,t){try{return Object.getOwnPropertyDescriptor(e,t)}catch(n){return q}}function m(t,n,r,o){for(var i=k(t),a=0;a<i.length;a++){var s=i[a];if("polymerBlackList_"!==s&&!(s in n||t.polymerBlackList_&&t.polymerBlackList_[s])){U&&t.__lookupGetter__(s);var c,u,p=w(t,s);if(r&&"function"==typeof p.value)n[s]=h(s);else{var m=l(s);c=m?e.getEventHandlerGetter(s):d(s),(p.writable||p.set||V)&&(u=m?e.getEventHandlerSetter(s):f(s));var g=V||p.configurable;I(n,s,{get:c,set:u,configurable:g,enumerable:p.enumerable})}}}}function g(e,t,n){var r=e.prototype;v(r,t,n),o(t,e)}function v(e,t,r){var o=t.prototype;n(void 0===R.get(e)),R.set(e,t),P.set(o,e),c(e,o),r&&u(o,r),a(o,"constructor",t),t.prototype=o}function b(e,t){return R.get(t.prototype)===e}function y(e){var t=Object.getPrototypeOf(e),n=s(t),r=E(n);return v(t,r,e),r}function E(e){function t(t){e.call(this,t)}var n=Object.create(e.prototype);return n.constructor=t,t.prototype=n,t}function S(e){return e&&e.__impl4cf1e782hg__}function M(e){return!S(e)}function T(e){return null===e?null:(n(M(e)),e.__wrapper8e3dd93a60__||(e.__wrapper8e3dd93a60__=new(s(e))(e)))}function O(e){return null===e?null:(n(S(e)),e.__impl4cf1e782hg__)}function j(e){return e.__impl4cf1e782hg__}function N(e,t){t.__impl4cf1e782hg__=e,e.__wrapper8e3dd93a60__=t}function L(e){return e&&S(e)?O(e):e}function _(e){return e&&!S(e)?T(e):e}function C(e,t){null!==t&&(n(M(e)),n(void 0===t||S(t)),e.__wrapper8e3dd93a60__=t)}function D(e,t,n){G.get=n,I(e.prototype,t,G)}function H(e,t){D(e,t,function(){return T(this.__impl4cf1e782hg__[t])})}function x(e,t){e.forEach(function(e){t.forEach(function(t){e.prototype[t]=function(){var e=_(this);return e[t].apply(e,arguments)}})})}var R=new WeakMap,P=new WeakMap,W=Object.create(null),A=t(),I=Object.defineProperty,k=Object.getOwnPropertyNames,F=Object.getOwnPropertyDescriptor,B={value:void 0,configurable:!0,enumerable:!1,writable:!0};k(window);var U=/Firefox/.test(navigator.userAgent),q={get:function(){},set:function(e){},configurable:!0,enumerable:!0},V=function(){var e=Object.getOwnPropertyDescriptor(Node.prototype,"nodeType");return e&&!e.get&&!e.set}(),G={get:void 0,configurable:!0,enumerable:!0};e.assert=n,e.constructorTable=R,e.defineGetter=D,e.defineWrapGetter=H,e.forwardMethodsToWrapper=x,e.isIdentifierName=p,e.isWrapper=S,e.isWrapperFor=b,e.mixin=r,e.nativePrototypeTable=P,e.oneOf=i,e.registerObject=y,e.registerWrapper=g,e.rewrap=C,e.setWrapper=N,e.unsafeUnwrap=j,e.unwrap=O,e.unwrapIfNeeded=L,e.wrap=T,e.wrapIfNeeded=_,e.wrappers=W}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t,n){return{index:e,removed:t,addedCount:n}}function n(){}var r=0,o=1,i=2,a=3;n.prototype={calcEditDistances:function(e,t,n,r,o,i){for(var a=i-o+1,s=n-t+1,c=new Array(a),u=0;a>u;u++)c[u]=new Array(s),c[u][0]=u;for(var l=0;s>l;l++)c[0][l]=l;for(var u=1;a>u;u++)for(var l=1;s>l;l++)if(this.equals(e[t+l-1],r[o+u-1]))c[u][l]=c[u-1][l-1];else{var p=c[u-1][l]+1,d=c[u][l-1]+1;c[u][l]=d>p?p:d}return c},spliceOperationsFromEditDistances:function(e){for(var t=e.length-1,n=e[0].length-1,s=e[t][n],c=[];t>0||n>0;)if(0!=t)if(0!=n){var u,l=e[t-1][n-1],p=e[t-1][n],d=e[t][n-1];u=d>p?l>p?p:l:l>d?d:l,u==l?(l==s?c.push(r):(c.push(o),s=l),t--,n--):u==p?(c.push(a),t--,s=p):(c.push(i),n--,s=d)}else c.push(a),t--;else c.push(i),n--;return c.reverse(),c},calcSplices:function(e,n,s,c,u,l){var p=0,d=0,f=Math.min(s-n,l-u);if(0==n&&0==u&&(p=this.sharedPrefix(e,c,f)),s==e.length&&l==c.length&&(d=this.sharedSuffix(e,c,f-p)),n+=p,u+=p,s-=d,l-=d,s-n==0&&l-u==0)return[];if(n==s){for(var h=t(n,[],0);l>u;)h.removed.push(c[u++]);return[h]}if(u==l)return[t(n,[],s-n)];for(var w=this.spliceOperationsFromEditDistances(this.calcEditDistances(e,n,s,c,u,l)),h=void 0,m=[],g=n,v=u,b=0;b<w.length;b++)switch(w[b]){case r:h&&(m.push(h),h=void 0),g++,v++;break;case o:h||(h=t(g,[],0)),h.addedCount++,g++,h.removed.push(c[v]),v++;break;case i:h||(h=t(g,[],0)),h.addedCount++,g++;break;case a:h||(h=t(g,[],0)),h.removed.push(c[v]),v++}return h&&m.push(h),m},sharedPrefix:function(e,t,n){for(var r=0;n>r;r++)if(!this.equals(e[r],t[r]))return r;return n},sharedSuffix:function(e,t,n){for(var r=e.length,o=t.length,i=0;n>i&&this.equals(e[--r],t[--o]);)i++;return i},calculateSplices:function(e,t){return this.calcSplices(e,0,e.length,t,0,t.length)},equals:function(e,t){return e===t}},e.ArraySplice=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(){a=!1;var e=i.slice(0);i=[];for(var t=0;t<e.length;t++)e[t]()}function n(e){i.push(e),a||(a=!0,r(t,0))}var r,o=window.MutationObserver,i=[],a=!1;if(o){var s=1,c=new o(t),u=document.createTextNode(s);c.observe(u,{characterData:!0}),r=function(){s=(s+1)%2,u.data=s}}else r=window.setTimeout;e.setEndOfMicrotask=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.scheduled_||(e.scheduled_=!0,h.push(e),w||(l(n),w=!0))}function n(){for(w=!1;h.length;){var e=h;h=[],e.sort(function(e,t){return e.uid_-t.uid_});for(var t=0;t<e.length;t++){var n=e[t];n.scheduled_=!1;var r=n.takeRecords();i(n),r.length&&n.callback_(r,n)}}}function r(e,t){this.type=e,this.target=t,this.addedNodes=new d.NodeList,this.removedNodes=new d.NodeList,this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function o(e,t){for(;e;e=e.parentNode){var n=f.get(e);if(n)for(var r=0;r<n.length;r++){var o=n[r];o.options.subtree&&o.addTransientObserver(t)}}}function i(e){for(var t=0;t<e.nodes_.length;t++){var n=e.nodes_[t],r=f.get(n);if(!r)return;for(var o=0;o<r.length;o++){var i=r[o];i.observer===e&&i.removeTransientObservers()}}}function a(e,n,o){for(var i=Object.create(null),a=Object.create(null),s=e;s;s=s.parentNode){var c=f.get(s);if(c)for(var u=0;u<c.length;u++){var l=c[u],p=l.options;if((s===e||p.subtree)&&!("attributes"===n&&!p.attributes||"attributes"===n&&p.attributeFilter&&(null!==o.namespace||-1===p.attributeFilter.indexOf(o.name))||"characterData"===n&&!p.characterData||"childList"===n&&!p.childList)){var d=l.observer;i[d.uid_]=d,("attributes"===n&&p.attributeOldValue||"characterData"===n&&p.characterDataOldValue)&&(a[d.uid_]=o.oldValue)}}}for(var h in i){var d=i[h],w=new r(n,e);"name"in o&&"namespace"in o&&(w.attributeName=o.name,w.attributeNamespace=o.namespace),o.addedNodes&&(w.addedNodes=o.addedNodes),o.removedNodes&&(w.removedNodes=o.removedNodes),o.previousSibling&&(w.previousSibling=o.previousSibling),o.nextSibling&&(w.nextSibling=o.nextSibling),void 0!==a[h]&&(w.oldValue=a[h]),t(d),d.records_.push(w)}}function s(e){if(this.childList=!!e.childList,this.subtree=!!e.subtree,this.attributes="attributes"in e||!("attributeOldValue"in e||"attributeFilter"in e)?!!e.attributes:!0,this.characterData="characterDataOldValue"in e&&!("characterData"in e)?!0:!!e.characterData,!this.attributes&&(e.attributeOldValue||"attributeFilter"in e)||!this.characterData&&e.characterDataOldValue)throw new TypeError;if(this.characterData=!!e.characterData,this.attributeOldValue=!!e.attributeOldValue,this.characterDataOldValue=!!e.characterDataOldValue,"attributeFilter"in e){if(null==e.attributeFilter||"object"!=typeof e.attributeFilter)throw new TypeError;this.attributeFilter=m.call(e.attributeFilter)}else this.attributeFilter=null}function c(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++g,this.scheduled_=!1}function u(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var l=e.setEndOfMicrotask,p=e.wrapIfNeeded,d=e.wrappers,f=new WeakMap,h=[],w=!1,m=Array.prototype.slice,g=0;c.prototype={constructor:c,observe:function(e,t){e=p(e);var n,r=new s(t),o=f.get(e);o||f.set(e,o=[]);for(var i=0;i<o.length;i++)o[i].observer===this&&(n=o[i],n.removeTransientObservers(),n.options=r);n||(n=new u(this,e,r),o.push(n),this.nodes_.push(e))},disconnect:function(){this.nodes_.forEach(function(e){for(var t=f.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}},u.prototype={addTransientObserver:function(e){if(e!==this.target){t(this.observer),this.transientObservedNodes.push(e);var n=f.get(e);n||f.set(e,n=[]),n.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[];for(var t=0;t<e.length;t++)for(var n=e[t],r=f.get(n),o=0;o<r.length;o++)if(r[o]===this){r.splice(o,1);break}}},e.enqueueMutation=a,e.registerTransientObservers=o,e.wrappers.MutationObserver=c,e.wrappers.MutationRecord=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){this.root=e,this.parent=t}function n(e,t){if(e.treeScope_!==t){e.treeScope_=t;for(var r=e.shadowRoot;r;r=r.olderShadowRoot)r.treeScope_.parent=t;for(var o=e.firstChild;o;o=o.nextSibling)n(o,t)}}function r(n){if(n instanceof e.wrappers.Window,n.treeScope_)return n.treeScope_;var o,i=n.parentNode;return o=i?r(i):new t(n,null),n.treeScope_=o}t.prototype={get renderer(){return this.root instanceof e.wrappers.ShadowRoot?e.getRendererForHost(this.root.host):null},contains:function(e){for(;e;e=e.parent)if(e===this)return!0;return!1}},e.TreeScope=t,e.getTreeScope=r,e.setTreeScope=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e instanceof G.ShadowRoot}function n(e){return I(e).root}function r(e,r){var s=[],c=e;for(s.push(c);c;){var u=a(c);if(u&&u.length>0){for(var l=0;l<u.length;l++){var d=u[l];if(i(d)){var f=n(d),h=f.olderShadowRoot;h&&s.push(h)}s.push(d)}c=u[u.length-1]}else if(t(c)){if(p(e,c)&&o(r))break;c=c.host,s.push(c)}else c=c.parentNode,c&&s.push(c)}return s}function o(e){if(!e)return!1;switch(e.type){case"abort":case"error":case"select":case"change":case"load":case"reset":case"resize":case"scroll":case"selectstart":return!0}return!1}function i(e){return e instanceof HTMLShadowElement}function a(t){return e.getDestinationInsertionPoints(t)}function s(e,t){if(0===e.length)return t;t instanceof G.Window&&(t=t.document);for(var n=I(t),r=e[0],o=I(r),i=u(n,o),a=0;a<e.length;a++){var s=e[a];if(I(s)===i)return s}return e[e.length-1]}function c(e){for(var t=[];e;e=e.parent)t.push(e);return t}function u(e,t){for(var n=c(e),r=c(t),o=null;n.length>0&&r.length>0;){var i=n.pop(),a=r.pop();if(i!==a)break;o=i}return o}function l(e,t,n){t instanceof G.Window&&(t=t.document);var o,i=I(t),a=I(n),s=r(n,e),o=u(i,a);o||(o=a.root);for(var c=o;c;c=c.parent)for(var l=0;l<s.length;l++){var p=s[l];if(I(p)===c)return p}return null}function p(e,t){return I(e)===I(t)}function d(e){if(!X.get(e)&&(X.set(e,!0),h(V(e),V(e.target)),W)){var t=W;throw W=null,t}}function f(e){switch(e.type){case"load":case"beforeunload":case"unload":return!0}return!1}function h(t,n){if(K.get(t))throw new Error("InvalidStateError");K.set(t,!0),e.renderAllPending();var o,i,a;if(f(t)&&!t.bubbles){var s=n;s instanceof G.Document&&(a=s.defaultView)&&(i=s,o=[])}if(!o)if(n instanceof G.Window)a=n,o=[];else if(o=r(n,t),!f(t)){var s=o[o.length-1];s instanceof G.Document&&(a=s.defaultView)}return ne.set(t,o),w(t,o,a,i)&&m(t,o,a,i)&&g(t,o,a,i),J.set(t,re),$["delete"](t,null),K["delete"](t),t.defaultPrevented}function w(e,t,n,r){var o=oe;if(n&&!v(n,e,o,t,r))return!1;for(var i=t.length-1;i>0;i--)if(!v(t[i],e,o,t,r))return!1;return!0}function m(e,t,n,r){var o=ie,i=t[0]||n;return v(i,e,o,t,r)}function g(e,t,n,r){for(var o=ae,i=1;i<t.length;i++)if(!v(t[i],e,o,t,r))return;n&&t.length>0&&v(n,e,o,t,r)}function v(e,t,n,r,o){var i=z.get(e);if(!i)return!0;var a=o||s(r,e);if(a===e){if(n===oe)return!0;n===ae&&(n=ie)}else if(n===ae&&!t.bubbles)return!0;if("relatedTarget"in t){var c=q(t),u=c.relatedTarget;if(u){if(u instanceof Object&&u.addEventListener){var p=V(u),d=l(t,e,p);if(d===a)return!0}else d=null;Z.set(t,d)}}J.set(t,n);var f=t.type,h=!1;Y.set(t,a),$.set(t,e),i.depth++;for(var w=0,m=i.length;m>w;w++){var g=i[w];if(g.removed)h=!0;else if(!(g.type!==f||!g.capture&&n===oe||g.capture&&n===ae))try{if("function"==typeof g.handler?g.handler.call(e,t):g.handler.handleEvent(t),ee.get(t))return!1}catch(v){W||(W=v)}}if(i.depth--,h&&0===i.depth){var b=i.slice();i.length=0;for(var w=0;w<b.length;w++)b[w].removed||i.push(b[w])}return!Q.get(t)}function b(e,t,n){this.type=e,this.handler=t,this.capture=Boolean(n)}function y(e,t){if(!(e instanceof se))return V(T(se,"Event",e,t));var n=e;return ve||"beforeunload"!==n.type||this instanceof O?void B(n,this):new O(n)}function E(e){return e&&e.relatedTarget?Object.create(e,{relatedTarget:{value:q(e.relatedTarget)}}):e}function S(e,t,n){var r=window[e],o=function(t,n){return t instanceof r?void B(t,this):V(T(r,e,t,n))};if(o.prototype=Object.create(t.prototype),n&&k(o.prototype,n),r)try{F(r,o,new r("temp"))}catch(i){F(r,o,document.createEvent(e))}return o}function M(e,t){return function(){arguments[t]=q(arguments[t]);var n=q(this);n[e].apply(n,arguments)}}function T(e,t,n,r){if(me)return new e(n,E(r));var o=q(document.createEvent(t)),i=we[t],a=[n];return Object.keys(i).forEach(function(e){var t=null!=r&&e in r?r[e]:i[e];"relatedTarget"===e&&(t=q(t)),a.push(t)}),o["init"+t].apply(o,a),o}function O(e){y.call(this,e)}function j(e){return"function"==typeof e?!0:e&&e.handleEvent}function N(e){switch(e){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function L(e){B(e,this)}function _(e){return e instanceof G.ShadowRoot&&(e=e.host),q(e)}function C(e,t){var n=z.get(e);if(n)for(var r=0;r<n.length;r++)if(!n[r].removed&&n[r].type===t)return!0;return!1}function D(e,t){for(var n=q(e);n;n=n.parentNode)if(C(V(n),t))return!0;return!1}function H(e){A(e,ye)}function x(t,n,o,i){e.renderAllPending();var a=V(Ee.call(U(n),o,i));if(!a)return null;var c=r(a,null),u=c.lastIndexOf(t);return-1==u?null:(c=c.slice(0,u),s(c,t))}function R(e){return function(){var t=te.get(this);return t&&t[e]&&t[e].value||null}}function P(e){var t=e.slice(2);return function(n){var r=te.get(this);r||(r=Object.create(null),te.set(this,r));var o=r[e];if(o&&this.removeEventListener(t,o.wrapped,!1),"function"==typeof n){var i=function(t){var r=n.call(this,t);r===!1?t.preventDefault():"onbeforeunload"===e&&"string"==typeof r&&(t.returnValue=r)};this.addEventListener(t,i,!1),r[e]={value:n,wrapped:i}}}}var W,A=e.forwardMethodsToWrapper,I=e.getTreeScope,k=e.mixin,F=e.registerWrapper,B=e.setWrapper,U=e.unsafeUnwrap,q=e.unwrap,V=e.wrap,G=e.wrappers,z=(new WeakMap,new WeakMap),X=new WeakMap,K=new WeakMap,Y=new WeakMap,$=new WeakMap,Z=new WeakMap,J=new WeakMap,Q=new WeakMap,ee=new WeakMap,te=new WeakMap,ne=new WeakMap,re=0,oe=1,ie=2,ae=3;b.prototype={equals:function(e){return this.handler===e.handler&&this.type===e.type&&this.capture===e.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var se=window.Event;se.prototype.polymerBlackList_={returnValue:!0,keyLocation:!0},y.prototype={get target(){return Y.get(this)},get currentTarget(){return $.get(this)},get eventPhase(){return J.get(this)},get path(){var e=ne.get(this);return e?e.slice():[]},stopPropagation:function(){Q.set(this,!0)},stopImmediatePropagation:function(){Q.set(this,!0),ee.set(this,!0)}},F(se,y,document.createEvent("Event"));var ce=S("UIEvent",y),ue=S("CustomEvent",y),le={get relatedTarget(){var e=Z.get(this);return void 0!==e?e:V(q(this).relatedTarget)}},pe=k({initMouseEvent:M("initMouseEvent",14)},le),de=k({initFocusEvent:M("initFocusEvent",5)},le),fe=S("MouseEvent",ce,pe),he=S("FocusEvent",ce,de),we=Object.create(null),me=function(){try{new window.FocusEvent("focus")}catch(e){return!1}return!0}();if(!me){var ge=function(e,t,n){if(n){var r=we[n];t=k(k({},r),t)}we[e]=t};ge("Event",{bubbles:!1,cancelable:!1}),ge("CustomEvent",{detail:null},"Event"),ge("UIEvent",{view:null,detail:0},"Event"),ge("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),ge("FocusEvent",{relatedTarget:null},"UIEvent")}var ve=window.BeforeUnloadEvent;O.prototype=Object.create(y.prototype),k(O.prototype,{get returnValue(){return U(this).returnValue},set returnValue(e){U(this).returnValue=e}}),ve&&F(ve,O);var be=window.EventTarget,ye=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(e){var t=e.prototype;ye.forEach(function(e){Object.defineProperty(t,e+"_",{value:t[e]})})}),L.prototype={addEventListener:function(e,t,n){if(j(t)&&!N(e)){var r=new b(e,t,n),o=z.get(this);if(o){for(var i=0;i<o.length;i++)if(r.equals(o[i]))return}else o=[],o.depth=0,z.set(this,o);o.push(r);var a=_(this);a.addEventListener_(e,d,!0)}},removeEventListener:function(e,t,n){n=Boolean(n);var r=z.get(this);if(r){for(var o=0,i=!1,a=0;a<r.length;a++)r[a].type===e&&r[a].capture===n&&(o++,r[a].handler===t&&(i=!0,r[a].remove()));if(i&&1===o){var s=_(this);s.removeEventListener_(e,d,!0)}}},dispatchEvent:function(t){var n=q(t),r=n.type;X.set(n,!1),e.renderAllPending();var o;D(this,r)||(o=function(){},this.addEventListener(r,o,!0));try{return q(this).dispatchEvent_(n)}finally{o&&this.removeEventListener(r,o,!0)}}},be&&F(be,L);var Ee=document.elementFromPoint;e.elementFromPoint=x,e.getEventHandlerGetter=R,e.getEventHandlerSetter=P,e.wrapEventTargetMethods=H,e.wrappers.BeforeUnloadEvent=O,e.wrappers.CustomEvent=ue,e.wrappers.Event=y,e.wrappers.EventTarget=L,e.wrappers.FocusEvent=he,e.wrappers.MouseEvent=fe,e.wrappers.UIEvent=ce}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,w)}function n(e){u(e,this)}function r(){this.length=0,t(this,"length")}function o(e){for(var t=new r,o=0;o<e.length;o++)t[o]=new n(e[o]);return t.length=o,t}function i(e){a.call(this,e)}var a=e.wrappers.UIEvent,s=e.mixin,c=e.registerWrapper,u=e.setWrapper,l=e.unsafeUnwrap,p=e.wrap,d=window.TouchEvent;if(d){var f;try{f=document.createEvent("TouchEvent")}catch(h){return}var w={enumerable:!1};n.prototype={get target(){return p(l(this).target)}};var m={configurable:!0,enumerable:!0,get:null};["clientX","clientY","screenX","screenY","pageX","pageY","identifier","webkitRadiusX","webkitRadiusY","webkitRotationAngle","webkitForce"].forEach(function(e){m.get=function(){return l(this)[e]},Object.defineProperty(n.prototype,e,m)}),r.prototype={item:function(e){return this[e]}},i.prototype=Object.create(a.prototype),s(i.prototype,{get touches(){return o(l(this).touches)},get targetTouches(){return o(l(this).targetTouches)},get changedTouches(){return o(l(this).changedTouches)},initTouchEvent:function(){throw new Error("Not implemented")}}),c(d,i,f),e.wrappers.Touch=n,e.wrappers.TouchEvent=i,e.wrappers.TouchList=r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,s)}function n(){this.length=0,t(this,"length")}function r(e){if(null==e)return e;for(var t=new n,r=0,o=e.length;o>r;r++)t[r]=a(e[r]);return t.length=o,t}function o(e,t){e.prototype[t]=function(){return r(i(this)[t].apply(i(this),arguments))}}var i=e.unsafeUnwrap,a=e.wrap,s={enumerable:!1};n.prototype={item:function(e){return this[e]}},t(n.prototype,"item"),e.wrappers.NodeList=n,e.addWrapNodeListMethod=o,e.wrapNodeList=r}(window.ShadowDOMPolyfill),function(e){"use strict";e.wrapHTMLCollection=e.wrapNodeList,e.wrappers.HTMLCollection=e.wrappers.NodeList}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){j(e instanceof S)}function n(e){var t=new T;return t[0]=e,t.length=1,t}function r(e,t,n){L(t,"childList",{removedNodes:n,previousSibling:e.previousSibling,nextSibling:e.nextSibling})}function o(e,t){L(e,"childList",{removedNodes:t})}function i(e,t,r,o){if(e instanceof DocumentFragment){var i=s(e);B=!0;for(var a=i.length-1;a>=0;a--)e.removeChild(i[a]),i[a].parentNode_=t;B=!1;for(var a=0;a<i.length;a++)i[a].previousSibling_=i[a-1]||r,i[a].nextSibling_=i[a+1]||o;return r&&(r.nextSibling_=i[0]),o&&(o.previousSibling_=i[i.length-1]),i}var i=n(e),c=e.parentNode;return c&&c.removeChild(e),e.parentNode_=t,e.previousSibling_=r,e.nextSibling_=o,r&&(r.nextSibling_=e),o&&(o.previousSibling_=e),i}function a(e){if(e instanceof DocumentFragment)return s(e);var t=n(e),o=e.parentNode;return o&&r(e,o,t),t}function s(e){for(var t=new T,n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t.length=n,o(e,t),t}function c(e){return e}function u(e,t){R(e,t),e.nodeIsInserted_()}function l(e,t){for(var n=_(t),r=0;r<e.length;r++)u(e[r],n)}function p(e){R(e,new O(e,null))}function d(e){for(var t=0;t<e.length;t++)p(e[t])}function f(e,t){var n=e.nodeType===S.DOCUMENT_NODE?e:e.ownerDocument;n!==t.ownerDocument&&n.adoptNode(t)}function h(t,n){if(n.length){var r=t.ownerDocument;if(r!==n[0].ownerDocument)for(var o=0;o<n.length;o++)e.adoptNodeNoRemove(n[o],r)}}function w(e,t){h(e,t);var n=t.length;if(1===n)return W(t[0]);for(var r=W(e.ownerDocument.createDocumentFragment()),o=0;n>o;o++)r.appendChild(W(t[o]));return r}function m(e){if(void 0!==e.firstChild_)for(var t=e.firstChild_;t;){var n=t;t=t.nextSibling_,n.parentNode_=n.previousSibling_=n.nextSibling_=void 0}e.firstChild_=e.lastChild_=void 0}function g(e){if(e.invalidateShadowRenderer()){for(var t=e.firstChild;t;){j(t.parentNode===e);var n=t.nextSibling,r=W(t),o=r.parentNode;o&&Y.call(o,r),t.previousSibling_=t.nextSibling_=t.parentNode_=null,t=n}e.firstChild_=e.lastChild_=null}else for(var n,i=W(e),a=i.firstChild;a;)n=a.nextSibling,Y.call(i,a),a=n}function v(e){var t=e.parentNode;return t&&t.invalidateShadowRenderer()}function b(e){for(var t,n=0;n<e.length;n++)t=e[n],t.parentNode.removeChild(t)}function y(e,t,n){var r;if(r=I(n?U.call(n,P(e),!1):q.call(P(e),!1)),t){for(var o=e.firstChild;o;o=o.nextSibling)r.appendChild(y(o,!0,n));if(e instanceof F.HTMLTemplateElement)for(var i=r.content,o=e.content.firstChild;o;o=o.nextSibling)i.appendChild(y(o,!0,n))}return r}function E(e,t){if(!t||_(e)!==_(t))return!1;for(var n=t;n;n=n.parentNode)if(n===e)return!0;return!1}function S(e){j(e instanceof V),M.call(this,e),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0,this.treeScope_=void 0}var M=e.wrappers.EventTarget,T=e.wrappers.NodeList,O=e.TreeScope,j=e.assert,N=e.defineWrapGetter,L=e.enqueueMutation,_=e.getTreeScope,C=e.isWrapper,D=e.mixin,H=e.registerTransientObservers,x=e.registerWrapper,R=e.setTreeScope,P=e.unsafeUnwrap,W=e.unwrap,A=e.unwrapIfNeeded,I=e.wrap,k=e.wrapIfNeeded,F=e.wrappers,B=!1,U=document.importNode,q=window.Node.prototype.cloneNode,V=window.Node,G=window.DocumentFragment,z=(V.prototype.appendChild,V.prototype.compareDocumentPosition),X=V.prototype.isEqualNode,K=V.prototype.insertBefore,Y=V.prototype.removeChild,$=V.prototype.replaceChild,Z=/Trident|Edge/.test(navigator.userAgent),J=Z?function(e,t){try{Y.call(e,t)}catch(n){if(!(e instanceof G))throw n}}:function(e,t){Y.call(e,t)};S.prototype=Object.create(M.prototype),D(S.prototype,{appendChild:function(e){return this.insertBefore(e,null)},insertBefore:function(e,n){t(e);var r;n?C(n)?r=W(n):(r=n,n=I(r)):(n=null,r=null),n&&j(n.parentNode===this);var o,s=n?n.previousSibling:this.lastChild,c=!this.invalidateShadowRenderer()&&!v(e);if(o=c?a(e):i(e,this,s,n),c)f(this,e),m(this),K.call(P(this),W(e),r);else{s||(this.firstChild_=o[0]),n||(this.lastChild_=o[o.length-1],void 0===this.firstChild_&&(this.firstChild_=this.firstChild));var u=r?r.parentNode:P(this);u?K.call(u,w(this,o),r):h(this,o)}return L(this,"childList",{addedNodes:o,nextSibling:n,previousSibling:s}),l(o,this),e},removeChild:function(e){if(t(e),e.parentNode!==this){for(var r=!1,o=(this.childNodes,this.firstChild);o;o=o.nextSibling)if(o===e){r=!0;break}if(!r)throw new Error("NotFoundError")}var i=W(e),a=e.nextSibling,s=e.previousSibling;if(this.invalidateShadowRenderer()){var c=this.firstChild,u=this.lastChild,l=i.parentNode;l&&J(l,i),c===e&&(this.firstChild_=a),u===e&&(this.lastChild_=s),s&&(s.nextSibling_=a),a&&(a.previousSibling_=s),e.previousSibling_=e.nextSibling_=e.parentNode_=void 0}else m(this),J(P(this),i);return B||L(this,"childList",{removedNodes:n(e),nextSibling:a,previousSibling:s}),H(this,e),e},replaceChild:function(e,r){t(e);var o;if(C(r)?o=W(r):(o=r,r=I(o)),r.parentNode!==this)throw new Error("NotFoundError");var s,c=r.nextSibling,u=r.previousSibling,d=!this.invalidateShadowRenderer()&&!v(e);return d?s=a(e):(c===e&&(c=e.nextSibling),s=i(e,this,u,c)),d?(f(this,e),m(this),$.call(P(this),W(e),o)):(this.firstChild===r&&(this.firstChild_=s[0]),this.lastChild===r&&(this.lastChild_=s[s.length-1]),r.previousSibling_=r.nextSibling_=r.parentNode_=void 0,o.parentNode&&$.call(o.parentNode,w(this,s),o)),L(this,"childList",{addedNodes:s,removedNodes:n(r),nextSibling:c,previousSibling:u}),p(r),l(s,this),r},nodeIsInserted_:function(){for(var e=this.firstChild;e;e=e.nextSibling)e.nodeIsInserted_()},hasChildNodes:function(){return null!==this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:I(P(this).parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:I(P(this).firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:I(P(this).lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:I(P(this).nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:I(P(this).previousSibling)},get parentElement(){for(var e=this.parentNode;e&&e.nodeType!==S.ELEMENT_NODE;)e=e.parentNode;return e},get textContent(){for(var e="",t=this.firstChild;t;t=t.nextSibling)t.nodeType!=S.COMMENT_NODE&&(e+=t.textContent);return e},set textContent(e){null==e&&(e="");var t=c(this.childNodes);if(this.invalidateShadowRenderer()){if(g(this),""!==e){var n=P(this).ownerDocument.createTextNode(e);this.appendChild(n)}}else m(this),P(this).textContent=e;var r=c(this.childNodes);L(this,"childList",{addedNodes:r,removedNodes:t}),d(t),l(r,this)},get childNodes(){for(var e=new T,t=0,n=this.firstChild;n;n=n.nextSibling)e[t++]=n;return e.length=t,e},cloneNode:function(e){return y(this,e)},contains:function(e){return E(this,k(e))},compareDocumentPosition:function(e){return z.call(P(this),A(e))},isEqualNode:function(e){return X.call(P(this),A(e))},normalize:function(){for(var e,t,n=c(this.childNodes),r=[],o="",i=0;i<n.length;i++)t=n[i],t.nodeType===S.TEXT_NODE?e||t.data.length?e?(o+=t.data,r.push(t)):e=t:this.removeChild(t):(e&&r.length&&(e.data+=o,b(r)),r=[],o="",e=null,t.childNodes.length&&t.normalize());e&&r.length&&(e.data+=o,b(r))}}),N(S,"ownerDocument"),x(V,S,document.createDocumentFragment()),delete S.prototype.querySelector,delete S.prototype.querySelectorAll,S.prototype=D(Object.create(M.prototype),S.prototype),e.cloneNode=y,e.nodeWasAdded=u,e.nodeWasRemoved=p,e.nodesWereAdded=l,e.nodesWereRemoved=d,e.originalInsertBefore=K,e.originalRemoveChild=Y,e.snapshotNodeList=c,e.wrappers.Node=S}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n,r,o){for(var i=null,a=null,s=0,c=t.length;c>s;s++)i=b(t[s]),!o&&(a=g(i).root)&&a instanceof e.wrappers.ShadowRoot||(r[n++]=i);return n}function n(e){return String(e).replace(/\/deep\/|::shadow|>>>/g," ")}function r(e){return String(e).replace(/:host\(([^\s]+)\)/g,"$1").replace(/([^\s]):host/g,"$1").replace(":host","*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content|>>>/g," ")}function o(e,t){for(var n,r=e.firstElementChild;r;){if(r.matches(t))return r;if(n=o(r,t))return n;r=r.nextElementSibling}return null}function i(e,t){return e.matches(t)}function a(e,t,n){var r=e.localName;return r===t||r===n&&e.namespaceURI===C}function s(){return!0}function c(e,t,n){return e.localName===n}function u(e,t){return e.namespaceURI===t}function l(e,t,n){return e.namespaceURI===t&&e.localName===n}function p(e,t,n,r,o,i){for(var a=e.firstElementChild;a;)r(a,o,i)&&(n[t++]=a),t=p(a,t,n,r,o,i),a=a.nextElementSibling;return t}function d(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,null);if(c instanceof L)s=M.call(c,i);else{if(!(c instanceof _))return p(this,r,o,n,i,null);s=S.call(c,i)}return t(s,r,o,a)}function f(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,a);if(c instanceof L)s=O.call(c,i,a);else{if(!(c instanceof _))return p(this,r,o,n,i,a);s=T.call(c,i,a)}return t(s,r,o,!1)}function h(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,a);if(c instanceof L)s=N.call(c,i,a);else{if(!(c instanceof _))return p(this,r,o,n,i,a);s=j.call(c,i,a)}return t(s,r,o,!1)}var w=e.wrappers.HTMLCollection,m=e.wrappers.NodeList,g=e.getTreeScope,v=e.unsafeUnwrap,b=e.wrap,y=document.querySelector,E=document.documentElement.querySelector,S=document.querySelectorAll,M=document.documentElement.querySelectorAll,T=document.getElementsByTagName,O=document.documentElement.getElementsByTagName,j=document.getElementsByTagNameNS,N=document.documentElement.getElementsByTagNameNS,L=window.Element,_=window.HTMLDocument||window.Document,C="http://www.w3.org/1999/xhtml",D={querySelector:function(t){var r=n(t),i=r!==t;t=r;var a,s=v(this),c=g(this).root;if(c instanceof e.wrappers.ShadowRoot)return o(this,t);if(s instanceof L)a=b(E.call(s,t));else{if(!(s instanceof _))return o(this,t);a=b(y.call(s,t))}return a&&!i&&(c=g(a).root)&&c instanceof e.wrappers.ShadowRoot?o(this,t):a},querySelectorAll:function(e){var t=n(e),r=t!==e;e=t;var o=new m;return o.length=d.call(this,i,0,o,e,r),o}},H={matches:function(t){return t=r(t),e.originalMatches.call(v(this),t)}},x={getElementsByTagName:function(e){var t=new w,n="*"===e?s:a;return t.length=f.call(this,n,0,t,e,e.toLowerCase()),t},getElementsByClassName:function(e){return this.querySelectorAll("."+e)},getElementsByTagNameNS:function(e,t){var n=new w,r=null;return r="*"===e?"*"===t?s:c:"*"===t?u:l,n.length=h.call(this,r,0,n,e||null,t),n}};e.GetElementsByInterface=x,e.SelectorsInterface=D,e.MatchesInterface=H}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;return e;
+
+}function n(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.previousSibling;return e}var r=e.wrappers.NodeList,o={get firstElementChild(){return t(this.firstChild)},get lastElementChild(){return n(this.lastChild)},get childElementCount(){for(var e=0,t=this.firstElementChild;t;t=t.nextElementSibling)e++;return e},get children(){for(var e=new r,t=0,n=this.firstElementChild;n;n=n.nextElementSibling)e[t++]=n;return e.length=t,e},remove:function(){var e=this.parentNode;e&&e.removeChild(this)}},i={get nextElementSibling(){return t(this.nextSibling)},get previousElementSibling(){return n(this.previousSibling)}};e.ChildNodeInterface=i,e.ParentNodeInterface=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}var n=e.ChildNodeInterface,r=e.wrappers.Node,o=e.enqueueMutation,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=window.CharacterData;t.prototype=Object.create(r.prototype),i(t.prototype,{get nodeValue(){return this.data},set nodeValue(e){this.data=e},get textContent(){return this.data},set textContent(e){this.data=e},get data(){return s(this).data},set data(e){var t=s(this).data;o(this,"characterData",{oldValue:t}),s(this).data=e}}),i(t.prototype,n),a(c,t,document.createTextNode("")),e.wrappers.CharacterData=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e>>>0}function n(e){r.call(this,e)}var r=e.wrappers.CharacterData,o=(e.enqueueMutation,e.mixin),i=e.registerWrapper,a=window.Text;n.prototype=Object.create(r.prototype),o(n.prototype,{splitText:function(e){e=t(e);var n=this.data;if(e>n.length)throw new Error("IndexSizeError");var r=n.slice(0,e),o=n.slice(e);this.data=r;var i=this.ownerDocument.createTextNode(o);return this.parentNode&&this.parentNode.insertBefore(i,this.nextSibling),i}}),i(a,n,document.createTextNode("")),e.wrappers.Text=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return i(e).getAttribute("class")}function n(e,t){a(e,"attributes",{name:"class",namespace:null,oldValue:t})}function r(t){e.invalidateRendererBasedOnAttribute(t,"class")}function o(e,o,i){var a=e.ownerElement_;if(null==a)return o.apply(e,i);var s=t(a),c=o.apply(e,i);return t(a)!==s&&(n(a,s),r(a)),c}if(!window.DOMTokenList)return void console.warn("Missing DOMTokenList prototype, please include a compatible classList polyfill such as http://goo.gl/uTcepH.");var i=e.unsafeUnwrap,a=e.enqueueMutation,s=DOMTokenList.prototype.add;DOMTokenList.prototype.add=function(){o(this,s,arguments)};var c=DOMTokenList.prototype.remove;DOMTokenList.prototype.remove=function(){o(this,c,arguments)};var u=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(){return o(this,u,arguments)}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n){var r=t.parentNode;if(r&&r.shadowRoot){var o=e.getRendererForHost(r);o.dependsOnAttribute(n)&&o.invalidate()}}function n(e,t,n){l(e,"attributes",{name:t,namespace:null,oldValue:n})}function r(e){a.call(this,e)}var o=e.ChildNodeInterface,i=e.GetElementsByInterface,a=e.wrappers.Node,s=e.ParentNodeInterface,c=e.SelectorsInterface,u=e.MatchesInterface,l=(e.addWrapNodeListMethod,e.enqueueMutation),p=e.mixin,d=(e.oneOf,e.registerWrapper),f=e.unsafeUnwrap,h=e.wrappers,w=window.Element,m=["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"].filter(function(e){return w.prototype[e]}),g=m[0],v=w.prototype[g],b=new WeakMap;r.prototype=Object.create(a.prototype),p(r.prototype,{createShadowRoot:function(){var t=new h.ShadowRoot(this);f(this).polymerShadowRoot_=t;var n=e.getRendererForHost(this);return n.invalidate(),t},get shadowRoot(){return f(this).polymerShadowRoot_||null},setAttribute:function(e,r){var o=f(this).getAttribute(e);f(this).setAttribute(e,r),n(this,e,o),t(this,e)},removeAttribute:function(e){var r=f(this).getAttribute(e);f(this).removeAttribute(e),n(this,e,r),t(this,e)},get classList(){var e=b.get(this);if(!e){if(e=f(this).classList,!e)return;e.ownerElement_=this,b.set(this,e)}return e},get className(){return f(this).className},set className(e){this.setAttribute("class",e)},get id(){return f(this).id},set id(e){this.setAttribute("id",e)}}),m.forEach(function(e){"matches"!==e&&(r.prototype[e]=function(e){return this.matches(e)})}),w.prototype.webkitCreateShadowRoot&&(r.prototype.webkitCreateShadowRoot=r.prototype.createShadowRoot),p(r.prototype,o),p(r.prototype,i),p(r.prototype,s),p(r.prototype,c),p(r.prototype,u),d(w,r,document.createElementNS(null,"x")),e.invalidateRendererBasedOnAttribute=t,e.matchesNames=m,e.originalMatches=v,e.wrappers.Element=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e){case"&":return"&amp;";case"<":return"&lt;";case">":return"&gt;";case'"':return"&quot;";case" ":return"&nbsp;"}}function n(e){return e.replace(j,t)}function r(e){return e.replace(N,t)}function o(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=!0;return t}function i(e,t){switch(e.nodeType){case Node.ELEMENT_NODE:for(var o,i=e.tagName.toLowerCase(),s="<"+i,c=e.attributes,u=0;o=c[u];u++)s+=" "+o.name+'="'+n(o.value)+'"';return s+=">",L[i]?s:s+a(e)+"</"+i+">";case Node.TEXT_NODE:var l=e.data;return t&&_[t.localName]?l:r(l);case Node.COMMENT_NODE:return"<!--"+e.data+"-->";default:throw console.error(e),new Error("not implemented")}}function a(e){e instanceof O.HTMLTemplateElement&&(e=e.content);for(var t="",n=e.firstChild;n;n=n.nextSibling)t+=i(n,e);return t}function s(e,t,n){var r=n||"div";e.textContent="";var o=M(e.ownerDocument.createElement(r));o.innerHTML=t;for(var i;i=o.firstChild;)e.appendChild(T(i))}function c(e){h.call(this,e)}function u(e,t){var n=M(e.cloneNode(!1));n.innerHTML=t;for(var r,o=M(document.createDocumentFragment());r=n.firstChild;)o.appendChild(r);return T(o)}function l(t){return function(){return e.renderAllPending(),S(this)[t]}}function p(e){w(c,e,l(e))}function d(t){Object.defineProperty(c.prototype,t,{get:l(t),set:function(n){e.renderAllPending(),S(this)[t]=n},configurable:!0,enumerable:!0})}function f(t){Object.defineProperty(c.prototype,t,{value:function(){return e.renderAllPending(),S(this)[t].apply(S(this),arguments)},configurable:!0,enumerable:!0})}var h=e.wrappers.Element,w=e.defineGetter,m=e.enqueueMutation,g=e.mixin,v=e.nodesWereAdded,b=e.nodesWereRemoved,y=e.registerWrapper,E=e.snapshotNodeList,S=e.unsafeUnwrap,M=e.unwrap,T=e.wrap,O=e.wrappers,j=/[&\u00A0"]/g,N=/[&\u00A0<>]/g,L=o(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),_=o(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),C=/MSIE/.test(navigator.userAgent),D=window.HTMLElement,H=window.HTMLTemplateElement;c.prototype=Object.create(h.prototype),g(c.prototype,{get innerHTML(){return a(this)},set innerHTML(e){if(C&&_[this.localName])return void(this.textContent=e);var t=E(this.childNodes);this.invalidateShadowRenderer()?this instanceof O.HTMLTemplateElement?s(this.content,e):s(this,e,this.tagName):!H&&this instanceof O.HTMLTemplateElement?s(this.content,e):S(this).innerHTML=e;var n=E(this.childNodes);m(this,"childList",{addedNodes:n,removedNodes:t}),b(t),v(n,this)},get outerHTML(){return i(this,this.parentNode)},set outerHTML(e){var t=this.parentNode;if(t){t.invalidateShadowRenderer();var n=u(t,e);t.replaceChild(n,this)}},insertAdjacentHTML:function(e,t){var n,r;switch(String(e).toLowerCase()){case"beforebegin":n=this.parentNode,r=this;break;case"afterend":n=this.parentNode,r=this.nextSibling;break;case"afterbegin":n=this,r=this.firstChild;break;case"beforeend":n=this,r=null;break;default:return}var o=u(n,t);n.insertBefore(o,r)},get hidden(){return this.hasAttribute("hidden")},set hidden(e){e?this.setAttribute("hidden",""):this.removeAttribute("hidden")}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollWidth"].forEach(p),["scrollLeft","scrollTop"].forEach(d),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(f),y(D,c,document.createElement("b")),e.wrappers.HTMLElement=c,e.getInnerHTML=a,e.setInnerHTML=s}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.HTMLCanvasElement;t.prototype=Object.create(n.prototype),r(t.prototype,{getContext:function(){var e=i(this).getContext.apply(i(this),arguments);return e&&a(e)}}),o(s,t,document.createElement("canvas")),e.wrappers.HTMLCanvasElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=window.HTMLContentElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get select(){return this.getAttribute("select")},set select(e){this.setAttribute("select",e)},setAttribute:function(e,t){n.prototype.setAttribute.call(this,e,t),"select"===String(e).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),i&&o(i,t),e.wrappers.HTMLContentElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=window.HTMLFormElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get elements(){return i(a(this).elements)}}),o(s,t,document.createElement("form")),e.wrappers.HTMLFormElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e,t){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var o=i(document.createElement("img"));r.call(this,o),a(o,this),void 0!==e&&(o.width=e),void 0!==t&&(o.height=t)}var r=e.wrappers.HTMLElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLImageElement;t.prototype=Object.create(r.prototype),o(s,t,document.createElement("img")),n.prototype=t.prototype,e.wrappers.HTMLImageElement=t,e.wrappers.Image=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=(e.mixin,e.wrappers.NodeList,e.registerWrapper),o=window.HTMLShadowElement;t.prototype=Object.create(n.prototype),t.prototype.constructor=t,o&&r(o,t),e.wrappers.HTMLShadowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){if(!e.defaultView)return e;var t=p.get(e);if(!t){for(t=e.implementation.createHTMLDocument("");t.lastChild;)t.removeChild(t.lastChild);p.set(e,t)}return t}function n(e){for(var n,r=t(e.ownerDocument),o=c(r.createDocumentFragment());n=e.firstChild;)o.appendChild(n);return o}function r(e){if(o.call(this,e),!d){var t=n(e);l.set(this,u(t))}}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=e.unwrap,u=e.wrap,l=new WeakMap,p=new WeakMap,d=window.HTMLTemplateElement;r.prototype=Object.create(o.prototype),i(r.prototype,{constructor:r,get content(){return d?u(s(this).content):l.get(this)}}),d&&a(d,r),e.wrappers.HTMLTemplateElement=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.registerWrapper,o=window.HTMLMediaElement;o&&(t.prototype=Object.create(n.prototype),r(o,t,document.createElement("audio")),e.wrappers.HTMLMediaElement=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var t=i(document.createElement("audio"));r.call(this,t),a(t,this),t.setAttribute("preload","auto"),void 0!==e&&t.setAttribute("src",e)}var r=e.wrappers.HTMLMediaElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLAudioElement;s&&(t.prototype=Object.create(r.prototype),o(s,t,document.createElement("audio")),n.prototype=t.prototype,e.wrappers.HTMLAudioElement=t,e.wrappers.Audio=n)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e.replace(/\s+/g," ").trim()}function n(e){o.call(this,e)}function r(e,t,n,i){if(!(this instanceof r))throw new TypeError("DOM object constructor cannot be called as a function.");var a=c(document.createElement("option"));o.call(this,a),s(a,this),void 0!==e&&(a.text=e),void 0!==t&&a.setAttribute("value",t),n===!0&&a.setAttribute("selected",""),a.selected=i===!0}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.rewrap,c=e.unwrap,u=e.wrap,l=window.HTMLOptionElement;n.prototype=Object.create(o.prototype),i(n.prototype,{get text(){return t(this.textContent)},set text(e){this.textContent=t(String(e))},get form(){return u(c(this).form)}}),a(l,n,document.createElement("option")),r.prototype=n.prototype,e.wrappers.HTMLOptionElement=n,e.wrappers.Option=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=window.HTMLSelectElement;t.prototype=Object.create(n.prototype),r(t.prototype,{add:function(e,t){"object"==typeof t&&(t=i(t)),i(this).add(i(e),t)},remove:function(e){return void 0===e?void n.prototype.remove.call(this):("object"==typeof e&&(e=i(e)),void i(this).remove(e))},get form(){return a(i(this).form)}}),o(s,t,document.createElement("select")),e.wrappers.HTMLSelectElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=e.wrapHTMLCollection,c=window.HTMLTableElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get caption(){return a(i(this).caption)},createCaption:function(){return a(i(this).createCaption())},get tHead(){return a(i(this).tHead)},createTHead:function(){return a(i(this).createTHead())},createTFoot:function(){return a(i(this).createTFoot())},get tFoot(){return a(i(this).tFoot)},get tBodies(){return s(i(this).tBodies)},createTBody:function(){return a(i(this).createTBody())},get rows(){return s(i(this).rows)},insertRow:function(e){return a(i(this).insertRow(e))}}),o(c,t,document.createElement("table")),e.wrappers.HTMLTableElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableSectionElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get rows(){return i(a(this).rows)},insertRow:function(e){return s(a(this).insertRow(e))}}),o(c,t,document.createElement("thead")),e.wrappers.HTMLTableSectionElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableRowElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get cells(){return i(a(this).cells)},insertCell:function(e){return s(a(this).insertCell(e))}}),o(c,t,document.createElement("tr")),e.wrappers.HTMLTableRowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e.localName){case"content":return new n(e);case"shadow":return new o(e);case"template":return new i(e)}r.call(this,e)}var n=e.wrappers.HTMLContentElement,r=e.wrappers.HTMLElement,o=e.wrappers.HTMLShadowElement,i=e.wrappers.HTMLTemplateElement,a=(e.mixin,e.registerWrapper),s=window.HTMLUnknownElement;t.prototype=Object.create(r.prototype),a(s,t),e.wrappers.HTMLUnknownElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.wrappers.Element,n=e.wrappers.HTMLElement,r=e.registerObject,o=e.defineWrapGetter,i="http://www.w3.org/2000/svg",a=document.createElementNS(i,"title"),s=r(a),c=Object.getPrototypeOf(s.prototype).constructor;if(!("classList"in a)){var u=Object.getOwnPropertyDescriptor(t.prototype,"classList");Object.defineProperty(n.prototype,"classList",u),delete t.prototype.classList}o(c,"ownerSVGElement"),e.wrappers.SVGElement=c}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){d.call(this,e)}var n=e.mixin,r=e.registerWrapper,o=e.unwrap,i=e.wrap,a=window.SVGUseElement,s="http://www.w3.org/2000/svg",c=i(document.createElementNS(s,"g")),u=document.createElementNS(s,"use"),l=c.constructor,p=Object.getPrototypeOf(l.prototype),d=p.constructor;t.prototype=Object.create(p),"instanceRoot"in u&&n(t.prototype,{get instanceRoot(){return i(o(this).instanceRoot)},get animatedInstanceRoot(){return i(o(this).animatedInstanceRoot)}}),r(a,t,u),e.wrappers.SVGUseElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.SVGElementInstance;s&&(t.prototype=Object.create(n.prototype),r(t.prototype,{get correspondingElement(){return a(i(this).correspondingElement)},get correspondingUseElement(){return a(i(this).correspondingUseElement)},get parentNode(){return a(i(this).parentNode)},get childNodes(){throw new Error("Not implemented")},get firstChild(){return a(i(this).firstChild)},get lastChild(){return a(i(this).lastChild)},get previousSibling(){return a(i(this).previousSibling)},get nextSibling(){return a(i(this).nextSibling)}}),o(s,t),e.wrappers.SVGElementInstance=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrap,s=e.unwrapIfNeeded,c=e.wrap,u=window.CanvasRenderingContext2D;n(t.prototype,{get canvas(){return c(i(this).canvas)},drawImage:function(){arguments[0]=s(arguments[0]),i(this).drawImage.apply(i(this),arguments)},createPattern:function(){return arguments[0]=a(arguments[0]),i(this).createPattern.apply(i(this),arguments)}}),r(u,t,document.createElement("canvas").getContext("2d")),e.wrappers.CanvasRenderingContext2D=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.WebGLRenderingContext;if(c){n(t.prototype,{get canvas(){return s(i(this).canvas)},texImage2D:function(){arguments[5]=a(arguments[5]),i(this).texImage2D.apply(i(this),arguments)},texSubImage2D:function(){arguments[6]=a(arguments[6]),i(this).texSubImage2D.apply(i(this),arguments)}});var u=/WebKit/.test(navigator.userAgent)?{drawingBufferHeight:null,drawingBufferWidth:null}:{};r(c,t,u),e.wrappers.WebGLRenderingContext=t}}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.GetElementsByInterface,n=e.ParentNodeInterface,r=e.SelectorsInterface,o=e.mixin,i=e.registerObject,a=i(document.createDocumentFragment());o(a.prototype,n),o(a.prototype,r),o(a.prototype,t);var s=i(document.createComment(""));e.wrappers.Comment=s,e.wrappers.DocumentFragment=a}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=p(l(e).ownerDocument.createDocumentFragment());n.call(this,t),c(t,this);var o=e.shadowRoot;f.set(this,o),this.treeScope_=new r(this,a(o||e)),d.set(this,e)}var n=e.wrappers.DocumentFragment,r=e.TreeScope,o=e.elementFromPoint,i=e.getInnerHTML,a=e.getTreeScope,s=e.mixin,c=e.rewrap,u=e.setInnerHTML,l=e.unsafeUnwrap,p=e.unwrap,d=new WeakMap,f=new WeakMap,h=/[ \t\n\r\f]/;t.prototype=Object.create(n.prototype),s(t.prototype,{constructor:t,get innerHTML(){return i(this)},set innerHTML(e){u(this,e),this.invalidateShadowRenderer()},get olderShadowRoot(){return f.get(this)||null},get host(){return d.get(this)||null},invalidateShadowRenderer:function(){return d.get(this).invalidateShadowRenderer()},elementFromPoint:function(e,t){return o(this,this.ownerDocument,e,t)},getElementById:function(e){return h.test(e)?null:this.querySelector('[id="'+e+'"]')}}),e.wrappers.ShadowRoot=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=p(e).root;return t instanceof f?t.host:null}function n(t,n){if(t.shadowRoot){n=Math.min(t.childNodes.length-1,n);var r=t.childNodes[n];if(r){var o=e.getDestinationInsertionPoints(r);if(o.length>0){var i=o[0].parentNode;i.nodeType==Node.ELEMENT_NODE&&(t=i)}}}return t}function r(e){return e=l(e),t(e)||e}function o(e){a(e,this)}var i=e.registerWrapper,a=e.setWrapper,s=e.unsafeUnwrap,c=e.unwrap,u=e.unwrapIfNeeded,l=e.wrap,p=e.getTreeScope,d=window.Range,f=e.wrappers.ShadowRoot;o.prototype={get startContainer(){return r(s(this).startContainer)},get endContainer(){return r(s(this).endContainer)},get commonAncestorContainer(){return r(s(this).commonAncestorContainer)},setStart:function(e,t){e=n(e,t),s(this).setStart(u(e),t)},setEnd:function(e,t){e=n(e,t),s(this).setEnd(u(e),t)},setStartBefore:function(e){s(this).setStartBefore(u(e))},setStartAfter:function(e){s(this).setStartAfter(u(e))},setEndBefore:function(e){s(this).setEndBefore(u(e))},setEndAfter:function(e){s(this).setEndAfter(u(e))},selectNode:function(e){s(this).selectNode(u(e))},selectNodeContents:function(e){s(this).selectNodeContents(u(e))},compareBoundaryPoints:function(e,t){return s(this).compareBoundaryPoints(e,c(t))},extractContents:function(){return l(s(this).extractContents())},cloneContents:function(){return l(s(this).cloneContents())},insertNode:function(e){s(this).insertNode(u(e))},surroundContents:function(e){s(this).surroundContents(u(e))},cloneRange:function(){return l(s(this).cloneRange())},isPointInRange:function(e,t){return s(this).isPointInRange(u(e),t)},comparePoint:function(e,t){return s(this).comparePoint(u(e),t)},intersectsNode:function(e){return s(this).intersectsNode(u(e))},toString:function(){return s(this).toString()}},d.prototype.createContextualFragment&&(o.prototype.createContextualFragment=function(e){return l(s(this).createContextualFragment(e))}),i(window.Range,o,document.createRange()),e.wrappers.Range=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.previousSibling_=e.previousSibling,e.nextSibling_=e.nextSibling,e.parentNode_=e.parentNode}function n(n,o,i){var a=x(n),s=x(o),c=i?x(i):null;if(r(o),t(o),i)n.firstChild===i&&(n.firstChild_=i),i.previousSibling_=i.previousSibling;else{n.lastChild_=n.lastChild,n.lastChild===n.firstChild&&(n.firstChild_=n.firstChild);var u=R(a.lastChild);u&&(u.nextSibling_=u.nextSibling)}e.originalInsertBefore.call(a,s,c)}function r(n){var r=x(n),o=r.parentNode;if(o){var i=R(o);t(n),n.previousSibling&&(n.previousSibling.nextSibling_=n),n.nextSibling&&(n.nextSibling.previousSibling_=n),i.lastChild===n&&(i.lastChild_=n),i.firstChild===n&&(i.firstChild_=n),e.originalRemoveChild.call(o,r)}}function o(e){W.set(e,[])}function i(e){var t=W.get(e);return t||W.set(e,t=[]),t}function a(e){for(var t=[],n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t}function s(){for(var e=0;e<F.length;e++){var t=F[e],n=t.parentRenderer;n&&n.dirty||t.render()}F=[]}function c(){T=null,s()}function u(e){var t=I.get(e);return t||(t=new f(e),I.set(e,t)),t}function l(e){var t=C(e).root;return t instanceof _?t:null}function p(e){return u(e.host)}function d(e){this.skip=!1,this.node=e,this.childNodes=[]}function f(e){this.host=e,this.dirty=!1,this.invalidateAttributes(),this.associateNode(e)}function h(e){for(var t=[],n=e.firstChild;n;n=n.nextSibling)E(n)?t.push.apply(t,i(n)):t.push(n);return t}function w(e){if(e instanceof N)return e;if(e instanceof j)return null;for(var t=e.firstChild;t;t=t.nextSibling){var n=w(t);if(n)return n}return null}function m(e,t){i(t).push(e);var n=A.get(e);n?n.push(t):A.set(e,[t])}function g(e){return A.get(e)}function v(e){A.set(e,void 0)}function b(e,t){var n=t.getAttribute("select");if(!n)return!0;if(n=n.trim(),!n)return!0;if(!(e instanceof O))return!1;if(!U.test(n))return!1;try{return e.matches(n)}catch(r){return!1}}function y(e,t){var n=g(t);return n&&n[n.length-1]===e}function E(e){return e instanceof j||e instanceof N}function S(e){return e.shadowRoot}function M(e){for(var t=[],n=e.shadowRoot;n;n=n.olderShadowRoot)t.push(n);return t}var T,O=e.wrappers.Element,j=e.wrappers.HTMLContentElement,N=e.wrappers.HTMLShadowElement,L=e.wrappers.Node,_=e.wrappers.ShadowRoot,C=(e.assert,e.getTreeScope),D=(e.mixin,e.oneOf),H=e.unsafeUnwrap,x=e.unwrap,R=e.wrap,P=e.ArraySplice,W=new WeakMap,A=new WeakMap,I=new WeakMap,k=D(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),F=[],B=new P;B.equals=function(e,t){return x(e.node)===t},d.prototype={append:function(e){var t=new d(e);return this.childNodes.push(t),t},sync:function(e){if(!this.skip){for(var t=this.node,o=this.childNodes,i=a(x(t)),s=e||new WeakMap,c=B.calculateSplices(o,i),u=0,l=0,p=0,d=0;d<c.length;d++){for(var f=c[d];p<f.index;p++)l++,o[u++].sync(s);for(var h=f.removed.length,w=0;h>w;w++){var m=R(i[l++]);s.get(m)||r(m)}for(var g=f.addedCount,v=i[l]&&R(i[l]),w=0;g>w;w++){var b=o[u++],y=b.node;n(t,y,v),s.set(y,!0),b.sync(s)}p+=g}for(var d=p;d<o.length;d++)o[d].sync(s)}}},f.prototype={render:function(e){if(this.dirty){this.invalidateAttributes();var t=this.host;this.distribution(t);var n=e||new d(t);this.buildRenderTree(n,t);var r=!e;r&&n.sync(),this.dirty=!1}},get parentRenderer(){return C(this.host).renderer},invalidate:function(){if(!this.dirty){this.dirty=!0;var e=this.parentRenderer;if(e&&e.invalidate(),F.push(this),T)return;T=window[k](c,0)}},distribution:function(e){this.resetAllSubtrees(e),this.distributionResolution(e)},resetAll:function(e){E(e)?o(e):v(e),this.resetAllSubtrees(e)},resetAllSubtrees:function(e){for(var t=e.firstChild;t;t=t.nextSibling)this.resetAll(t);e.shadowRoot&&this.resetAll(e.shadowRoot),e.olderShadowRoot&&this.resetAll(e.olderShadowRoot)},distributionResolution:function(e){if(S(e)){for(var t=e,n=h(t),r=M(t),o=0;o<r.length;o++)this.poolDistribution(r[o],n);for(var o=r.length-1;o>=0;o--){var i=r[o],a=w(i);if(a){var s=i.olderShadowRoot;s&&(n=h(s));for(var c=0;c<n.length;c++)m(n[c],a)}this.distributionResolution(i)}}for(var u=e.firstChild;u;u=u.nextSibling)this.distributionResolution(u)},poolDistribution:function(e,t){if(!(e instanceof N))if(e instanceof j){var n=e;this.updateDependentAttributes(n.getAttribute("select"));for(var r=!1,o=0;o<t.length;o++){var e=t[o];e&&b(e,n)&&(m(e,n),t[o]=void 0,r=!0)}if(!r)for(var i=n.firstChild;i;i=i.nextSibling)m(i,n)}else for(var i=e.firstChild;i;i=i.nextSibling)this.poolDistribution(i,t)},buildRenderTree:function(e,t){for(var n=this.compose(t),r=0;r<n.length;r++){var o=n[r],i=e.append(o);this.buildRenderTree(i,o)}if(S(t)){var a=u(t);a.dirty=!1}},compose:function(e){for(var t=[],n=e.shadowRoot||e,r=n.firstChild;r;r=r.nextSibling)if(E(r)){this.associateNode(n);for(var o=i(r),a=0;a<o.length;a++){var s=o[a];y(r,s)&&t.push(s)}}else t.push(r);return t},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(e){if(e){var t=this.attributes;/\.\w+/.test(e)&&(t["class"]=!0),/#\w+/.test(e)&&(t.id=!0),e.replace(/\[\s*([^\s=\|~\]]+)/g,function(e,n){t[n]=!0})}},dependsOnAttribute:function(e){return this.attributes[e]},associateNode:function(e){H(e).polymerShadowRenderer_=this}};var U=/^(:not\()?[*.#[a-zA-Z_|]/;L.prototype.invalidateShadowRenderer=function(e){var t=H(this).polymerShadowRenderer_;return t?(t.invalidate(),!0):!1},j.prototype.getDistributedNodes=N.prototype.getDistributedNodes=function(){return s(),i(this)},O.prototype.getDestinationInsertionPoints=function(){return s(),g(this)||[]},j.prototype.nodeIsInserted_=N.prototype.nodeIsInserted_=function(){this.invalidateShadowRenderer();var e,t=l(this);t&&(e=p(t)),H(this).polymerShadowRenderer_=e,e&&e.invalidate()},e.getRendererForHost=u,e.getShadowTrees=M,e.renderAllPending=s,e.getDestinationInsertionPoints=g,e.visual={insertBefore:n,remove:r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t){if(window[t]){r(!e.wrappers[t]);var c=function(e){n.call(this,e)};c.prototype=Object.create(n.prototype),o(c.prototype,{get form(){return s(a(this).form)}}),i(window[t],c,document.createElement(t.slice(4,-7))),e.wrappers[t]=c}}var n=e.wrappers.HTMLElement,r=e.assert,o=e.mixin,i=e.registerWrapper,a=e.unwrap,s=e.wrap,c=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOutputElement","HTMLTextAreaElement"];c.forEach(t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.Selection;t.prototype={get anchorNode(){return s(o(this).anchorNode)},get focusNode(){return s(o(this).focusNode)},addRange:function(e){o(this).addRange(a(e))},collapse:function(e,t){o(this).collapse(a(e),t)},containsNode:function(e,t){return o(this).containsNode(a(e),t)},getRangeAt:function(e){return s(o(this).getRangeAt(e))},removeRange:function(e){o(this).removeRange(i(e))},selectAllChildren:function(e){o(this).selectAllChildren(a(e))},toString:function(){return o(this).toString()}},c.prototype.extend&&(t.prototype.extend=function(e,t){o(this).extend(a(e),t)}),n(window.Selection,t,window.getSelection()),e.wrappers.Selection=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrapIfNeeded,a=e.wrap,s=window.TreeWalker;t.prototype={get root(){return a(o(this).root)},get currentNode(){return a(o(this).currentNode)},set currentNode(e){o(this).currentNode=i(e)},get filter(){return o(this).filter},parentNode:function(){return a(o(this).parentNode())},firstChild:function(){return a(o(this).firstChild())},lastChild:function(){return a(o(this).lastChild())},previousSibling:function(){return a(o(this).previousSibling())},previousNode:function(){return a(o(this).previousNode())},nextNode:function(){return a(o(this).nextNode())}},n(s,t),e.wrappers.TreeWalker=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){l.call(this,e),this.treeScope_=new w(this,null)}function n(e){var n=document[e];t.prototype[e]=function(){return L(n.apply(j(this),arguments))}}function r(e,t){D.call(j(t),N(e)),o(e,t)}function o(e,t){e.shadowRoot&&t.adoptNode(e.shadowRoot),e instanceof h&&i(e,t);for(var n=e.firstChild;n;n=n.nextSibling)o(n,t)}function i(e,t){var n=e.olderShadowRoot;n&&t.adoptNode(n)}function a(e){O(e,this)}function s(e,t){var n=document.implementation[t];e.prototype[t]=function(){return L(n.apply(j(this),arguments))}}function c(e,t){var n=document.implementation[t];e.prototype[t]=function(){return n.apply(j(this),arguments)}}var u=e.GetElementsByInterface,l=e.wrappers.Node,p=e.ParentNodeInterface,d=e.wrappers.Selection,f=e.SelectorsInterface,h=e.wrappers.ShadowRoot,w=e.TreeScope,m=e.cloneNode,g=e.defineWrapGetter,v=e.elementFromPoint,b=e.forwardMethodsToWrapper,y=e.matchesNames,E=e.mixin,S=e.registerWrapper,M=e.renderAllPending,T=e.rewrap,O=e.setWrapper,j=e.unsafeUnwrap,N=e.unwrap,L=e.wrap,_=e.wrapEventTargetMethods,C=(e.wrapNodeList,new WeakMap);t.prototype=Object.create(l.prototype),g(t,"documentElement"),g(t,"body"),g(t,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(n);var D=document.adoptNode,H=document.getSelection;E(t.prototype,{adoptNode:function(e){return e.parentNode&&e.parentNode.removeChild(e),r(e,this),e},elementFromPoint:function(e,t){return v(this,this,e,t)},importNode:function(e,t){return m(e,t,j(this))},getSelection:function(){return M(),new d(H.call(N(this)))},getElementsByName:function(e){return f.querySelectorAll.call(this,"[name="+JSON.stringify(String(e))+"]")}});var x=document.createTreeWalker,R=e.wrappers.TreeWalker;if(t.prototype.createTreeWalker=function(e,t,n,r){var o=null;return n&&(n.acceptNode&&"function"==typeof n.acceptNode?o={acceptNode:function(e){return n.acceptNode(L(e))}}:"function"==typeof n&&(o=function(e){return n(L(e))})),new R(x.call(N(this),N(e),t,o,r))},document.registerElement){var P=document.registerElement;t.prototype.registerElement=function(t,n){function r(e){return e?void O(e,this):i?document.createElement(i,t):document.createElement(t)}var o,i;if(void 0!==n&&(o=n.prototype,i=n["extends"]),o||(o=Object.create(HTMLElement.prototype)),e.nativePrototypeTable.get(o))throw new Error("NotSupportedError");for(var a,s=Object.getPrototypeOf(o),c=[];s&&!(a=e.nativePrototypeTable.get(s));)c.push(s),
+s=Object.getPrototypeOf(s);if(!a)throw new Error("NotSupportedError");for(var u=Object.create(a),l=c.length-1;l>=0;l--)u=Object.create(u);["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"].forEach(function(e){var t=o[e];t&&(u[e]=function(){L(this)instanceof r||T(this),t.apply(L(this),arguments)})});var p={prototype:u};i&&(p["extends"]=i),r.prototype=o,r.prototype.constructor=r,e.constructorTable.set(u,r),e.nativePrototypeTable.set(o,u);P.call(N(this),t,p);return r},b([window.HTMLDocument||window.Document],["registerElement"])}b([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),b([window.HTMLBodyElement,window.HTMLHeadElement,window.HTMLHtmlElement],y),b([window.HTMLDocument||window.Document],["adoptNode","importNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","createTreeWalker","elementFromPoint","getElementById","getElementsByName","getSelection"]),E(t.prototype,u),E(t.prototype,p),E(t.prototype,f),E(t.prototype,{get implementation(){var e=C.get(this);return e?e:(e=new a(N(this).implementation),C.set(this,e),e)},get defaultView(){return L(N(this).defaultView)}}),S(window.Document,t,document.implementation.createHTMLDocument("")),window.HTMLDocument&&S(window.HTMLDocument,t),_([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),s(a,"createDocumentType"),s(a,"createDocument"),s(a,"createHTMLDocument"),c(a,"hasFeature"),S(window.DOMImplementation,a),b([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),e.adoptNodeNoRemove=r,e.wrappers.DOMImplementation=a,e.wrappers.Document=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.wrappers.Selection,o=e.mixin,i=e.registerWrapper,a=e.renderAllPending,s=e.unwrap,c=e.unwrapIfNeeded,u=e.wrap,l=window.Window,p=window.getComputedStyle,d=window.getDefaultComputedStyle,f=window.getSelection;t.prototype=Object.create(n.prototype),l.prototype.getComputedStyle=function(e,t){return u(this||window).getComputedStyle(c(e),t)},d&&(l.prototype.getDefaultComputedStyle=function(e,t){return u(this||window).getDefaultComputedStyle(c(e),t)}),l.prototype.getSelection=function(){return u(this||window).getSelection()},delete window.getComputedStyle,delete window.getDefaultComputedStyle,delete window.getSelection,["addEventListener","removeEventListener","dispatchEvent"].forEach(function(e){l.prototype[e]=function(){var t=u(this||window);return t[e].apply(t,arguments)},delete window[e]}),o(t.prototype,{getComputedStyle:function(e,t){return a(),p.call(s(this),c(e),t)},getSelection:function(){return a(),new r(f.call(s(this)))},get document(){return u(s(this).document)}}),d&&(t.prototype.getDefaultComputedStyle=function(e,t){return a(),d.call(s(this),c(e),t)}),i(l,t,window),e.wrappers.Window=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrap,n=window.DataTransfer||window.Clipboard,r=n.prototype.setDragImage;r&&(n.prototype.setDragImage=function(e,n,o){r.call(this,t(e),n,o)})}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t;t=e instanceof i?e:new i(e&&o(e)),r(t,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unwrap,i=window.FormData;i&&(n(i,t,new i),e.wrappers.FormData=t)}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrapIfNeeded,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(e){return n.call(this,t(e))}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=n[e],r=window[t];if(r){var o=document.createElement(e),i=o.constructor;window[t]=i}}var n=(e.isWrapperFor,{a:"HTMLAnchorElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",base:"HTMLBaseElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",content:"HTMLContentElement",data:"HTMLDataElement",datalist:"HTMLDataListElement",del:"HTMLModElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",head:"HTMLHeadElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",marquee:"HTMLMarqueeElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",shadow:"HTMLShadowElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",template:"HTMLTemplateElement",textarea:"HTMLTextAreaElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",ul:"HTMLUListElement",video:"HTMLVideoElement"});Object.keys(n).forEach(t),Object.getOwnPropertyNames(e.wrappers).forEach(function(t){window[t]=e.wrappers[t]})}(window.ShadowDOMPolyfill); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/bower.json b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/bower.json
index 4129deb3d42..36d2b0e5c59 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/bower.json
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/bower.json
@@ -1,7 +1,7 @@
{
"name": "webcomponentsjs",
"main": "webcomponents.js",
- "version": "0.5.5",
+ "version": "0.6.1",
"homepage": "http://webcomponents.org",
"authors": [
"The Polymer Authors"
@@ -11,4 +11,4 @@
],
"license": "BSD",
"ignore": []
-} \ No newline at end of file
+}
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/build.log b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/build.log
new file mode 100644
index 00000000000..9f85a5bf023
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/build.log
@@ -0,0 +1,31 @@
+BUILD LOG
+---------
+Build Time: 2015-04-13T13:57:39-0700
+
+NODEJS INFORMATION
+==================
+nodejs: v0.12.0
+gulp: 3.8.11
+gulp-audit: 1.0.0
+gulp-concat: 2.5.2
+gulp-header: 1.2.2
+gulp-uglify: 1.2.0
+run-sequence: 1.0.2
+web-component-tester: 2.2.6
+
+REPO REVISIONS
+==============
+webcomponentsjs: ef29f20f1678f1b121ea5acce84cf36c599f7627
+
+BUILD HASHES
+============
+CustomElements.js: 2292abfeeb0ca0e03314f35edc50867c89b2dc93
+CustomElements.min.js: 131750c5b4297103b7702bb9123498bd5d4113a3
+HTMLImports.js: 5488833312a155d45744190715c0a702ba4d1340
+HTMLImports.min.js: 3d3cc90f2ff3fd718cb80253b4dc18ac54157411
+ShadowDOM.js: bf6aa1c79006401b100f0b60caa8b4f60333c209
+ShadowDOM.min.js: bf7028b266a9567556e3e99946dee55b451db0a8
+webcomponents-lite.js: 22a5d4a7b77eff8bca4dff1d0ed8c0cf11bd43e1
+webcomponents-lite.min.js: 45223241dc94cf226d7626e6f85af2370e186134
+webcomponents.js: eb64d78f556c672f905a703e10dba21bfe97694b
+webcomponents.min.js: 65d1bdca02300557e2055f91b236c20624ca0317 \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/package.json b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/package.json
index 52fdd0e7889..65b003e8a6b 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/package.json
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/package.json
@@ -1,6 +1,6 @@
{
"name": "webcomponents.js",
- "version": "0.5.5",
+ "version": "0.6.1",
"description": "webcomponents.js",
"main": "webcomponents.js",
"directories": {
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.js
index a6e17b56036..19285253dd1 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.js
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.js
@@ -7,7 +7,7 @@
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
-// @version 0.5.5
+// @version 0.6.1
window.WebComponents = window.WebComponents || {};
(function(scope) {
@@ -26,7 +26,7 @@ window.WebComponents = window.WebComponents || {};
}
}
}
- if (flags.log) {
+ if (flags.log && flags.log.split) {
var parts = flags.log.split(",");
flags.log = {};
parts.forEach(function(f) {
@@ -51,6 +51,554 @@ window.WebComponents = window.WebComponents || {};
scope.flags = flags;
})(WebComponents);
+(function(scope) {
+ "use strict";
+ var hasWorkingUrl = false;
+ if (!scope.forceJURL) {
+ try {
+ var u = new URL("b", "http://a");
+ u.pathname = "c%20d";
+ hasWorkingUrl = u.href === "http://a/c%20d";
+ } catch (e) {}
+ }
+ if (hasWorkingUrl) return;
+ var relative = Object.create(null);
+ relative["ftp"] = 21;
+ relative["file"] = 0;
+ relative["gopher"] = 70;
+ relative["http"] = 80;
+ relative["https"] = 443;
+ relative["ws"] = 80;
+ relative["wss"] = 443;
+ var relativePathDotMapping = Object.create(null);
+ relativePathDotMapping["%2e"] = ".";
+ relativePathDotMapping[".%2e"] = "..";
+ relativePathDotMapping["%2e."] = "..";
+ relativePathDotMapping["%2e%2e"] = "..";
+ function isRelativeScheme(scheme) {
+ return relative[scheme] !== undefined;
+ }
+ function invalid() {
+ clear.call(this);
+ this._isInvalid = true;
+ }
+ function IDNAToASCII(h) {
+ if ("" == h) {
+ invalid.call(this);
+ }
+ return h.toLowerCase();
+ }
+ function percentEscape(c) {
+ var unicode = c.charCodeAt(0);
+ if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 63, 96 ].indexOf(unicode) == -1) {
+ return c;
+ }
+ return encodeURIComponent(c);
+ }
+ function percentEscapeQuery(c) {
+ var unicode = c.charCodeAt(0);
+ if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 96 ].indexOf(unicode) == -1) {
+ return c;
+ }
+ return encodeURIComponent(c);
+ }
+ var EOF = undefined, ALPHA = /[a-zA-Z]/, ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
+ function parse(input, stateOverride, base) {
+ function err(message) {
+ errors.push(message);
+ }
+ var state = stateOverride || "scheme start", cursor = 0, buffer = "", seenAt = false, seenBracket = false, errors = [];
+ loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
+ var c = input[cursor];
+ switch (state) {
+ case "scheme start":
+ if (c && ALPHA.test(c)) {
+ buffer += c.toLowerCase();
+ state = "scheme";
+ } else if (!stateOverride) {
+ buffer = "";
+ state = "no scheme";
+ continue;
+ } else {
+ err("Invalid scheme.");
+ break loop;
+ }
+ break;
+
+ case "scheme":
+ if (c && ALPHANUMERIC.test(c)) {
+ buffer += c.toLowerCase();
+ } else if (":" == c) {
+ this._scheme = buffer;
+ buffer = "";
+ if (stateOverride) {
+ break loop;
+ }
+ if (isRelativeScheme(this._scheme)) {
+ this._isRelative = true;
+ }
+ if ("file" == this._scheme) {
+ state = "relative";
+ } else if (this._isRelative && base && base._scheme == this._scheme) {
+ state = "relative or authority";
+ } else if (this._isRelative) {
+ state = "authority first slash";
+ } else {
+ state = "scheme data";
+ }
+ } else if (!stateOverride) {
+ buffer = "";
+ cursor = 0;
+ state = "no scheme";
+ continue;
+ } else if (EOF == c) {
+ break loop;
+ } else {
+ err("Code point not allowed in scheme: " + c);
+ break loop;
+ }
+ break;
+
+ case "scheme data":
+ if ("?" == c) {
+ query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ } else {
+ if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._schemeData += percentEscape(c);
+ }
+ }
+ break;
+
+ case "no scheme":
+ if (!base || !isRelativeScheme(base._scheme)) {
+ err("Missing scheme.");
+ invalid.call(this);
+ } else {
+ state = "relative";
+ continue;
+ }
+ break;
+
+ case "relative or authority":
+ if ("/" == c && "/" == input[cursor + 1]) {
+ state = "authority ignore slashes";
+ } else {
+ err("Expected /, got: " + c);
+ state = "relative";
+ continue;
+ }
+ break;
+
+ case "relative":
+ this._isRelative = true;
+ if ("file" != this._scheme) this._scheme = base._scheme;
+ if (EOF == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = base._query;
+ break loop;
+ } else if ("/" == c || "\\" == c) {
+ if ("\\" == c) err("\\ is an invalid code point.");
+ state = "relative slash";
+ } else if ("?" == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = base._query;
+ this._fragment = "#";
+ state = "fragment";
+ } else {
+ var nextC = input[cursor + 1];
+ var nextNextC = input[cursor + 2];
+ if ("file" != this._scheme || !ALPHA.test(c) || nextC != ":" && nextC != "|" || EOF != nextNextC && "/" != nextNextC && "\\" != nextNextC && "?" != nextNextC && "#" != nextNextC) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._path.pop();
+ }
+ state = "relative path";
+ continue;
+ }
+ break;
+
+ case "relative slash":
+ if ("/" == c || "\\" == c) {
+ if ("\\" == c) {
+ err("\\ is an invalid code point.");
+ }
+ if ("file" == this._scheme) {
+ state = "file host";
+ } else {
+ state = "authority ignore slashes";
+ }
+ } else {
+ if ("file" != this._scheme) {
+ this._host = base._host;
+ this._port = base._port;
+ }
+ state = "relative path";
+ continue;
+ }
+ break;
+
+ case "authority first slash":
+ if ("/" == c) {
+ state = "authority second slash";
+ } else {
+ err("Expected '/', got: " + c);
+ state = "authority ignore slashes";
+ continue;
+ }
+ break;
+
+ case "authority second slash":
+ state = "authority ignore slashes";
+ if ("/" != c) {
+ err("Expected '/', got: " + c);
+ continue;
+ }
+ break;
+
+ case "authority ignore slashes":
+ if ("/" != c && "\\" != c) {
+ state = "authority";
+ continue;
+ } else {
+ err("Expected authority, got: " + c);
+ }
+ break;
+
+ case "authority":
+ if ("@" == c) {
+ if (seenAt) {
+ err("@ already seen.");
+ buffer += "%40";
+ }
+ seenAt = true;
+ for (var i = 0; i < buffer.length; i++) {
+ var cp = buffer[i];
+ if (" " == cp || "\n" == cp || "\r" == cp) {
+ err("Invalid whitespace in authority.");
+ continue;
+ }
+ if (":" == cp && null === this._password) {
+ this._password = "";
+ continue;
+ }
+ var tempC = percentEscape(cp);
+ null !== this._password ? this._password += tempC : this._username += tempC;
+ }
+ buffer = "";
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ cursor -= buffer.length;
+ buffer = "";
+ state = "host";
+ continue;
+ } else {
+ buffer += c;
+ }
+ break;
+
+ case "file host":
+ if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ":" || buffer[1] == "|")) {
+ state = "relative path";
+ } else if (buffer.length == 0) {
+ state = "relative path start";
+ } else {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "relative path start";
+ }
+ continue;
+ } else if (" " == c || "\n" == c || "\r" == c) {
+ err("Invalid whitespace in file host.");
+ } else {
+ buffer += c;
+ }
+ break;
+
+ case "host":
+ case "hostname":
+ if (":" == c && !seenBracket) {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "port";
+ if ("hostname" == stateOverride) {
+ break loop;
+ }
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "relative path start";
+ if (stateOverride) {
+ break loop;
+ }
+ continue;
+ } else if (" " != c && "\n" != c && "\r" != c) {
+ if ("[" == c) {
+ seenBracket = true;
+ } else if ("]" == c) {
+ seenBracket = false;
+ }
+ buffer += c;
+ } else {
+ err("Invalid code point in host/hostname: " + c);
+ }
+ break;
+
+ case "port":
+ if (/[0-9]/.test(c)) {
+ buffer += c;
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c || stateOverride) {
+ if ("" != buffer) {
+ var temp = parseInt(buffer, 10);
+ if (temp != relative[this._scheme]) {
+ this._port = temp + "";
+ }
+ buffer = "";
+ }
+ if (stateOverride) {
+ break loop;
+ }
+ state = "relative path start";
+ continue;
+ } else if (" " == c || "\n" == c || "\r" == c) {
+ err("Invalid code point in port: " + c);
+ } else {
+ invalid.call(this);
+ }
+ break;
+
+ case "relative path start":
+ if ("\\" == c) err("'\\' not allowed in path.");
+ state = "relative path";
+ if ("/" != c && "\\" != c) {
+ continue;
+ }
+ break;
+
+ case "relative path":
+ if (EOF == c || "/" == c || "\\" == c || !stateOverride && ("?" == c || "#" == c)) {
+ if ("\\" == c) {
+ err("\\ not allowed in relative path.");
+ }
+ var tmp;
+ if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
+ buffer = tmp;
+ }
+ if (".." == buffer) {
+ this._path.pop();
+ if ("/" != c && "\\" != c) {
+ this._path.push("");
+ }
+ } else if ("." == buffer && "/" != c && "\\" != c) {
+ this._path.push("");
+ } else if ("." != buffer) {
+ if ("file" == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == "|") {
+ buffer = buffer[0] + ":";
+ }
+ this._path.push(buffer);
+ }
+ buffer = "";
+ if ("?" == c) {
+ this._query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ }
+ } else if (" " != c && "\n" != c && "\r" != c) {
+ buffer += percentEscape(c);
+ }
+ break;
+
+ case "query":
+ if (!stateOverride && "#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ } else if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._query += percentEscapeQuery(c);
+ }
+ break;
+
+ case "fragment":
+ if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._fragment += c;
+ }
+ break;
+ }
+ cursor++;
+ }
+ }
+ function clear() {
+ this._scheme = "";
+ this._schemeData = "";
+ this._username = "";
+ this._password = null;
+ this._host = "";
+ this._port = "";
+ this._path = [];
+ this._query = "";
+ this._fragment = "";
+ this._isInvalid = false;
+ this._isRelative = false;
+ }
+ function jURL(url, base) {
+ if (base !== undefined && !(base instanceof jURL)) base = new jURL(String(base));
+ this._url = url;
+ clear.call(this);
+ var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, "");
+ parse.call(this, input, null, base);
+ }
+ jURL.prototype = {
+ toString: function() {
+ return this.href;
+ },
+ get href() {
+ if (this._isInvalid) return this._url;
+ var authority = "";
+ if ("" != this._username || null != this._password) {
+ authority = this._username + (null != this._password ? ":" + this._password : "") + "@";
+ }
+ return this.protocol + (this._isRelative ? "//" + authority + this.host : "") + this.pathname + this._query + this._fragment;
+ },
+ set href(href) {
+ clear.call(this);
+ parse.call(this, href);
+ },
+ get protocol() {
+ return this._scheme + ":";
+ },
+ set protocol(protocol) {
+ if (this._isInvalid) return;
+ parse.call(this, protocol + ":", "scheme start");
+ },
+ get host() {
+ return this._isInvalid ? "" : this._port ? this._host + ":" + this._port : this._host;
+ },
+ set host(host) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, host, "host");
+ },
+ get hostname() {
+ return this._host;
+ },
+ set hostname(hostname) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, hostname, "hostname");
+ },
+ get port() {
+ return this._port;
+ },
+ set port(port) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, port, "port");
+ },
+ get pathname() {
+ return this._isInvalid ? "" : this._isRelative ? "/" + this._path.join("/") : this._schemeData;
+ },
+ set pathname(pathname) {
+ if (this._isInvalid || !this._isRelative) return;
+ this._path = [];
+ parse.call(this, pathname, "relative path start");
+ },
+ get search() {
+ return this._isInvalid || !this._query || "?" == this._query ? "" : this._query;
+ },
+ set search(search) {
+ if (this._isInvalid || !this._isRelative) return;
+ this._query = "?";
+ if ("?" == search[0]) search = search.slice(1);
+ parse.call(this, search, "query");
+ },
+ get hash() {
+ return this._isInvalid || !this._fragment || "#" == this._fragment ? "" : this._fragment;
+ },
+ set hash(hash) {
+ if (this._isInvalid) return;
+ this._fragment = "#";
+ if ("#" == hash[0]) hash = hash.slice(1);
+ parse.call(this, hash, "fragment");
+ },
+ get origin() {
+ var host;
+ if (this._isInvalid || !this._scheme) {
+ return "";
+ }
+ switch (this._scheme) {
+ case "data":
+ case "file":
+ case "javascript":
+ case "mailto":
+ return "null";
+ }
+ host = this.host;
+ if (!host) {
+ return "";
+ }
+ return this._scheme + "://" + host;
+ }
+ };
+ var OriginalURL = scope.URL;
+ if (OriginalURL) {
+ jURL.createObjectURL = function(blob) {
+ return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
+ };
+ jURL.revokeObjectURL = function(url) {
+ OriginalURL.revokeObjectURL(url);
+ };
+ }
+ scope.URL = jURL;
+})(this);
+
+if (typeof WeakMap === "undefined") {
+ (function() {
+ var defineProperty = Object.defineProperty;
+ var counter = Date.now() % 1e9;
+ var WeakMap = function() {
+ this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
+ };
+ WeakMap.prototype = {
+ set: function(key, value) {
+ var entry = key[this.name];
+ if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
+ value: [ key, value ],
+ writable: true
+ });
+ return this;
+ },
+ get: function(key) {
+ var entry;
+ return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
+ },
+ "delete": function(key) {
+ var entry = key[this.name];
+ if (!entry || entry[0] !== key) return false;
+ entry[0] = entry[1] = undefined;
+ return true;
+ },
+ has: function(key) {
+ var entry = key[this.name];
+ if (!entry) return false;
+ return entry[0] === key;
+ }
+ };
+ window.WeakMap = WeakMap;
+ })();
+}
+
(function(global) {
var registrationsTable = new WeakMap();
var setImmediate;
@@ -350,42 +898,6 @@ window.WebComponents = window.WebComponents || {};
if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;
})(this);
-if (typeof WeakMap === "undefined") {
- (function() {
- var defineProperty = Object.defineProperty;
- var counter = Date.now() % 1e9;
- var WeakMap = function() {
- this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
- };
- WeakMap.prototype = {
- set: function(key, value) {
- var entry = key[this.name];
- if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
- value: [ key, value ],
- writable: true
- });
- return this;
- },
- get: function(key) {
- var entry;
- return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
- },
- "delete": function(key) {
- var entry = key[this.name];
- if (!entry || entry[0] !== key) return false;
- entry[0] = entry[1] = undefined;
- return true;
- },
- has: function(key) {
- var entry = key[this.name];
- if (!entry) return false;
- return entry[0] === key;
- }
- };
- window.WeakMap = WeakMap;
- })();
-}
-
window.HTMLImports = window.HTMLImports || {
flags: {}
};
@@ -437,26 +949,35 @@ window.HTMLImports = window.HTMLImports || {
}
function watchImportsLoad(callback, doc) {
var imports = doc.querySelectorAll("link[rel=import]");
- var loaded = 0, l = imports.length;
- function checkDone(d) {
- if (loaded == l && callback) {
- callback();
+ var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];
+ function checkDone() {
+ if (parsedCount == importCount && callback) {
+ callback({
+ allImports: imports,
+ loadedImports: newImports,
+ errorImports: errorImports
+ });
}
}
function loadedImport(e) {
markTargetLoaded(e);
- loaded++;
+ newImports.push(this);
+ parsedCount++;
checkDone();
}
- if (l) {
- for (var i = 0, imp; i < l && (imp = imports[i]); i++) {
+ function errorLoadingImport(e) {
+ errorImports.push(this);
+ parsedCount++;
+ checkDone();
+ }
+ if (importCount) {
+ for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) {
if (isImportLoaded(imp)) {
- loadedImport.call(imp, {
- target: imp
- });
+ parsedCount++;
+ checkDone();
} else {
imp.addEventListener("load", loadedImport);
- imp.addEventListener("error", loadedImport);
+ imp.addEventListener("error", errorLoadingImport);
}
}
} else {
@@ -506,11 +1027,11 @@ window.HTMLImports = window.HTMLImports || {
}
})();
}
- whenReady(function() {
+ whenReady(function(detail) {
HTMLImports.ready = true;
HTMLImports.readyTime = new Date().getTime();
var evt = rootDocument.createEvent("CustomEvent");
- evt.initCustomEvent("HTMLImportsLoaded", true, true, {});
+ evt.initCustomEvent("HTMLImportsLoaded", true, true, detail);
rootDocument.dispatchEvent(evt);
});
scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
@@ -538,20 +1059,23 @@ HTMLImports.addModule(function(scope) {
var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
var path = {
- resolveUrlsInStyle: function(style) {
+ resolveUrlsInStyle: function(style, linkUrl) {
var doc = style.ownerDocument;
var resolver = doc.createElement("a");
- style.textContent = this.resolveUrlsInCssText(style.textContent, resolver);
+ style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver);
return style;
},
- resolveUrlsInCssText: function(cssText, urlObj) {
- var r = this.replaceUrls(cssText, urlObj, CSS_URL_REGEXP);
- r = this.replaceUrls(r, urlObj, CSS_IMPORT_REGEXP);
+ resolveUrlsInCssText: function(cssText, linkUrl, urlObj) {
+ var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP);
+ r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP);
return r;
},
- replaceUrls: function(text, urlObj, regexp) {
+ replaceUrls: function(text, urlObj, linkUrl, regexp) {
return text.replace(regexp, function(m, pre, url, post) {
var urlPath = url.replace(/["']/g, "");
+ if (linkUrl) {
+ urlPath = new URL(urlPath, linkUrl).href;
+ }
urlObj.href = urlPath;
urlPath = urlObj.href;
return pre + "'" + urlPath + "'" + post;
@@ -819,6 +1343,7 @@ HTMLImports.addModule(function(scope) {
parseStyle: function(elt) {
var src = elt;
elt = cloneStyle(elt);
+ src.__appliedElement = elt;
elt.__importElement = src;
this.parseGeneric(elt);
},
@@ -1160,13 +1685,10 @@ CustomElements.addModule(function(scope) {
root = root.olderShadowRoot;
}
}
- var processingDocuments;
function forDocumentTree(doc, cb) {
- processingDocuments = [];
- _forDocumentTree(doc, cb);
- processingDocuments = null;
+ _forDocumentTree(doc, cb, []);
}
- function _forDocumentTree(doc, cb) {
+ function _forDocumentTree(doc, cb, processingDocuments) {
doc = wrap(doc);
if (processingDocuments.indexOf(doc) >= 0) {
return;
@@ -1175,7 +1697,7 @@ CustomElements.addModule(function(scope) {
var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
if (n.import) {
- _forDocumentTree(n.import, cb);
+ _forDocumentTree(n.import, cb, processingDocuments);
}
}
cb(doc);
@@ -1282,7 +1804,7 @@ CustomElements.addModule(function(scope) {
if (p == doc) {
return true;
}
- p = p.parentNode || p.host;
+ p = p.parentNode || p.nodeType === Node.DOCUMENT_FRAGMENT_NODE && p.host;
}
}
function watchShadow(node) {
@@ -1441,8 +1963,9 @@ CustomElements.addModule(function(scope) {
});
CustomElements.addModule(function(scope) {
+ var isIE11OrOlder = scope.isIE11OrOlder;
var upgradeDocumentTree = scope.upgradeDocumentTree;
- var upgrade = scope.upgrade;
+ var upgradeAll = scope.upgradeAll;
var upgradeWithDefinition = scope.upgradeWithDefinition;
var implementPrototype = scope.implementPrototype;
var useNative = scope.useNative;
@@ -1592,14 +2115,8 @@ CustomElements.addModule(function(scope) {
}
return element;
}
- function cloneNode(deep) {
- var n = domCloneNode.call(this, deep);
- upgrade(n);
- return n;
- }
var domCreateElement = document.createElement.bind(document);
var domCreateElementNS = document.createElementNS.bind(document);
- var domCloneNode = Node.prototype.cloneNode;
var isInstance;
if (!Object.__proto__ && !useNative) {
isInstance = function(obj, ctor) {
@@ -1617,10 +2134,34 @@ CustomElements.addModule(function(scope) {
return obj instanceof base;
};
}
+ function wrapDomMethodToForceUpgrade(obj, methodName) {
+ var orig = obj[methodName];
+ obj[methodName] = function() {
+ var n = orig.apply(this, arguments);
+ upgradeAll(n);
+ return n;
+ };
+ }
+ wrapDomMethodToForceUpgrade(Node.prototype, "cloneNode");
+ wrapDomMethodToForceUpgrade(document, "importNode");
+ if (isIE11OrOlder) {
+ (function() {
+ var importNode = document.importNode;
+ document.importNode = function() {
+ var n = importNode.apply(document, arguments);
+ if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
+ var f = document.createDocumentFragment();
+ f.appendChild(n);
+ return f;
+ } else {
+ return n;
+ }
+ };
+ })();
+ }
document.registerElement = register;
document.createElement = createElement;
document.createElementNS = createElementNS;
- Node.prototype.cloneNode = cloneNode;
scope.registry = registry;
scope.instanceof = isInstance;
scope.reservedTagList = reservedTagList;
@@ -1692,6 +2233,7 @@ CustomElements.addModule(function(scope) {
var loadEvent = window.HTMLImports && !HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
window.addEventListener(loadEvent, bootstrap);
}
+ scope.isIE11OrOlder = isIE11OrOlder;
})(window.CustomElements);
if (typeof HTMLTemplateElement === "undefined") {
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.min.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.min.js
new file mode 100644
index 00000000000..8fbb97239cf
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents-lite.min.js
@@ -0,0 +1,12 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.6.1
+window.WebComponents=window.WebComponents||{},function(e){var t=e.flags||{},n="webcomponents.js",r=document.querySelector('script[src*="'+n+'"]');if(!t.noOpts){if(location.search.slice(1).split("&").forEach(function(e){e=e.split("="),e[0]&&(t[e[0]]=e[1]||!0)}),r)for(var o,i=0;o=r.attributes[i];i++)"src"!==o.name&&(t[o.name]=o.value||!0);if(t.log&&t.log.split){var a=t.log.split(",");t.log={},a.forEach(function(e){t.log[e]=!0})}else t.log={}}t.shadow=t.shadow||t.shadowdom||t.polyfill,t.shadow="native"===t.shadow?!1:t.shadow||!HTMLElement.prototype.createShadowRoot,t.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=t.register),e.flags=t}(WebComponents),function(e){"use strict";function t(e){return void 0!==h[e]}function n(){s.call(this),this._isInvalid=!0}function r(e){return""==e&&n.call(this),e.toLowerCase()}function o(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,63,96].indexOf(t)?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,96].indexOf(t)?e:encodeURIComponent(e)}function a(e,a,s){function c(e){b.push(e)}var d=a||"scheme start",l=0,u="",_=!1,g=!1,b=[];e:for(;(e[l-1]!=p||0==l)&&!this._isInvalid;){var w=e[l];switch(d){case"scheme start":if(!w||!m.test(w)){if(a){c("Invalid scheme.");break e}u="",d="no scheme";continue}u+=w.toLowerCase(),d="scheme";break;case"scheme":if(w&&v.test(w))u+=w.toLowerCase();else{if(":"!=w){if(a){if(p==w)break e;c("Code point not allowed in scheme: "+w);break e}u="",l=0,d="no scheme";continue}if(this._scheme=u,u="",a)break e;t(this._scheme)&&(this._isRelative=!0),d="file"==this._scheme?"relative":this._isRelative&&s&&s._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==w?(query="?",d="query"):"#"==w?(this._fragment="#",d="fragment"):p!=w&&" "!=w&&"\n"!=w&&"\r"!=w&&(this._schemeData+=o(w));break;case"no scheme":if(s&&t(s._scheme)){d="relative";continue}c("Missing scheme."),n.call(this);break;case"relative or authority":if("/"!=w||"/"!=e[l+1]){c("Expected /, got: "+w),d="relative";continue}d="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=s._scheme),p==w){this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query;break e}if("/"==w||"\\"==w)"\\"==w&&c("\\ is an invalid code point."),d="relative slash";else if("?"==w)this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query="?",d="query";else{if("#"!=w){var y=e[l+1],E=e[l+2];("file"!=this._scheme||!m.test(w)||":"!=y&&"|"!=y||p!=E&&"/"!=E&&"\\"!=E&&"?"!=E&&"#"!=E)&&(this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._path.pop()),d="relative path";continue}this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._fragment="#",d="fragment"}break;case"relative slash":if("/"!=w&&"\\"!=w){"file"!=this._scheme&&(this._host=s._host,this._port=s._port),d="relative path";continue}"\\"==w&&c("\\ is an invalid code point."),d="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=w){c("Expected '/', got: "+w),d="authority ignore slashes";continue}d="authority second slash";break;case"authority second slash":if(d="authority ignore slashes","/"!=w){c("Expected '/', got: "+w);continue}break;case"authority ignore slashes":if("/"!=w&&"\\"!=w){d="authority";continue}c("Expected authority, got: "+w);break;case"authority":if("@"==w){_&&(c("@ already seen."),u+="%40"),_=!0;for(var L=0;L<u.length;L++){var M=u[L];if(" "!=M&&"\n"!=M&&"\r"!=M)if(":"!=M||null!==this._password){var T=o(M);null!==this._password?this._password+=T:this._username+=T}else this._password="";else c("Invalid whitespace in authority.")}u=""}else{if(p==w||"/"==w||"\\"==w||"?"==w||"#"==w){l-=u.length,u="",d="host";continue}u+=w}break;case"file host":if(p==w||"/"==w||"\\"==w||"?"==w||"#"==w){2!=u.length||!m.test(u[0])||":"!=u[1]&&"|"!=u[1]?0==u.length?d="relative path start":(this._host=r.call(this,u),u="",d="relative path start"):d="relative path";continue}" "==w||"\n"==w||"\r"==w?c("Invalid whitespace in file host."):u+=w;break;case"host":case"hostname":if(":"!=w||g){if(p==w||"/"==w||"\\"==w||"?"==w||"#"==w){if(this._host=r.call(this,u),u="",d="relative path start",a)break e;continue}" "!=w&&"\n"!=w&&"\r"!=w?("["==w?g=!0:"]"==w&&(g=!1),u+=w):c("Invalid code point in host/hostname: "+w)}else if(this._host=r.call(this,u),u="",d="port","hostname"==a)break e;break;case"port":if(/[0-9]/.test(w))u+=w;else{if(p==w||"/"==w||"\\"==w||"?"==w||"#"==w||a){if(""!=u){var N=parseInt(u,10);N!=h[this._scheme]&&(this._port=N+""),u=""}if(a)break e;d="relative path start";continue}" "==w||"\n"==w||"\r"==w?c("Invalid code point in port: "+w):n.call(this)}break;case"relative path start":if("\\"==w&&c("'\\' not allowed in path."),d="relative path","/"!=w&&"\\"!=w)continue;break;case"relative path":if(p!=w&&"/"!=w&&"\\"!=w&&(a||"?"!=w&&"#"!=w))" "!=w&&"\n"!=w&&"\r"!=w&&(u+=o(w));else{"\\"==w&&c("\\ not allowed in relative path.");var O;(O=f[u.toLowerCase()])&&(u=O),".."==u?(this._path.pop(),"/"!=w&&"\\"!=w&&this._path.push("")):"."==u&&"/"!=w&&"\\"!=w?this._path.push(""):"."!=u&&("file"==this._scheme&&0==this._path.length&&2==u.length&&m.test(u[0])&&"|"==u[1]&&(u=u[0]+":"),this._path.push(u)),u="","?"==w?(this._query="?",d="query"):"#"==w&&(this._fragment="#",d="fragment")}break;case"query":a||"#"!=w?p!=w&&" "!=w&&"\n"!=w&&"\r"!=w&&(this._query+=i(w)):(this._fragment="#",d="fragment");break;case"fragment":p!=w&&" "!=w&&"\n"!=w&&"\r"!=w&&(this._fragment+=w)}l++}}function s(){this._scheme="",this._schemeData="",this._username="",this._password=null,this._host="",this._port="",this._path=[],this._query="",this._fragment="",this._isInvalid=!1,this._isRelative=!1}function c(e,t){void 0===t||t instanceof c||(t=new c(String(t))),this._url=e,s.call(this);var n=e.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g,"");a.call(this,n,null,t)}var d=!1;if(!e.forceJURL)try{var l=new URL("b","http://a");l.pathname="c%20d",d="http://a/c%20d"===l.href}catch(u){}if(!d){var h=Object.create(null);h.ftp=21,h.file=0,h.gopher=70,h.http=80,h.https=443,h.ws=80,h.wss=443;var f=Object.create(null);f["%2e"]=".",f[".%2e"]="..",f["%2e."]="..",f["%2e%2e"]="..";var p=void 0,m=/[a-zA-Z]/,v=/[a-zA-Z0-9\+\-\.]/;c.prototype={toString:function(){return this.href},get href(){if(this._isInvalid)return this._url;var e="";return(""!=this._username||null!=this._password)&&(e=this._username+(null!=this._password?":"+this._password:"")+"@"),this.protocol+(this._isRelative?"//"+e+this.host:"")+this.pathname+this._query+this._fragment},set href(e){s.call(this),a.call(this,e)},get protocol(){return this._scheme+":"},set protocol(e){this._isInvalid||a.call(this,e+":","scheme start")},get host(){return this._isInvalid?"":this._port?this._host+":"+this._port:this._host},set host(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"host")},get hostname(){return this._host},set hostname(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"hostname")},get port(){return this._port},set port(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"port")},get pathname(){return this._isInvalid?"":this._isRelative?"/"+this._path.join("/"):this._schemeData},set pathname(e){!this._isInvalid&&this._isRelative&&(this._path=[],a.call(this,e,"relative path start"))},get search(){return this._isInvalid||!this._query||"?"==this._query?"":this._query},set search(e){!this._isInvalid&&this._isRelative&&(this._query="?","?"==e[0]&&(e=e.slice(1)),a.call(this,e,"query"))},get hash(){return this._isInvalid||!this._fragment||"#"==this._fragment?"":this._fragment},set hash(e){this._isInvalid||(this._fragment="#","#"==e[0]&&(e=e.slice(1)),a.call(this,e,"fragment"))},get origin(){var e;if(this._isInvalid||!this._scheme)return"";switch(this._scheme){case"data":case"file":case"javascript":case"mailto":return"null"}return e=this.host,e?this._scheme+"://"+e:""}};var _=e.URL;_&&(c.createObjectURL=function(e){return _.createObjectURL.apply(_,arguments)},c.revokeObjectURL=function(e){_.revokeObjectURL(e)}),e.URL=c}}(this),"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),function(e){function t(e){w.push(e),b||(b=!0,m(r))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function r(){b=!1;var e=w;w=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();o(e),n.length&&(e.callback_(n,e),t=!0)}),t&&r()}function o(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var r=v.get(n);if(r)for(var o=0;o<r.length;o++){var i=r[o],a=i.options;if(n===e||a.subtree){var s=t(a);s&&i.enqueue(s)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++y}function s(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function c(e){var t=new s(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function d(e,t){return E=new s(e,t)}function l(e){return L?L:(L=c(E),L.oldValue=e,L)}function u(){E=L=void 0}function h(e){return e===L||e===E}function f(e,t){return e===t?e:L&&h(e)?L:null}function p(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var m,v=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))m=setTimeout;else if(window.setImmediate)m=window.setImmediate;else{var _=[],g=String(Math.random());window.addEventListener("message",function(e){if(e.data===g){var t=_;_=[],t.forEach(function(e){e()})}}),m=function(e){_.push(e),window.postMessage(g,"*")}}var b=!1,w=[],y=0;a.prototype={observe:function(e,t){if(e=n(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var r=v.get(e);r||v.set(e,r=[]);for(var o,i=0;i<r.length;i++)if(r[i].observer===this){o=r[i],o.removeListeners(),o.options=t;break}o||(o=new p(this,e,t),r.push(o),this.nodes_.push(e)),o.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=v.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){r.removeListeners(),t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var E,L;p.prototype={enqueue:function(e){var n=this.observer.records_,r=n.length;if(n.length>0){var o=n[r-1],i=f(o,e);if(i)return void(n[r-1]=i)}else t(this.observer);n[r]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n<t.length;n++)if(t[n]===this){t.splice(n,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,n=e.relatedNode.namespaceURI,r=e.target,o=new d("attributes",r);o.attributeName=t,o.attributeNamespace=n;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(r,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(n)?void 0:e.attributeOldValue?l(a):o});break;case"DOMCharacterDataModified":var r=e.target,o=d("characterData",r),a=e.prevValue;i(r,function(e){return e.characterData?e.characterDataOldValue?l(a):o:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var s,c,h=e.target;"DOMNodeInserted"===e.type?(s=[h],c=[]):(s=[],c=[h]);var f=h.previousSibling,p=h.nextSibling,o=d("childList",e.target.parentNode);o.addedNodes=s,o.removedNodes=c,o.previousSibling=f,o.nextSibling=p,i(e.relatedNode,function(e){return e.childList?o:void 0})}u()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a)}(this),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===_}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===_)&&(t.removeEventListener(g,o),r(e,t))};t.addEventListener(g,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){c==d&&e&&e({allImports:s,loadedImports:l,errorImports:u})}function r(e){o(e),l.push(this),c++,n()}function i(e){u.push(this),c++,n()}var s=t.querySelectorAll("link[rel=import]"),c=0,d=s.length,l=[],u=[];if(d)for(var h,f=0;d>f&&(h=s[f]);f++)a(h)?(c++,n()):(h.addEventListener("load",r),h.addEventListener("error",i));else n()}function a(e){return u?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&d(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function d(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var l="import",u=Boolean(l in document.createElement("link")),h=Boolean(window.ShadowDOMPolyfill),f=function(e){return h?ShadowDOMPolyfill.wrapIfNeeded(e):e},p=f(document),m={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return f(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(p,"_currentScript",m);var v=/Trident|Edge/.test(navigator.userAgent),_=v?"complete":"interactive",g="readystatechange";u&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)d(e)}()),t(function(e){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var t=p.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),p.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=l,e.useNative=u,e.rootDocument=p,e.whenReady=t,e.isIE=v}(HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e,t){var n=e.ownerDocument,r=n.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,r),e},resolveUrlsInCssText:function(e,r,o){var i=this.replaceUrls(e,o,r,t);return i=this.replaceUrls(i,o,r,n)},replaceUrls:function(e,t,n,r){return e.replace(r,function(e,r,o,i){var a=o.replace(/["']/g,"");return n&&(a=new URL(a,n).href),t.href=a,a=t.href,r+"'"+a+"'"+i})}};e.path=r}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var n=i.getResponseHeader("Location"),a=null;if(n)var a="/"===n.substr(0,1)?location.origin+n:n;r.call(o,!t.ok(i)&&i,i.response||i.responseText,a)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===l}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,d=e.isIE,l=e.IMPORT_LINK_TYPE,u="link[rel="+l+"]",h={documentSelectors:u,importsSelectors:[u,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(r){t&&t(r),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),d&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(t){r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r["import"],r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=h,e.IMPORT_SELECTOR=u}),HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,d=e.Loader,l=e.Observer,u=e.parser,h={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){f.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);f.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n["import"]=c}u.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),u.parseNext()},loadedAll:function(){u.parseNext()}},f=new d(h.loaded.bind(h),h.loadedAll.bind(h));if(h.observer=new l,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(c,"baseURI",p)}e.importer=h,e.importLoader=f}),HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(o)}var n=e.initializeModules,r=e.isIE;if(!e.useNative){r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),n();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],r=function(e){n.push(e)},o=function(){n.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void r(e,t)}),r(e,t)}function n(e,t,r){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,r)!==!0&&n(o,t,r),o=o.nextElementSibling;return null}function r(e,n){for(var r=e.shadowRoot;r;)t(r,n),r=r.olderShadowRoot}function o(e,t){i(e,t,[])}function i(e,t,n){if(e=wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var r,o=e.querySelectorAll("link[rel="+a+"]"),s=0,c=o.length;c>s&&(r=o[s]);s++)r["import"]&&i(r["import"],t,n);t(e)}}var a=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return n(e)||r(e)}function n(t){return e.upgrade(t)?!0:void s(t)}function r(e){w(e,function(e){return n(e)?!0:void 0})}function o(e){s(e),h(e)&&w(e,function(e){s(e)})}function i(e){M.push(e),L||(L=!0,setTimeout(a))}function a(){L=!1;for(var e,t=M,n=0,r=t.length;r>n&&(e=t[n]);n++)e();M=[]}function s(e){E?i(function(){c(e)}):c(e)}function c(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&h(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function d(e){l(e),w(e,function(e){l(e)})}function l(e){E?i(function(){u(e)}):u(e)}function u(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!h(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function h(e){for(var t=e,n=wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function f(e){if(e.shadowRoot&&!e.shadowRoot.__watched){b.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)v(t),t=t.olderShadowRoot}}function p(e){if(b.dom){var n=e[0];if(n&&"childList"===n.type&&n.addedNodes&&n.addedNodes){for(var r=n.addedNodes[0];r&&r!==document&&!r.host;)r=r.parentNode;var o=r&&(r.URL||r._URL||r.host&&r.host.localName)||"";o=o.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,o||"")}e.forEach(function(e){"childList"===e.type&&(T(e.addedNodes,function(e){e.localName&&t(e)}),T(e.removedNodes,function(e){e.localName&&d(e)}))}),b.dom&&console.groupEnd()}function m(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(p(t.takeRecords()),a())}function v(e){if(!e.__observer){var t=new MutationObserver(p);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function _(e){e=wrap(e),b.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),v(e),b.dom&&console.groupEnd()}function g(e){y(e,_)}var b=e.flags,w=e.forSubtree,y=e.forDocumentTree,E=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=E;var L=!1,M=[],T=Array.prototype.forEach.call.bind(Array.prototype.forEach),N=Element.prototype.createShadowRoot;N&&(Element.prototype.createShadowRoot=function(){var e=N.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=f,e.upgradeDocumentTree=g,e.upgradeSubtree=r,e.upgradeAll=t,e.attachedNode=o,e.takeRecords=m}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var r=t.getAttribute("is"),o=e.getRegisteredDefinition(r||t.localName);if(o){if(r&&o.tag==t.localName)return n(t,o);if(!r&&!o["extends"])return n(t,o)}}}function n(t,n){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),r(t,n),t.__upgraded__=!0,i(t),e.attachedNode(t),e.upgradeSubtree(t),a.upgrade&&console.groupEnd(),t}function r(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,n){for(var r={},o=t;o!==n&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)r[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),r[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=r}),CustomElements.addModule(function(e){function t(t,r){var c=r||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(d(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),l(c.__name,c),c.ctor=u(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&_(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){r.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){r.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function r(e,t,n){e=e.toLowerCase();var r=this.getAttribute(e);n.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==r&&this.attributeChangedCallback(e,r,o)}function o(e){for(var t=0;t<E.length;t++)if(e===E[t])return!0}function i(e){var t=d(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,n=e["extends"],r=0;t=e.ancestry[r];r++)n=t.is&&t.tag;e.tag=n||e.__name,n&&(e.is=e.__name)}function s(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var n=document.createElement(e.tag),r=Object.getPrototypeOf(n);r===e.prototype&&(t=r)}for(var o,i=e.prototype;i&&i!==t;)o=Object.getPrototypeOf(i),
+i.__proto__=o,i=o;e["native"]=t}}function c(e){return b(T(e.tag),e)}function d(e){return e?L[e.toLowerCase()]:void 0}function l(e,t){L[e]=t}function u(e){return function(){return c(e)}}function h(e,t,n){return e===M?f(t,n):N(e,t)}function f(e,t){var n=d(t||e);if(n){if(e==n.tag&&t==n.is)return new n.ctor;if(!t&&!n.is)return new n.ctor}var r;return t?(r=f(e),r.setAttribute("is",t),r):(r=T(e),e.indexOf("-")>=0&&w(r,HTMLElement),r)}function p(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return g(e),e}}var m,v=e.isIE11OrOlder,_=e.upgradeDocumentTree,g=e.upgradeAll,b=e.upgradeWithDefinition,w=e.implementPrototype,y=e.useNative,E=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],L={},M="http://www.w3.org/1999/xhtml",T=document.createElement.bind(document),N=document.createElementNS.bind(document);m=Object.__proto__||y?function(e,t){return e instanceof t}:function(e,t){for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},p(Node.prototype,"cloneNode"),p(document,"importNode"),v&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType==t.DOCUMENT_FRAGMENT_NODE){var n=document.createDocumentFragment();return n.appendChild(t),n}return t}}(),document.registerElement=t,document.createElement=f,document.createElementNS=h,e.registry=L,e["instanceof"]=m,e.reservedTagList=E,e.getRegisteredDefinition=d,document.register=document.registerElement}),function(e){function t(){a(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){a(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var n=e.useNative,r=e.initializeModules,o=/Trident/.test(navigator.userAgent);if(n){var i=function(){};e.watchShadow=i,e.upgrade=i,e.upgradeAll=i,e.upgradeDocumentTree=i,e.upgradeSubtree=i,e.takeRecords=i,e["instanceof"]=function(e,t){return e instanceof t}}else r();var a=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),o&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t();e.isIE11OrOlder=o}(window.CustomElements),"undefined"==typeof HTMLTemplateElement&&!function(){var e="template";HTMLTemplateElement=function(){},HTMLTemplateElement.prototype=Object.create(HTMLElement.prototype),HTMLTemplateElement.decorate=function(e){if(!e.content){e.content=e.ownerDocument.createDocumentFragment();for(var t;t=e.firstChild;)e.content.appendChild(t)}},HTMLTemplateElement.bootstrap=function(t){for(var n,r=t.querySelectorAll(e),o=0,i=r.length;i>o&&(n=r[o]);o++)HTMLTemplateElement.decorate(n)},addEventListener("DOMContentLoaded",function(){HTMLTemplateElement.bootstrap(document)})}(),function(e){var t=document.createElement("style");t.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var n=document.querySelector("head");n.insertBefore(t,n.firstChild)}(window.WebComponents); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.js
index 26f5d5bf6cc..b11ce5cafb4 100644
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.js
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.js
@@ -7,7 +7,7 @@
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
-// @version 0.5.5
+// @version 0.6.1
window.WebComponents = window.WebComponents || {};
(function(scope) {
@@ -26,7 +26,7 @@ window.WebComponents = window.WebComponents || {};
}
}
}
- if (flags.log) {
+ if (flags.log && flags.log.split) {
var parts = flags.log.split(",");
flags.log = {};
parts.forEach(function(f) {
@@ -188,7 +188,7 @@ if (WebComponents.flags.shadow) {
return /^on[a-z]+$/.test(name);
}
function isIdentifierName(name) {
- return /^\w[a-zA-Z_0-9]*$/.test(name);
+ return /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(name);
}
function getGetter(name) {
return hasEval && isIdentifierName(name) ? new Function("return this.__impl4cf1e782hg__." + name) : function() {
@@ -344,6 +344,7 @@ if (WebComponents.flags.shadow) {
scope.defineGetter = defineGetter;
scope.defineWrapGetter = defineWrapGetter;
scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
+ scope.isIdentifierName = isIdentifierName;
scope.isWrapper = isWrapper;
scope.isWrapperFor = isWrapperFor;
scope.mixin = mixin;
@@ -1764,6 +1765,7 @@ if (WebComponents.flags.shadow) {
var OriginalDocumentFragment = window.DocumentFragment;
var originalAppendChild = OriginalNode.prototype.appendChild;
var originalCompareDocumentPosition = OriginalNode.prototype.compareDocumentPosition;
+ var originalIsEqualNode = OriginalNode.prototype.isEqualNode;
var originalInsertBefore = OriginalNode.prototype.insertBefore;
var originalRemoveChild = OriginalNode.prototype.removeChild;
var originalReplaceChild = OriginalNode.prototype.replaceChild;
@@ -1992,6 +1994,9 @@ if (WebComponents.flags.shadow) {
compareDocumentPosition: function(otherNode) {
return originalCompareDocumentPosition.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));
},
+ isEqualNode: function(otherNode) {
+ return originalIsEqualNode.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode));
+ },
normalize: function() {
var nodes = snapshotNodeList(this.childNodes);
var remNodes = [];
@@ -2068,10 +2073,10 @@ if (WebComponents.flags.shadow) {
return index;
}
function shimSelector(selector) {
- return String(selector).replace(/\/deep\/|::shadow/g, " ");
+ return String(selector).replace(/\/deep\/|::shadow|>>>/g, " ");
}
function shimMatchesSelector(selector) {
- return String(selector).replace(/:host\(([^\s]+)\)/g, "$1").replace(/([^\s]):host/g, "$1").replace(":host", "*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content/g, " ");
+ return String(selector).replace(/:host\(([^\s]+)\)/g, "$1").replace(/([^\s]):host/g, "$1").replace(":host", "*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content|>>>/g, " ");
}
function findOne(node, selector) {
var m, el = node.firstElementChild;
@@ -2292,6 +2297,12 @@ if (WebComponents.flags.shadow) {
}
CharacterData.prototype = Object.create(Node.prototype);
mixin(CharacterData.prototype, {
+ get nodeValue() {
+ return this.data;
+ },
+ set nodeValue(data) {
+ this.data = data;
+ },
get textContent() {
return this.data;
},
@@ -3271,30 +3282,129 @@ if (WebComponents.flags.shadow) {
})(window.ShadowDOMPolyfill);
(function(scope) {
"use strict";
+ var GetElementsByInterface = scope.GetElementsByInterface;
+ var ParentNodeInterface = scope.ParentNodeInterface;
+ var SelectorsInterface = scope.SelectorsInterface;
+ var mixin = scope.mixin;
+ var registerObject = scope.registerObject;
+ var DocumentFragment = registerObject(document.createDocumentFragment());
+ mixin(DocumentFragment.prototype, ParentNodeInterface);
+ mixin(DocumentFragment.prototype, SelectorsInterface);
+ mixin(DocumentFragment.prototype, GetElementsByInterface);
+ var Comment = registerObject(document.createComment(""));
+ scope.wrappers.Comment = Comment;
+ scope.wrappers.DocumentFragment = DocumentFragment;
+ })(window.ShadowDOMPolyfill);
+ (function(scope) {
+ "use strict";
+ var DocumentFragment = scope.wrappers.DocumentFragment;
+ var TreeScope = scope.TreeScope;
+ var elementFromPoint = scope.elementFromPoint;
+ var getInnerHTML = scope.getInnerHTML;
+ var getTreeScope = scope.getTreeScope;
+ var mixin = scope.mixin;
+ var rewrap = scope.rewrap;
+ var setInnerHTML = scope.setInnerHTML;
+ var unsafeUnwrap = scope.unsafeUnwrap;
+ var unwrap = scope.unwrap;
+ var shadowHostTable = new WeakMap();
+ var nextOlderShadowTreeTable = new WeakMap();
+ var spaceCharRe = /[ \t\n\r\f]/;
+ function ShadowRoot(hostWrapper) {
+ var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment());
+ DocumentFragment.call(this, node);
+ rewrap(node, this);
+ var oldShadowRoot = hostWrapper.shadowRoot;
+ nextOlderShadowTreeTable.set(this, oldShadowRoot);
+ this.treeScope_ = new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
+ shadowHostTable.set(this, hostWrapper);
+ }
+ ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
+ mixin(ShadowRoot.prototype, {
+ constructor: ShadowRoot,
+ get innerHTML() {
+ return getInnerHTML(this);
+ },
+ set innerHTML(value) {
+ setInnerHTML(this, value);
+ this.invalidateShadowRenderer();
+ },
+ get olderShadowRoot() {
+ return nextOlderShadowTreeTable.get(this) || null;
+ },
+ get host() {
+ return shadowHostTable.get(this) || null;
+ },
+ invalidateShadowRenderer: function() {
+ return shadowHostTable.get(this).invalidateShadowRenderer();
+ },
+ elementFromPoint: function(x, y) {
+ return elementFromPoint(this, this.ownerDocument, x, y);
+ },
+ getElementById: function(id) {
+ if (spaceCharRe.test(id)) return null;
+ return this.querySelector('[id="' + id + '"]');
+ }
+ });
+ scope.wrappers.ShadowRoot = ShadowRoot;
+ })(window.ShadowDOMPolyfill);
+ (function(scope) {
+ "use strict";
var registerWrapper = scope.registerWrapper;
var setWrapper = scope.setWrapper;
var unsafeUnwrap = scope.unsafeUnwrap;
var unwrap = scope.unwrap;
var unwrapIfNeeded = scope.unwrapIfNeeded;
var wrap = scope.wrap;
+ var getTreeScope = scope.getTreeScope;
var OriginalRange = window.Range;
+ var ShadowRoot = scope.wrappers.ShadowRoot;
+ function getHost(node) {
+ var root = getTreeScope(node).root;
+ if (root instanceof ShadowRoot) {
+ return root.host;
+ }
+ return null;
+ }
+ function hostNodeToShadowNode(refNode, offset) {
+ if (refNode.shadowRoot) {
+ offset = Math.min(refNode.childNodes.length - 1, offset);
+ var child = refNode.childNodes[offset];
+ if (child) {
+ var insertionPoint = scope.getDestinationInsertionPoints(child);
+ if (insertionPoint.length > 0) {
+ var parentNode = insertionPoint[0].parentNode;
+ if (parentNode.nodeType == Node.ELEMENT_NODE) {
+ refNode = parentNode;
+ }
+ }
+ }
+ }
+ return refNode;
+ }
+ function shadowNodeToHostNode(node) {
+ node = wrap(node);
+ return getHost(node) || node;
+ }
function Range(impl) {
setWrapper(impl, this);
}
Range.prototype = {
get startContainer() {
- return wrap(unsafeUnwrap(this).startContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).startContainer);
},
get endContainer() {
- return wrap(unsafeUnwrap(this).endContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).endContainer);
},
get commonAncestorContainer() {
- return wrap(unsafeUnwrap(this).commonAncestorContainer);
+ return shadowNodeToHostNode(unsafeUnwrap(this).commonAncestorContainer);
},
setStart: function(refNode, offset) {
+ refNode = hostNodeToShadowNode(refNode, offset);
unsafeUnwrap(this).setStart(unwrapIfNeeded(refNode), offset);
},
setEnd: function(refNode, offset) {
+ refNode = hostNodeToShadowNode(refNode, offset);
unsafeUnwrap(this).setEnd(unwrapIfNeeded(refNode), offset);
},
setStartBefore: function(refNode) {
@@ -3356,74 +3466,6 @@ if (WebComponents.flags.shadow) {
})(window.ShadowDOMPolyfill);
(function(scope) {
"use strict";
- var GetElementsByInterface = scope.GetElementsByInterface;
- var ParentNodeInterface = scope.ParentNodeInterface;
- var SelectorsInterface = scope.SelectorsInterface;
- var mixin = scope.mixin;
- var registerObject = scope.registerObject;
- var DocumentFragment = registerObject(document.createDocumentFragment());
- mixin(DocumentFragment.prototype, ParentNodeInterface);
- mixin(DocumentFragment.prototype, SelectorsInterface);
- mixin(DocumentFragment.prototype, GetElementsByInterface);
- var Comment = registerObject(document.createComment(""));
- scope.wrappers.Comment = Comment;
- scope.wrappers.DocumentFragment = DocumentFragment;
- })(window.ShadowDOMPolyfill);
- (function(scope) {
- "use strict";
- var DocumentFragment = scope.wrappers.DocumentFragment;
- var TreeScope = scope.TreeScope;
- var elementFromPoint = scope.elementFromPoint;
- var getInnerHTML = scope.getInnerHTML;
- var getTreeScope = scope.getTreeScope;
- var mixin = scope.mixin;
- var rewrap = scope.rewrap;
- var setInnerHTML = scope.setInnerHTML;
- var unsafeUnwrap = scope.unsafeUnwrap;
- var unwrap = scope.unwrap;
- var shadowHostTable = new WeakMap();
- var nextOlderShadowTreeTable = new WeakMap();
- var spaceCharRe = /[ \t\n\r\f]/;
- function ShadowRoot(hostWrapper) {
- var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment());
- DocumentFragment.call(this, node);
- rewrap(node, this);
- var oldShadowRoot = hostWrapper.shadowRoot;
- nextOlderShadowTreeTable.set(this, oldShadowRoot);
- this.treeScope_ = new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
- shadowHostTable.set(this, hostWrapper);
- }
- ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
- mixin(ShadowRoot.prototype, {
- constructor: ShadowRoot,
- get innerHTML() {
- return getInnerHTML(this);
- },
- set innerHTML(value) {
- setInnerHTML(this, value);
- this.invalidateShadowRenderer();
- },
- get olderShadowRoot() {
- return nextOlderShadowTreeTable.get(this) || null;
- },
- get host() {
- return shadowHostTable.get(this) || null;
- },
- invalidateShadowRenderer: function() {
- return shadowHostTable.get(this).invalidateShadowRenderer();
- },
- elementFromPoint: function(x, y) {
- return elementFromPoint(this, this.ownerDocument, x, y);
- },
- getElementById: function(id) {
- if (spaceCharRe.test(id)) return null;
- return this.querySelector('[id="' + id + '"]');
- }
- });
- scope.wrappers.ShadowRoot = ShadowRoot;
- })(window.ShadowDOMPolyfill);
- (function(scope) {
- "use strict";
var Element = scope.wrappers.Element;
var HTMLContentElement = scope.wrappers.HTMLContentElement;
var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
@@ -3874,7 +3916,7 @@ if (WebComponents.flags.shadow) {
return wrap(unsafeUnwrap(this).focusNode);
},
addRange: function(range) {
- unsafeUnwrap(this).addRange(unwrap(range));
+ unsafeUnwrap(this).addRange(unwrapIfNeeded(range));
},
collapse: function(node, index) {
unsafeUnwrap(this).collapse(unwrapIfNeeded(node), index);
@@ -3882,9 +3924,6 @@ if (WebComponents.flags.shadow) {
containsNode: function(node, allowPartial) {
return unsafeUnwrap(this).containsNode(unwrapIfNeeded(node), allowPartial);
},
- extend: function(node, offset) {
- unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);
- },
getRangeAt: function(index) {
return wrap(unsafeUnwrap(this).getRangeAt(index));
},
@@ -3898,11 +3937,62 @@ if (WebComponents.flags.shadow) {
return unsafeUnwrap(this).toString();
}
};
+ if (OriginalSelection.prototype.extend) {
+ Selection.prototype.extend = function(node, offset) {
+ unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);
+ };
+ }
registerWrapper(window.Selection, Selection, window.getSelection());
scope.wrappers.Selection = Selection;
})(window.ShadowDOMPolyfill);
(function(scope) {
"use strict";
+ var registerWrapper = scope.registerWrapper;
+ var setWrapper = scope.setWrapper;
+ var unsafeUnwrap = scope.unsafeUnwrap;
+ var unwrapIfNeeded = scope.unwrapIfNeeded;
+ var wrap = scope.wrap;
+ var OriginalTreeWalker = window.TreeWalker;
+ function TreeWalker(impl) {
+ setWrapper(impl, this);
+ }
+ TreeWalker.prototype = {
+ get root() {
+ return wrap(unsafeUnwrap(this).root);
+ },
+ get currentNode() {
+ return wrap(unsafeUnwrap(this).currentNode);
+ },
+ set currentNode(node) {
+ unsafeUnwrap(this).currentNode = unwrapIfNeeded(node);
+ },
+ get filter() {
+ return unsafeUnwrap(this).filter;
+ },
+ parentNode: function() {
+ return wrap(unsafeUnwrap(this).parentNode());
+ },
+ firstChild: function() {
+ return wrap(unsafeUnwrap(this).firstChild());
+ },
+ lastChild: function() {
+ return wrap(unsafeUnwrap(this).lastChild());
+ },
+ previousSibling: function() {
+ return wrap(unsafeUnwrap(this).previousSibling());
+ },
+ previousNode: function() {
+ return wrap(unsafeUnwrap(this).previousNode());
+ },
+ nextNode: function() {
+ return wrap(unsafeUnwrap(this).nextNode());
+ }
+ };
+ registerWrapper(OriginalTreeWalker, TreeWalker);
+ scope.wrappers.TreeWalker = TreeWalker;
+ })(window.ShadowDOMPolyfill);
+ (function(scope) {
+ "use strict";
var GetElementsByInterface = scope.GetElementsByInterface;
var Node = scope.wrappers.Node;
var ParentNodeInterface = scope.ParentNodeInterface;
@@ -3978,6 +4068,25 @@ if (WebComponents.flags.shadow) {
return SelectorsInterface.querySelectorAll.call(this, "[name=" + JSON.stringify(String(name)) + "]");
}
});
+ var originalCreateTreeWalker = document.createTreeWalker;
+ var TreeWalkerWrapper = scope.wrappers.TreeWalker;
+ Document.prototype.createTreeWalker = function(root, whatToShow, filter, expandEntityReferences) {
+ var newFilter = null;
+ if (filter) {
+ if (filter.acceptNode && typeof filter.acceptNode === "function") {
+ newFilter = {
+ acceptNode: function(node) {
+ return filter.acceptNode(wrap(node));
+ }
+ };
+ } else if (typeof filter === "function") {
+ newFilter = function(node) {
+ return filter(wrap(node));
+ };
+ }
+ }
+ return new TreeWalkerWrapper(originalCreateTreeWalker.call(unwrap(this), unwrap(root), whatToShow, newFilter, expandEntityReferences));
+ };
if (document.registerElement) {
var originalRegisterElement = document.registerElement;
Document.prototype.registerElement = function(tagName, object) {
@@ -4041,7 +4150,7 @@ if (WebComponents.flags.shadow) {
}
forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLDocument || window.Document, window.HTMLHeadElement, window.HTMLHtmlElement ], [ "appendChild", "compareDocumentPosition", "contains", "getElementsByClassName", "getElementsByTagName", "getElementsByTagNameNS", "insertBefore", "querySelector", "querySelectorAll", "removeChild", "replaceChild" ]);
forwardMethodsToWrapper([ window.HTMLBodyElement, window.HTMLHeadElement, window.HTMLHtmlElement ], matchesNames);
- forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ "adoptNode", "importNode", "contains", "createComment", "createDocumentFragment", "createElement", "createElementNS", "createEvent", "createEventNS", "createRange", "createTextNode", "elementFromPoint", "getElementById", "getElementsByName", "getSelection" ]);
+ forwardMethodsToWrapper([ window.HTMLDocument || window.Document ], [ "adoptNode", "importNode", "contains", "createComment", "createDocumentFragment", "createElement", "createElementNS", "createEvent", "createEventNS", "createRange", "createTextNode", "createTreeWalker", "elementFromPoint", "getElementById", "getElementsByName", "getSelection" ]);
mixin(Document.prototype, GetElementsByInterface);
mixin(Document.prototype, ParentNodeInterface);
mixin(Document.prototype, SelectorsInterface);
@@ -4556,7 +4665,7 @@ if (WebComponents.flags.shadow) {
}
};
var selectorRe = /([^{]*)({[\s\S]*?})/gim, cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, cssCommentNextSelectorRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim, cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim, cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim, cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim, cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim, cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim, cssPseudoRe = /::(x-[^\s{,(]*)/gim, cssPartRe = /::part\(([^)]*)\)/gim, polyfillHost = "-shadowcsshost", polyfillHostContext = "-shadowcsscontext", parenSuffix = ")(?:\\((" + "(?:\\([^)(]*\\)|[^)(]*)+?" + ")\\))?([^,{]*)";
- var cssColonHostRe = new RegExp("(" + polyfillHost + parenSuffix, "gim"), cssColonHostContextRe = new RegExp("(" + polyfillHostContext + parenSuffix, "gim"), selectorReSuffix = "([>\\s~+[.,{:][\\s\\S]*)?$", colonHostRe = /\:host/gim, colonHostContextRe = /\:host-context/gim, polyfillHostNoCombinator = polyfillHost + "-no-combinator", polyfillHostRe = new RegExp(polyfillHost, "gim"), polyfillHostContextRe = new RegExp(polyfillHostContext, "gim"), shadowDOMSelectorsRe = [ /\^\^/g, /\^/g, /\/shadow\//g, /\/shadow-deep\//g, /::shadow/g, /\/deep\//g, /::content/g ];
+ var cssColonHostRe = new RegExp("(" + polyfillHost + parenSuffix, "gim"), cssColonHostContextRe = new RegExp("(" + polyfillHostContext + parenSuffix, "gim"), selectorReSuffix = "([>\\s~+[.,{:][\\s\\S]*)?$", colonHostRe = /\:host/gim, colonHostContextRe = /\:host-context/gim, polyfillHostNoCombinator = polyfillHost + "-no-combinator", polyfillHostRe = new RegExp(polyfillHost, "gim"), polyfillHostContextRe = new RegExp(polyfillHostContext, "gim"), shadowDOMSelectorsRe = [ />>>/g, /::shadow/g, /::content/g, /\/deep\//g, /\/shadow\//g, /\/shadow-deep\//g, /\^\^/g, /\^/g ];
function stylesToCssText(styles, preserveComments) {
var cssText = "";
Array.prototype.forEach.call(styles, function(s) {
@@ -4678,7 +4787,7 @@ if (WebComponents.flags.shadow) {
style = elt.ownerDocument.createElement("style");
style.textContent = elt.__resource;
}
- HTMLImports.path.resolveUrlsInStyle(style);
+ HTMLImports.path.resolveUrlsInStyle(style, elt.href);
style.textContent = ShadowCSS.shimStyle(style);
style.removeAttribute(SHIM_ATTRIBUTE, "");
style.setAttribute(SHIMMED_ATTRIBUTE, "");
@@ -4720,6 +4829,817 @@ if (WebComponents.flags.shadow) {
}
})(window.WebComponents);
+(function(scope) {
+ "use strict";
+ var hasWorkingUrl = false;
+ if (!scope.forceJURL) {
+ try {
+ var u = new URL("b", "http://a");
+ u.pathname = "c%20d";
+ hasWorkingUrl = u.href === "http://a/c%20d";
+ } catch (e) {}
+ }
+ if (hasWorkingUrl) return;
+ var relative = Object.create(null);
+ relative["ftp"] = 21;
+ relative["file"] = 0;
+ relative["gopher"] = 70;
+ relative["http"] = 80;
+ relative["https"] = 443;
+ relative["ws"] = 80;
+ relative["wss"] = 443;
+ var relativePathDotMapping = Object.create(null);
+ relativePathDotMapping["%2e"] = ".";
+ relativePathDotMapping[".%2e"] = "..";
+ relativePathDotMapping["%2e."] = "..";
+ relativePathDotMapping["%2e%2e"] = "..";
+ function isRelativeScheme(scheme) {
+ return relative[scheme] !== undefined;
+ }
+ function invalid() {
+ clear.call(this);
+ this._isInvalid = true;
+ }
+ function IDNAToASCII(h) {
+ if ("" == h) {
+ invalid.call(this);
+ }
+ return h.toLowerCase();
+ }
+ function percentEscape(c) {
+ var unicode = c.charCodeAt(0);
+ if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 63, 96 ].indexOf(unicode) == -1) {
+ return c;
+ }
+ return encodeURIComponent(c);
+ }
+ function percentEscapeQuery(c) {
+ var unicode = c.charCodeAt(0);
+ if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 96 ].indexOf(unicode) == -1) {
+ return c;
+ }
+ return encodeURIComponent(c);
+ }
+ var EOF = undefined, ALPHA = /[a-zA-Z]/, ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
+ function parse(input, stateOverride, base) {
+ function err(message) {
+ errors.push(message);
+ }
+ var state = stateOverride || "scheme start", cursor = 0, buffer = "", seenAt = false, seenBracket = false, errors = [];
+ loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
+ var c = input[cursor];
+ switch (state) {
+ case "scheme start":
+ if (c && ALPHA.test(c)) {
+ buffer += c.toLowerCase();
+ state = "scheme";
+ } else if (!stateOverride) {
+ buffer = "";
+ state = "no scheme";
+ continue;
+ } else {
+ err("Invalid scheme.");
+ break loop;
+ }
+ break;
+
+ case "scheme":
+ if (c && ALPHANUMERIC.test(c)) {
+ buffer += c.toLowerCase();
+ } else if (":" == c) {
+ this._scheme = buffer;
+ buffer = "";
+ if (stateOverride) {
+ break loop;
+ }
+ if (isRelativeScheme(this._scheme)) {
+ this._isRelative = true;
+ }
+ if ("file" == this._scheme) {
+ state = "relative";
+ } else if (this._isRelative && base && base._scheme == this._scheme) {
+ state = "relative or authority";
+ } else if (this._isRelative) {
+ state = "authority first slash";
+ } else {
+ state = "scheme data";
+ }
+ } else if (!stateOverride) {
+ buffer = "";
+ cursor = 0;
+ state = "no scheme";
+ continue;
+ } else if (EOF == c) {
+ break loop;
+ } else {
+ err("Code point not allowed in scheme: " + c);
+ break loop;
+ }
+ break;
+
+ case "scheme data":
+ if ("?" == c) {
+ query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ } else {
+ if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._schemeData += percentEscape(c);
+ }
+ }
+ break;
+
+ case "no scheme":
+ if (!base || !isRelativeScheme(base._scheme)) {
+ err("Missing scheme.");
+ invalid.call(this);
+ } else {
+ state = "relative";
+ continue;
+ }
+ break;
+
+ case "relative or authority":
+ if ("/" == c && "/" == input[cursor + 1]) {
+ state = "authority ignore slashes";
+ } else {
+ err("Expected /, got: " + c);
+ state = "relative";
+ continue;
+ }
+ break;
+
+ case "relative":
+ this._isRelative = true;
+ if ("file" != this._scheme) this._scheme = base._scheme;
+ if (EOF == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = base._query;
+ break loop;
+ } else if ("/" == c || "\\" == c) {
+ if ("\\" == c) err("\\ is an invalid code point.");
+ state = "relative slash";
+ } else if ("?" == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._query = base._query;
+ this._fragment = "#";
+ state = "fragment";
+ } else {
+ var nextC = input[cursor + 1];
+ var nextNextC = input[cursor + 2];
+ if ("file" != this._scheme || !ALPHA.test(c) || nextC != ":" && nextC != "|" || EOF != nextNextC && "/" != nextNextC && "\\" != nextNextC && "?" != nextNextC && "#" != nextNextC) {
+ this._host = base._host;
+ this._port = base._port;
+ this._path = base._path.slice();
+ this._path.pop();
+ }
+ state = "relative path";
+ continue;
+ }
+ break;
+
+ case "relative slash":
+ if ("/" == c || "\\" == c) {
+ if ("\\" == c) {
+ err("\\ is an invalid code point.");
+ }
+ if ("file" == this._scheme) {
+ state = "file host";
+ } else {
+ state = "authority ignore slashes";
+ }
+ } else {
+ if ("file" != this._scheme) {
+ this._host = base._host;
+ this._port = base._port;
+ }
+ state = "relative path";
+ continue;
+ }
+ break;
+
+ case "authority first slash":
+ if ("/" == c) {
+ state = "authority second slash";
+ } else {
+ err("Expected '/', got: " + c);
+ state = "authority ignore slashes";
+ continue;
+ }
+ break;
+
+ case "authority second slash":
+ state = "authority ignore slashes";
+ if ("/" != c) {
+ err("Expected '/', got: " + c);
+ continue;
+ }
+ break;
+
+ case "authority ignore slashes":
+ if ("/" != c && "\\" != c) {
+ state = "authority";
+ continue;
+ } else {
+ err("Expected authority, got: " + c);
+ }
+ break;
+
+ case "authority":
+ if ("@" == c) {
+ if (seenAt) {
+ err("@ already seen.");
+ buffer += "%40";
+ }
+ seenAt = true;
+ for (var i = 0; i < buffer.length; i++) {
+ var cp = buffer[i];
+ if (" " == cp || "\n" == cp || "\r" == cp) {
+ err("Invalid whitespace in authority.");
+ continue;
+ }
+ if (":" == cp && null === this._password) {
+ this._password = "";
+ continue;
+ }
+ var tempC = percentEscape(cp);
+ null !== this._password ? this._password += tempC : this._username += tempC;
+ }
+ buffer = "";
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ cursor -= buffer.length;
+ buffer = "";
+ state = "host";
+ continue;
+ } else {
+ buffer += c;
+ }
+ break;
+
+ case "file host":
+ if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ":" || buffer[1] == "|")) {
+ state = "relative path";
+ } else if (buffer.length == 0) {
+ state = "relative path start";
+ } else {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "relative path start";
+ }
+ continue;
+ } else if (" " == c || "\n" == c || "\r" == c) {
+ err("Invalid whitespace in file host.");
+ } else {
+ buffer += c;
+ }
+ break;
+
+ case "host":
+ case "hostname":
+ if (":" == c && !seenBracket) {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "port";
+ if ("hostname" == stateOverride) {
+ break loop;
+ }
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
+ this._host = IDNAToASCII.call(this, buffer);
+ buffer = "";
+ state = "relative path start";
+ if (stateOverride) {
+ break loop;
+ }
+ continue;
+ } else if (" " != c && "\n" != c && "\r" != c) {
+ if ("[" == c) {
+ seenBracket = true;
+ } else if ("]" == c) {
+ seenBracket = false;
+ }
+ buffer += c;
+ } else {
+ err("Invalid code point in host/hostname: " + c);
+ }
+ break;
+
+ case "port":
+ if (/[0-9]/.test(c)) {
+ buffer += c;
+ } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c || stateOverride) {
+ if ("" != buffer) {
+ var temp = parseInt(buffer, 10);
+ if (temp != relative[this._scheme]) {
+ this._port = temp + "";
+ }
+ buffer = "";
+ }
+ if (stateOverride) {
+ break loop;
+ }
+ state = "relative path start";
+ continue;
+ } else if (" " == c || "\n" == c || "\r" == c) {
+ err("Invalid code point in port: " + c);
+ } else {
+ invalid.call(this);
+ }
+ break;
+
+ case "relative path start":
+ if ("\\" == c) err("'\\' not allowed in path.");
+ state = "relative path";
+ if ("/" != c && "\\" != c) {
+ continue;
+ }
+ break;
+
+ case "relative path":
+ if (EOF == c || "/" == c || "\\" == c || !stateOverride && ("?" == c || "#" == c)) {
+ if ("\\" == c) {
+ err("\\ not allowed in relative path.");
+ }
+ var tmp;
+ if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
+ buffer = tmp;
+ }
+ if (".." == buffer) {
+ this._path.pop();
+ if ("/" != c && "\\" != c) {
+ this._path.push("");
+ }
+ } else if ("." == buffer && "/" != c && "\\" != c) {
+ this._path.push("");
+ } else if ("." != buffer) {
+ if ("file" == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == "|") {
+ buffer = buffer[0] + ":";
+ }
+ this._path.push(buffer);
+ }
+ buffer = "";
+ if ("?" == c) {
+ this._query = "?";
+ state = "query";
+ } else if ("#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ }
+ } else if (" " != c && "\n" != c && "\r" != c) {
+ buffer += percentEscape(c);
+ }
+ break;
+
+ case "query":
+ if (!stateOverride && "#" == c) {
+ this._fragment = "#";
+ state = "fragment";
+ } else if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._query += percentEscapeQuery(c);
+ }
+ break;
+
+ case "fragment":
+ if (EOF != c && " " != c && "\n" != c && "\r" != c) {
+ this._fragment += c;
+ }
+ break;
+ }
+ cursor++;
+ }
+ }
+ function clear() {
+ this._scheme = "";
+ this._schemeData = "";
+ this._username = "";
+ this._password = null;
+ this._host = "";
+ this._port = "";
+ this._path = [];
+ this._query = "";
+ this._fragment = "";
+ this._isInvalid = false;
+ this._isRelative = false;
+ }
+ function jURL(url, base) {
+ if (base !== undefined && !(base instanceof jURL)) base = new jURL(String(base));
+ this._url = url;
+ clear.call(this);
+ var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, "");
+ parse.call(this, input, null, base);
+ }
+ jURL.prototype = {
+ toString: function() {
+ return this.href;
+ },
+ get href() {
+ if (this._isInvalid) return this._url;
+ var authority = "";
+ if ("" != this._username || null != this._password) {
+ authority = this._username + (null != this._password ? ":" + this._password : "") + "@";
+ }
+ return this.protocol + (this._isRelative ? "//" + authority + this.host : "") + this.pathname + this._query + this._fragment;
+ },
+ set href(href) {
+ clear.call(this);
+ parse.call(this, href);
+ },
+ get protocol() {
+ return this._scheme + ":";
+ },
+ set protocol(protocol) {
+ if (this._isInvalid) return;
+ parse.call(this, protocol + ":", "scheme start");
+ },
+ get host() {
+ return this._isInvalid ? "" : this._port ? this._host + ":" + this._port : this._host;
+ },
+ set host(host) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, host, "host");
+ },
+ get hostname() {
+ return this._host;
+ },
+ set hostname(hostname) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, hostname, "hostname");
+ },
+ get port() {
+ return this._port;
+ },
+ set port(port) {
+ if (this._isInvalid || !this._isRelative) return;
+ parse.call(this, port, "port");
+ },
+ get pathname() {
+ return this._isInvalid ? "" : this._isRelative ? "/" + this._path.join("/") : this._schemeData;
+ },
+ set pathname(pathname) {
+ if (this._isInvalid || !this._isRelative) return;
+ this._path = [];
+ parse.call(this, pathname, "relative path start");
+ },
+ get search() {
+ return this._isInvalid || !this._query || "?" == this._query ? "" : this._query;
+ },
+ set search(search) {
+ if (this._isInvalid || !this._isRelative) return;
+ this._query = "?";
+ if ("?" == search[0]) search = search.slice(1);
+ parse.call(this, search, "query");
+ },
+ get hash() {
+ return this._isInvalid || !this._fragment || "#" == this._fragment ? "" : this._fragment;
+ },
+ set hash(hash) {
+ if (this._isInvalid) return;
+ this._fragment = "#";
+ if ("#" == hash[0]) hash = hash.slice(1);
+ parse.call(this, hash, "fragment");
+ },
+ get origin() {
+ var host;
+ if (this._isInvalid || !this._scheme) {
+ return "";
+ }
+ switch (this._scheme) {
+ case "data":
+ case "file":
+ case "javascript":
+ case "mailto":
+ return "null";
+ }
+ host = this.host;
+ if (!host) {
+ return "";
+ }
+ return this._scheme + "://" + host;
+ }
+ };
+ var OriginalURL = scope.URL;
+ if (OriginalURL) {
+ jURL.createObjectURL = function(blob) {
+ return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
+ };
+ jURL.revokeObjectURL = function(url) {
+ OriginalURL.revokeObjectURL(url);
+ };
+ }
+ scope.URL = jURL;
+})(this);
+
+(function(global) {
+ var registrationsTable = new WeakMap();
+ var setImmediate;
+ if (/Trident|Edge/.test(navigator.userAgent)) {
+ setImmediate = setTimeout;
+ } else if (window.setImmediate) {
+ setImmediate = window.setImmediate;
+ } else {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener("message", function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, "*");
+ };
+ }
+ var isScheduled = false;
+ var scheduledObservers = [];
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
+ }
+ function dispatchCallbacks() {
+ isScheduled = false;
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+ var queue = observer.takeRecords();
+ removeTransientObserversFor(observer);
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+ if (anyNonEmpty) dispatchCallbacks();
+ }
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations) return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer) registration.removeTransientObservers();
+ });
+ });
+ }
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+ if (node !== target && !options.subtree) continue;
+ var record = callback(options);
+ if (record) registration.enqueue(record);
+ }
+ }
+ }
+ }
+ var uidCounter = 0;
+ function JsMutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+ JsMutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+ if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
+ throw new SyntaxError();
+ }
+ var registrations = registrationsTable.get(target);
+ if (!registrations) registrationsTable.set(target, registrations = []);
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+ registration.addListeners();
+ },
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ }
+ var currentRecord, recordWithOldValue;
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue) return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord) return lastRecord;
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
+ return null;
+ }
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+ records[length] = record;
+ },
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
+ },
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
+ if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
+ if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
+ if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
+ },
+ addTransientObserver: function(node) {
+ if (node === this.target) return;
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations) registrationsTable.set(node, registrations = []);
+ registrations.push(this);
+ },
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+ transientObservedNodes.forEach(function(node) {
+ this.removeListeners_(node);
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ break;
+ }
+ }
+ }, this);
+ },
+ handleEvent: function(e) {
+ e.stopImmediatePropagation();
+ switch (e.type) {
+ case "DOMAttrModified":
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+ var record = new getRecord("attributes", target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+ var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.attributes) return;
+ if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMCharacterDataModified":
+ var target = e.target;
+ var record = getRecord("characterData", target);
+ var oldValue = e.prevValue;
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ if (!options.characterData) return;
+ if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
+ return record;
+ });
+ break;
+
+ case "DOMNodeRemoved":
+ this.addTransientObserver(e.target);
+
+ case "DOMNodeInserted":
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === "DOMNodeInserted") {
+ addedNodes = [ changedNode ];
+ removedNodes = [];
+ } else {
+ addedNodes = [];
+ removedNodes = [ changedNode ];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+ var record = getRecord("childList", e.target.parentNode);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+ forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
+ if (!options.childList) return;
+ return record;
+ });
+ }
+ clearRecords();
+ }
+ };
+ global.JsMutationObserver = JsMutationObserver;
+ if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;
+})(this);
+
window.HTMLImports = window.HTMLImports || {
flags: {}
};
@@ -4771,26 +5691,35 @@ window.HTMLImports = window.HTMLImports || {
}
function watchImportsLoad(callback, doc) {
var imports = doc.querySelectorAll("link[rel=import]");
- var loaded = 0, l = imports.length;
- function checkDone(d) {
- if (loaded == l && callback) {
- callback();
+ var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];
+ function checkDone() {
+ if (parsedCount == importCount && callback) {
+ callback({
+ allImports: imports,
+ loadedImports: newImports,
+ errorImports: errorImports
+ });
}
}
function loadedImport(e) {
markTargetLoaded(e);
- loaded++;
+ newImports.push(this);
+ parsedCount++;
+ checkDone();
+ }
+ function errorLoadingImport(e) {
+ errorImports.push(this);
+ parsedCount++;
checkDone();
}
- if (l) {
- for (var i = 0, imp; i < l && (imp = imports[i]); i++) {
+ if (importCount) {
+ for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) {
if (isImportLoaded(imp)) {
- loadedImport.call(imp, {
- target: imp
- });
+ parsedCount++;
+ checkDone();
} else {
imp.addEventListener("load", loadedImport);
- imp.addEventListener("error", loadedImport);
+ imp.addEventListener("error", errorLoadingImport);
}
}
} else {
@@ -4840,11 +5769,11 @@ window.HTMLImports = window.HTMLImports || {
}
})();
}
- whenReady(function() {
+ whenReady(function(detail) {
HTMLImports.ready = true;
HTMLImports.readyTime = new Date().getTime();
var evt = rootDocument.createEvent("CustomEvent");
- evt.initCustomEvent("HTMLImportsLoaded", true, true, {});
+ evt.initCustomEvent("HTMLImportsLoaded", true, true, detail);
rootDocument.dispatchEvent(evt);
});
scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
@@ -4872,20 +5801,23 @@ HTMLImports.addModule(function(scope) {
var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
var path = {
- resolveUrlsInStyle: function(style) {
+ resolveUrlsInStyle: function(style, linkUrl) {
var doc = style.ownerDocument;
var resolver = doc.createElement("a");
- style.textContent = this.resolveUrlsInCssText(style.textContent, resolver);
+ style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver);
return style;
},
- resolveUrlsInCssText: function(cssText, urlObj) {
- var r = this.replaceUrls(cssText, urlObj, CSS_URL_REGEXP);
- r = this.replaceUrls(r, urlObj, CSS_IMPORT_REGEXP);
+ resolveUrlsInCssText: function(cssText, linkUrl, urlObj) {
+ var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP);
+ r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP);
return r;
},
- replaceUrls: function(text, urlObj, regexp) {
+ replaceUrls: function(text, urlObj, linkUrl, regexp) {
return text.replace(regexp, function(m, pre, url, post) {
var urlPath = url.replace(/["']/g, "");
+ if (linkUrl) {
+ urlPath = new URL(urlPath, linkUrl).href;
+ }
urlObj.href = urlPath;
urlPath = urlObj.href;
return pre + "'" + urlPath + "'" + post;
@@ -5153,6 +6085,7 @@ HTMLImports.addModule(function(scope) {
parseStyle: function(elt) {
var src = elt;
elt = cloneStyle(elt);
+ src.__appliedElement = elt;
elt.__importElement = src;
this.parseGeneric(elt);
},
@@ -5494,13 +6427,10 @@ CustomElements.addModule(function(scope) {
root = root.olderShadowRoot;
}
}
- var processingDocuments;
function forDocumentTree(doc, cb) {
- processingDocuments = [];
- _forDocumentTree(doc, cb);
- processingDocuments = null;
+ _forDocumentTree(doc, cb, []);
}
- function _forDocumentTree(doc, cb) {
+ function _forDocumentTree(doc, cb, processingDocuments) {
doc = wrap(doc);
if (processingDocuments.indexOf(doc) >= 0) {
return;
@@ -5509,7 +6439,7 @@ CustomElements.addModule(function(scope) {
var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
if (n.import) {
- _forDocumentTree(n.import, cb);
+ _forDocumentTree(n.import, cb, processingDocuments);
}
}
cb(doc);
@@ -5616,7 +6546,7 @@ CustomElements.addModule(function(scope) {
if (p == doc) {
return true;
}
- p = p.parentNode || p.host;
+ p = p.parentNode || p.nodeType === Node.DOCUMENT_FRAGMENT_NODE && p.host;
}
}
function watchShadow(node) {
@@ -5775,8 +6705,9 @@ CustomElements.addModule(function(scope) {
});
CustomElements.addModule(function(scope) {
+ var isIE11OrOlder = scope.isIE11OrOlder;
var upgradeDocumentTree = scope.upgradeDocumentTree;
- var upgrade = scope.upgrade;
+ var upgradeAll = scope.upgradeAll;
var upgradeWithDefinition = scope.upgradeWithDefinition;
var implementPrototype = scope.implementPrototype;
var useNative = scope.useNative;
@@ -5926,14 +6857,8 @@ CustomElements.addModule(function(scope) {
}
return element;
}
- function cloneNode(deep) {
- var n = domCloneNode.call(this, deep);
- upgrade(n);
- return n;
- }
var domCreateElement = document.createElement.bind(document);
var domCreateElementNS = document.createElementNS.bind(document);
- var domCloneNode = Node.prototype.cloneNode;
var isInstance;
if (!Object.__proto__ && !useNative) {
isInstance = function(obj, ctor) {
@@ -5951,10 +6876,34 @@ CustomElements.addModule(function(scope) {
return obj instanceof base;
};
}
+ function wrapDomMethodToForceUpgrade(obj, methodName) {
+ var orig = obj[methodName];
+ obj[methodName] = function() {
+ var n = orig.apply(this, arguments);
+ upgradeAll(n);
+ return n;
+ };
+ }
+ wrapDomMethodToForceUpgrade(Node.prototype, "cloneNode");
+ wrapDomMethodToForceUpgrade(document, "importNode");
+ if (isIE11OrOlder) {
+ (function() {
+ var importNode = document.importNode;
+ document.importNode = function() {
+ var n = importNode.apply(document, arguments);
+ if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
+ var f = document.createDocumentFragment();
+ f.appendChild(n);
+ return f;
+ } else {
+ return n;
+ }
+ };
+ })();
+ }
document.registerElement = register;
document.createElement = createElement;
document.createElementNS = createElementNS;
- Node.prototype.cloneNode = cloneNode;
scope.registry = registry;
scope.instanceof = isInstance;
scope.reservedTagList = reservedTagList;
@@ -6026,6 +6975,7 @@ CustomElements.addModule(function(scope) {
var loadEvent = window.HTMLImports && !HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
window.addEventListener(loadEvent, bootstrap);
}
+ scope.isIE11OrOlder = isIE11OrOlder;
})(window.CustomElements);
(function(scope) {
diff --git a/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.min.js b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.min.js
new file mode 100644
index 00000000000..0fa8b57549e
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer/components/webcomponentsjs/webcomponents.min.js
@@ -0,0 +1,16 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.6.1
+window.WebComponents=window.WebComponents||{},function(e){var t=e.flags||{},n="webcomponents.js",r=document.querySelector('script[src*="'+n+'"]');if(!t.noOpts){if(location.search.slice(1).split("&").forEach(function(e){e=e.split("="),e[0]&&(t[e[0]]=e[1]||!0)}),r)for(var o,i=0;o=r.attributes[i];i++)"src"!==o.name&&(t[o.name]=o.value||!0);if(t.log&&t.log.split){var a=t.log.split(",");t.log={},a.forEach(function(e){t.log[e]=!0})}else t.log={}}t.shadow=t.shadow||t.shadowdom||t.polyfill,t.shadow="native"===t.shadow?!1:t.shadow||!HTMLElement.prototype.createShadowRoot,t.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=t.register),e.flags=t}(WebComponents),WebComponents.flags.shadow&&("undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.ShadowDOMPolyfill={},function(e){"use strict";function t(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if(navigator.getDeviceStorage)return!1;try{var e=new Function("return true;");return e()}catch(t){return!1}}function n(e){if(!e)throw new Error("Assertion failed")}function r(e,t){for(var n=W(t),r=0;r<n.length;r++){var o=n[r];A(e,o,F(t,o))}return e}function o(e,t){for(var n=W(t),r=0;r<n.length;r++){var o=n[r];switch(o){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":continue}A(e,o,F(t,o))}return e}function i(e,t){for(var n=0;n<t.length;n++)if(t[n]in e)return t[n]}function a(e,t,n){U.value=n,A(e,t,U)}function s(e){var t=e.__proto__||Object.getPrototypeOf(e);if(q)try{W(t)}catch(n){t=t.__proto__}var r=R.get(t);if(r)return r;var o=s(t),i=E(o);return g(t,i,e),i}function c(e,t){w(e,t,!0)}function l(e,t){w(t,e,!1)}function u(e){return/^on[a-z]+$/.test(e)}function d(e){return/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(e)}function p(e){return k&&d(e)?new Function("return this.__impl4cf1e782hg__."+e):function(){return this.__impl4cf1e782hg__[e]}}function h(e){return k&&d(e)?new Function("v","this.__impl4cf1e782hg__."+e+" = v"):function(t){this.__impl4cf1e782hg__[e]=t}}function f(e){return k&&d(e)?new Function("return this.__impl4cf1e782hg__."+e+".apply(this.__impl4cf1e782hg__, arguments)"):function(){return this.__impl4cf1e782hg__[e].apply(this.__impl4cf1e782hg__,arguments)}}function m(e,t){try{return Object.getOwnPropertyDescriptor(e,t)}catch(n){return B}}function w(t,n,r,o){for(var i=W(t),a=0;a<i.length;a++){var s=i[a];if("polymerBlackList_"!==s&&!(s in n||t.polymerBlackList_&&t.polymerBlackList_[s])){q&&t.__lookupGetter__(s);var c,l,d=m(t,s);if(r&&"function"==typeof d.value)n[s]=f(s);else{var w=u(s);c=w?e.getEventHandlerGetter(s):p(s),(d.writable||d.set||V)&&(l=w?e.getEventHandlerSetter(s):h(s));var v=V||d.configurable;A(n,s,{get:c,set:l,configurable:v,enumerable:d.enumerable})}}}}function v(e,t,n){var r=e.prototype;g(r,t,n),o(t,e)}function g(e,t,r){var o=t.prototype;n(void 0===R.get(e)),R.set(e,t),I.set(o,e),c(e,o),r&&l(o,r),a(o,"constructor",t),t.prototype=o}function b(e,t){return R.get(t.prototype)===e}function y(e){var t=Object.getPrototypeOf(e),n=s(t),r=E(n);return g(t,r,e),r}function E(e){function t(t){e.call(this,t)}var n=Object.create(e.prototype);return n.constructor=t,t.prototype=n,t}function _(e){return e&&e.__impl4cf1e782hg__}function S(e){return!_(e)}function T(e){return null===e?null:(n(S(e)),e.__wrapper8e3dd93a60__||(e.__wrapper8e3dd93a60__=new(s(e))(e)))}function M(e){return null===e?null:(n(_(e)),e.__impl4cf1e782hg__)}function O(e){return e.__impl4cf1e782hg__}function L(e,t){t.__impl4cf1e782hg__=e,e.__wrapper8e3dd93a60__=t}function N(e){return e&&_(e)?M(e):e}function C(e){return e&&!_(e)?T(e):e}function j(e,t){null!==t&&(n(S(e)),n(void 0===t||_(t)),e.__wrapper8e3dd93a60__=t)}function D(e,t,n){G.get=n,A(e.prototype,t,G)}function H(e,t){D(e,t,function(){return T(this.__impl4cf1e782hg__[t])})}function x(e,t){e.forEach(function(e){t.forEach(function(t){e.prototype[t]=function(){var e=C(this);return e[t].apply(e,arguments)}})})}var R=new WeakMap,I=new WeakMap,P=Object.create(null),k=t(),A=Object.defineProperty,W=Object.getOwnPropertyNames,F=Object.getOwnPropertyDescriptor,U={value:void 0,configurable:!0,enumerable:!1,writable:!0};W(window);var q=/Firefox/.test(navigator.userAgent),B={get:function(){},set:function(e){},configurable:!0,enumerable:!0},V=function(){var e=Object.getOwnPropertyDescriptor(Node.prototype,"nodeType");return e&&!e.get&&!e.set}(),G={get:void 0,configurable:!0,enumerable:!0};e.assert=n,e.constructorTable=R,e.defineGetter=D,e.defineWrapGetter=H,e.forwardMethodsToWrapper=x,e.isIdentifierName=d,e.isWrapper=_,e.isWrapperFor=b,e.mixin=r,e.nativePrototypeTable=I,e.oneOf=i,e.registerObject=y,e.registerWrapper=v,e.rewrap=j,e.setWrapper=L,e.unsafeUnwrap=O,e.unwrap=M,e.unwrapIfNeeded=N,e.wrap=T,e.wrapIfNeeded=C,e.wrappers=P}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t,n){return{index:e,removed:t,addedCount:n}}function n(){}var r=0,o=1,i=2,a=3;n.prototype={calcEditDistances:function(e,t,n,r,o,i){for(var a=i-o+1,s=n-t+1,c=new Array(a),l=0;a>l;l++)c[l]=new Array(s),c[l][0]=l;for(var u=0;s>u;u++)c[0][u]=u;for(var l=1;a>l;l++)for(var u=1;s>u;u++)if(this.equals(e[t+u-1],r[o+l-1]))c[l][u]=c[l-1][u-1];else{var d=c[l-1][u]+1,p=c[l][u-1]+1;c[l][u]=p>d?d:p}return c},spliceOperationsFromEditDistances:function(e){for(var t=e.length-1,n=e[0].length-1,s=e[t][n],c=[];t>0||n>0;)if(0!=t)if(0!=n){var l,u=e[t-1][n-1],d=e[t-1][n],p=e[t][n-1];l=p>d?u>d?d:u:u>p?p:u,l==u?(u==s?c.push(r):(c.push(o),s=u),t--,n--):l==d?(c.push(a),t--,s=d):(c.push(i),n--,s=p)}else c.push(a),t--;else c.push(i),n--;return c.reverse(),c},calcSplices:function(e,n,s,c,l,u){var d=0,p=0,h=Math.min(s-n,u-l);if(0==n&&0==l&&(d=this.sharedPrefix(e,c,h)),s==e.length&&u==c.length&&(p=this.sharedSuffix(e,c,h-d)),n+=d,l+=d,s-=p,u-=p,s-n==0&&u-l==0)return[];if(n==s){for(var f=t(n,[],0);u>l;)f.removed.push(c[l++]);return[f]}if(l==u)return[t(n,[],s-n)];for(var m=this.spliceOperationsFromEditDistances(this.calcEditDistances(e,n,s,c,l,u)),f=void 0,w=[],v=n,g=l,b=0;b<m.length;b++)switch(m[b]){case r:f&&(w.push(f),f=void 0),v++,g++;break;case o:f||(f=t(v,[],0)),f.addedCount++,v++,f.removed.push(c[g]),g++;break;case i:f||(f=t(v,[],0)),f.addedCount++,v++;break;case a:f||(f=t(v,[],0)),f.removed.push(c[g]),g++}return f&&w.push(f),w},sharedPrefix:function(e,t,n){for(var r=0;n>r;r++)if(!this.equals(e[r],t[r]))return r;return n},sharedSuffix:function(e,t,n){for(var r=e.length,o=t.length,i=0;n>i&&this.equals(e[--r],t[--o]);)i++;return i},calculateSplices:function(e,t){return this.calcSplices(e,0,e.length,t,0,t.length)},equals:function(e,t){return e===t}},e.ArraySplice=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(){a=!1;var e=i.slice(0);i=[];for(var t=0;t<e.length;t++)e[t]()}function n(e){i.push(e),a||(a=!0,r(t,0))}var r,o=window.MutationObserver,i=[],a=!1;if(o){var s=1,c=new o(t),l=document.createTextNode(s);c.observe(l,{characterData:!0}),r=function(){s=(s+1)%2,l.data=s}}else r=window.setTimeout;e.setEndOfMicrotask=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.scheduled_||(e.scheduled_=!0,f.push(e),m||(u(n),m=!0))}function n(){for(m=!1;f.length;){var e=f;f=[],e.sort(function(e,t){return e.uid_-t.uid_});for(var t=0;t<e.length;t++){var n=e[t];n.scheduled_=!1;var r=n.takeRecords();i(n),r.length&&n.callback_(r,n)}}}function r(e,t){this.type=e,this.target=t,this.addedNodes=new p.NodeList,this.removedNodes=new p.NodeList,this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function o(e,t){for(;e;e=e.parentNode){var n=h.get(e);if(n)for(var r=0;r<n.length;r++){var o=n[r];o.options.subtree&&o.addTransientObserver(t)}}}function i(e){for(var t=0;t<e.nodes_.length;t++){var n=e.nodes_[t],r=h.get(n);if(!r)return;for(var o=0;o<r.length;o++){var i=r[o];i.observer===e&&i.removeTransientObservers()}}}function a(e,n,o){for(var i=Object.create(null),a=Object.create(null),s=e;s;s=s.parentNode){var c=h.get(s);if(c)for(var l=0;l<c.length;l++){var u=c[l],d=u.options;if((s===e||d.subtree)&&!("attributes"===n&&!d.attributes||"attributes"===n&&d.attributeFilter&&(null!==o.namespace||-1===d.attributeFilter.indexOf(o.name))||"characterData"===n&&!d.characterData||"childList"===n&&!d.childList)){var p=u.observer;i[p.uid_]=p,("attributes"===n&&d.attributeOldValue||"characterData"===n&&d.characterDataOldValue)&&(a[p.uid_]=o.oldValue)}}}for(var f in i){var p=i[f],m=new r(n,e);"name"in o&&"namespace"in o&&(m.attributeName=o.name,m.attributeNamespace=o.namespace),o.addedNodes&&(m.addedNodes=o.addedNodes),o.removedNodes&&(m.removedNodes=o.removedNodes),o.previousSibling&&(m.previousSibling=o.previousSibling),o.nextSibling&&(m.nextSibling=o.nextSibling),void 0!==a[f]&&(m.oldValue=a[f]),t(p),p.records_.push(m)}}function s(e){if(this.childList=!!e.childList,this.subtree=!!e.subtree,this.attributes="attributes"in e||!("attributeOldValue"in e||"attributeFilter"in e)?!!e.attributes:!0,this.characterData="characterDataOldValue"in e&&!("characterData"in e)?!0:!!e.characterData,!this.attributes&&(e.attributeOldValue||"attributeFilter"in e)||!this.characterData&&e.characterDataOldValue)throw new TypeError;if(this.characterData=!!e.characterData,this.attributeOldValue=!!e.attributeOldValue,this.characterDataOldValue=!!e.characterDataOldValue,"attributeFilter"in e){if(null==e.attributeFilter||"object"!=typeof e.attributeFilter)throw new TypeError;this.attributeFilter=w.call(e.attributeFilter)}else this.attributeFilter=null}function c(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++v,this.scheduled_=!1}function l(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var u=e.setEndOfMicrotask,d=e.wrapIfNeeded,p=e.wrappers,h=new WeakMap,f=[],m=!1,w=Array.prototype.slice,v=0;c.prototype={constructor:c,observe:function(e,t){e=d(e);var n,r=new s(t),o=h.get(e);o||h.set(e,o=[]);for(var i=0;i<o.length;i++)o[i].observer===this&&(n=o[i],n.removeTransientObservers(),n.options=r);n||(n=new l(this,e,r),o.push(n),this.nodes_.push(e))},disconnect:function(){this.nodes_.forEach(function(e){for(var t=h.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}},l.prototype={addTransientObserver:function(e){if(e!==this.target){t(this.observer),this.transientObservedNodes.push(e);var n=h.get(e);n||h.set(e,n=[]),n.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[];for(var t=0;t<e.length;t++)for(var n=e[t],r=h.get(n),o=0;o<r.length;o++)if(r[o]===this){r.splice(o,1);break}}},e.enqueueMutation=a,e.registerTransientObservers=o,e.wrappers.MutationObserver=c,e.wrappers.MutationRecord=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){this.root=e,this.parent=t}function n(e,t){if(e.treeScope_!==t){e.treeScope_=t;for(var r=e.shadowRoot;r;r=r.olderShadowRoot)r.treeScope_.parent=t;for(var o=e.firstChild;o;o=o.nextSibling)n(o,t)}}function r(n){if(n instanceof e.wrappers.Window,n.treeScope_)return n.treeScope_;var o,i=n.parentNode;return o=i?r(i):new t(n,null),n.treeScope_=o}t.prototype={get renderer(){return this.root instanceof e.wrappers.ShadowRoot?e.getRendererForHost(this.root.host):null},contains:function(e){for(;e;e=e.parent)if(e===this)return!0;return!1}},e.TreeScope=t,e.getTreeScope=r,e.setTreeScope=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e instanceof G.ShadowRoot}function n(e){return A(e).root}function r(e,r){var s=[],c=e;for(s.push(c);c;){var l=a(c);if(l&&l.length>0){for(var u=0;u<l.length;u++){var p=l[u];if(i(p)){var h=n(p),f=h.olderShadowRoot;f&&s.push(f)}s.push(p)}c=l[l.length-1]}else if(t(c)){if(d(e,c)&&o(r))break;c=c.host,s.push(c)}else c=c.parentNode,c&&s.push(c)}return s}function o(e){if(!e)return!1;switch(e.type){case"abort":case"error":case"select":case"change":case"load":case"reset":case"resize":case"scroll":case"selectstart":return!0}return!1}function i(e){return e instanceof HTMLShadowElement}function a(t){return e.getDestinationInsertionPoints(t)}function s(e,t){if(0===e.length)return t;t instanceof G.Window&&(t=t.document);for(var n=A(t),r=e[0],o=A(r),i=l(n,o),a=0;a<e.length;a++){var s=e[a];if(A(s)===i)return s}return e[e.length-1]}function c(e){for(var t=[];e;e=e.parent)t.push(e);return t}function l(e,t){for(var n=c(e),r=c(t),o=null;n.length>0&&r.length>0;){var i=n.pop(),a=r.pop();if(i!==a)break;o=i}return o}function u(e,t,n){t instanceof G.Window&&(t=t.document);var o,i=A(t),a=A(n),s=r(n,e),o=l(i,a);o||(o=a.root);for(var c=o;c;c=c.parent)for(var u=0;u<s.length;u++){var d=s[u];if(A(d)===c)return d}return null}function d(e,t){return A(e)===A(t)}function p(e){if(!K.get(e)&&(K.set(e,!0),f(V(e),V(e.target)),P)){var t=P;throw P=null,t}}function h(e){switch(e.type){case"load":case"beforeunload":case"unload":return!0}return!1}function f(t,n){if(Y.get(t))throw new Error("InvalidStateError");Y.set(t,!0),e.renderAllPending();var o,i,a;if(h(t)&&!t.bubbles){var s=n;s instanceof G.Document&&(a=s.defaultView)&&(i=s,o=[])}if(!o)if(n instanceof G.Window)a=n,o=[];else if(o=r(n,t),!h(t)){var s=o[o.length-1];s instanceof G.Document&&(a=s.defaultView)}return ne.set(t,o),m(t,o,a,i)&&w(t,o,a,i)&&v(t,o,a,i),J.set(t,re),X["delete"](t,null),Y["delete"](t),t.defaultPrevented}function m(e,t,n,r){var o=oe;if(n&&!g(n,e,o,t,r))return!1;for(var i=t.length-1;i>0;i--)if(!g(t[i],e,o,t,r))return!1;return!0}function w(e,t,n,r){var o=ie,i=t[0]||n;return g(i,e,o,t,r)}function v(e,t,n,r){for(var o=ae,i=1;i<t.length;i++)if(!g(t[i],e,o,t,r))return;n&&t.length>0&&g(n,e,o,t,r)}function g(e,t,n,r,o){var i=z.get(e);if(!i)return!0;var a=o||s(r,e);if(a===e){if(n===oe)return!0;n===ae&&(n=ie)}else if(n===ae&&!t.bubbles)return!0;if("relatedTarget"in t){var c=B(t),l=c.relatedTarget;if(l){if(l instanceof Object&&l.addEventListener){var d=V(l),p=u(t,e,d);if(p===a)return!0}else p=null;Z.set(t,p)}}J.set(t,n);var h=t.type,f=!1;$.set(t,a),X.set(t,e),i.depth++;for(var m=0,w=i.length;w>m;m++){var v=i[m];if(v.removed)f=!0;else if(!(v.type!==h||!v.capture&&n===oe||v.capture&&n===ae))try{if("function"==typeof v.handler?v.handler.call(e,t):v.handler.handleEvent(t),ee.get(t))return!1}catch(g){P||(P=g)}}if(i.depth--,f&&0===i.depth){var b=i.slice();i.length=0;for(var m=0;m<b.length;m++)b[m].removed||i.push(b[m])}return!Q.get(t)}function b(e,t,n){this.type=e,this.handler=t,this.capture=Boolean(n)}function y(e,t){if(!(e instanceof se))return V(T(se,"Event",e,t));var n=e;return ge||"beforeunload"!==n.type||this instanceof M?void U(n,this):new M(n)}function E(e){return e&&e.relatedTarget?Object.create(e,{relatedTarget:{value:B(e.relatedTarget)}}):e}function _(e,t,n){var r=window[e],o=function(t,n){return t instanceof r?void U(t,this):V(T(r,e,t,n))};if(o.prototype=Object.create(t.prototype),n&&W(o.prototype,n),r)try{F(r,o,new r("temp"))}catch(i){F(r,o,document.createEvent(e))}return o}function S(e,t){return function(){arguments[t]=B(arguments[t]);var n=B(this);n[e].apply(n,arguments)}}function T(e,t,n,r){if(we)return new e(n,E(r));var o=B(document.createEvent(t)),i=me[t],a=[n];return Object.keys(i).forEach(function(e){var t=null!=r&&e in r?r[e]:i[e];"relatedTarget"===e&&(t=B(t)),a.push(t)}),o["init"+t].apply(o,a),o}function M(e){y.call(this,e)}function O(e){return"function"==typeof e?!0:e&&e.handleEvent}function L(e){switch(e){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function N(e){U(e,this)}function C(e){return e instanceof G.ShadowRoot&&(e=e.host),B(e)}function j(e,t){var n=z.get(e);if(n)for(var r=0;r<n.length;r++)if(!n[r].removed&&n[r].type===t)return!0;return!1}function D(e,t){for(var n=B(e);n;n=n.parentNode)if(j(V(n),t))return!0;return!1}function H(e){k(e,ye)}function x(t,n,o,i){e.renderAllPending();var a=V(Ee.call(q(n),o,i));if(!a)return null;var c=r(a,null),l=c.lastIndexOf(t);return-1==l?null:(c=c.slice(0,l),s(c,t))}function R(e){return function(){var t=te.get(this);return t&&t[e]&&t[e].value||null}}function I(e){var t=e.slice(2);return function(n){var r=te.get(this);r||(r=Object.create(null),te.set(this,r));var o=r[e];if(o&&this.removeEventListener(t,o.wrapped,!1),"function"==typeof n){var i=function(t){var r=n.call(this,t);r===!1?t.preventDefault():"onbeforeunload"===e&&"string"==typeof r&&(t.returnValue=r)};this.addEventListener(t,i,!1),r[e]={value:n,wrapped:i}}}}var P,k=e.forwardMethodsToWrapper,A=e.getTreeScope,W=e.mixin,F=e.registerWrapper,U=e.setWrapper,q=e.unsafeUnwrap,B=e.unwrap,V=e.wrap,G=e.wrappers,z=(new WeakMap,new WeakMap),K=new WeakMap,Y=new WeakMap,$=new WeakMap,X=new WeakMap,Z=new WeakMap,J=new WeakMap,Q=new WeakMap,ee=new WeakMap,te=new WeakMap,ne=new WeakMap,re=0,oe=1,ie=2,ae=3;b.prototype={equals:function(e){return this.handler===e.handler&&this.type===e.type&&this.capture===e.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var se=window.Event;se.prototype.polymerBlackList_={returnValue:!0,keyLocation:!0},y.prototype={get target(){return $.get(this)},get currentTarget(){return X.get(this)},get eventPhase(){return J.get(this)},get path(){var e=ne.get(this);return e?e.slice():[]},stopPropagation:function(){Q.set(this,!0)},stopImmediatePropagation:function(){Q.set(this,!0),ee.set(this,!0)}},F(se,y,document.createEvent("Event"));var ce=_("UIEvent",y),le=_("CustomEvent",y),ue={get relatedTarget(){var e=Z.get(this);return void 0!==e?e:V(B(this).relatedTarget)}},de=W({initMouseEvent:S("initMouseEvent",14)},ue),pe=W({initFocusEvent:S("initFocusEvent",5)},ue),he=_("MouseEvent",ce,de),fe=_("FocusEvent",ce,pe),me=Object.create(null),we=function(){try{new window.FocusEvent("focus")}catch(e){return!1}return!0}();if(!we){var ve=function(e,t,n){if(n){var r=me[n];t=W(W({},r),t)}me[e]=t};ve("Event",{bubbles:!1,cancelable:!1}),ve("CustomEvent",{detail:null},"Event"),ve("UIEvent",{view:null,detail:0},"Event"),ve("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),ve("FocusEvent",{relatedTarget:null},"UIEvent")}var ge=window.BeforeUnloadEvent;M.prototype=Object.create(y.prototype),W(M.prototype,{get returnValue(){return q(this).returnValue},set returnValue(e){q(this).returnValue=e}}),ge&&F(ge,M);var be=window.EventTarget,ye=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(e){var t=e.prototype;ye.forEach(function(e){Object.defineProperty(t,e+"_",{value:t[e]})})}),N.prototype={addEventListener:function(e,t,n){if(O(t)&&!L(e)){var r=new b(e,t,n),o=z.get(this);if(o){for(var i=0;i<o.length;i++)if(r.equals(o[i]))return}else o=[],o.depth=0,z.set(this,o);o.push(r);var a=C(this);a.addEventListener_(e,p,!0)}},removeEventListener:function(e,t,n){n=Boolean(n);var r=z.get(this);if(r){for(var o=0,i=!1,a=0;a<r.length;a++)r[a].type===e&&r[a].capture===n&&(o++,r[a].handler===t&&(i=!0,r[a].remove()));if(i&&1===o){var s=C(this);s.removeEventListener_(e,p,!0)}}},dispatchEvent:function(t){var n=B(t),r=n.type;K.set(n,!1),e.renderAllPending();var o;D(this,r)||(o=function(){},this.addEventListener(r,o,!0));try{return B(this).dispatchEvent_(n)}finally{o&&this.removeEventListener(r,o,!0)}}},be&&F(be,N);var Ee=document.elementFromPoint;e.elementFromPoint=x,e.getEventHandlerGetter=R,e.getEventHandlerSetter=I,e.wrapEventTargetMethods=H,e.wrappers.BeforeUnloadEvent=M,e.wrappers.CustomEvent=le,e.wrappers.Event=y,e.wrappers.EventTarget=N,e.wrappers.FocusEvent=fe,e.wrappers.MouseEvent=he,e.wrappers.UIEvent=ce}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,m)}function n(e){l(e,this)}function r(){this.length=0,t(this,"length")}function o(e){for(var t=new r,o=0;o<e.length;o++)t[o]=new n(e[o]);return t.length=o,t}function i(e){a.call(this,e)}var a=e.wrappers.UIEvent,s=e.mixin,c=e.registerWrapper,l=e.setWrapper,u=e.unsafeUnwrap,d=e.wrap,p=window.TouchEvent;if(p){var h;try{h=document.createEvent("TouchEvent")}catch(f){return}var m={enumerable:!1};n.prototype={get target(){return d(u(this).target)}};var w={configurable:!0,enumerable:!0,get:null};["clientX","clientY","screenX","screenY","pageX","pageY","identifier","webkitRadiusX","webkitRadiusY","webkitRotationAngle","webkitForce"].forEach(function(e){w.get=function(){return u(this)[e]},Object.defineProperty(n.prototype,e,w)}),r.prototype={item:function(e){return this[e]}},i.prototype=Object.create(a.prototype),s(i.prototype,{get touches(){return o(u(this).touches)},get targetTouches(){return o(u(this).targetTouches)},get changedTouches(){return o(u(this).changedTouches)},initTouchEvent:function(){throw new Error("Not implemented")}}),c(p,i,h),e.wrappers.Touch=n,e.wrappers.TouchEvent=i,e.wrappers.TouchList=r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,s)}function n(){this.length=0,t(this,"length")}function r(e){if(null==e)return e;for(var t=new n,r=0,o=e.length;o>r;r++)t[r]=a(e[r]);return t.length=o,t}function o(e,t){e.prototype[t]=function(){return r(i(this)[t].apply(i(this),arguments))}}var i=e.unsafeUnwrap,a=e.wrap,s={enumerable:!1};n.prototype={item:function(e){return this[e]}},t(n.prototype,"item"),e.wrappers.NodeList=n,e.addWrapNodeListMethod=o,e.wrapNodeList=r}(window.ShadowDOMPolyfill),function(e){"use strict";e.wrapHTMLCollection=e.wrapNodeList,e.wrappers.HTMLCollection=e.wrappers.NodeList}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){O(e instanceof _)}function n(e){var t=new T;return t[0]=e,t.length=1,t}function r(e,t,n){N(t,"childList",{removedNodes:n,previousSibling:e.previousSibling,nextSibling:e.nextSibling})}function o(e,t){N(e,"childList",{removedNodes:t})}function i(e,t,r,o){if(e instanceof DocumentFragment){var i=s(e);U=!0;for(var a=i.length-1;a>=0;a--)e.removeChild(i[a]),i[a].parentNode_=t;U=!1;for(var a=0;a<i.length;a++)i[a].previousSibling_=i[a-1]||r,i[a].nextSibling_=i[a+1]||o;return r&&(r.nextSibling_=i[0]),o&&(o.previousSibling_=i[i.length-1]),i}var i=n(e),c=e.parentNode;return c&&c.removeChild(e),e.parentNode_=t,e.previousSibling_=r,e.nextSibling_=o,r&&(r.nextSibling_=e),o&&(o.previousSibling_=e),i}function a(e){if(e instanceof DocumentFragment)return s(e);var t=n(e),o=e.parentNode;return o&&r(e,o,t),t}function s(e){for(var t=new T,n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t.length=n,o(e,t),t}function c(e){return e}function l(e,t){R(e,t),e.nodeIsInserted_()}function u(e,t){for(var n=C(t),r=0;r<e.length;r++)l(e[r],n)}function d(e){R(e,new M(e,null))}function p(e){for(var t=0;t<e.length;t++)d(e[t])}function h(e,t){var n=e.nodeType===_.DOCUMENT_NODE?e:e.ownerDocument;n!==t.ownerDocument&&n.adoptNode(t)}function f(t,n){if(n.length){var r=t.ownerDocument;if(r!==n[0].ownerDocument)for(var o=0;o<n.length;o++)e.adoptNodeNoRemove(n[o],r)}}function m(e,t){f(e,t);var n=t.length;if(1===n)return P(t[0]);for(var r=P(e.ownerDocument.createDocumentFragment()),o=0;n>o;o++)r.appendChild(P(t[o]));return r}function w(e){if(void 0!==e.firstChild_)for(var t=e.firstChild_;t;){var n=t;t=t.nextSibling_,n.parentNode_=n.previousSibling_=n.nextSibling_=void 0}e.firstChild_=e.lastChild_=void 0}function v(e){if(e.invalidateShadowRenderer()){for(var t=e.firstChild;t;){O(t.parentNode===e);var n=t.nextSibling,r=P(t),o=r.parentNode;o&&$.call(o,r),t.previousSibling_=t.nextSibling_=t.parentNode_=null,t=n}e.firstChild_=e.lastChild_=null}else for(var n,i=P(e),a=i.firstChild;a;)n=a.nextSibling,$.call(i,a),a=n}function g(e){var t=e.parentNode;return t&&t.invalidateShadowRenderer()}function b(e){for(var t,n=0;n<e.length;n++)t=e[n],t.parentNode.removeChild(t)}function y(e,t,n){var r;if(r=A(n?q.call(n,I(e),!1):B.call(I(e),!1)),t){for(var o=e.firstChild;o;o=o.nextSibling)r.appendChild(y(o,!0,n));if(e instanceof F.HTMLTemplateElement)for(var i=r.content,o=e.content.firstChild;o;o=o.nextSibling)i.appendChild(y(o,!0,n))}return r}function E(e,t){if(!t||C(e)!==C(t))return!1;for(var n=t;n;n=n.parentNode)if(n===e)return!0;return!1}function _(e){O(e instanceof V),S.call(this,e),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0,this.treeScope_=void 0}var S=e.wrappers.EventTarget,T=e.wrappers.NodeList,M=e.TreeScope,O=e.assert,L=e.defineWrapGetter,N=e.enqueueMutation,C=e.getTreeScope,j=e.isWrapper,D=e.mixin,H=e.registerTransientObservers,x=e.registerWrapper,R=e.setTreeScope,I=e.unsafeUnwrap,P=e.unwrap,k=e.unwrapIfNeeded,A=e.wrap,W=e.wrapIfNeeded,F=e.wrappers,U=!1,q=document.importNode,B=window.Node.prototype.cloneNode,V=window.Node,G=window.DocumentFragment,z=(V.prototype.appendChild,V.prototype.compareDocumentPosition),K=V.prototype.isEqualNode,Y=V.prototype.insertBefore,$=V.prototype.removeChild,X=V.prototype.replaceChild,Z=/Trident|Edge/.test(navigator.userAgent),J=Z?function(e,t){try{$.call(e,t)}catch(n){if(!(e instanceof G))throw n}}:function(e,t){$.call(e,t)};_.prototype=Object.create(S.prototype),D(_.prototype,{appendChild:function(e){return this.insertBefore(e,null)},insertBefore:function(e,n){t(e);var r;n?j(n)?r=P(n):(r=n,n=A(r)):(n=null,r=null),n&&O(n.parentNode===this);var o,s=n?n.previousSibling:this.lastChild,c=!this.invalidateShadowRenderer()&&!g(e);if(o=c?a(e):i(e,this,s,n),c)h(this,e),w(this),Y.call(I(this),P(e),r);else{s||(this.firstChild_=o[0]),n||(this.lastChild_=o[o.length-1],void 0===this.firstChild_&&(this.firstChild_=this.firstChild));var l=r?r.parentNode:I(this);l?Y.call(l,m(this,o),r):f(this,o)}return N(this,"childList",{addedNodes:o,nextSibling:n,previousSibling:s}),u(o,this),e},removeChild:function(e){if(t(e),e.parentNode!==this){for(var r=!1,o=(this.childNodes,this.firstChild);o;o=o.nextSibling)if(o===e){r=!0;break}if(!r)throw new Error("NotFoundError")}var i=P(e),a=e.nextSibling,s=e.previousSibling;if(this.invalidateShadowRenderer()){var c=this.firstChild,l=this.lastChild,u=i.parentNode;u&&J(u,i),c===e&&(this.firstChild_=a),l===e&&(this.lastChild_=s),s&&(s.nextSibling_=a),a&&(a.previousSibling_=s),e.previousSibling_=e.nextSibling_=e.parentNode_=void 0}else w(this),J(I(this),i);return U||N(this,"childList",{removedNodes:n(e),nextSibling:a,previousSibling:s}),H(this,e),e},replaceChild:function(e,r){t(e);var o;if(j(r)?o=P(r):(o=r,r=A(o)),r.parentNode!==this)throw new Error("NotFoundError");var s,c=r.nextSibling,l=r.previousSibling,p=!this.invalidateShadowRenderer()&&!g(e);return p?s=a(e):(c===e&&(c=e.nextSibling),s=i(e,this,l,c)),p?(h(this,e),w(this),X.call(I(this),P(e),o)):(this.firstChild===r&&(this.firstChild_=s[0]),this.lastChild===r&&(this.lastChild_=s[s.length-1]),r.previousSibling_=r.nextSibling_=r.parentNode_=void 0,o.parentNode&&X.call(o.parentNode,m(this,s),o)),N(this,"childList",{addedNodes:s,removedNodes:n(r),nextSibling:c,previousSibling:l}),d(r),u(s,this),r},nodeIsInserted_:function(){for(var e=this.firstChild;e;e=e.nextSibling)e.nodeIsInserted_()},hasChildNodes:function(){return null!==this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:A(I(this).parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:A(I(this).firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:A(I(this).lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:A(I(this).nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:A(I(this).previousSibling)},get parentElement(){for(var e=this.parentNode;e&&e.nodeType!==_.ELEMENT_NODE;)e=e.parentNode;return e},get textContent(){for(var e="",t=this.firstChild;t;t=t.nextSibling)t.nodeType!=_.COMMENT_NODE&&(e+=t.textContent);return e},set textContent(e){null==e&&(e="");var t=c(this.childNodes);if(this.invalidateShadowRenderer()){if(v(this),""!==e){var n=I(this).ownerDocument.createTextNode(e);this.appendChild(n)}}else w(this),I(this).textContent=e;var r=c(this.childNodes);N(this,"childList",{addedNodes:r,removedNodes:t}),p(t),u(r,this)},get childNodes(){for(var e=new T,t=0,n=this.firstChild;n;n=n.nextSibling)e[t++]=n;return e.length=t,e},cloneNode:function(e){return y(this,e)},contains:function(e){return E(this,W(e))},compareDocumentPosition:function(e){return z.call(I(this),k(e))},isEqualNode:function(e){return K.call(I(this),k(e))},normalize:function(){for(var e,t,n=c(this.childNodes),r=[],o="",i=0;i<n.length;i++)t=n[i],t.nodeType===_.TEXT_NODE?e||t.data.length?e?(o+=t.data,r.push(t)):e=t:this.removeChild(t):(e&&r.length&&(e.data+=o,b(r)),r=[],o="",e=null,t.childNodes.length&&t.normalize());e&&r.length&&(e.data+=o,b(r))}}),L(_,"ownerDocument"),x(V,_,document.createDocumentFragment()),delete _.prototype.querySelector,delete _.prototype.querySelectorAll,_.prototype=D(Object.create(S.prototype),_.prototype),e.cloneNode=y,e.nodeWasAdded=l,e.nodeWasRemoved=d,e.nodesWereAdded=u,e.nodesWereRemoved=p,e.originalInsertBefore=Y,e.originalRemoveChild=$,e.snapshotNodeList=c,e.wrappers.Node=_}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n,r,o){for(var i=null,a=null,s=0,c=t.length;c>s;s++)i=b(t[s]),!o&&(a=v(i).root)&&a instanceof e.wrappers.ShadowRoot||(r[n++]=i);return n}function n(e){return String(e).replace(/\/deep\/|::shadow|>>>/g," ")}function r(e){return String(e).replace(/:host\(([^\s]+)\)/g,"$1").replace(/([^\s]):host/g,"$1").replace(":host","*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content|>>>/g," ")}function o(e,t){for(var n,r=e.firstElementChild;r;){if(r.matches(t))return r;if(n=o(r,t))return n;r=r.nextElementSibling}return null}function i(e,t){return e.matches(t)}function a(e,t,n){var r=e.localName;return r===t||r===n&&e.namespaceURI===j}function s(){return!0}function c(e,t,n){return e.localName===n}function l(e,t){return e.namespaceURI===t}function u(e,t,n){return e.namespaceURI===t&&e.localName===n}function d(e,t,n,r,o,i){for(var a=e.firstElementChild;a;)r(a,o,i)&&(n[t++]=a),t=d(a,t,n,r,o,i),a=a.nextElementSibling;return t}function p(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,null);if(c instanceof N)s=S.call(c,i);else{if(!(c instanceof C))return d(this,r,o,n,i,null);s=_.call(c,i)}return t(s,r,o,a)}function h(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,a);if(c instanceof N)s=M.call(c,i,a);else{if(!(c instanceof C))return d(this,r,o,n,i,a);s=T.call(c,i,a)}return t(s,r,o,!1)}function f(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,a);if(c instanceof N)s=L.call(c,i,a);else{if(!(c instanceof C))return d(this,r,o,n,i,a);s=O.call(c,i,a)}return t(s,r,o,!1)}var m=e.wrappers.HTMLCollection,w=e.wrappers.NodeList,v=e.getTreeScope,g=e.unsafeUnwrap,b=e.wrap,y=document.querySelector,E=document.documentElement.querySelector,_=document.querySelectorAll,S=document.documentElement.querySelectorAll,T=document.getElementsByTagName,M=document.documentElement.getElementsByTagName,O=document.getElementsByTagNameNS,L=document.documentElement.getElementsByTagNameNS,N=window.Element,C=window.HTMLDocument||window.Document,j="http://www.w3.org/1999/xhtml",D={querySelector:function(t){var r=n(t),i=r!==t;t=r;var a,s=g(this),c=v(this).root;if(c instanceof e.wrappers.ShadowRoot)return o(this,t);if(s instanceof N)a=b(E.call(s,t));else{if(!(s instanceof C))return o(this,t);a=b(y.call(s,t))}return a&&!i&&(c=v(a).root)&&c instanceof e.wrappers.ShadowRoot?o(this,t):a;
+
+},querySelectorAll:function(e){var t=n(e),r=t!==e;e=t;var o=new w;return o.length=p.call(this,i,0,o,e,r),o}},H={matches:function(t){return t=r(t),e.originalMatches.call(g(this),t)}},x={getElementsByTagName:function(e){var t=new m,n="*"===e?s:a;return t.length=h.call(this,n,0,t,e,e.toLowerCase()),t},getElementsByClassName:function(e){return this.querySelectorAll("."+e)},getElementsByTagNameNS:function(e,t){var n=new m,r=null;return r="*"===e?"*"===t?s:c:"*"===t?l:u,n.length=f.call(this,r,0,n,e||null,t),n}};e.GetElementsByInterface=x,e.SelectorsInterface=D,e.MatchesInterface=H}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;return e}function n(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.previousSibling;return e}var r=e.wrappers.NodeList,o={get firstElementChild(){return t(this.firstChild)},get lastElementChild(){return n(this.lastChild)},get childElementCount(){for(var e=0,t=this.firstElementChild;t;t=t.nextElementSibling)e++;return e},get children(){for(var e=new r,t=0,n=this.firstElementChild;n;n=n.nextElementSibling)e[t++]=n;return e.length=t,e},remove:function(){var e=this.parentNode;e&&e.removeChild(this)}},i={get nextElementSibling(){return t(this.nextSibling)},get previousElementSibling(){return n(this.previousSibling)}};e.ChildNodeInterface=i,e.ParentNodeInterface=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}var n=e.ChildNodeInterface,r=e.wrappers.Node,o=e.enqueueMutation,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=window.CharacterData;t.prototype=Object.create(r.prototype),i(t.prototype,{get nodeValue(){return this.data},set nodeValue(e){this.data=e},get textContent(){return this.data},set textContent(e){this.data=e},get data(){return s(this).data},set data(e){var t=s(this).data;o(this,"characterData",{oldValue:t}),s(this).data=e}}),i(t.prototype,n),a(c,t,document.createTextNode("")),e.wrappers.CharacterData=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e>>>0}function n(e){r.call(this,e)}var r=e.wrappers.CharacterData,o=(e.enqueueMutation,e.mixin),i=e.registerWrapper,a=window.Text;n.prototype=Object.create(r.prototype),o(n.prototype,{splitText:function(e){e=t(e);var n=this.data;if(e>n.length)throw new Error("IndexSizeError");var r=n.slice(0,e),o=n.slice(e);this.data=r;var i=this.ownerDocument.createTextNode(o);return this.parentNode&&this.parentNode.insertBefore(i,this.nextSibling),i}}),i(a,n,document.createTextNode("")),e.wrappers.Text=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return i(e).getAttribute("class")}function n(e,t){a(e,"attributes",{name:"class",namespace:null,oldValue:t})}function r(t){e.invalidateRendererBasedOnAttribute(t,"class")}function o(e,o,i){var a=e.ownerElement_;if(null==a)return o.apply(e,i);var s=t(a),c=o.apply(e,i);return t(a)!==s&&(n(a,s),r(a)),c}if(!window.DOMTokenList)return void console.warn("Missing DOMTokenList prototype, please include a compatible classList polyfill such as http://goo.gl/uTcepH.");var i=e.unsafeUnwrap,a=e.enqueueMutation,s=DOMTokenList.prototype.add;DOMTokenList.prototype.add=function(){o(this,s,arguments)};var c=DOMTokenList.prototype.remove;DOMTokenList.prototype.remove=function(){o(this,c,arguments)};var l=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(){return o(this,l,arguments)}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n){var r=t.parentNode;if(r&&r.shadowRoot){var o=e.getRendererForHost(r);o.dependsOnAttribute(n)&&o.invalidate()}}function n(e,t,n){u(e,"attributes",{name:t,namespace:null,oldValue:n})}function r(e){a.call(this,e)}var o=e.ChildNodeInterface,i=e.GetElementsByInterface,a=e.wrappers.Node,s=e.ParentNodeInterface,c=e.SelectorsInterface,l=e.MatchesInterface,u=(e.addWrapNodeListMethod,e.enqueueMutation),d=e.mixin,p=(e.oneOf,e.registerWrapper),h=e.unsafeUnwrap,f=e.wrappers,m=window.Element,w=["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"].filter(function(e){return m.prototype[e]}),v=w[0],g=m.prototype[v],b=new WeakMap;r.prototype=Object.create(a.prototype),d(r.prototype,{createShadowRoot:function(){var t=new f.ShadowRoot(this);h(this).polymerShadowRoot_=t;var n=e.getRendererForHost(this);return n.invalidate(),t},get shadowRoot(){return h(this).polymerShadowRoot_||null},setAttribute:function(e,r){var o=h(this).getAttribute(e);h(this).setAttribute(e,r),n(this,e,o),t(this,e)},removeAttribute:function(e){var r=h(this).getAttribute(e);h(this).removeAttribute(e),n(this,e,r),t(this,e)},get classList(){var e=b.get(this);if(!e){if(e=h(this).classList,!e)return;e.ownerElement_=this,b.set(this,e)}return e},get className(){return h(this).className},set className(e){this.setAttribute("class",e)},get id(){return h(this).id},set id(e){this.setAttribute("id",e)}}),w.forEach(function(e){"matches"!==e&&(r.prototype[e]=function(e){return this.matches(e)})}),m.prototype.webkitCreateShadowRoot&&(r.prototype.webkitCreateShadowRoot=r.prototype.createShadowRoot),d(r.prototype,o),d(r.prototype,i),d(r.prototype,s),d(r.prototype,c),d(r.prototype,l),p(m,r,document.createElementNS(null,"x")),e.invalidateRendererBasedOnAttribute=t,e.matchesNames=w,e.originalMatches=g,e.wrappers.Element=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e){case"&":return"&amp;";case"<":return"&lt;";case">":return"&gt;";case'"':return"&quot;";case" ":return"&nbsp;"}}function n(e){return e.replace(O,t)}function r(e){return e.replace(L,t)}function o(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=!0;return t}function i(e,t){switch(e.nodeType){case Node.ELEMENT_NODE:for(var o,i=e.tagName.toLowerCase(),s="<"+i,c=e.attributes,l=0;o=c[l];l++)s+=" "+o.name+'="'+n(o.value)+'"';return s+=">",N[i]?s:s+a(e)+"</"+i+">";case Node.TEXT_NODE:var u=e.data;return t&&C[t.localName]?u:r(u);case Node.COMMENT_NODE:return"<!--"+e.data+"-->";default:throw console.error(e),new Error("not implemented")}}function a(e){e instanceof M.HTMLTemplateElement&&(e=e.content);for(var t="",n=e.firstChild;n;n=n.nextSibling)t+=i(n,e);return t}function s(e,t,n){var r=n||"div";e.textContent="";var o=S(e.ownerDocument.createElement(r));o.innerHTML=t;for(var i;i=o.firstChild;)e.appendChild(T(i))}function c(e){f.call(this,e)}function l(e,t){var n=S(e.cloneNode(!1));n.innerHTML=t;for(var r,o=S(document.createDocumentFragment());r=n.firstChild;)o.appendChild(r);return T(o)}function u(t){return function(){return e.renderAllPending(),_(this)[t]}}function d(e){m(c,e,u(e))}function p(t){Object.defineProperty(c.prototype,t,{get:u(t),set:function(n){e.renderAllPending(),_(this)[t]=n},configurable:!0,enumerable:!0})}function h(t){Object.defineProperty(c.prototype,t,{value:function(){return e.renderAllPending(),_(this)[t].apply(_(this),arguments)},configurable:!0,enumerable:!0})}var f=e.wrappers.Element,m=e.defineGetter,w=e.enqueueMutation,v=e.mixin,g=e.nodesWereAdded,b=e.nodesWereRemoved,y=e.registerWrapper,E=e.snapshotNodeList,_=e.unsafeUnwrap,S=e.unwrap,T=e.wrap,M=e.wrappers,O=/[&\u00A0"]/g,L=/[&\u00A0<>]/g,N=o(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),C=o(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),j=/MSIE/.test(navigator.userAgent),D=window.HTMLElement,H=window.HTMLTemplateElement;c.prototype=Object.create(f.prototype),v(c.prototype,{get innerHTML(){return a(this)},set innerHTML(e){if(j&&C[this.localName])return void(this.textContent=e);var t=E(this.childNodes);this.invalidateShadowRenderer()?this instanceof M.HTMLTemplateElement?s(this.content,e):s(this,e,this.tagName):!H&&this instanceof M.HTMLTemplateElement?s(this.content,e):_(this).innerHTML=e;var n=E(this.childNodes);w(this,"childList",{addedNodes:n,removedNodes:t}),b(t),g(n,this)},get outerHTML(){return i(this,this.parentNode)},set outerHTML(e){var t=this.parentNode;if(t){t.invalidateShadowRenderer();var n=l(t,e);t.replaceChild(n,this)}},insertAdjacentHTML:function(e,t){var n,r;switch(String(e).toLowerCase()){case"beforebegin":n=this.parentNode,r=this;break;case"afterend":n=this.parentNode,r=this.nextSibling;break;case"afterbegin":n=this,r=this.firstChild;break;case"beforeend":n=this,r=null;break;default:return}var o=l(n,t);n.insertBefore(o,r)},get hidden(){return this.hasAttribute("hidden")},set hidden(e){e?this.setAttribute("hidden",""):this.removeAttribute("hidden")}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollWidth"].forEach(d),["scrollLeft","scrollTop"].forEach(p),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(h),y(D,c,document.createElement("b")),e.wrappers.HTMLElement=c,e.getInnerHTML=a,e.setInnerHTML=s}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.HTMLCanvasElement;t.prototype=Object.create(n.prototype),r(t.prototype,{getContext:function(){var e=i(this).getContext.apply(i(this),arguments);return e&&a(e)}}),o(s,t,document.createElement("canvas")),e.wrappers.HTMLCanvasElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=window.HTMLContentElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get select(){return this.getAttribute("select")},set select(e){this.setAttribute("select",e)},setAttribute:function(e,t){n.prototype.setAttribute.call(this,e,t),"select"===String(e).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),i&&o(i,t),e.wrappers.HTMLContentElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=window.HTMLFormElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get elements(){return i(a(this).elements)}}),o(s,t,document.createElement("form")),e.wrappers.HTMLFormElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e,t){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var o=i(document.createElement("img"));r.call(this,o),a(o,this),void 0!==e&&(o.width=e),void 0!==t&&(o.height=t)}var r=e.wrappers.HTMLElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLImageElement;t.prototype=Object.create(r.prototype),o(s,t,document.createElement("img")),n.prototype=t.prototype,e.wrappers.HTMLImageElement=t,e.wrappers.Image=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=(e.mixin,e.wrappers.NodeList,e.registerWrapper),o=window.HTMLShadowElement;t.prototype=Object.create(n.prototype),t.prototype.constructor=t,o&&r(o,t),e.wrappers.HTMLShadowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){if(!e.defaultView)return e;var t=d.get(e);if(!t){for(t=e.implementation.createHTMLDocument("");t.lastChild;)t.removeChild(t.lastChild);d.set(e,t)}return t}function n(e){for(var n,r=t(e.ownerDocument),o=c(r.createDocumentFragment());n=e.firstChild;)o.appendChild(n);return o}function r(e){if(o.call(this,e),!p){var t=n(e);u.set(this,l(t))}}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=e.unwrap,l=e.wrap,u=new WeakMap,d=new WeakMap,p=window.HTMLTemplateElement;r.prototype=Object.create(o.prototype),i(r.prototype,{constructor:r,get content(){return p?l(s(this).content):u.get(this)}}),p&&a(p,r),e.wrappers.HTMLTemplateElement=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.registerWrapper,o=window.HTMLMediaElement;o&&(t.prototype=Object.create(n.prototype),r(o,t,document.createElement("audio")),e.wrappers.HTMLMediaElement=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var t=i(document.createElement("audio"));r.call(this,t),a(t,this),t.setAttribute("preload","auto"),void 0!==e&&t.setAttribute("src",e)}var r=e.wrappers.HTMLMediaElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLAudioElement;s&&(t.prototype=Object.create(r.prototype),o(s,t,document.createElement("audio")),n.prototype=t.prototype,e.wrappers.HTMLAudioElement=t,e.wrappers.Audio=n)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e.replace(/\s+/g," ").trim()}function n(e){o.call(this,e)}function r(e,t,n,i){if(!(this instanceof r))throw new TypeError("DOM object constructor cannot be called as a function.");var a=c(document.createElement("option"));o.call(this,a),s(a,this),void 0!==e&&(a.text=e),void 0!==t&&a.setAttribute("value",t),n===!0&&a.setAttribute("selected",""),a.selected=i===!0}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.rewrap,c=e.unwrap,l=e.wrap,u=window.HTMLOptionElement;n.prototype=Object.create(o.prototype),i(n.prototype,{get text(){return t(this.textContent)},set text(e){this.textContent=t(String(e))},get form(){return l(c(this).form)}}),a(u,n,document.createElement("option")),r.prototype=n.prototype,e.wrappers.HTMLOptionElement=n,e.wrappers.Option=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=window.HTMLSelectElement;t.prototype=Object.create(n.prototype),r(t.prototype,{add:function(e,t){"object"==typeof t&&(t=i(t)),i(this).add(i(e),t)},remove:function(e){return void 0===e?void n.prototype.remove.call(this):("object"==typeof e&&(e=i(e)),void i(this).remove(e))},get form(){return a(i(this).form)}}),o(s,t,document.createElement("select")),e.wrappers.HTMLSelectElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=e.wrapHTMLCollection,c=window.HTMLTableElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get caption(){return a(i(this).caption)},createCaption:function(){return a(i(this).createCaption())},get tHead(){return a(i(this).tHead)},createTHead:function(){return a(i(this).createTHead())},createTFoot:function(){return a(i(this).createTFoot())},get tFoot(){return a(i(this).tFoot)},get tBodies(){return s(i(this).tBodies)},createTBody:function(){return a(i(this).createTBody())},get rows(){return s(i(this).rows)},insertRow:function(e){return a(i(this).insertRow(e))}}),o(c,t,document.createElement("table")),e.wrappers.HTMLTableElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableSectionElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get rows(){return i(a(this).rows)},insertRow:function(e){return s(a(this).insertRow(e))}}),o(c,t,document.createElement("thead")),e.wrappers.HTMLTableSectionElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableRowElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get cells(){return i(a(this).cells)},insertCell:function(e){return s(a(this).insertCell(e))}}),o(c,t,document.createElement("tr")),e.wrappers.HTMLTableRowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e.localName){case"content":return new n(e);case"shadow":return new o(e);case"template":return new i(e)}r.call(this,e)}var n=e.wrappers.HTMLContentElement,r=e.wrappers.HTMLElement,o=e.wrappers.HTMLShadowElement,i=e.wrappers.HTMLTemplateElement,a=(e.mixin,e.registerWrapper),s=window.HTMLUnknownElement;t.prototype=Object.create(r.prototype),a(s,t),e.wrappers.HTMLUnknownElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.wrappers.Element,n=e.wrappers.HTMLElement,r=e.registerObject,o=e.defineWrapGetter,i="http://www.w3.org/2000/svg",a=document.createElementNS(i,"title"),s=r(a),c=Object.getPrototypeOf(s.prototype).constructor;if(!("classList"in a)){var l=Object.getOwnPropertyDescriptor(t.prototype,"classList");Object.defineProperty(n.prototype,"classList",l),delete t.prototype.classList}o(c,"ownerSVGElement"),e.wrappers.SVGElement=c}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){p.call(this,e)}var n=e.mixin,r=e.registerWrapper,o=e.unwrap,i=e.wrap,a=window.SVGUseElement,s="http://www.w3.org/2000/svg",c=i(document.createElementNS(s,"g")),l=document.createElementNS(s,"use"),u=c.constructor,d=Object.getPrototypeOf(u.prototype),p=d.constructor;t.prototype=Object.create(d),"instanceRoot"in l&&n(t.prototype,{get instanceRoot(){return i(o(this).instanceRoot)},get animatedInstanceRoot(){return i(o(this).animatedInstanceRoot)}}),r(a,t,l),e.wrappers.SVGUseElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.SVGElementInstance;s&&(t.prototype=Object.create(n.prototype),r(t.prototype,{get correspondingElement(){return a(i(this).correspondingElement)},get correspondingUseElement(){return a(i(this).correspondingUseElement)},get parentNode(){return a(i(this).parentNode)},get childNodes(){throw new Error("Not implemented")},get firstChild(){return a(i(this).firstChild)},get lastChild(){return a(i(this).lastChild)},get previousSibling(){return a(i(this).previousSibling)},get nextSibling(){return a(i(this).nextSibling)}}),o(s,t),e.wrappers.SVGElementInstance=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrap,s=e.unwrapIfNeeded,c=e.wrap,l=window.CanvasRenderingContext2D;n(t.prototype,{get canvas(){return c(i(this).canvas)},drawImage:function(){arguments[0]=s(arguments[0]),i(this).drawImage.apply(i(this),arguments)},createPattern:function(){return arguments[0]=a(arguments[0]),i(this).createPattern.apply(i(this),arguments)}}),r(l,t,document.createElement("canvas").getContext("2d")),e.wrappers.CanvasRenderingContext2D=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.WebGLRenderingContext;if(c){n(t.prototype,{get canvas(){return s(i(this).canvas)},texImage2D:function(){arguments[5]=a(arguments[5]),i(this).texImage2D.apply(i(this),arguments)},texSubImage2D:function(){arguments[6]=a(arguments[6]),i(this).texSubImage2D.apply(i(this),arguments)}});var l=/WebKit/.test(navigator.userAgent)?{drawingBufferHeight:null,drawingBufferWidth:null}:{};r(c,t,l),e.wrappers.WebGLRenderingContext=t}}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.GetElementsByInterface,n=e.ParentNodeInterface,r=e.SelectorsInterface,o=e.mixin,i=e.registerObject,a=i(document.createDocumentFragment());o(a.prototype,n),o(a.prototype,r),o(a.prototype,t);var s=i(document.createComment(""));e.wrappers.Comment=s,e.wrappers.DocumentFragment=a}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=d(u(e).ownerDocument.createDocumentFragment());n.call(this,t),c(t,this);var o=e.shadowRoot;h.set(this,o),this.treeScope_=new r(this,a(o||e)),p.set(this,e)}var n=e.wrappers.DocumentFragment,r=e.TreeScope,o=e.elementFromPoint,i=e.getInnerHTML,a=e.getTreeScope,s=e.mixin,c=e.rewrap,l=e.setInnerHTML,u=e.unsafeUnwrap,d=e.unwrap,p=new WeakMap,h=new WeakMap,f=/[ \t\n\r\f]/;t.prototype=Object.create(n.prototype),s(t.prototype,{constructor:t,get innerHTML(){return i(this)},set innerHTML(e){l(this,e),this.invalidateShadowRenderer()},get olderShadowRoot(){return h.get(this)||null},get host(){return p.get(this)||null},invalidateShadowRenderer:function(){return p.get(this).invalidateShadowRenderer()},elementFromPoint:function(e,t){return o(this,this.ownerDocument,e,t)},getElementById:function(e){return f.test(e)?null:this.querySelector('[id="'+e+'"]')}}),e.wrappers.ShadowRoot=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=d(e).root;return t instanceof h?t.host:null}function n(t,n){if(t.shadowRoot){n=Math.min(t.childNodes.length-1,n);var r=t.childNodes[n];if(r){var o=e.getDestinationInsertionPoints(r);if(o.length>0){var i=o[0].parentNode;i.nodeType==Node.ELEMENT_NODE&&(t=i)}}}return t}function r(e){return e=u(e),t(e)||e}function o(e){a(e,this)}var i=e.registerWrapper,a=e.setWrapper,s=e.unsafeUnwrap,c=e.unwrap,l=e.unwrapIfNeeded,u=e.wrap,d=e.getTreeScope,p=window.Range,h=e.wrappers.ShadowRoot;o.prototype={get startContainer(){return r(s(this).startContainer)},get endContainer(){return r(s(this).endContainer)},get commonAncestorContainer(){return r(s(this).commonAncestorContainer)},setStart:function(e,t){e=n(e,t),s(this).setStart(l(e),t)},setEnd:function(e,t){e=n(e,t),s(this).setEnd(l(e),t)},setStartBefore:function(e){s(this).setStartBefore(l(e))},setStartAfter:function(e){s(this).setStartAfter(l(e))},setEndBefore:function(e){s(this).setEndBefore(l(e))},setEndAfter:function(e){s(this).setEndAfter(l(e))},selectNode:function(e){s(this).selectNode(l(e))},selectNodeContents:function(e){s(this).selectNodeContents(l(e))},compareBoundaryPoints:function(e,t){return s(this).compareBoundaryPoints(e,c(t))},extractContents:function(){return u(s(this).extractContents())},cloneContents:function(){return u(s(this).cloneContents())},insertNode:function(e){s(this).insertNode(l(e))},surroundContents:function(e){s(this).surroundContents(l(e))},cloneRange:function(){return u(s(this).cloneRange())},isPointInRange:function(e,t){return s(this).isPointInRange(l(e),t)},comparePoint:function(e,t){return s(this).comparePoint(l(e),t)},intersectsNode:function(e){return s(this).intersectsNode(l(e))},toString:function(){return s(this).toString()}},p.prototype.createContextualFragment&&(o.prototype.createContextualFragment=function(e){return u(s(this).createContextualFragment(e))}),i(window.Range,o,document.createRange()),e.wrappers.Range=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.previousSibling_=e.previousSibling,e.nextSibling_=e.nextSibling,e.parentNode_=e.parentNode}function n(n,o,i){var a=x(n),s=x(o),c=i?x(i):null;if(r(o),t(o),i)n.firstChild===i&&(n.firstChild_=i),i.previousSibling_=i.previousSibling;else{n.lastChild_=n.lastChild,n.lastChild===n.firstChild&&(n.firstChild_=n.firstChild);var l=R(a.lastChild);l&&(l.nextSibling_=l.nextSibling)}e.originalInsertBefore.call(a,s,c)}function r(n){var r=x(n),o=r.parentNode;if(o){var i=R(o);t(n),n.previousSibling&&(n.previousSibling.nextSibling_=n),n.nextSibling&&(n.nextSibling.previousSibling_=n),i.lastChild===n&&(i.lastChild_=n),i.firstChild===n&&(i.firstChild_=n),e.originalRemoveChild.call(o,r)}}function o(e){P.set(e,[])}function i(e){var t=P.get(e);return t||P.set(e,t=[]),t}function a(e){for(var t=[],n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t}function s(){for(var e=0;e<F.length;e++){var t=F[e],n=t.parentRenderer;n&&n.dirty||t.render()}F=[]}function c(){T=null,s()}function l(e){var t=A.get(e);return t||(t=new h(e),A.set(e,t)),t}function u(e){var t=j(e).root;return t instanceof C?t:null}function d(e){return l(e.host)}function p(e){this.skip=!1,this.node=e,this.childNodes=[]}function h(e){this.host=e,this.dirty=!1,this.invalidateAttributes(),this.associateNode(e)}function f(e){for(var t=[],n=e.firstChild;n;n=n.nextSibling)E(n)?t.push.apply(t,i(n)):t.push(n);return t}function m(e){if(e instanceof L)return e;if(e instanceof O)return null;for(var t=e.firstChild;t;t=t.nextSibling){var n=m(t);if(n)return n}return null}function w(e,t){i(t).push(e);var n=k.get(e);n?n.push(t):k.set(e,[t])}function v(e){return k.get(e)}function g(e){k.set(e,void 0)}function b(e,t){var n=t.getAttribute("select");if(!n)return!0;if(n=n.trim(),!n)return!0;if(!(e instanceof M))return!1;if(!q.test(n))return!1;try{return e.matches(n)}catch(r){return!1}}function y(e,t){var n=v(t);return n&&n[n.length-1]===e}function E(e){return e instanceof O||e instanceof L}function _(e){return e.shadowRoot}function S(e){for(var t=[],n=e.shadowRoot;n;n=n.olderShadowRoot)t.push(n);return t}var T,M=e.wrappers.Element,O=e.wrappers.HTMLContentElement,L=e.wrappers.HTMLShadowElement,N=e.wrappers.Node,C=e.wrappers.ShadowRoot,j=(e.assert,e.getTreeScope),D=(e.mixin,e.oneOf),H=e.unsafeUnwrap,x=e.unwrap,R=e.wrap,I=e.ArraySplice,P=new WeakMap,k=new WeakMap,A=new WeakMap,W=D(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),F=[],U=new I;U.equals=function(e,t){return x(e.node)===t},p.prototype={append:function(e){var t=new p(e);return this.childNodes.push(t),t},sync:function(e){if(!this.skip){for(var t=this.node,o=this.childNodes,i=a(x(t)),s=e||new WeakMap,c=U.calculateSplices(o,i),l=0,u=0,d=0,p=0;p<c.length;p++){for(var h=c[p];d<h.index;d++)u++,o[l++].sync(s);for(var f=h.removed.length,m=0;f>m;m++){var w=R(i[u++]);s.get(w)||r(w)}for(var v=h.addedCount,g=i[u]&&R(i[u]),m=0;v>m;m++){var b=o[l++],y=b.node;n(t,y,g),s.set(y,!0),b.sync(s)}d+=v}for(var p=d;p<o.length;p++)o[p].sync(s)}}},h.prototype={render:function(e){if(this.dirty){this.invalidateAttributes();var t=this.host;this.distribution(t);var n=e||new p(t);this.buildRenderTree(n,t);var r=!e;r&&n.sync(),this.dirty=!1}},get parentRenderer(){return j(this.host).renderer},invalidate:function(){if(!this.dirty){this.dirty=!0;var e=this.parentRenderer;if(e&&e.invalidate(),F.push(this),T)return;T=window[W](c,0)}},distribution:function(e){this.resetAllSubtrees(e),this.distributionResolution(e)},resetAll:function(e){E(e)?o(e):g(e),this.resetAllSubtrees(e)},resetAllSubtrees:function(e){for(var t=e.firstChild;t;t=t.nextSibling)this.resetAll(t);e.shadowRoot&&this.resetAll(e.shadowRoot),e.olderShadowRoot&&this.resetAll(e.olderShadowRoot)},distributionResolution:function(e){if(_(e)){for(var t=e,n=f(t),r=S(t),o=0;o<r.length;o++)this.poolDistribution(r[o],n);for(var o=r.length-1;o>=0;o--){var i=r[o],a=m(i);if(a){var s=i.olderShadowRoot;s&&(n=f(s));for(var c=0;c<n.length;c++)w(n[c],a)}this.distributionResolution(i)}}for(var l=e.firstChild;l;l=l.nextSibling)this.distributionResolution(l)},poolDistribution:function(e,t){if(!(e instanceof L))if(e instanceof O){var n=e;this.updateDependentAttributes(n.getAttribute("select"));for(var r=!1,o=0;o<t.length;o++){var e=t[o];e&&b(e,n)&&(w(e,n),t[o]=void 0,r=!0)}if(!r)for(var i=n.firstChild;i;i=i.nextSibling)w(i,n)}else for(var i=e.firstChild;i;i=i.nextSibling)this.poolDistribution(i,t)},buildRenderTree:function(e,t){for(var n=this.compose(t),r=0;r<n.length;r++){var o=n[r],i=e.append(o);this.buildRenderTree(i,o)}if(_(t)){var a=l(t);a.dirty=!1}},compose:function(e){for(var t=[],n=e.shadowRoot||e,r=n.firstChild;r;r=r.nextSibling)if(E(r)){this.associateNode(n);for(var o=i(r),a=0;a<o.length;a++){var s=o[a];y(r,s)&&t.push(s)}}else t.push(r);return t},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(e){if(e){var t=this.attributes;/\.\w+/.test(e)&&(t["class"]=!0),/#\w+/.test(e)&&(t.id=!0),e.replace(/\[\s*([^\s=\|~\]]+)/g,function(e,n){t[n]=!0})}},dependsOnAttribute:function(e){return this.attributes[e]},associateNode:function(e){H(e).polymerShadowRenderer_=this}};var q=/^(:not\()?[*.#[a-zA-Z_|]/;N.prototype.invalidateShadowRenderer=function(e){var t=H(this).polymerShadowRenderer_;return t?(t.invalidate(),!0):!1},O.prototype.getDistributedNodes=L.prototype.getDistributedNodes=function(){return s(),i(this)},M.prototype.getDestinationInsertionPoints=function(){return s(),v(this)||[]},O.prototype.nodeIsInserted_=L.prototype.nodeIsInserted_=function(){this.invalidateShadowRenderer();var e,t=u(this);t&&(e=d(t)),H(this).polymerShadowRenderer_=e,e&&e.invalidate()},e.getRendererForHost=l,e.getShadowTrees=S,e.renderAllPending=s,e.getDestinationInsertionPoints=v,e.visual={insertBefore:n,remove:r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t){if(window[t]){r(!e.wrappers[t]);var c=function(e){n.call(this,e)};c.prototype=Object.create(n.prototype),o(c.prototype,{get form(){return s(a(this).form)}}),i(window[t],c,document.createElement(t.slice(4,-7))),e.wrappers[t]=c}}var n=e.wrappers.HTMLElement,r=e.assert,o=e.mixin,i=e.registerWrapper,a=e.unwrap,s=e.wrap,c=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOutputElement","HTMLTextAreaElement"];c.forEach(t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.Selection;t.prototype={get anchorNode(){return s(o(this).anchorNode)},get focusNode(){return s(o(this).focusNode)},addRange:function(e){o(this).addRange(a(e))},collapse:function(e,t){o(this).collapse(a(e),t)},containsNode:function(e,t){return o(this).containsNode(a(e),t)},getRangeAt:function(e){return s(o(this).getRangeAt(e))},removeRange:function(e){o(this).removeRange(i(e))},selectAllChildren:function(e){o(this).selectAllChildren(a(e))},toString:function(){return o(this).toString()}},c.prototype.extend&&(t.prototype.extend=function(e,t){o(this).extend(a(e),t)}),n(window.Selection,t,window.getSelection()),e.wrappers.Selection=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrapIfNeeded,a=e.wrap,s=window.TreeWalker;t.prototype={get root(){return a(o(this).root)},get currentNode(){return a(o(this).currentNode)},set currentNode(e){o(this).currentNode=i(e)},get filter(){return o(this).filter},parentNode:function(){return a(o(this).parentNode())},firstChild:function(){return a(o(this).firstChild())},lastChild:function(){return a(o(this).lastChild())},previousSibling:function(){return a(o(this).previousSibling())},previousNode:function(){return a(o(this).previousNode())},nextNode:function(){return a(o(this).nextNode())}},n(s,t),e.wrappers.TreeWalker=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){u.call(this,e),this.treeScope_=new m(this,null)}function n(e){var n=document[e];t.prototype[e]=function(){return N(n.apply(O(this),arguments))}}function r(e,t){D.call(O(t),L(e)),o(e,t)}function o(e,t){e.shadowRoot&&t.adoptNode(e.shadowRoot),e instanceof f&&i(e,t);for(var n=e.firstChild;n;n=n.nextSibling)o(n,t)}function i(e,t){var n=e.olderShadowRoot;n&&t.adoptNode(n)}function a(e){M(e,this)}function s(e,t){var n=document.implementation[t];e.prototype[t]=function(){return N(n.apply(O(this),arguments))}}function c(e,t){var n=document.implementation[t];e.prototype[t]=function(){return n.apply(O(this),arguments)}}var l=e.GetElementsByInterface,u=e.wrappers.Node,d=e.ParentNodeInterface,p=e.wrappers.Selection,h=e.SelectorsInterface,f=e.wrappers.ShadowRoot,m=e.TreeScope,w=e.cloneNode,v=e.defineWrapGetter,g=e.elementFromPoint,b=e.forwardMethodsToWrapper,y=e.matchesNames,E=e.mixin,_=e.registerWrapper,S=e.renderAllPending,T=e.rewrap,M=e.setWrapper,O=e.unsafeUnwrap,L=e.unwrap,N=e.wrap,C=e.wrapEventTargetMethods,j=(e.wrapNodeList,new WeakMap);t.prototype=Object.create(u.prototype),v(t,"documentElement"),v(t,"body"),v(t,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(n);var D=document.adoptNode,H=document.getSelection;E(t.prototype,{adoptNode:function(e){return e.parentNode&&e.parentNode.removeChild(e),r(e,this),e},elementFromPoint:function(e,t){return g(this,this,e,t)},importNode:function(e,t){return w(e,t,O(this))},getSelection:function(){return S(),new p(H.call(L(this)))},getElementsByName:function(e){return h.querySelectorAll.call(this,"[name="+JSON.stringify(String(e))+"]");
+
+}});var x=document.createTreeWalker,R=e.wrappers.TreeWalker;if(t.prototype.createTreeWalker=function(e,t,n,r){var o=null;return n&&(n.acceptNode&&"function"==typeof n.acceptNode?o={acceptNode:function(e){return n.acceptNode(N(e))}}:"function"==typeof n&&(o=function(e){return n(N(e))})),new R(x.call(L(this),L(e),t,o,r))},document.registerElement){var I=document.registerElement;t.prototype.registerElement=function(t,n){function r(e){return e?void M(e,this):i?document.createElement(i,t):document.createElement(t)}var o,i;if(void 0!==n&&(o=n.prototype,i=n["extends"]),o||(o=Object.create(HTMLElement.prototype)),e.nativePrototypeTable.get(o))throw new Error("NotSupportedError");for(var a,s=Object.getPrototypeOf(o),c=[];s&&!(a=e.nativePrototypeTable.get(s));)c.push(s),s=Object.getPrototypeOf(s);if(!a)throw new Error("NotSupportedError");for(var l=Object.create(a),u=c.length-1;u>=0;u--)l=Object.create(l);["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"].forEach(function(e){var t=o[e];t&&(l[e]=function(){N(this)instanceof r||T(this),t.apply(N(this),arguments)})});var d={prototype:l};i&&(d["extends"]=i),r.prototype=o,r.prototype.constructor=r,e.constructorTable.set(l,r),e.nativePrototypeTable.set(o,l);I.call(L(this),t,d);return r},b([window.HTMLDocument||window.Document],["registerElement"])}b([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),b([window.HTMLBodyElement,window.HTMLHeadElement,window.HTMLHtmlElement],y),b([window.HTMLDocument||window.Document],["adoptNode","importNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","createTreeWalker","elementFromPoint","getElementById","getElementsByName","getSelection"]),E(t.prototype,l),E(t.prototype,d),E(t.prototype,h),E(t.prototype,{get implementation(){var e=j.get(this);return e?e:(e=new a(L(this).implementation),j.set(this,e),e)},get defaultView(){return N(L(this).defaultView)}}),_(window.Document,t,document.implementation.createHTMLDocument("")),window.HTMLDocument&&_(window.HTMLDocument,t),C([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),s(a,"createDocumentType"),s(a,"createDocument"),s(a,"createHTMLDocument"),c(a,"hasFeature"),_(window.DOMImplementation,a),b([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),e.adoptNodeNoRemove=r,e.wrappers.DOMImplementation=a,e.wrappers.Document=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.wrappers.Selection,o=e.mixin,i=e.registerWrapper,a=e.renderAllPending,s=e.unwrap,c=e.unwrapIfNeeded,l=e.wrap,u=window.Window,d=window.getComputedStyle,p=window.getDefaultComputedStyle,h=window.getSelection;t.prototype=Object.create(n.prototype),u.prototype.getComputedStyle=function(e,t){return l(this||window).getComputedStyle(c(e),t)},p&&(u.prototype.getDefaultComputedStyle=function(e,t){return l(this||window).getDefaultComputedStyle(c(e),t)}),u.prototype.getSelection=function(){return l(this||window).getSelection()},delete window.getComputedStyle,delete window.getDefaultComputedStyle,delete window.getSelection,["addEventListener","removeEventListener","dispatchEvent"].forEach(function(e){u.prototype[e]=function(){var t=l(this||window);return t[e].apply(t,arguments)},delete window[e]}),o(t.prototype,{getComputedStyle:function(e,t){return a(),d.call(s(this),c(e),t)},getSelection:function(){return a(),new r(h.call(s(this)))},get document(){return l(s(this).document)}}),p&&(t.prototype.getDefaultComputedStyle=function(e,t){return a(),p.call(s(this),c(e),t)}),i(u,t,window),e.wrappers.Window=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrap,n=window.DataTransfer||window.Clipboard,r=n.prototype.setDragImage;r&&(n.prototype.setDragImage=function(e,n,o){r.call(this,t(e),n,o)})}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t;t=e instanceof i?e:new i(e&&o(e)),r(t,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unwrap,i=window.FormData;i&&(n(i,t,new i),e.wrappers.FormData=t)}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrapIfNeeded,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(e){return n.call(this,t(e))}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=n[e],r=window[t];if(r){var o=document.createElement(e),i=o.constructor;window[t]=i}}var n=(e.isWrapperFor,{a:"HTMLAnchorElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",base:"HTMLBaseElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",content:"HTMLContentElement",data:"HTMLDataElement",datalist:"HTMLDataListElement",del:"HTMLModElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",head:"HTMLHeadElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",marquee:"HTMLMarqueeElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",shadow:"HTMLShadowElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",template:"HTMLTemplateElement",textarea:"HTMLTextAreaElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",ul:"HTMLUListElement",video:"HTMLVideoElement"});Object.keys(n).forEach(t),Object.getOwnPropertyNames(e.wrappers).forEach(function(t){window[t]=e.wrappers[t]})}(window.ShadowDOMPolyfill),function(e){function t(e,t){var n="";return Array.prototype.forEach.call(e,function(e){n+=e.textContent+"\n\n"}),t||(n=n.replace(d,"")),n}function n(e){var t=document.createElement("style");return t.textContent=e,t}function r(e){var t=n(e);document.head.appendChild(t);var r=[];if(t.sheet)try{r=t.sheet.cssRules}catch(o){}else console.warn("sheet not found",t);return t.parentNode.removeChild(t),r}function o(){C.initialized=!0,document.body.appendChild(C);var e=C.contentDocument,t=e.createElement("base");t.href=document.baseURI,e.head.appendChild(t)}function i(e){C.initialized||o(),document.body.appendChild(C),e(C.contentDocument),document.body.removeChild(C)}function a(e,t){if(t){var o;if(e.match("@import")&&D){var a=n(e);i(function(e){e.head.appendChild(a.impl),o=Array.prototype.slice.call(a.sheet.cssRules,0),t(o)})}else o=r(e),t(o)}}function s(e){e&&l().appendChild(document.createTextNode(e))}function c(e,t){var r=n(e);r.setAttribute(t,""),r.setAttribute(x,""),document.head.appendChild(r)}function l(){return j||(j=document.createElement("style"),j.setAttribute(x,""),j[x]=!0),j}var u={strictStyling:!1,registry:{},shimStyling:function(e,n,r){var o=this.prepareRoot(e,n,r),i=this.isTypeExtension(r),a=this.makeScopeSelector(n,i),s=t(o,!0);s=this.scopeCssText(s,a),e&&(e.shimmedStyle=s),this.addCssToDocument(s,n)},shimStyle:function(e,t){return this.shimCssText(e.textContent,t)},shimCssText:function(e,t){return e=this.insertDirectives(e),this.scopeCssText(e,t)},makeScopeSelector:function(e,t){return e?t?"[is="+e+"]":e:""},isTypeExtension:function(e){return e&&e.indexOf("-")<0},prepareRoot:function(e,t,n){var r=this.registerRoot(e,t,n);return this.replaceTextInStyles(r.rootStyles,this.insertDirectives),this.removeStyles(e,r.rootStyles),this.strictStyling&&this.applyScopeToContent(e,t),r.scopeStyles},removeStyles:function(e,t){for(var n,r=0,o=t.length;o>r&&(n=t[r]);r++)n.parentNode.removeChild(n)},registerRoot:function(e,t,n){var r=this.registry[t]={root:e,name:t,extendsName:n},o=this.findStyles(e);r.rootStyles=o,r.scopeStyles=r.rootStyles;var i=this.registry[r.extendsName];return i&&(r.scopeStyles=i.scopeStyles.concat(r.scopeStyles)),r},findStyles:function(e){if(!e)return[];var t=e.querySelectorAll("style");return Array.prototype.filter.call(t,function(e){return!e.hasAttribute(R)})},applyScopeToContent:function(e,t){e&&(Array.prototype.forEach.call(e.querySelectorAll("*"),function(e){e.setAttribute(t,"")}),Array.prototype.forEach.call(e.querySelectorAll("template"),function(e){this.applyScopeToContent(e.content,t)},this))},insertDirectives:function(e){return e=this.insertPolyfillDirectivesInCssText(e),this.insertPolyfillRulesInCssText(e)},insertPolyfillDirectivesInCssText:function(e){return e=e.replace(p,function(e,t){return t.slice(0,-2)+"{"}),e.replace(h,function(e,t){return t+" {"})},insertPolyfillRulesInCssText:function(e){return e=e.replace(f,function(e,t){return t.slice(0,-1)}),e.replace(m,function(e,t,n,r){var o=e.replace(t,"").replace(n,"");return r+o})},scopeCssText:function(e,t){var n=this.extractUnscopedRulesFromCssText(e);if(e=this.insertPolyfillHostInCssText(e),e=this.convertColonHost(e),e=this.convertColonHostContext(e),e=this.convertShadowDOMSelectors(e),t){var e,r=this;a(e,function(n){e=r.scopeRules(n,t)})}return e=e+"\n"+n,e.trim()},extractUnscopedRulesFromCssText:function(e){for(var t,n="";t=w.exec(e);)n+=t[1].slice(0,-1)+"\n\n";for(;t=v.exec(e);)n+=t[0].replace(t[2],"").replace(t[1],t[3])+"\n\n";return n},convertColonHost:function(e){return this.convertColonRule(e,E,this.colonHostPartReplacer)},convertColonHostContext:function(e){return this.convertColonRule(e,_,this.colonHostContextPartReplacer)},convertColonRule:function(e,t,n){return e.replace(t,function(e,t,r,o){if(t=O,r){for(var i,a=r.split(","),s=[],c=0,l=a.length;l>c&&(i=a[c]);c++)i=i.trim(),s.push(n(t,i,o));return s.join(",")}return t+o})},colonHostContextPartReplacer:function(e,t,n){return t.match(g)?this.colonHostPartReplacer(e,t,n):e+t+n+", "+t+" "+e+n},colonHostPartReplacer:function(e,t,n){return e+t.replace(g,"")+n},convertShadowDOMSelectors:function(e){for(var t=0;t<N.length;t++)e=e.replace(N[t]," ");return e},scopeRules:function(e,t){var n="";return e&&Array.prototype.forEach.call(e,function(e){if(e.selectorText&&e.style&&void 0!==e.style.cssText)n+=this.scopeSelector(e.selectorText,t,this.strictStyling)+" {\n ",n+=this.propertiesFromRule(e)+"\n}\n\n";else if(e.type===CSSRule.MEDIA_RULE)n+="@media "+e.media.mediaText+" {\n",n+=this.scopeRules(e.cssRules,t),n+="\n}\n\n";else try{e.cssText&&(n+=e.cssText+"\n\n")}catch(r){e.type===CSSRule.KEYFRAMES_RULE&&e.cssRules&&(n+=this.ieSafeCssTextFromKeyFrameRule(e))}},this),n},ieSafeCssTextFromKeyFrameRule:function(e){var t="@keyframes "+e.name+" {";return Array.prototype.forEach.call(e.cssRules,function(e){t+=" "+e.keyText+" {"+e.style.cssText+"}"}),t+=" }"},scopeSelector:function(e,t,n){var r=[],o=e.split(",");return o.forEach(function(e){e=e.trim(),this.selectorNeedsScoping(e,t)&&(e=n&&!e.match(O)?this.applyStrictSelectorScope(e,t):this.applySelectorScope(e,t)),r.push(e)},this),r.join(", ")},selectorNeedsScoping:function(e,t){if(Array.isArray(t))return!0;var n=this.makeScopeMatcher(t);return!e.match(n)},makeScopeMatcher:function(e){return e=e.replace(/\[/g,"\\[").replace(/\]/g,"\\]"),new RegExp("^("+e+")"+S,"m")},applySelectorScope:function(e,t){return Array.isArray(t)?this.applySelectorScopeList(e,t):this.applySimpleSelectorScope(e,t)},applySelectorScopeList:function(e,t){for(var n,r=[],o=0;n=t[o];o++)r.push(this.applySimpleSelectorScope(e,n));return r.join(", ")},applySimpleSelectorScope:function(e,t){return e.match(L)?(e=e.replace(O,t),e.replace(L,t+" ")):t+" "+e},applyStrictSelectorScope:function(e,t){t=t.replace(/\[is=([^\]]*)\]/g,"$1");var n=[" ",">","+","~"],r=e,o="["+t+"]";return n.forEach(function(e){var t=r.split(e);r=t.map(function(e){var t=e.trim().replace(L,"");return t&&n.indexOf(t)<0&&t.indexOf(o)<0&&(e=t.replace(/([^:]*)(:*)(.*)/,"$1"+o+"$2$3")),e}).join(e)}),r},insertPolyfillHostInCssText:function(e){return e.replace(M,b).replace(T,g)},propertiesFromRule:function(e){var t=e.style.cssText;e.style.content&&!e.style.content.match(/['"]+|attr/)&&(t=t.replace(/content:[^;]*;/g,"content: '"+e.style.content+"';"));var n=e.style;for(var r in n)"initial"===n[r]&&(t+=r+": initial; ");return t},replaceTextInStyles:function(e,t){e&&t&&(e instanceof Array||(e=[e]),Array.prototype.forEach.call(e,function(e){e.textContent=t.call(this,e.textContent)},this))},addCssToDocument:function(e,t){e.match("@import")?c(e,t):s(e)}},d=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,p=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,h=/polyfill-next-selector[^}]*content\:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim,f=/\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,m=/(polyfill-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,w=/\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,v=/(polyfill-unscoped-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,g="-shadowcsshost",b="-shadowcsscontext",y=")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)",E=new RegExp("("+g+y,"gim"),_=new RegExp("("+b+y,"gim"),S="([>\\s~+[.,{:][\\s\\S]*)?$",T=/\:host/gim,M=/\:host-context/gim,O=g+"-no-combinator",L=new RegExp(g,"gim"),N=(new RegExp(b,"gim"),[/>>>/g,/::shadow/g,/::content/g,/\/deep\//g,/\/shadow\//g,/\/shadow-deep\//g,/\^\^/g,/\^/g]),C=document.createElement("iframe");C.style.display="none";var j,D=navigator.userAgent.match("Chrome"),H="shim-shadowdom",x="shim-shadowdom-css",R="no-shim";if(window.ShadowDOMPolyfill){s("style { display: none !important; }\n");var I=ShadowDOMPolyfill.wrap(document),P=I.querySelector("head");P.insertBefore(l(),P.childNodes[0]),document.addEventListener("DOMContentLoaded",function(){e.urlResolver;if(window.HTMLImports&&!HTMLImports.useNative){var t="link[rel=stylesheet]["+H+"]",n="style["+H+"]";HTMLImports.importer.documentPreloadSelectors+=","+t,HTMLImports.importer.importsPreloadSelectors+=","+t,HTMLImports.parser.documentSelectors=[HTMLImports.parser.documentSelectors,t,n].join(",");var r=HTMLImports.parser.parseGeneric;HTMLImports.parser.parseGeneric=function(e){if(!e[x]){var t=e.__importElement||e;if(!t.hasAttribute(H))return void r.call(this,e);e.__resource&&(t=e.ownerDocument.createElement("style"),t.textContent=e.__resource),HTMLImports.path.resolveUrlsInStyle(t,e.href),t.textContent=u.shimStyle(t),t.removeAttribute(H,""),t.setAttribute(x,""),t[x]=!0,t.parentNode!==P&&(e.parentNode===P?P.replaceChild(t,e):this.addElementToDocument(t)),t.__importParsed=!0,this.markParsingComplete(e),this.parseNext()}};var o=HTMLImports.parser.hasResource;HTMLImports.parser.hasResource=function(e){return"link"===e.localName&&"stylesheet"===e.rel&&e.hasAttribute(H)?e.__resource:o.call(this,e)}}})}e.ShadowCSS=u}(window.WebComponents)),function(e){window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}}(window.WebComponents),function(e){"use strict";function t(e){return void 0!==p[e]}function n(){s.call(this),this._isInvalid=!0}function r(e){return""==e&&n.call(this),e.toLowerCase()}function o(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,63,96].indexOf(t)?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,96].indexOf(t)?e:encodeURIComponent(e)}function a(e,a,s){function c(e){b.push(e)}var l=a||"scheme start",u=0,d="",v=!1,g=!1,b=[];e:for(;(e[u-1]!=f||0==u)&&!this._isInvalid;){var y=e[u];switch(l){case"scheme start":if(!y||!m.test(y)){if(a){c("Invalid scheme.");break e}d="",l="no scheme";continue}d+=y.toLowerCase(),l="scheme";break;case"scheme":if(y&&w.test(y))d+=y.toLowerCase();else{if(":"!=y){if(a){if(f==y)break e;c("Code point not allowed in scheme: "+y);break e}d="",u=0,l="no scheme";continue}if(this._scheme=d,d="",a)break e;t(this._scheme)&&(this._isRelative=!0),l="file"==this._scheme?"relative":this._isRelative&&s&&s._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==y?(query="?",l="query"):"#"==y?(this._fragment="#",l="fragment"):f!=y&&" "!=y&&"\n"!=y&&"\r"!=y&&(this._schemeData+=o(y));break;case"no scheme":if(s&&t(s._scheme)){l="relative";continue}c("Missing scheme."),n.call(this);break;case"relative or authority":if("/"!=y||"/"!=e[u+1]){c("Expected /, got: "+y),l="relative";continue}l="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=s._scheme),f==y){this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query;break e}if("/"==y||"\\"==y)"\\"==y&&c("\\ is an invalid code point."),l="relative slash";else if("?"==y)this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query="?",l="query";else{if("#"!=y){var E=e[u+1],_=e[u+2];("file"!=this._scheme||!m.test(y)||":"!=E&&"|"!=E||f!=_&&"/"!=_&&"\\"!=_&&"?"!=_&&"#"!=_)&&(this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._path.pop()),l="relative path";continue}this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._fragment="#",l="fragment"}break;case"relative slash":if("/"!=y&&"\\"!=y){"file"!=this._scheme&&(this._host=s._host,this._port=s._port),l="relative path";continue}"\\"==y&&c("\\ is an invalid code point."),l="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=y){c("Expected '/', got: "+y),l="authority ignore slashes";continue}l="authority second slash";break;case"authority second slash":if(l="authority ignore slashes","/"!=y){c("Expected '/', got: "+y);continue}break;case"authority ignore slashes":if("/"!=y&&"\\"!=y){l="authority";continue}c("Expected authority, got: "+y);break;case"authority":if("@"==y){v&&(c("@ already seen."),d+="%40"),v=!0;for(var S=0;S<d.length;S++){var T=d[S];if(" "!=T&&"\n"!=T&&"\r"!=T)if(":"!=T||null!==this._password){var M=o(T);null!==this._password?this._password+=M:this._username+=M}else this._password="";else c("Invalid whitespace in authority.")}d=""}else{if(f==y||"/"==y||"\\"==y||"?"==y||"#"==y){u-=d.length,d="",l="host";continue}d+=y}break;case"file host":if(f==y||"/"==y||"\\"==y||"?"==y||"#"==y){2!=d.length||!m.test(d[0])||":"!=d[1]&&"|"!=d[1]?0==d.length?l="relative path start":(this._host=r.call(this,d),d="",l="relative path start"):l="relative path";continue}" "==y||"\n"==y||"\r"==y?c("Invalid whitespace in file host."):d+=y;break;case"host":case"hostname":if(":"!=y||g){if(f==y||"/"==y||"\\"==y||"?"==y||"#"==y){if(this._host=r.call(this,d),d="",l="relative path start",a)break e;continue}" "!=y&&"\n"!=y&&"\r"!=y?("["==y?g=!0:"]"==y&&(g=!1),d+=y):c("Invalid code point in host/hostname: "+y)}else if(this._host=r.call(this,d),d="",l="port","hostname"==a)break e;break;case"port":if(/[0-9]/.test(y))d+=y;else{if(f==y||"/"==y||"\\"==y||"?"==y||"#"==y||a){if(""!=d){var O=parseInt(d,10);O!=p[this._scheme]&&(this._port=O+""),d=""}if(a)break e;l="relative path start";continue}" "==y||"\n"==y||"\r"==y?c("Invalid code point in port: "+y):n.call(this)}break;case"relative path start":if("\\"==y&&c("'\\' not allowed in path."),l="relative path","/"!=y&&"\\"!=y)continue;break;case"relative path":if(f!=y&&"/"!=y&&"\\"!=y&&(a||"?"!=y&&"#"!=y))" "!=y&&"\n"!=y&&"\r"!=y&&(d+=o(y));else{"\\"==y&&c("\\ not allowed in relative path.");var L;(L=h[d.toLowerCase()])&&(d=L),".."==d?(this._path.pop(),"/"!=y&&"\\"!=y&&this._path.push("")):"."==d&&"/"!=y&&"\\"!=y?this._path.push(""):"."!=d&&("file"==this._scheme&&0==this._path.length&&2==d.length&&m.test(d[0])&&"|"==d[1]&&(d=d[0]+":"),this._path.push(d)),d="","?"==y?(this._query="?",l="query"):"#"==y&&(this._fragment="#",l="fragment")}break;case"query":a||"#"!=y?f!=y&&" "!=y&&"\n"!=y&&"\r"!=y&&(this._query+=i(y)):(this._fragment="#",l="fragment");break;case"fragment":f!=y&&" "!=y&&"\n"!=y&&"\r"!=y&&(this._fragment+=y)}u++}}function s(){this._scheme="",this._schemeData="",this._username="",this._password=null,this._host="",this._port="",this._path=[],this._query="",this._fragment="",this._isInvalid=!1,this._isRelative=!1}function c(e,t){void 0===t||t instanceof c||(t=new c(String(t))),this._url=e,s.call(this);var n=e.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g,"");a.call(this,n,null,t)}var l=!1;if(!e.forceJURL)try{var u=new URL("b","http://a");u.pathname="c%20d",l="http://a/c%20d"===u.href}catch(d){}if(!l){var p=Object.create(null);p.ftp=21,p.file=0,p.gopher=70,p.http=80,p.https=443,p.ws=80,p.wss=443;var h=Object.create(null);h["%2e"]=".",h[".%2e"]="..",h["%2e."]="..",h["%2e%2e"]="..";var f=void 0,m=/[a-zA-Z]/,w=/[a-zA-Z0-9\+\-\.]/;c.prototype={toString:function(){return this.href},get href(){if(this._isInvalid)return this._url;var e="";return(""!=this._username||null!=this._password)&&(e=this._username+(null!=this._password?":"+this._password:"")+"@"),this.protocol+(this._isRelative?"//"+e+this.host:"")+this.pathname+this._query+this._fragment},set href(e){s.call(this),a.call(this,e)},get protocol(){return this._scheme+":"},set protocol(e){this._isInvalid||a.call(this,e+":","scheme start")},get host(){return this._isInvalid?"":this._port?this._host+":"+this._port:this._host},set host(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"host")},get hostname(){return this._host},set hostname(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"hostname")},get port(){return this._port},set port(e){!this._isInvalid&&this._isRelative&&a.call(this,e,"port")},get pathname(){return this._isInvalid?"":this._isRelative?"/"+this._path.join("/"):this._schemeData},set pathname(e){!this._isInvalid&&this._isRelative&&(this._path=[],a.call(this,e,"relative path start"))},get search(){return this._isInvalid||!this._query||"?"==this._query?"":this._query},set search(e){!this._isInvalid&&this._isRelative&&(this._query="?","?"==e[0]&&(e=e.slice(1)),a.call(this,e,"query"))},get hash(){return this._isInvalid||!this._fragment||"#"==this._fragment?"":this._fragment},set hash(e){this._isInvalid||(this._fragment="#","#"==e[0]&&(e=e.slice(1)),a.call(this,e,"fragment"))},get origin(){var e;if(this._isInvalid||!this._scheme)return"";switch(this._scheme){case"data":case"file":case"javascript":case"mailto":return"null"}return e=this.host,e?this._scheme+"://"+e:""}};var v=e.URL;v&&(c.createObjectURL=function(e){return v.createObjectURL.apply(v,arguments)},c.revokeObjectURL=function(e){v.revokeObjectURL(e)}),e.URL=c}}(this),function(e){function t(e){y.push(e),b||(b=!0,m(r))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function r(){b=!1;var e=y;y=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();o(e),n.length&&(e.callback_(n,e),t=!0)}),t&&r()}function o(e){e.nodes_.forEach(function(t){var n=w.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var r=w.get(n);if(r)for(var o=0;o<r.length;o++){var i=r[o],a=i.options;if(n===e||a.subtree){var s=t(a);s&&i.enqueue(s)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++E}function s(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function c(e){var t=new s(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function l(e,t){return _=new s(e,t)}function u(e){return S?S:(S=c(_),S.oldValue=e,S)}function d(){_=S=void 0}function p(e){return e===S||e===_}function h(e,t){return e===t?e:S&&p(e)?S:null}function f(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var m,w=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))m=setTimeout;else if(window.setImmediate)m=window.setImmediate;else{var v=[],g=String(Math.random());window.addEventListener("message",function(e){if(e.data===g){var t=v;v=[],t.forEach(function(e){e()})}}),m=function(e){v.push(e),window.postMessage(g,"*")}}var b=!1,y=[],E=0;a.prototype={observe:function(e,t){if(e=n(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var r=w.get(e);r||w.set(e,r=[]);for(var o,i=0;i<r.length;i++)if(r[i].observer===this){o=r[i],o.removeListeners(),o.options=t;break}o||(o=new f(this,e,t),r.push(o),this.nodes_.push(e)),o.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=w.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){r.removeListeners(),t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var _,S;f.prototype={enqueue:function(e){var n=this.observer.records_,r=n.length;if(n.length>0){var o=n[r-1],i=h(o,e);if(i)return void(n[r-1]=i)}else t(this.observer);n[r]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=w.get(e);t||w.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=w.get(e),n=0;n<t.length;n++)if(t[n]===this){t.splice(n,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,n=e.relatedNode.namespaceURI,r=e.target,o=new l("attributes",r);o.attributeName=t,o.attributeNamespace=n;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(r,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(n)?void 0:e.attributeOldValue?u(a):o});break;case"DOMCharacterDataModified":var r=e.target,o=l("characterData",r),a=e.prevValue;i(r,function(e){return e.characterData?e.characterDataOldValue?u(a):o:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var s,c,p=e.target;"DOMNodeInserted"===e.type?(s=[p],c=[]):(s=[],c=[p]);var h=p.previousSibling,f=p.nextSibling,o=l("childList",e.target.parentNode);o.addedNodes=s,o.removedNodes=c,o.previousSibling=h,o.nextSibling=f,i(e.relatedNode,function(e){return e.childList?o:void 0})}d()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a)}(this),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||f,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===v}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===v)&&(t.removeEventListener(g,o),r(e,t))};t.addEventListener(g,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){c==l&&e&&e({allImports:s,loadedImports:u,errorImports:d})}function r(e){o(e),u.push(this),c++,n()}function i(e){d.push(this),c++,n()}var s=t.querySelectorAll("link[rel=import]"),c=0,l=s.length,u=[],d=[];if(l)for(var p,h=0;l>h&&(p=s[h]);h++)a(p)?(c++,n()):(p.addEventListener("load",r),p.addEventListener("error",i));else n()}function a(e){return d?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&l(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function l(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var u="import",d=Boolean(u in document.createElement("link")),p=Boolean(window.ShadowDOMPolyfill),h=function(e){return p?ShadowDOMPolyfill.wrapIfNeeded(e):e},f=h(document),m={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return h(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(f,"_currentScript",m);var w=/Trident|Edge/.test(navigator.userAgent),v=w?"complete":"interactive",g="readystatechange";d&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)l(e)}()),t(function(e){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var t=f.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),f.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=u,e.useNative=d,e.rootDocument=f,e.whenReady=t,e.isIE=w}(HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e,t){var n=e.ownerDocument,r=n.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,r),e},resolveUrlsInCssText:function(e,r,o){var i=this.replaceUrls(e,o,r,t);return i=this.replaceUrls(i,o,r,n)},replaceUrls:function(e,t,n,r){return e.replace(r,function(e,r,o,i){var a=o.replace(/["']/g,"");return n&&(a=new URL(a,n).href),t.href=a,a=t.href,r+"'"+a+"'"+i})}};e.path=r}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var n=i.getResponseHeader("Location"),a=null;if(n)var a="/"===n.substr(0,1)?location.origin+n:n;r.call(o,!t.ok(i)&&i,i.response||i.responseText,a)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),
+this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,l=e.isIE,u=e.IMPORT_LINK_TYPE,d="link[rel="+u+"]",p={documentSelectors:d,importsSelectors:[d,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(r){t&&t(r),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),l&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(t){r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r["import"],r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=p,e.IMPORT_SELECTOR=d}),HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,l=e.Loader,u=e.Observer,d=e.parser,p={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){h.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);h.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n["import"]=c}d.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),d.parseNext()},loadedAll:function(){d.parseNext()}},h=new l(p.loaded.bind(p),p.loadedAll.bind(p));if(p.observer=new u,!document.baseURI){var f={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",f),Object.defineProperty(c,"baseURI",f)}e.importer=p,e.importLoader=h}),HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(o)}var n=e.initializeModules,r=e.isIE;if(!e.useNative){r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),n();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],r=function(e){n.push(e)},o=function(){n.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void r(e,t)}),r(e,t)}function n(e,t,r){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,r)!==!0&&n(o,t,r),o=o.nextElementSibling;return null}function r(e,n){for(var r=e.shadowRoot;r;)t(r,n),r=r.olderShadowRoot}function o(e,t){i(e,t,[])}function i(e,t,n){if(e=wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var r,o=e.querySelectorAll("link[rel="+a+"]"),s=0,c=o.length;c>s&&(r=o[s]);s++)r["import"]&&i(r["import"],t,n);t(e)}}var a=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return n(e)||r(e)}function n(t){return e.upgrade(t)?!0:void s(t)}function r(e){y(e,function(e){return n(e)?!0:void 0})}function o(e){s(e),p(e)&&y(e,function(e){s(e)})}function i(e){T.push(e),S||(S=!0,setTimeout(a))}function a(){S=!1;for(var e,t=T,n=0,r=t.length;r>n&&(e=t[n]);n++)e();T=[]}function s(e){_?i(function(){c(e)}):c(e)}function c(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&p(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function l(e){u(e),y(e,function(e){u(e)})}function u(e){_?i(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!p(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function p(e){for(var t=e,n=wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function h(e){if(e.shadowRoot&&!e.shadowRoot.__watched){b.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)w(t),t=t.olderShadowRoot}}function f(e){if(b.dom){var n=e[0];if(n&&"childList"===n.type&&n.addedNodes&&n.addedNodes){for(var r=n.addedNodes[0];r&&r!==document&&!r.host;)r=r.parentNode;var o=r&&(r.URL||r._URL||r.host&&r.host.localName)||"";o=o.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,o||"")}e.forEach(function(e){"childList"===e.type&&(M(e.addedNodes,function(e){e.localName&&t(e)}),M(e.removedNodes,function(e){e.localName&&l(e)}))}),b.dom&&console.groupEnd()}function m(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(f(t.takeRecords()),a())}function w(e){if(!e.__observer){var t=new MutationObserver(f);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=wrap(e),b.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),w(e),b.dom&&console.groupEnd()}function g(e){E(e,v)}var b=e.flags,y=e.forSubtree,E=e.forDocumentTree,_=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=_;var S=!1,T=[],M=Array.prototype.forEach.call.bind(Array.prototype.forEach),O=Element.prototype.createShadowRoot;O&&(Element.prototype.createShadowRoot=function(){var e=O.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=h,e.upgradeDocumentTree=g,e.upgradeSubtree=r,e.upgradeAll=t,e.attachedNode=o,e.takeRecords=m}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var r=t.getAttribute("is"),o=e.getRegisteredDefinition(r||t.localName);if(o){if(r&&o.tag==t.localName)return n(t,o);if(!r&&!o["extends"])return n(t,o)}}}function n(t,n){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),r(t,n),t.__upgraded__=!0,i(t),e.attachedNode(t),e.upgradeSubtree(t),a.upgrade&&console.groupEnd(),t}function r(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,n){for(var r={},o=t;o!==n&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)r[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),r[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=r}),CustomElements.addModule(function(e){function t(t,r){var c=r||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(l(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),u(c.__name,c),c.ctor=d(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&v(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){r.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){r.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function r(e,t,n){e=e.toLowerCase();var r=this.getAttribute(e);n.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==r&&this.attributeChangedCallback(e,r,o)}function o(e){for(var t=0;t<_.length;t++)if(e===_[t])return!0}function i(e){var t=l(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,n=e["extends"],r=0;t=e.ancestry[r];r++)n=t.is&&t.tag;e.tag=n||e.__name,n&&(e.is=e.__name)}function s(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var n=document.createElement(e.tag),r=Object.getPrototypeOf(n);r===e.prototype&&(t=r)}for(var o,i=e.prototype;i&&i!==t;)o=Object.getPrototypeOf(i),i.__proto__=o,i=o;e["native"]=t}}function c(e){return b(M(e.tag),e)}function l(e){return e?S[e.toLowerCase()]:void 0}function u(e,t){S[e]=t}function d(e){return function(){return c(e)}}function p(e,t,n){return e===T?h(t,n):O(e,t)}function h(e,t){var n=l(t||e);if(n){if(e==n.tag&&t==n.is)return new n.ctor;if(!t&&!n.is)return new n.ctor}var r;return t?(r=h(e),r.setAttribute("is",t),r):(r=M(e),e.indexOf("-")>=0&&y(r,HTMLElement),r)}function f(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return g(e),e}}var m,w=e.isIE11OrOlder,v=e.upgradeDocumentTree,g=e.upgradeAll,b=e.upgradeWithDefinition,y=e.implementPrototype,E=e.useNative,_=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],S={},T="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),O=document.createElementNS.bind(document);m=Object.__proto__||E?function(e,t){return e instanceof t}:function(e,t){for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},f(Node.prototype,"cloneNode"),f(document,"importNode"),w&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType==t.DOCUMENT_FRAGMENT_NODE){var n=document.createDocumentFragment();return n.appendChild(t),n}return t}}(),document.registerElement=t,document.createElement=h,document.createElementNS=p,e.registry=S,e["instanceof"]=m,e.reservedTagList=_,e.getRegisteredDefinition=l,document.register=document.registerElement}),function(e){function t(){a(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){a(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var n=e.useNative,r=e.initializeModules,o=/Trident/.test(navigator.userAgent);if(n){var i=function(){};e.watchShadow=i,e.upgrade=i,e.upgradeAll=i,e.upgradeDocumentTree=i,e.upgradeSubtree=i,e.takeRecords=i,e["instanceof"]=function(e,t){return e instanceof t}}else r();var a=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),o&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t();e.isIE11OrOlder=o}(window.CustomElements),function(e){Function.prototype.bind||(Function.prototype.bind=function(e){var t=this,n=Array.prototype.slice.call(arguments,1);return function(){var r=n.slice();return r.push.apply(r,arguments),t.apply(e,r)}})}(window.WebComponents),function(e){"use strict";function t(){window.Polymer===o&&(window.Polymer=function(){throw new Error('You tried to use polymer without loading it first. To load polymer, <link rel="import" href="components/polymer/polymer.html">')})}if(!window.performance){var n=Date.now();window.performance={now:function(){return Date.now()-n}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var r=[],o=function(e,t){"string"!=typeof e&&1===arguments.length&&Array.prototype.push.call(arguments,document._currentScript),r.push(arguments)};window.Polymer=o,e.consumeDeclarations=function(t){e.consumeDeclarations=function(){throw"Possible attempt to load Polymer twice"},t&&t(r),r=null},HTMLImports.useNative?t():addEventListener("DOMContentLoaded",t)}(window.WebComponents),function(e){var t=document.createElement("style");t.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var n=document.querySelector("head");n.insertBefore(t,n.firstChild)}(window.WebComponents),function(e){window.Platform=e}(window.WebComponents); \ No newline at end of file
diff --git a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py
index c3e08cbc2b0..636838006ca 100644
--- a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py
+++ b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py
@@ -103,11 +103,6 @@ def GenerateJSToFile(f,
f.write(js_warning_message)
f.write('\n')
- loader = load_sequence[0].loader
-
- polymer_script = loader.LoadRawScript('components/polymer/polymer.min.js')
- f.write(polymer_script.contents)
-
if not minify:
flatten_to_file = f
else:
diff --git a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py
index d6b594e1f4e..97855cae838 100644
--- a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py
+++ b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py
@@ -56,10 +56,7 @@ class HTMLModule(module.Module):
use_include_tags_for_scripts,
dir_for_include_tag_root)
for inline_script in self._parser_results.inline_scripts:
- if not HasPolymerCall(inline_script.stripped_contents):
- js = inline_script.contents
- else:
- js = GetInlineScriptContentWithPolymerizingApplied(inline_script)
+ js = inline_script.contents
js = js_utils.EscapeJSIfNeeded(js)
@@ -91,53 +88,6 @@ class HTMLModule(module.Module):
ss.AppendDirectlyDependentFilenamesTo(dependent_filenames)
-def GetInlineScriptContentWithPolymerizingApplied(inline_script):
- polymer_element_name = GetPolymerElementNameFromOpenTags(
- inline_script.open_tags)
- if polymer_element_name is None:
- raise module.DepsException(
- 'Tagless Polymer() call must be made inside a <polymer-element> tag')
-
- return UpdatePolymerCallsGivenElementName(
- inline_script.stripped_contents, polymer_element_name)
-
-
-def GetPolymerElementNameFromOpenTags(open_tags):
- found_tag = None
- for tag in reversed(open_tags):
- if tag.tag == 'polymer-element':
- found_tag = tag
- break
-
- if not found_tag:
- return None
-
- return found_tag.attrs.get('name', None)
-
-_POLYMER_RE_1 = 'Polymer(\s*?)\((\s*?)\{'
-_POLYMER_RE_2 = 'Polymer(\s*?)\((\s*?)\)'
-
-
-def HasPolymerCall(js):
- if re.search(_POLYMER_RE_1, js) is not None:
- return True
- if re.search(_POLYMER_RE_2, js) is not None:
- return True
- return False
-
-
-def UpdatePolymerCallsGivenElementName(js, polymer_element_name):
- if re.search(_POLYMER_RE_1, js) is not None:
- return re.sub(_POLYMER_RE_1,
- 'Polymer\g<1>(\g<2>\'%s\', {' % polymer_element_name,
- js, 0, re.DOTALL)
- if re.search(_POLYMER_RE_2, js) is not None:
- return re.sub(_POLYMER_RE_2,
- 'Polymer\g<1>(\g<2>\'%s\')' % polymer_element_name,
- js, 0, re.DOTALL)
- assert False, 'This should never be reached'
-
-
def _HRefToResource(
loader, module_name, module_dir_name, href, tag_for_err_msg):
if href[0] == '/':
diff --git a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module_unittest.py b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module_unittest.py
index 1931bb58267..828d29b0409 100644
--- a/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module_unittest.py
+++ b/chromium/third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module_unittest.py
@@ -183,14 +183,14 @@ class HTMLModuleTests(unittest.TestCase):
<link rel="import" href="/widget.html">
<link rel="stylesheet" href="../common.css">
<script src="/raw_script.js"></script>
-<polymer-element name="start">
+<dom-module id="start">
<template>
</template>
<script>
'use strict';
console.log('inline script for start.html got written');
</script>
-</polymer-element>
+</dom-module>
"""
file_contents[os.path.normpath('/py_vulcanize/py_vulcanize.html')] = """<!DOCTYPE html>
"""
@@ -244,7 +244,7 @@ console.log('/raw/raw_script.js was written');
# Check HTML generation.
html = generate.GenerateStandaloneHTMLAsString(
load_sequence, title='', flattened_js_url='/blah.js')
- assert '<polymer-element name="start">' in html
+ assert '<dom-module id="start">' in html
assert 'inline script for widget.html' not in html
assert 'common.css' in html
@@ -252,15 +252,16 @@ console.log('/raw/raw_script.js was written');
file_contents = {}
file_contents[os.path.normpath('/tmp/a/b/my_component.html')] = """
<!DOCTYPE html>
-<polymer-element name="my-component">
+<dom-module id="my-component">
<template>
</template>
<script>
'use strict';
Polymer ( {
+ is: "my-component"
});
</script>
-</polymer-element>
+</dom-module>
"""
with fake_fs.FakeFS(file_contents):
project = project_module.Project([
@@ -276,42 +277,12 @@ console.log('/raw/raw_script.js was written');
js = f.getvalue().rstrip()
expected_js = """
'use strict';
- Polymer ( 'my-component', {
+ Polymer ( {
+ is: "my-component"
});
""".rstrip()
self.assertEquals(expected_js, js)
- def testPolymerConversion2(self):
- file_contents = {}
- file_contents[os.path.normpath('/tmp/a/b/my_component.html')] = """
-<!DOCTYPE html>
-<polymer-element name="my-component">
- <template>
- </template>
- <script>
- 'use strict';
- Polymer ( );
- </script>
-</polymer-element>
-"""
- with fake_fs.FakeFS(file_contents):
- project = project_module.Project([
- os.path.normpath('/py_vulcanize/'), os.path.normpath('/tmp/')])
- loader = resource_loader.ResourceLoader(project)
- my_component = loader.LoadModule(module_name='a.b.my_component')
-
- f = StringIO.StringIO()
- my_component.AppendJSContentsToFile(
- f,
- use_include_tags_for_scripts=False,
- dir_for_include_tag_root=None)
- js = f.getvalue().rstrip()
- expected_js = """
- 'use strict';
- Polymer ( 'my-component');
-""".rstrip()
- self.assertEquals(expected_js, js)
-
def testInlineStylesheetURLs(self):
file_contents = {}
file_contents[os.path.normpath('/tmp/a/b/my_component.html')] = """
diff --git a/chromium/third_party/catapult/tracing/bin/compare_samples b/chromium/third_party/catapult/tracing/bin/compare_samples
new file mode 100755
index 00000000000..ff56ccc69fa
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/bin/compare_samples
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import os
+import sys
+
+tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ '..'))
+sys.path.append(tracing_path)
+from tracing.metrics import compare_samples
+
+def Main(argv):
+ parser = argparse.ArgumentParser(
+ description='Compare samples.')
+ parser.add_argument('sample_a', type=str,
+ help='comma-separated list of paths to valuesets from '
+ 'sample a')
+ parser.add_argument('sample_b', type=str,
+ help='comma-separated list of paths to valuesets from '
+ 'sample b')
+ parser.add_argument('metric', type=str,
+ help='name of the metric to compare')
+ parser.add_argument('--chartjson', dest='format', action='store_const',
+ const='chartjson',
+ help='assume chartjson format for the input data')
+ parser.add_argument('--buildbot', dest='format', action='store_const',
+ const='buildbot',
+ help='assume buildbot result line format for the data')
+ parser.add_argument('--valueset', dest='format', action='store_const',
+ const='valueset',
+ help='assume valueset format for the input data')
+ args = parser.parse_args(argv[1:])
+
+ if not args.format:
+ filename = os.path.basename(sample_a.split(',')[0])
+ if filename == 'results-valueset.json':
+ args.format = 'valueset'
+ else:
+ args.format = 'chartjson'
+
+ vinn_result = compare_samples.CompareSamples(
+ args.sample_a,
+ args.sample_b,
+ args.metric,
+ args.format
+ )
+ print vinn_result.stdout
+ return vinn_result.returncode
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/generate_about_tracing_contents b/chromium/third_party/catapult/tracing/bin/generate_about_tracing_contents
index 37b868ccfd5..feee8828976 100755
--- a/chromium/third_party/catapult/tracing/bin/generate_about_tracing_contents
+++ b/chromium/third_party/catapult/tracing/bin/generate_about_tracing_contents
@@ -7,8 +7,8 @@ import os
import sys
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import generate_about_tracing_contents
sys.exit(generate_about_tracing_contents.Main(sys.argv[1:]))
diff --git a/chromium/third_party/catapult/tracing/bin/html2trace b/chromium/third_party/catapult/tracing/bin/html2trace
index 2d81211368e..82161fb1cfd 100755
--- a/chromium/third_party/catapult/tracing/bin/html2trace
+++ b/chromium/third_party/catapult/tracing/bin/html2trace
@@ -4,10 +4,13 @@
# found in the LICENSE file.
import argparse
+import codecs
import sys
import os
-sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
+sys.path.append(tracing_path)
from tracing_build import html2trace
@@ -38,8 +41,9 @@ def main():
else:
gzipped_output = args.trace_path.endswith('.gz')
- saved_paths = html2trace.CopyTraceDataFromHTMLFilePath(
- args.html_path, args.trace_path, gzipped_output)
+ with codecs.open(args.html_path, mode='r', encoding='utf-8') as html_file:
+ saved_paths = html2trace.CopyTraceDataFromHTMLFilePath(
+ html_file, args.trace_path, gzipped_output)
if not args.quiet:
print '\n'.join(saved_paths)
diff --git a/chromium/third_party/catapult/tracing/bin/index.html b/chromium/third_party/catapult/tracing/bin/index.html
index dca63e3e970..d48ccc92a4a 100644
--- a/chromium/third_party/catapult/tracing/bin/index.html
+++ b/chromium/third_party/catapult/tracing/bin/index.html
@@ -6,6 +6,8 @@ found in the LICENSE file.
-->
<head>
<script>
+'use strict';
+
function onTraceViewerImportFail() {
document.addEventListener('DOMContentLoaded', function() {
document.body.textContent =
@@ -35,6 +37,8 @@ function onTraceViewerImportFail() {
}
</style>
<script>
+'use strict';
+
(function() {
var viewer;
var url;
@@ -94,11 +98,11 @@ function onTraceViewerImportFail() {
viewer = document.createElement('tr-ui-timeline-view');
viewer.track_view_container = container;
- viewer.appendChild(container);
+ Polymer.dom(viewer).appendChild(container);
viewer.id = 'trace-viewer';
viewer.globalMode = true;
- document.body.appendChild(viewer);
+ Polymer.dom(document.body).appendChild(viewer);
url = '../test_data/big_trace.json';
load();
diff --git a/chromium/third_party/catapult/tracing/bin/map_traces b/chromium/third_party/catapult/tracing/bin/map_traces
new file mode 100755
index 00000000000..af58491504d
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/bin/map_traces
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+if __name__ == '__main__':
+ tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ '..'))
+ sys.path.append(tracing_path)
+ from tracing.mre import map_traces
+ sys.exit(map_traces.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/merge_traces b/chromium/third_party/catapult/tracing/bin/merge_traces
index bce07dba316..4b610dd0699 100755
--- a/chromium/third_party/catapult/tracing/bin/merge_traces
+++ b/chromium/third_party/catapult/tracing/bin/merge_traces
@@ -7,7 +7,8 @@ import os
import sys
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import merge_traces
sys.exit(merge_traces.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/run_dev_server_tests b/chromium/third_party/catapult/tracing/bin/run_dev_server_tests
index 1e97395009c..bd09476721e 100755
--- a/chromium/third_party/catapult/tracing/bin/run_dev_server_tests
+++ b/chromium/third_party/catapult/tracing/bin/run_dev_server_tests
@@ -7,8 +7,8 @@ import os
import sys
if __name__ == '__main__':
- catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..'))
- sys.path.append(catapult_path)
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..', '..'))
+ sys.path.append(tracing_path)
from catapult_build import run_dev_server_tests
sys.exit(run_dev_server_tests.Main(sys.argv + ['--tests=tracing']))
diff --git a/chromium/third_party/catapult/tracing/bin/run_metric b/chromium/third_party/catapult/tracing/bin/run_metric
index 91a0eb35fb8..c1d913c5658 100755
--- a/chromium/third_party/catapult/tracing/bin/run_metric
+++ b/chromium/third_party/catapult/tracing/bin/run_metric
@@ -4,48 +4,71 @@
# found in the LICENSE file.
import argparse
+import codecs
import json
import os
import sys
sys.path.insert(1, os.path.join(os.path.dirname(__file__), '..'))
+from tracing import results_renderer
from tracing.metrics import metric_runner
from tracing.metrics import discover
def Main(argv):
all_metrics = discover.DiscoverMetrics(
['/tracing/metrics/all_metrics.html'])
+
parser = argparse.ArgumentParser(
description='Runs metrics on local traces')
- parser.add_argument('metric_name',
- help=('The function name of a registered metric, NOT '
- 'filename. Available metrics are: %s' %
- ', '.join(all_metrics)),
- choices=all_metrics, metavar='metricName')
parser.add_argument('trace_file_or_dir',
help='A trace file, or a dir containing trace files')
+ parser.add_argument('metrics', nargs='+',
+ help=('Function names of registered metrics '
+ '(not filenames.) '
+ 'Available metrics are: %s' %
+ ', '.join(all_metrics)),
+ choices=all_metrics, metavar='metricName')
+ parser.add_argument('--filename', default='results2', type=str,
+ help='Output file name (no extension)')
+ parser.add_argument('--reset', action='store_true',
+ help=('Whether to ignore existing results in HTML file '
+ '(if it exists'))
+ parser.add_argument('--also-output-json', action='store_true',
+ help=('Also output json file containing values. Note that'
+ 'this only contains the results of current run'))
args = parser.parse_args(argv[1:])
- metric = args.metric_name
+ trace_file_or_dir = os.path.abspath(args.trace_file_or_dir)
- if os.path.isdir(args.trace_file_or_dir):
- trace_dir = args.trace_file_or_dir
+ if os.path.isdir(trace_file_or_dir):
+ trace_dir = trace_file_or_dir
traces = [os.path.join(trace_dir, trace) for trace in os.listdir(trace_dir)]
else:
- traces = [args.trace_file_or_dir]
-
- results = {k: v.AsDict()
- for k, v in metric_runner.RunMetricOnTraces(traces, metric).iteritems()}
+ traces = [trace_file_or_dir]
failures = []
- for trace in traces:
- failures.extend(results[trace].get('failures', []))
+ histograms = []
+ for trace_url, mre_result in metric_runner.RunMetricOnTraces(
+ traces, args.metrics).iteritems():
+ failures.extend(mre_result.failures)
+ histograms.extend(mre_result.pairs.get('histograms', []))
+
if failures:
print 'Running metric failed:'
for failure in failures:
print failure['stack']
- else:
- print json.dumps(results, indent=2, sort_keys=True, separators=(',', ': '))
+
+ output_file = args.filename + '.html'
+ open(output_file, 'a').close() # Create file if it doesn't exist.
+ with codecs.open(output_file, mode='r+', encoding='utf-8') as output_stream:
+ results_renderer.RenderHTMLView(histograms, output_stream, args.reset)
+ print 'HTML result created in file://' + os.path.abspath(output_file)
+
+ if args.also_output_json:
+ output_file = args.filename + '.json'
+ with open(output_file, 'w') as f:
+ json.dump(histograms, f, indent=2, sort_keys=True, separators=(',', ': '))
+ print 'JSON result created in file://' + os.path.abspath(output_file)
if __name__ == '__main__':
diff --git a/chromium/third_party/catapult/tracing/bin/run_py_tests b/chromium/third_party/catapult/tracing/bin/run_py_tests
index d5cf781888a..23a6ceaa31f 100755
--- a/chromium/third_party/catapult/tracing/bin/run_py_tests
+++ b/chromium/third_party/catapult/tracing/bin/run_py_tests
@@ -7,8 +7,11 @@ import os
import platform
import sys
-_CATAPULT_PATH = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+_CATAPULT_PATH = os.path.abspath(
+ os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ os.path.pardir,
+ os.path.pardir))
_TRACING_PATH = os.path.join(_CATAPULT_PATH, 'tracing')
@@ -33,8 +36,6 @@ if __name__ == '__main__':
install.InstallHooks()
from catapult_build import run_with_typ
- # https://github.com/catapult-project/catapult/issues/2050
- if platform.system() != 'Windows':
- _RunTestsOrDie(os.path.join(_TRACING_PATH, 'tracing'))
+ _RunTestsOrDie(os.path.join(_TRACING_PATH, 'tracing'))
_RunTestsOrDie(os.path.join(_TRACING_PATH, 'tracing_build'))
sys.exit(0)
diff --git a/chromium/third_party/catapult/tracing/bin/run_tests b/chromium/third_party/catapult/tracing/bin/run_tests
index a1bbf158267..df95b1d6c4e 100755
--- a/chromium/third_party/catapult/tracing/bin/run_tests
+++ b/chromium/third_party/catapult/tracing/bin/run_tests
@@ -7,7 +7,7 @@ import os
import sys
-_THIS_PATH = os.path.dirname(__file__)
+_THIS_PATH = os.path.dirname(os.path.realpath(__file__))
_TESTS = [
{'path': os.path.join(_THIS_PATH, 'run_py_tests')},
{'path': os.path.join(_THIS_PATH, 'run_vinn_tests'),
@@ -18,8 +18,8 @@ _TESTS = [
if __name__ == '__main__':
- catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..'))
- sys.path.append(catapult_path)
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
+ sys.path.append(tracing_path)
from catapult_build import test_runner
sys.exit(test_runner.Main('tracing', _TESTS, sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/run_vinn_tests b/chromium/third_party/catapult/tracing/bin/run_vinn_tests
index cc68ef0d267..42ec180f119 100755
--- a/chromium/third_party/catapult/tracing/bin/run_vinn_tests
+++ b/chromium/third_party/catapult/tracing/bin/run_vinn_tests
@@ -7,8 +7,8 @@ import os
import sys
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import run_vinn_tests
sys.exit(run_vinn_tests.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/slim_trace b/chromium/third_party/catapult/tracing/bin/slim_trace
new file mode 100755
index 00000000000..2e170777840
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/bin/slim_trace
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+import os
+
+tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
+sys.path.append(tracing_path)
+from tracing_build import slim_trace
+
+
+if __name__ == '__main__':
+ sys.exit(slim_trace.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/strip_memory_infra_trace b/chromium/third_party/catapult/tracing/bin/strip_memory_infra_trace
new file mode 100755
index 00000000000..8bdc8375d75
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/bin/strip_memory_infra_trace
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+if __name__ == '__main__':
+ tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ sys.path.append(tracing_path)
+ from tracing_build import strip_memory_infra_trace
+ sys.exit(strip_memory_infra_trace.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/symbolize_trace b/chromium/third_party/catapult/tracing/bin/symbolize_trace
index 4aad7d94e52..ecfbb673bf0 100755
--- a/chromium/third_party/catapult/tracing/bin/symbolize_trace
+++ b/chromium/third_party/catapult/tracing/bin/symbolize_trace
@@ -10,10 +10,11 @@ import gzip
import json
import os
import re
+import subprocess
import sys
_SYMBOLS_PATH = os.path.abspath(os.path.join(
- os.path.dirname(__file__),
+ os.path.dirname(os.path.realpath(__file__)),
'..',
'third_party',
'symbols'))
@@ -32,12 +33,31 @@ TRACE_EVENT_PHASE_MEMORY_DUMP = 'v'
# as well as L+ (/data/app/<>/lib/<>/lib.so). Library name is available
# via 'name' group.
ANDROID_PATH_MATCHER = re.compile(
- r'^/data/(?:app/[^/]+/lib/[^/]+/|app-lib/[^/]+/)(?P<name>.*\.so)')
+ r'^/data/(?:'
+ r'app/[^/]+/lib/[^/]+/|'
+ r'app-lib/[^/]+/|'
+ r'data/[^/]+/incremental-install-files/lib/'
+ r')(?P<name>.*\.so)')
# Subpath of output path where unstripped libraries are stored.
ANDROID_UNSTRIPPED_SUBPATH = 'lib.unstripped'
+def FindInSystemPath(binary_name):
+ paths = os.environ['PATH'].split(os.pathsep)
+ for path in paths:
+ binary_path = os.path.join(path, binary_name)
+ if os.path.isfile(binary_path):
+ return binary_path
+ return None
+
+
+def IsSymbolizableFile(file_path):
+ result = subprocess.check_output(['file', '-0', file_path])
+ type_string = result[result.find('\0') + 1:]
+ return bool(re.match(r'\: (ELF|Mach-O) (32|64)-bit\b', type_string))
+
+
class ProcessMemoryMaps(object):
"""Represents 'process_mmaps' trace file entry."""
@@ -222,6 +242,7 @@ class SymbolizableFile(object):
"""
def __init__(self, file_path):
self.path = file_path
+ self.symbolizable_path = file_path # path to use for symbolization
self.frames_by_address = collections.defaultdict(list)
@@ -264,14 +285,16 @@ def SymbolizeFiles(symfiles, addr2line_path):
symfile.path if symfile.path else 'unnamed')
problem = None
- if not os.path.isabs(symfile.path):
+ if not os.path.isabs(symfile.symbolizable_path):
problem = 'not a file'
- elif not os.path.isfile(symfile.path):
+ elif not os.path.isfile(symfile.symbolizable_path):
problem = "file doesn't exist"
+ elif not IsSymbolizableFile(symfile.symbolizable_path):
+ problem = 'file is not symbolizable'
if problem:
- _SubPrintf("Can't symbolize {} PCs for '{}': {}.",
+ _SubPrintf("Won't symbolize {} PCs for '{}': {}.",
len(symfile.frames_by_address),
- symfile.path,
+ symfile.symbolizable_path,
problem)
for frames in symfile.frames_by_address.itervalues():
for frame in frames:
@@ -287,7 +310,7 @@ def SymbolizeFiles(symfiles, addr2line_path):
for frame in frames:
frame.name = symbolized_name
- symbolizer = elf_symbolizer.ELFSymbolizer(symfile.path,
+ symbolizer = elf_symbolizer.ELFSymbolizer(symfile.symbolizable_path,
addr2line_path,
_SymbolizerCallback,
inlines=True)
@@ -309,15 +332,6 @@ def SymbolizeFiles(symfiles, addr2line_path):
return symbolized
-def FindInSystemPath(binary_name):
- paths = os.environ['PATH'].split(os.pathsep)
- for path in paths:
- binary_path = os.path.join(path, binary_name)
- if os.path.isfile(binary_path):
- return binary_path
- return None
-
-
def HaveFilesFromAndroid(symfiles):
return any(ANDROID_PATH_MATCHER.match(f.path) for f in symfiles)
@@ -327,7 +341,13 @@ def RemapAndroidFiles(symfiles, output_path):
match = ANDROID_PATH_MATCHER.match(symfile.path)
if match:
name = match.group('name')
- symfile.path = os.path.join(output_path, ANDROID_UNSTRIPPED_SUBPATH, name)
+ symfile.symbolizable_path = os.path.join(
+ output_path, ANDROID_UNSTRIPPED_SUBPATH, name)
+ else:
+ # Clobber file path to trigger "not a file" problem in SymbolizeFiles().
+ # Without this, files won't be symbolized with "file not found" problem,
+ # which is not accurate.
+ symfile.symbolizable_path = 'android://{}'.format(symfile.path)
# Suffix used for backup files.
diff --git a/chromium/third_party/catapult/tracing/bin/trace2html b/chromium/third_party/catapult/tracing/bin/trace2html
index 2aa20273b2d..0457d39a66b 100755
--- a/chromium/third_party/catapult/tracing/bin/trace2html
+++ b/chromium/third_party/catapult/tracing/bin/trace2html
@@ -7,8 +7,8 @@ import sys
import os
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import trace2html
sys.exit(trace2html.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/update_gypi b/chromium/third_party/catapult/tracing/bin/update_gypi
index 2c66ae1a38f..a4e54fdf348 100755
--- a/chromium/third_party/catapult/tracing/bin/update_gypi
+++ b/chromium/third_party/catapult/tracing/bin/update_gypi
@@ -7,8 +7,8 @@ import os
import sys
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import update_gypi
sys.exit(update_gypi.Update())
diff --git a/chromium/third_party/catapult/tracing/bin/validate_all_metrics b/chromium/third_party/catapult/tracing/bin/validate_all_metrics
index 4711c5590f8..b4b26307bc1 100755
--- a/chromium/third_party/catapult/tracing/bin/validate_all_metrics
+++ b/chromium/third_party/catapult/tracing/bin/validate_all_metrics
@@ -9,7 +9,9 @@ import os
import string
import sys
-sys.path.insert(1, os.path.join(os.path.dirname(__file__), '..'))
+sys.path.insert(
+ 1,
+ os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
from tracing.metrics import discover
import tracing_project
diff --git a/chromium/third_party/catapult/tracing/bin/vulcanize_trace_viewer b/chromium/third_party/catapult/tracing/bin/vulcanize_trace_viewer
index 2ce8d81deac..c3602d40447 100755
--- a/chromium/third_party/catapult/tracing/bin/vulcanize_trace_viewer
+++ b/chromium/third_party/catapult/tracing/bin/vulcanize_trace_viewer
@@ -7,8 +7,8 @@ import os
import sys
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..'))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
from tracing_build import vulcanize_trace_viewer
sys.exit(vulcanize_trace_viewer.Main(sys.argv))
diff --git a/chromium/third_party/catapult/tracing/bin/why_imported b/chromium/third_party/catapult/tracing/bin/why_imported
index a8c78220749..9b5a59a6f49 100755
--- a/chromium/third_party/catapult/tracing/bin/why_imported
+++ b/chromium/third_party/catapult/tracing/bin/why_imported
@@ -40,8 +40,8 @@ def Main():
if __name__ == '__main__':
- tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
- os.path.pardir))
+ tracing_path = os.path.abspath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), '..'))
sys.path.append(tracing_path)
import tracing_project
tracing_project.UpdateSysPathIfNeeded()
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/README.md b/chromium/third_party/catapult/tracing/third_party/components/core-component-page/README.md
deleted file mode 100644
index 7cb18ec7fef..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-core-component-page
-===================
-
-See the [component page](http://polymer-project.org/docs/elements/core-elements.html#core-component-page) for more information.
-
-Note: this is the vulcanized version of [`core-component-page-dev`](https://github.com/Polymer/core-component-page-dev) (the source).
diff --git a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/core-component-page.html b/chromium/third_party/catapult/tracing/third_party/components/core-component-page/core-component-page.html
deleted file mode 100644
index 5c642c77667..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/core-component-page/core-component-page.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!--
-Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--->
-
-<style>body{margin:0}</style>
-
-<div hidden><link rel="import" href="../polymer/polymer.html"><polymer-element name="core-meta" attributes="label type" hidden assetpath="../core-meta/"><script>(function(){var SKIP_ID="meta";var metaData={},metaArray={};Polymer("core-meta",{type:"default",alwaysPrepare:true,ready:function(){this.register(this.id)},get metaArray(){var t=this.type;if(!metaArray[t]){metaArray[t]=[]}return metaArray[t]},get metaData(){var t=this.type;if(!metaData[t]){metaData[t]={}}return metaData[t]},register:function(id,old){if(id&&id!==SKIP_ID){this.unregister(this,old);this.metaData[id]=this;this.metaArray.push(this)}},unregister:function(meta,id){delete this.metaData[id||meta.id];var i=this.metaArray.indexOf(meta);if(i>=0){this.metaArray.splice(i,1)}},get list(){return this.metaArray},byId:function(id){return this.metaData[id]}})})();</script></polymer-element><polymer-element name="core-iconset" extends="core-meta" attributes="src width icons iconSize" assetpath="../core-iconset/"><script>Polymer("core-iconset",{src:"",width:0,icons:"",iconSize:24,offsetX:0,offsetY:0,type:"iconset",created:function(){this.iconMap={};this.iconNames=[];this.themes={}},ready:function(){if(this.src&&this.ownerDocument!==document){this.src=this.resolvePath(this.src,this.ownerDocument.baseURI)}this.super();this.updateThemes()},iconsChanged:function(){var ox=this.offsetX;var oy=this.offsetY;this.icons&&this.icons.split(/\s+/g).forEach(function(name,i){this.iconNames.push(name);this.iconMap[name]={offsetX:ox,offsetY:oy};if(ox+this.iconSize<this.width){ox+=this.iconSize}else{ox=this.offsetX;oy+=this.iconSize}},this)},updateThemes:function(){var ts=this.querySelectorAll("property[theme]");ts&&ts.array().forEach(function(t){this.themes[t.getAttribute("theme")]={offsetX:parseInt(t.getAttribute("offsetX"))||0,offsetY:parseInt(t.getAttribute("offsetY"))||0}},this)},getOffset:function(icon,theme){var i=this.iconMap[icon];if(!i){var n=this.iconNames[Number(icon)];i=this.iconMap[n]}var t=this.themes[theme];if(i&&t){return{offsetX:i.offsetX+t.offsetX,offsetY:i.offsetY+t.offsetY}}return i},applyIcon:function(element,icon,scale){var offset=this.getOffset(icon);scale=scale||1;if(element&&offset){var icon=element._icon||document.createElement("div");var style=icon.style;style.backgroundImage="url("+this.src+")";style.backgroundPosition=-offset.offsetX*scale+"px"+" "+(-offset.offsetY*scale+"px");style.backgroundSize=scale===1?"auto":this.width*scale+"px";if(icon.parentNode!==element){element.appendChild(icon)}return icon}}});</script></polymer-element><style shim-shadowdom="">html /deep/ core-icon{display:inline-block;vertical-align:middle;background-repeat:no-repeat;fill:currentcolor;position:relative;height:24px;width:24px}</style><polymer-element name="core-icon" attributes="src icon alt" assetpath="../core-icon/"><script>(function(){var meta;Polymer("core-icon",{src:"",icon:"",alt:null,observe:{icon:"updateIcon",alt:"updateAlt"},defaultIconset:"icons",ready:function(){if(!meta){meta=document.createElement("core-iconset")}if(this.hasAttribute("aria-label")){if(!this.hasAttribute("role")){this.setAttribute("role","img")}return}this.updateAlt()},srcChanged:function(){var icon=this._icon||document.createElement("div");icon.textContent="";icon.setAttribute("fit","");icon.style.backgroundImage="url("+this.src+")";icon.style.backgroundPosition="center";icon.style.backgroundSize="100%";if(!icon.parentNode){this.appendChild(icon)}this._icon=icon},getIconset:function(name){return meta.byId(name||this.defaultIconset)},updateIcon:function(oldVal,newVal){if(!this.icon){this.updateAlt();return}var parts=String(this.icon).split(":");var icon=parts.pop();if(icon){var set=this.getIconset(parts.pop());if(set){this._icon=set.applyIcon(this,icon);if(this._icon){this._icon.setAttribute("fit","")}}}if(oldVal){if(oldVal.split(":").pop()==this.getAttribute("aria-label")){this.updateAlt()}}},updateAlt:function(){if(this.getAttribute("aria-hidden")){return}if(this.alt===""){this.setAttribute("aria-hidden","true");if(this.hasAttribute("role")){this.removeAttribute("role")}if(this.hasAttribute("aria-label")){this.removeAttribute("aria-label")}}else{this.setAttribute("aria-label",this.alt||this.icon.split(":").pop());if(!this.hasAttribute("role")){this.setAttribute("role","img")}if(this.hasAttribute("aria-hidden")){this.removeAttribute("aria-hidden")}}}})})();</script></polymer-element><polymer-element name="core-iconset-svg" extends="core-meta" attributes="iconSize" assetpath="../core-iconset-svg/"><script>Polymer("core-iconset-svg",{iconSize:24,type:"iconset",created:function(){this._icons={}},ready:function(){this.super();this.updateIcons()},iconById:function(id){return this._icons[id]||(this._icons[id]=this.querySelector("#"+id))},cloneIcon:function(id){var icon=this.iconById(id);if(icon){var content=icon.cloneNode(true);content.removeAttribute("id");var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 "+this.iconSize+" "+this.iconSize);svg.style.pointerEvents="none";svg.appendChild(content);return svg}},get iconNames(){if(!this._iconNames){this._iconNames=this.findIconNames()}return this._iconNames},findIconNames:function(){var icons=this.querySelectorAll("[id]").array();if(icons.length){return icons.map(function(n){return n.id})}},applyIcon:function(element,icon){var root=element;var old=root.querySelector("svg");if(old){old.remove()}var svg=this.cloneIcon(icon);if(!svg){return}svg.setAttribute("height","100%");svg.setAttribute("width","100%");svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.display="block";root.insertBefore(svg,root.firstElementChild);return svg},updateIcons:function(selector,method){selector=selector||"[icon]";method=method||"updateIcon";var deep=window.ShadowDOMPolyfill?"":"html /deep/ ";var i$=document.querySelectorAll(deep+selector);for(var i=0,e;e=i$[i];i++){if(e[method]){e[method].call(e)}}}});</script></polymer-element><core-iconset-svg id="icons" iconsize="24"><svg><defs><g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6h-2v-13h-6v-2h18v2z"/></g><g id="account-balance"><path d="M4 10v7h3v-7h-3zm6 0v7h3v-7h-3zm-8 12h19v-3h-19v3zm14-12v7h3v-7h-3zm-4.5-9l-9.5 5v2h19v-2l-9.5-5z"/></g><g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2h-14c-1.11 0-2-.9-2-2v-14c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10v-8h-10v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g><g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2h-14c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1h-12v-1z"/></g><g id="account-child"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5s-1.11-2.5-2.49-2.5c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5zm-7.5-1c1.66 0 2.99-1.34 2.99-3s-1.33-3-2.99-3c-1.66 0-3 1.34-3 3s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75v2.25h11v-2.25c0-1.83-3.67-2.75-5.5-2.75zm-7.5-1c-2.33 0-7 1.17-7 3.5v2.5h7v-2.25c0-.85.33-2.34 2.37-3.47-.87-.18-1.71-.28-2.37-.28z"/></g><g id="account-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></g><g id="add-box"><path d="M19 3h-14c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4h-4v-2h4v-4h2v4h4v2z"/></g><g id="add-circle-outline"><path d="M13 7h-2v4h-4v2h4v4h2v-4h4v-2h-4v-4zm-1-5c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g><g id="add-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm5 11h-4v4h-2v-4h-4v-2h4v-4h2v4h4v2z"/></g><g id="add"><path d="M19 13h-6v6h-2v-6h-6v-2h6v-6h2v6h6v2z"/></g><g id="add-shopping-cart"><path d="M11 9h2v-3h3v-2h-3v-3h-2v3h-3v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01-1.74-.96h-.01l-1.1 2-2.76 5h-7.02l-.13-.27-2.24-4.73-.95-2-.94-2h-3.27v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2h-11.58c-.13 0-.25-.11-.25-.25z"/></g><g id="alarm-add"><path d="M7.88 3.39l-1.28-1.53-4.6 3.85 1.29 1.53 4.59-3.85zm14.12 2.33l-4.6-3.86-1.29 1.53 4.6 3.86 1.29-1.53zm-10-1.72c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></g><g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91l1.52 1.52c.75-.27 1.56-.43 2.4-.43zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86 1.29-1.53zm-19.08-3.43l-1.27 1.28 1.33 1.33-1.11.93 1.42 1.42 1.11-.94.8.8c-1.37 1.58-2.2 3.64-2.2 5.89 0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27-17.47-17.46-.97-.98zm13.55 16.1c-1.21 1-2.77 1.61-4.47 1.61-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zm-8.45-15.11l-1.42-1.42-.86.71 1.42 1.42.86-.71z"/></g><g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86 1.29-1.53zm-14.12-2.33l-1.28-1.53-4.6 3.85 1.29 1.53 4.59-3.85zm4.12.61c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47l-2.13-2.13-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"/></g><g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86 1.29-1.53zm-14.12-2.33l-1.28-1.53-4.6 3.85 1.29 1.53 4.59-3.85zm4.62 4.61h-1.5v6l4.75 2.85.75-1.23-4-2.37v-5.25zm-.5-4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g><g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-3.5h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-3.5h1c.55 0 1-.45 1-1v-10h-12v10zm-2.5-10c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48c-.79-.4-1.69-.63-2.64-.63-.96 0-1.86.23-2.66.63l-1.49-1.48c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31c-1.48 1.09-2.45 2.84-2.45 4.83h12c0-1.99-.97-3.75-2.47-4.84zm-5.53 2.84h-1v-1h1v1zm5 0h-1v-1h1v1z"/></g><g id="announcement"><path d="M20 2h-16c-1.1 0-1.99.9-1.99 2l-.01 18 4-4h14c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm-7 9h-2v-6h2v6zm0 4h-2v-2h2v2z"/></g><g id="apps"><path d="M4 8h4v-4h-4v4zm6 12h4v-4h-4v4zm-6 0h4v-4h-4v4zm0-6h4v-4h-4v4zm6 0h4v-4h-4v4zm6-10v4h4v-4h-4zm-6 4h4v-4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></g><g id="archive"><path d="M20.54 5.23l-1.39-1.68c-.27-.34-.68-.55-1.15-.55h-12c-.47 0-.88.21-1.16.55l-1.38 1.68c-.29.34-.46.79-.46 1.27v12.5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-12.5c0-.48-.17-.93-.46-1.27zm-8.54 12.27l-5.5-5.5h3.5v-2h4v2h3.5l-5.5 5.5zm-6.88-12.5l.81-1h12l.94 1h-13.75z"/></g><g id="arrow-back"><path d="M20 11h-12.17l5.59-5.59-1.42-1.41-8 8 8 8 1.41-1.41-5.58-5.59h12.17v-2z"/></g><g id="arrow-drop-down-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 12l-4-4h8l-4 4z"/></g><g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"/></g><g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"/></g><g id="arrow-forward"><path d="M12 4l-1.41 1.41 5.58 5.59h-12.17v2h12.17l-5.58 5.59 1.41 1.41 8-8z"/></g><g id="aspect-ratio"><path d="M19 12h-2v3h-3v2h5v-5zm-12-3h3v-2h-5v5h2v-3zm14-6h-18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16.01h-18v-14.02h18v14.02z"/></g><g id="assessment"><path d="M19 3h-14c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-10 14h-2v-7h2v7zm4 0h-2v-10h2v10zm4 0h-2v-4h2v4z"/></g><g id="assignment-ind"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 4c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12h-12v-1.4c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1.4z"/></g><g id="assignment-late"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-6 15h-2v-2h2v2zm0-4h-2v-6h2v6zm-1-9c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></g><g id="assignment"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14h-7v-2h7v2zm3-4h-10v-2h10v2zm0-4h-10v-2h10v2z"/></g><g id="assignment-returned"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 15l-5-5h3v-4h4v4h3l-5 5z"/></g><g id="assignment-return"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm4 12h-4v3l-5-5 5-5v3h4v4z"/></g><g id="assignment-turned-in"><path d="M19 3h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 14l-4-4 1.41-1.41 2.59 2.58 6.59-6.59 1.41 1.42-8 8z"/></g><g id="attachment"><path d="M7.5 18c-3.04 0-5.5-2.46-5.5-5.5s2.46-5.5 5.5-5.5h10.5c2.21 0 4 1.79 4 4s-1.79 4-4 4h-8.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5h7.5v1.5h-7.5c-.55 0-1 .45-1 1s.45 1 1 1h8.5c1.38 0 2.5-1.12 2.5-2.5s-1.12-2.5-2.5-2.5h-10.5c-2.21 0-4 1.79-4 4s1.79 4 4 4h9.5v1.5h-9.5z"/></g><g id="autorenew"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26l1.46-1.46c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74l-1.46 1.46c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/></g><g id="backspace"><path d="M22 3h-15c-.69 0-1.23.35-1.59.88l-5.41 8.12 5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-3 12.59l-1.41 1.41-3.59-3.59-3.59 3.59-1.41-1.41 3.59-3.59-3.59-3.59 1.41-1.41 3.59 3.59 3.59-3.59 1.41 1.41-3.59 3.59 3.59 3.59z"/></g><g id="backup"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zm-5.35 2.96v4h-4v-4h-3l5-5 5 5h-3z"/></g><g id="block"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm-8 10c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69l-11.21 11.21c-1.06-1.35-1.69-3.05-1.69-4.9zm8 8c-1.85 0-3.55-.63-4.9-1.69l11.21-11.21c1.06 1.35 1.69 3.05 1.69 4.9 0 4.42-3.58 8-8 8z"/></g><g id="bookmark-outline"><path d="M17 3h-10c-1.1 0-1.99.9-1.99 2l-.01 16 7-3 7 3v-16c0-1.1-.9-2-2-2zm0 15l-5-2.18-5 2.18v-13h10v13z"/></g><g id="bookmark"><path d="M17 3h-10c-1.1 0-1.99.9-1.99 2l-.01 16 7-3 7 3v-16c0-1.1-.9-2-2-2z"/></g><g id="book"><path d="M18 2h-12c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-16c0-1.1-.9-2-2-2zm-12 2h5v8l-2.5-1.5-2.5 1.5v-8z"/></g><g id="bug-report"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96l1.63-1.63-1.41-1.41-2.17 2.17c-.46-.11-.93-.17-1.42-.17-.49 0-.96.06-1.41.17l-2.18-2.17-1.41 1.41 1.62 1.63c-.74.51-1.36 1.18-1.81 1.96h-2.81v2h2.09c-.05.33-.09.66-.09 1v1h-2v2h2v1c0 .34.04.67.09 1h-2.09v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3h2.81v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1h2.09v-2zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/></g><g id="cached"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46c1.23.78 2.69 1.24 4.26 1.24 4.42 0 8-3.58 8-8h3l-4-4zm-13 4c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46c-1.23-.78-2.69-1.24-4.26-1.24-4.42 0-8 3.58-8 8h-3l4 4 4-4h-3z"/></g><g id="cancel"><path d="M12 2c-5.53 0-10 4.47-10 10s4.47 10 10 10 10-4.47 10-10-4.47-10-10-10zm5 13.59l-1.41 1.41-3.59-3.59-3.59 3.59-1.41-1.41 3.59-3.59-3.59-3.59 1.41-1.41 3.59 3.59 3.59-3.59 1.41 1.41-3.59 3.59 3.59 3.59z"/></g><g id="check-box-outline-blank"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></g><g id="check-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></g><g id="check"><path d="M9 16.17l-4.17-4.17-1.42 1.41 5.59 5.59 12-12-1.41-1.41z"/></g><g id="chevron-left"><path d="M15.41 7.41l-1.41-1.41-6 6 6 6 1.41-1.41-4.58-4.59z"/></g><g id="chevron-right"><path d="M10 6l-1.41 1.41 4.58 4.59-4.58 4.59 1.41 1.41 6-6z"/></g><g id="class"><path d="M18 2h-12c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-16c0-1.1-.9-2-2-2zm-12 2h5v8l-2.5-1.5-2.5 1.5v-8z"/></g><g id="clear"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/></g><g id="close"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/></g><g id="cloud-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm4.5 14h-8.5c-1.66 0-3-1.34-3-3s1.34-3 3-3l.14.01c.44-1.73 1.99-3.01 3.86-3.01 2.21 0 4 1.79 4 4h.5c1.38 0 2.5 1.12 2.5 2.5s-1.12 2.5-2.5 2.5z"/></g><g id="cloud-done"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zm-9.35 6.96l-3.5-3.5 1.41-1.41 2.09 2.08 5.18-5.17 1.41 1.41-6.59 6.59z"/></g><g id="cloud-download"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zm-2.35 2.96l-5 5-5-5h3v-4h4v4h3z"/></g><g id="cloud-off"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-1.48 0-2.85.43-4.01 1.17l1.46 1.46c.76-.4 1.63-.63 2.55-.63 3.04 0 5.5 2.46 5.5 5.5v.5h1.5c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45c1.27-.91 2.11-2.39 2.11-4.07 0-2.64-2.05-4.78-4.65-4.96zm-16.35-4.77l2.75 2.74c-3.19.14-5.75 2.76-5.75 5.99 0 3.31 2.69 6 6 6h11.73l2 2 1.27-1.27-16.73-16.73-1.27 1.27zm4.73 4.73l8 8h-9.73c-2.21 0-4-1.79-4-4s1.79-4 4-4h1.73z"/></g><g id="cloud"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></g><g id="cloud-queue"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zm-.35 7.96h-13c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71c.66-2.31 2.77-4 5.29-4 3.04 0 5.5 2.46 5.5 5.5v.5h1.5c1.66 0 3 1.34 3 3s-1.34 3-3 3z"/></g><g id="cloud-upload"><path d="M19.35 10.04c-.68-3.45-3.71-6.04-7.35-6.04-2.89 0-5.4 1.64-6.65 4.04-3.01.32-5.35 2.87-5.35 5.96 0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zm-5.35 2.96v4h-4v-4h-3l5-5 5 5h-3z"/></g><g id="content-copy"><path d="M16 1h-12c-1.1 0-2 .9-2 2v14h2v-14h12v-2zm3 4h-11c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16h-11v-14h11v14z"/></g><g id="content-cut"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4s-4 1.79-4 4 1.79 4 4 4c.59 0 1.14-.13 1.64-.36l2.36 2.36-2.36 2.36c-.5-.23-1.05-.36-1.64-.36-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64l2.36-2.36 7 7h3v-1l-12.36-12.36zm-3.64.36c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zm7-9.5l-6 6 2 2 7-7v-1z"/></g><g id="content-paste"><path d="M19 2h-4.18c-.42-1.16-1.52-2-2.82-2-1.3 0-2.4.84-2.82 2h-4.18c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-16c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18h-14v-16h2v3h10v-3h2v16z"/></g><g id="create"><path d="M3 17.25v3.75h3.75l11.06-11.06-3.75-3.75-11.06 11.06zm17.71-10.21c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></g><g id="credit-card"><path d="M4 12h16v6h-16z"/><path d="M20 4h-16c-1.11 0-1.99.89-1.99 2l-.01 12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-12c0-1.11-.89-2-2-2zm0 14h-16v-6h16v6zm0-10h-16v-2h16v2z"/></g><g id="dashboard"><path d="M3 13h8v-10h-8v10zm0 8h8v-6h-8v6zm10 0h8v-10h-8v10zm0-18v6h8v-6h-8z"/></g><g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2v-12h-12v12zm13-15h-3.5l-1-1h-5l-1 1h-3.5v2h14v-2z"/></g><g id="description"><path d="M14 2h-8c-1.1 0-1.99.9-1.99 2l-.01 16c0 1.1.89 2 1.99 2h12.01c1.1 0 2-.9 2-2v-12l-6-6zm2 16h-8v-2h8v2zm0-4h-8v-2h8v2zm-3-5v-5.5l5.5 5.5h-5.5z"/></g><g id="developer-mode-tv"><path d="M4 5h16v2h2v-2c0-1.1-.9-2-2-2h-16c-1.1 0-2 .9-2 2v2h2v-2zm3.55 8.83l-2.83-2.83 2.83-2.83-1.41-1.41-4.25 4.24 4.24 4.24 1.42-1.41zm12.45 3.17h-16v-2h-2v2c0 1.1.9 2 2 2h4v2h8v-2h4c1.1 0 1.99-.9 1.99-2v-2h-1.99v2zm2-6.01l-4.24-4.24-1.41 1.41 2.82 2.84-2.83 2.83 1.41 1.41 4.25-4.23v-.02z"/></g><g id="dns"><path d="M20 13h-16c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm-13 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm13-16h-16c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm-13 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g><g id="done-all"><path d="M18 7l-1.41-1.41-6.34 6.34 1.41 1.41 6.34-6.34zm4.24-1.41l-10.58 10.58-4.18-4.17-1.41 1.41 5.59 5.59 12-12-1.42-1.41zm-21.83 7.82l5.59 5.59 1.41-1.41-5.58-5.59-1.42 1.41z"/></g><g id="done"><path d="M9 16.17l-4.17-4.17-1.42 1.41 5.59 5.59 12-12-1.41-1.41z"/></g><g id="drafts"><path d="M21.99 8c0-.72-.37-1.35-.94-1.7l-9.05-5.3-9.05 5.3c-.57.35-.95.98-.95 1.7v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zm-9.99 5l-8.26-5.16 8.26-4.84 8.26 4.84-8.26 5.16z"/></g><g id="drawer"><path d="M20,4H4C2.8,4,2,4.8,2,6v12c0,1.2,0.8,2,2,2h16c1,0,2-0.8,2-2V6C22,4.8,21,4,20,4z M20,18h-6V6h6V18z"/></g><g id="error"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm1 15h-2v-2h2v2zm0-4h-2v-6h2v6z"/></g><g id="event"><path d="M17 12h-5v5h5v-5zm-1-11v2h-8v-2h-2v2h-1c-1.11 0-1.99.9-1.99 2l-.01 14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2h-1v-2h-2zm3 18h-14v-11h14v11z"/></g><g id="exit-to-app"><path d="M10.09 15.59l1.41 1.41 5-5-5-5-1.41 1.41 2.58 2.59h-9.67v2h9.67l-2.58 2.59zm8.91-12.59h-14c-1.11 0-2 .9-2 2v4h2v-4h14v14h-14v-4h-2v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2z"/></g><g id="expand-less"><path d="M12 8l-6 6 1.41 1.41 4.59-4.58 4.59 4.58 1.41-1.41z"/></g><g id="expand-more"><path d="M16.59 8.59l-4.59 4.58-4.59-4.58-1.41 1.41 6 6 6-6z"/></g><g id="explore"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zm0-8.9c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm2.19 12.19l-8.19 3.81 3.81-8.19 8.19-3.81-3.81 8.19z"/></g><g id="extension"><path d="M20.5 11h-1.5v-4c0-1.1-.9-2-2-2h-4v-1.5c0-1.38-1.12-2.5-2.5-2.5s-2.5 1.12-2.5 2.5v1.5h-4c-1.1 0-1.99.9-1.99 2v3.8h1.49c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7h-1.5v3.8c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7v1.5h3.8c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5s-1.12-2.5-2.5-2.5z"/></g><g id="face-unlock"><path d="M14.69 17.1c-.74.58-1.7.9-2.69.9s-1.95-.32-2.69-.9c-.22-.17-.53-.13-.7.09-.17.22-.13.53.09.7.91.72 2.09 1.11 3.3 1.11s2.39-.39 3.31-1.1c.22-.17.26-.48.09-.7-.17-.23-.49-.26-.71-.1z"/><circle cx="8.5" cy="12.5" r="1"/><path d="M12 0c-6.63 0-12 5.37-12 12s5.37 12 12 12 12-5.37 12-12-5.37-12-12-12zm7.96 14.82c-1.09 3.74-4.27 6.46-8.04 6.46-3.78 0-6.96-2.72-8.04-6.47-1.19-.11-2.13-1.18-2.13-2.52 0-1.27.85-2.31 1.97-2.5 2.09-1.46 3.8-3.49 4.09-5.05v-.01c1.35 2.63 6.3 5.19 11.83 5.06l.3-.03c1.28 0 2.31 1.14 2.31 2.54 0 1.38-1.02 2.51-2.29 2.52z"/><circle cx="15.5" cy="12.5" r="1"/></g><g id="favorite-outline"><path d="M16.5 3c-1.74 0-3.41.81-4.5 2.09-1.09-1.28-2.76-2.09-4.5-2.09-3.08 0-5.5 2.42-5.5 5.5 0 3.78 3.4 6.86 8.55 11.54l1.45 1.31 1.45-1.32c5.15-4.67 8.55-7.75 8.55-11.53 0-3.08-2.42-5.5-5.5-5.5zm-4.4 15.55l-.1.1-.1-.1c-4.76-4.31-7.9-7.16-7.9-10.05 0-2 1.5-3.5 3.5-3.5 1.54 0 3.04.99 3.57 2.36h1.87c.52-1.37 2.02-2.36 3.56-2.36 2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"/></g><g id="favorite"><path d="M12 21.35l-1.45-1.32c-5.15-4.67-8.55-7.75-8.55-11.53 0-3.08 2.42-5.5 5.5-5.5 1.74 0 3.41.81 4.5 2.09 1.09-1.28 2.76-2.09 4.5-2.09 3.08 0 5.5 2.42 5.5 5.5 0 3.78-3.4 6.86-8.55 11.54l-1.45 1.31z"/></g><g id="file-download"><path d="M19 9h-4v-6h-6v6h-4l7 7 7-7zm-14 9v2h14v-2h-14z"/></g><g id="file-map"><path d="M12 6.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm7-5.5h-14c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-6.5 16h-1c-.95-4.09-3.99-5.84-3.99-9 0-2.49 2-4.5 4.49-4.5s4.51 2.01 4.51 4.5c0 3.16-3.06 4.91-4.01 9z"/></g><g id="file-upload"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2h-14z"/></g><g id="filter-list"><path d="M10 18h4v-2h-4v2zm-7-12v2h18v-2h-18zm3 7h12v-2h-12v2z"/></g><g id="find-in-page"><path d="M20 19.59v-11.59l-6-6h-8c-1.1 0-1.99.9-1.99 2l-.01 16c0 1.1.89 2 1.99 2h12.01c.45 0 .85-.15 1.19-.4l-4.43-4.43c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75l3.83 3.84zm-11-6.59c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z"/></g><g id="find-replace"><path d="M11 6c1.38 0 2.63.56 3.54 1.46l-2.54 2.54h6v-6l-2.05 2.05c-1.27-1.27-3.02-2.05-4.95-2.05-3.53 0-6.43 2.61-6.92 6h2.02c.46-2.28 2.48-4 4.9-4zm5.64 9.14c.66-.9 1.12-1.97 1.28-3.14h-2.02c-.46 2.28-2.48 4-4.9 4-1.38 0-2.63-.56-3.54-1.46l2.54-2.54h-6v6l2.05-2.05c1.27 1.27 3.02 2.05 4.95 2.05 1.55 0 2.98-.51 4.14-1.36l4.86 4.85 1.49-1.49-4.85-4.86z"/></g><g id="flag"><path d="M14.4 6l-.4-2h-9v17h2v-7h5.6l.4 2h7v-10z"/></g><g id="flip-to-back"><path d="M9 7h-2v2h2v-2zm0 4h-2v2h2v-2zm0-8c-1.11 0-2 .9-2 2h2v-2zm4 12h-2v2h2v-2zm6-12v2h2c0-1.1-.9-2-2-2zm-6 0h-2v2h2v-2zm-4 14v-2h-2c0 1.1.89 2 2 2zm10-4h2v-2h-2v2zm0-4h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm-14-10h-2v12c0 1.1.89 2 2 2h12v-2h-12v-12zm10-2h2v-2h-2v2zm0 12h2v-2h-2v2z"/></g><g id="flip-to-front"><path d="M3 13h2v-2h-2v2zm0 4h2v-2h-2v2zm2 4v-2h-2c0 1.1.89 2 2 2zm-2-12h2v-2h-2v2zm12 12h2v-2h-2v2zm4-18h-10c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm0 12h-10v-10h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2h-2v2z"/></g><g id="folder-open"><path d="M20 6h-8l-2-2h-6c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm0 12h-16v-10h16v10z"/></g><g id="folder"><path d="M10 4h-6c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2h-8l-2-2z"/></g><g id="folder-shared"><path d="M20 6h-8l-2-2h-6c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4 8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z"/></g><g id="forward"><path d="M12 8v-4l8 8-8 8v-4h-8v-8z"/></g><g id="fullscreen-exit"><path d="M5 16h3v3h2v-5h-5v2zm3-8h-3v2h5v-5h-2v3zm6 11h2v-3h3v-2h-5v5zm2-11v-3h-2v5h5v-2h-3z"/></g><g id="fullscreen"><path d="M7 14h-2v5h5v-2h-3v-3zm-2-4h2v-3h3v-2h-5v5zm12 7h-3v2h5v-5h-2v3zm-3-12v2h3v3h2v-5h-5z"/></g><g id="gesture"><path d="M4.59 6.89c.7-.71 1.4-1.35 1.71-1.22.5.2 0 1.03-.3 1.52-.25.42-2.86 3.89-2.86 6.31 0 1.28.48 2.34 1.34 2.98.75.56 1.74.73 2.64.46 1.07-.31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79-3.78.64-5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1h2.46v-2.5h-2.47c-.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-.58.73-2.06 2.48-2.29 2.72-.25.3-.68.84-1.11.84-.45 0-.72-.83-.36-1.92.35-1.09 1.4-2.86 1.85-3.52.78-1.14 1.3-1.92 1.3-3.28 0-2.17-1.64-2.86-2.51-2.86-1.32 0-2.47 1-2.72 1.25-.36.36-.66.66-.88.93l1.75 1.71zm9.29 11.66c-.31 0-.74-.26-.74-.72 0-.6.73-2.2 2.87-2.76-.3 2.69-1.43 3.48-2.13 3.48z"/></g><g id="get-app"><path d="M19 9h-4v-6h-6v6h-4l7 7 7-7zm-14 9v2h14v-2h-14z"/></g><g id="grade"><path d="M12 17.27l6.18 3.73-1.64-7.03 5.46-4.73-7.19-.61-2.81-6.63-2.81 6.63-7.19.61 5.46 4.73-1.64 7.03z"/></g><g id="group-work"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm-4 15.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zm1.5-9.5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5-2.5-1.12-2.5-2.5zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g><g id="help"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92c-.72.73-1.17 1.33-1.17 2.83h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2h-2c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></g><g id="highlight-remove"><path d="M14.59 8l-2.59 2.59-2.59-2.59-1.41 1.41 2.59 2.59-2.59 2.59 1.41 1.41 2.59-2.59 2.59 2.59 1.41-1.41-2.59-2.59 2.59-2.59-1.41-1.41zm-2.59-6c-5.53 0-10 4.47-10 10s4.47 10 10 10 10-4.47 10-10-4.47-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g><g id="history"><path opacity=".9" d="M13 3c-4.97 0-9 4.03-9 9h-3l3.89 3.89.07.14 4.04-4.03h-3c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42c1.63 1.63 3.87 2.64 6.36 2.64 4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08v-4.25h-1.5z"/></g><g id="home"><path d="M10 20v-6h4v6h5v-8h3l-10-9-10 9h3v8z"/></g><g id="https"><path d="M18 8h-1v-2c0-2.76-2.24-5-5-5s-5 2.24-5 5v2h-1c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9h-6.2v-2c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/></g><g id="inbox"><path d="M19 3h-14.01c-1.1 0-1.98.9-1.98 2l-.01 14c0 1.1.89 2 1.99 2h14.01c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.34 3-3 3s-3-1.34-3-3h-4.01v-10h14.01v10zm-3-5h-2v-3h-4v3h-2l4 4 4-4z"/></g><g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-11h2v-2h-2v2z"/></g><g id="info"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm1 15h-2v-6h2v6zm0-8h-2v-2h2v2z"/></g><g id="input"><path d="M21 3.01h-18c-1.1 0-2 .9-2 2v3.99h2v-4.01h18v14.03h-18v-4.02h-2v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zm-10 12.99l4-4-4-4v3h-10v2h10v3z"/></g><g id="invert-colors"><path d="M17.66 7.93l-5.66-5.66-5.66 5.66c-3.12 3.12-3.12 8.19 0 11.31 1.56 1.56 3.61 2.34 5.66 2.34 2.05 0 4.1-.78 5.66-2.34 3.12-3.12 3.12-8.19 0-11.31zm-5.66 11.66c-1.6 0-3.11-.62-4.24-1.76-1.14-1.14-1.76-2.64-1.76-4.24s.62-3.11 1.76-4.24l4.24-4.25v14.49z"/></g><g id="label-outline"><path d="M17.63 5.84c-.36-.51-.96-.84-1.63-.84l-11 .01c-1.1 0-2 .89-2 1.99v10c0 1.1.9 1.99 2 1.99l11 .01c.67 0 1.27-.33 1.63-.84l4.37-6.16-4.37-6.16zm-1.63 11.16h-11v-10h11l3.55 5-3.55 5z"/></g><g id="label"><path d="M17.63 5.84c-.36-.51-.96-.84-1.63-.84l-11 .01c-1.1 0-2 .89-2 1.99v10c0 1.1.9 1.99 2 1.99l11 .01c.67 0 1.27-.33 1.63-.84l4.37-6.16-4.37-6.16z"/></g><g id="language"><path d="M11.99 2c-5.52 0-9.99 4.48-9.99 10s4.47 10 9.99 10c5.53 0 10.01-4.48 10.01-10s-4.48-10-10.01-10zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zm-6.92-3.96c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zm-7.74 9.96c-.16-.64-.26-1.31-.26-2s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2h-3.38zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8h-2.95c.96-1.66 2.49-2.93 4.33-3.56-.6 1.11-1.06 2.31-1.38 3.56zm3.97 11.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zm2.34-5.96h-4.68c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zm1.77-5.56c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/></g><g id="launch"><path d="M19 19h-14v-14h7v-2h-7c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zm-5-16v2h3.59l-9.83 9.83 1.41 1.41 9.83-9.83v3.59h2v-7h-7z"/></g><g id="link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4v-1.9h-4c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9h-4c-1.71 0-3.1-1.39-3.1-3.1zm4.1 1h8v-2h-8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4v1.9h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></g><g id="list"><path d="M3 13h2v-2h-2v2zm0 4h2v-2h-2v2zm0-8h2v-2h-2v2zm4 4h14v-2h-14v2zm0 4h14v-2h-14v2zm0-10v2h14v-2h-14z"/></g><g id="lock-open"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1v-2c0-2.76-2.24-5-5-5s-5 2.24-5 5h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2h-9.1c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm0 12h-12v-10h12v10z"/></g><g id="lock-outline"><path d="M18 8h-1v-2c0-2.76-2.24-5-5-5s-5 2.24-5 5v2h-1c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm-6-5.1c1.71 0 3.1 1.39 3.1 3.1v2h-6.1v-2h-.1c0-1.71 1.39-3.1 3.1-3.1zm6 17.1h-12v-10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></g><g id="lock"><path d="M18 8h-1v-2c0-2.76-2.24-5-5-5s-5 2.24-5 5v2h-1c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9h-6.2v-2c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/></g><g id="loyalty"><path d="M21.41 11.58l-9-9c-.36-.36-.86-.58-1.41-.58h-7c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zm-15.91-4.58c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11.77 8.27l-4.27 4.27-4.27-4.27c-.45-.46-.73-1.08-.73-1.77 0-1.38 1.12-2.5 2.5-2.5.69 0 1.32.28 1.77.74l.73.72.73-.73c.45-.45 1.08-.73 1.77-.73 1.38 0 2.5 1.12 2.5 2.5 0 .69-.28 1.32-.73 1.77z"/></g><g id="mail"><path d="M20 4h-16c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm0 4l-8 5-8-5v-2l8 5 8-5v2z"/></g><g id="markunread-mailbox"><path d="M20 6h-10v6h-2v-8h6v-4h-8v6h-2c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2z"/></g><g id="markunread"><path d="M20 4h-16c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm0 4l-8 5-8-5v-2l8 5 8-5v2z"/></g><g id="menu"><path d="M3 18h18v-2h-18v2zm0-5h18v-2h-18v2zm0-7v2h18v-2h-18z"/></g><g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g><g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></g><g id="note-add"><path d="M14 2h-8c-1.1 0-1.99.9-1.99 2l-.01 16c0 1.1.89 2 1.99 2h12.01c1.1 0 2-.9 2-2v-12l-6-6zm2 14h-3v3h-2v-3h-3v-2h3v-3h2v3h3v2zm-3-7v-5.5l5.5 5.5h-5.5z"/></g><g id="open-in-browser"><path d="M19 4h-14c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2h-4v-10h14v10h-4v2h4c1.1 0 2-.9 2-2v-12c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"/></g><g id="open-in-new"><path d="M19 19h-14v-14h7v-2h-7c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zm-5-16v2h3.59l-9.83 9.83 1.41 1.41 9.83-9.83v3.59h2v-7h-7z"/></g><g id="open-with"><path d="M10 9h4v-3h3l-5-5-5 5h3v3zm-1 1h-3v-3l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3h-3l5 5 5-5h-3v-3z"/></g><g id="pageview"><path d="M11 8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3zm8-5h-14c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-1.41 16l-3.83-3.83c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75l3.83 3.84-1.41 1.41z"/></g><g id="payment"><path d="M20 4h-16c-1.11 0-1.99.89-1.99 2l-.01 12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-12c0-1.11-.89-2-2-2zm0 14h-16v-6h16v6zm0-10h-16v-2h16v2z"/></g><g id="perm-camera-mic"><path d="M20 5h-3.17l-1.83-2h-6l-1.83 2h-3.17c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7v-2.09c-2.83-.48-5-2.94-5-5.91h2c0 2.21 1.79 4 4 4s4-1.79 4-4h2c0 2.97-2.17 5.43-5 5.91v2.09h7c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm-6 8c0 1.1-.9 2-2 2s-2-.9-2-2v-4c0-1.1.9-2 2-2s2 .9 2 2v4z"/></g><g id="perm-contact-cal"><path d="M19 3h-1v-2h-2v2h-8v-2h-2v2h-1c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm-7 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12h-12v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1z"/></g><g id="perm-data-setting"><path d="M18.99 11.5c.34 0 .67.03 1 .07l.01-11.57-20 20h11.56c-.04-.33-.07-.66-.07-1 0-4.14 3.36-7.5 7.5-7.5zm3.71 7.99c.02-.16.04-.32.04-.49 0-.17-.01-.33-.04-.49l1.06-.83c.09-.08.12-.21.06-.32l-1-1.73c-.06-.11-.19-.15-.31-.11l-1.24.5c-.26-.2-.54-.37-.85-.49l-.19-1.32c-.01-.12-.12-.21-.24-.21h-2c-.12 0-.23.09-.25.21l-.19 1.32c-.3.13-.59.29-.85.49l-1.24-.5c-.11-.04-.24 0-.31.11l-1 1.73c-.06.11-.04.24.06.32l1.06.83c-.02.16-.03.32-.03.49 0 .17.01.33.03.49l-1.06.83c-.09.08-.12.21-.06.32l1 1.73c.06.11.19.15.31.11l1.24-.5c.26.2.54.37.85.49l.19 1.32c.02.12.12.21.25.21h2c.12 0 .23-.09.25-.21l.19-1.32c.3-.13.59-.29.84-.49l1.25.5c.11.04.24 0 .31-.11l1-1.73c.06-.11.03-.24-.06-.32l-1.07-.83zm-3.71 1.01c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g><g id="perm-device-info"><path d="M13 7h-2v2h2v-2zm0 4h-2v6h2v-6zm4-9.99l-10-.01c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-18c0-1.1-.9-1.99-2-1.99zm0 17.99h-10v-14h10v14z"/></g><g id="perm-identity"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1-2.1-.94-2.1-2.1.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1h-12.2v-1.1c0-.64 3.13-2.1 6.1-2.1m0-10.9c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/></g><g id="perm-media"><path d="M2 6h-2v5h.01l-.01 9c0 1.1.9 2 2 2h18v-2h-18v-14zm20-2h-8l-2-2h-6c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-10c0-1.1-.9-2-2-2zm-15 11l4.5-6 3.5 4.51 2.5-3.01 3.5 4.5h-14z"/></g><g id="perm-phone-msg"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01-.37-1.12-.57-2.32-.57-3.57 0-.55-.45-1-1-1h-3.5c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zm-8-12.5v10l3-3h6v-7h-9z"/></g><g id="perm-scan-wifi"><path d="M12 3c-5.05 0-8.85 1.85-12 4.23l12 14.77 12-14.75c-3.15-2.38-6.95-4.25-12-4.25zm1 13h-2v-6h2v6zm-2-8v-2h2v2h-2z"/></g><g id="picture-in-picture"><path d="M19 7h-8v6h8v-6zm2-4h-18c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.1-.9-2-2-2zm0 16.01h-18v-14.03h18v14.03z"/></g><g id="polymer"><path d="M19 4h-4l-7.89 12.63-2.61-4.63 4.5-8h-4l-4.5 8 4.5 8h4l7.89-12.63 2.61 4.63-4.5 8h4l4.5-8z"/></g><g id="print"><path d="M19 8h-14c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11h-8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9h-12v4h12v-4z"/></g><g id="query-builder"><path d="M11.99 2c-5.52 0-9.99 4.48-9.99 10s4.47 10 9.99 10c5.53 0 10.01-4.48 10.01-10s-4.48-10-10.01-10zm.01 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path d="M12.5 7h-1.5v6l5.25 3.15.75-1.23-4.5-2.67z"/></g><g id="question-answer"><path d="M21 6h-2v9h-13v2c0 .55.45 1 1 1h11l4 4v-15c0-.55-.45-1-1-1zm-4 6v-9c0-.55-.45-1-1-1h-13c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"/></g><g id="radio-button-off"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g><g id="radio-button-on"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></g><g id="receipt"><path d="M18 17h-12v-2h12v2zm0-4h-12v-2h12v2zm0-4h-12v-2h12v2zm-15 13l1.5-1.5 1.5 1.5 1.5-1.5 1.5 1.5 1.5-1.5 1.5 1.5 1.5-1.5 1.5 1.5 1.5-1.5 1.5 1.5 1.5-1.5 1.5 1.5v-20l-1.5 1.5-1.5-1.5-1.5 1.5-1.5-1.5-1.5 1.5-1.5-1.5-1.5 1.5-1.5-1.5-1.5 1.5-1.5-1.5-1.5 1.5-1.5-1.5v20z"/></g><g id="redeem"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68c-.54-.8-1.45-1.34-2.5-1.34-1.66 0-3 1.34-3 3 0 .35.07.69.18 1h-2.18c-1.11 0-1.99.89-1.99 2l-.01 11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-11c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-6 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15h-16v-2h16v2zm0-5h-16v-6h5.08l-2.08 2.83 1.62 1.17 2.38-3.24 1-1.36 1 1.36 2.38 3.24 1.62-1.17-2.08-2.83h5.08v6z"/></g><g id="redo"><path d="M18.4 10.6c-1.85-1.61-4.25-2.6-6.9-2.6-4.65 0-8.58 3.03-9.96 7.22l2.36.78c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88l-3.62 3.62h9v-9l-3.6 3.6z"/></g><g id="refresh"><path d="M17.65 6.35c-1.45-1.45-3.44-2.35-5.65-2.35-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78l-3.22 3.22h7v-7l-2.35 2.35z"/></g><g id="remove-circle-outline"><path d="M7 11v2h10v-2h-10zm5-9c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g><g id="remove-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm5 11h-10v-2h10v2z"/></g><g id="remove"><path d="M19 13h-14v-2h14v2z"/></g><g id="reorder"><path d="M3,15h18v-2H3V15z M3,19h18v-2H3V19z M3,11h18V9H3V11z M3,5v2h18V5H3z"/></g><g id="reply-all"><path d="M7 8v-3l-7 7 7 7v-3l-4-4 4-4zm6 1v-4l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/></g><g id="reply"><path d="M10 9v-4l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/></g><g id="report"><path d="M15.73 3h-7.46l-5.27 5.27v7.46l5.27 5.27h7.46l5.27-5.27v-7.46l-5.27-5.27zm-3.73 14.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2v-6h2v6z"/></g><g id="report-problem"><path d="M1 21h22l-11-19-11 19zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></g><g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9h-3l3.89 3.89.07.14 4.04-4.03h-3c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42c1.63 1.63 3.87 2.64 6.36 2.64 4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08v-4.25h-1.5z"/></g><g id="room"><path d="M12 2c-3.87 0-7 3.13-7 7 0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></g><g id="rotation-3d"><path d="M7.52 21.48c-3.27-1.54-5.61-4.72-5.97-8.48h-1.5c.51 6.16 5.66 11 11.95 11l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43-.31-.09-.65-.14-1.02-.14-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09h-.77v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27h-2.36v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91v-5.77h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zm-4.57-12.2l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5c-.5-6.15-5.65-10.99-11.94-10.99z"/></g><g id="save"><path d="M17 3h-12c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-12l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10h-10v-4h10v4z"/></g><g id="schedule"><path fill-opacity=".9" d="M11.99 2c-5.52 0-9.99 4.48-9.99 10s4.47 10 9.99 10c5.53 0 10.01-4.48 10.01-10s-4.48-10-10.01-10zm.01 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path fill-opacity=".9" d="M12.5 7h-1.5v6l5.25 3.15.75-1.23-4.5-2.67z"/></g><g id="search"><path d="M15.5 14h-.79l-.28-.27c.98-1.14 1.57-2.62 1.57-4.23 0-3.59-2.91-6.5-6.5-6.5s-6.5 2.91-6.5 6.5 2.91 6.5 6.5 6.5c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99 1.49-1.49-4.99-5zm-6 0c-2.49 0-4.5-2.01-4.5-4.5s2.01-4.5 4.5-4.5 4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5z"/></g><g id="select-all"><path d="M3 5h2v-2c-1.1 0-2 .9-2 2zm0 8h2v-2h-2v2zm4 8h2v-2h-2v2zm-4-12h2v-2h-2v2zm10-6h-2v2h2v-2zm6 0v2h2c0-1.1-.9-2-2-2zm-14 18v-2h-2c0 1.1.9 2 2 2zm-2-4h2v-2h-2v2zm6-14h-2v2h2v-2zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2v-2h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2v-2h-2v2zm-8 12h10v-10h-10v10zm2-8h6v6h-6v-6z"/></g><g id="send-money"><path d="M2 12c0-2.61 1.67-4.83 4-5.65v-2.09c-3.45.89-6 4.01-6 7.74s2.55 6.85 6 7.74v-2.09c-2.33-.82-4-3.04-4-5.65zm22 0l-4-4v3h-7v2h7v3l4-4zm-10 6c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.16.67 4.24 1.76l1.42-1.41c-1.45-1.45-3.45-2.35-5.66-2.35-4.42 0-8 3.58-8 8s3.58 8 8 8c2.21 0 4.21-.9 5.66-2.34l-1.42-1.41c-1.08 1.08-2.58 1.75-4.24 1.75z"/></g><g id="send"><path d="M2.01 21l20.99-9-20.99-9-.01 7 15 2-15 2z"/></g><g id="settings-applications"><path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm7-7h-14c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2v-14c0-1.1-.89-2-2-2zm-1.75 9c0 .23-.02.46-.05.68l1.48 1.16c.13.11.17.3.08.45l-1.4 2.42c-.09.15-.27.21-.43.15l-1.74-.7c-.36.28-.76.51-1.18.69l-.26 1.85c-.03.17-.18.3-.35.3h-2.8c-.17 0-.32-.13-.35-.29l-.26-1.85c-.43-.18-.82-.41-1.18-.69l-1.74.7c-.16.06-.34 0-.43-.15l-1.4-2.42c-.09-.15-.05-.34.08-.45l1.48-1.16c-.03-.23-.05-.46-.05-.69 0-.23.02-.46.05-.68l-1.48-1.16c-.13-.11-.17-.3-.08-.45l1.4-2.42c.09-.15.27-.21.43-.15l1.74.7c.36-.28.76-.51 1.18-.69l.26-1.85c.03-.17.18-.3.35-.3h2.8c.17 0 .32.13.35.29l.26 1.85c.43.18.82.41 1.18.69l1.74-.7c.16-.06.34 0 .43.15l1.4 2.42c.09.15.05.34-.08.45l-1.48 1.16c.03.23.05.46.05.69z"/></g><g id="settings-backup-restore"><path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9h-3l4 4 4-4h-3c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44c1.52 1.16 3.42 1.86 5.48 1.86 4.97 0 9-4.03 9-9s-4.03-9-9-9z"/></g><g id="settings-bluetooth"><path d="M11 24h2v-2h-2v2zm-4 0h2v-2h-2v2zm8 0h2v-2h-2v2zm2.71-18.29l-5.71-5.71h-1v7.59l-4.59-4.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 4.59-4.59v7.59h1l5.71-5.71-4.3-4.29 4.3-4.29zm-4.71-1.88l1.88 1.88-1.88 1.88v-3.76zm1.88 10.46l-1.88 1.88v-3.76l1.88 1.88z"/></g><g id="settings-cell"><path d="M7 24h2v-2h-2v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm1-23.99l-8-.01c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2v-16c0-1.1-.9-1.99-2-1.99zm0 15.99h-8v-12h8v12z"/></g><g id="settings-display"><path d="M21 3h-18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16.01h-18v-14.02h18v14.02zm-13-3.01h2.5l1.5 1.5 1.5-1.5h2.5v-2.5l1.5-1.5-1.5-1.5v-2.5h-2.5l-1.5-1.5-1.5 1.5h-2.5v2.5l-1.5 1.5 1.5 1.5v2.5zm4-7c1.66 0 3 1.34 3 3s-1.34 3-3 3v-6z"/></g><g id="settings-ethernet"><path d="M7.77 6.76l-1.54-1.28-5.41 6.52 5.41 6.52 1.54-1.28-4.35-5.24 4.35-5.24zm-.77 6.24h2v-2h-2v2zm10-2h-2v2h2v-2zm-6 2h2v-2h-2v2zm6.77-7.52l-1.54 1.28 4.35 5.24-4.35 5.24 1.54 1.28 5.41-6.52-5.41-6.52z"/></g><g id="settings-input-antenna"><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.12-2.5-2.5-2.5s-2.5 1.12-2.5 2.5c0 1.02.62 1.9 1.5 2.29v3.3l-3.41 3.41 1.41 1.41 3-3 3 3 1.41-1.41-3.41-3.41v-3.3zm-1-13.29c-6.07 0-11 4.93-11 11h2c0-4.97 4.03-9 9-9s9 4.03 9 9h2c0-6.07-4.93-11-11-11z"/></g><g id="settings-input-component"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2v-4zm4 14c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2zm-8 0c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.42 2-1.52 2-2.82v-2h-6v2zm20-10v-4c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2v-4zm4 14c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"/></g><g id="settings-input-composite"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2v-4zm4 14c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2zm-8 0c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.42 2-1.52 2-2.82v-2h-6v2zm20-10v-4c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4h-2v6h6v-6h-2v-4zm4 14c0 1.3.84 2.4 2 2.82v4.18h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"/></g><g id="settings-input-hdmi"><path d="M18 7v-3c0-1.1-.9-2-2-2h-8c-1.1 0-2 .9-2 2v3h-1v6l3 6v3h8v-3l3-6v-6h-1zm-10-3h8v3h-2v-2h-1v2h-2v-2h-1v2h-2v-3z"/></g><g id="settings-input-svideo"><path d="M8 11.5c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5.67 1.5 1.5 1.5 1.5-.67 1.5-1.5zm7-5c0-.83-.67-1.5-1.5-1.5h-3c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5h3c.83 0 1.5-.67 1.5-1.5zm-6.5 8.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm3.5-14c-6.07 0-11 4.93-11 11s4.93 11 11 11 11-4.93 11-11-4.93-11-11-11zm0 20c-4.96 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9zm5.5-11c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm-2 5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"/></g><g id="settings-overscan"><path d="M12.01 5.5l-2.01 2.5h4l-1.99-2.5zm5.99 4.5v4l2.5-1.99-2.5-2.01zm-12 0l-2.5 2.01 2.5 1.99v-4zm8 6h-4l2.01 2.5 1.99-2.5zm7-13h-18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16.01h-18v-14.02h18v14.02z"/></g><g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65c-.03-.24-.24-.42-.49-.42h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-7.43 2.52c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></g><g id="settings-phone"><path d="M13 9h-2v2h2v-2zm4 0h-2v2h2v-2zm3 6.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01-.37-1.12-.57-2.32-.57-3.57 0-.55-.45-1-1-1h-3.5c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zm-1-6.5v2h2v-2h-2z"/></g><g id="settings-power"><path d="M7 24h2v-2h-2v2zm4 0h2v-2h-2v2zm2-22h-2v10h2v-10zm3.56 2.44l-1.45 1.45c1.73 1.05 2.89 2.94 2.89 5.11 0 3.31-2.69 6-6 6s-6-2.69-6-6c0-2.17 1.16-4.06 2.88-5.12l-1.44-1.44c-2.08 1.44-3.44 3.84-3.44 6.56 0 4.42 3.58 8 8 8s8-3.58 8-8c0-2.72-1.36-5.12-3.44-6.56zm-1.56 19.56h2v-2h-2v2z"/></g><g id="settings-remote"><path d="M15 9h-6c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-12c0-.55-.45-1-1-1zm-3 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm-4.95-8.95l1.41 1.41c.91-.9 2.16-1.46 3.54-1.46s2.63.56 3.54 1.46l1.41-1.41c-1.27-1.27-3.02-2.05-4.95-2.05s-3.68.78-4.95 2.05zm4.95-6.05c-3.04 0-5.79 1.23-7.78 3.22l1.41 1.41c1.63-1.62 3.88-2.63 6.37-2.63s4.74 1.01 6.36 2.64l1.41-1.41c-1.98-2-4.73-3.23-7.77-3.23z"/></g><g id="settings-voice"><path d="M7 24h2v-2h-2v2zm5-11c1.66 0 2.99-1.34 2.99-3l.01-6c0-1.66-1.34-3-3-3s-3 1.34-3 3v6c0 1.66 1.34 3 3 3zm-1 11h2v-2h-2v2zm4 0h2v-2h-2v2zm4-14h-1.7c0 3-2.54 5.1-5.3 5.1s-5.3-2.1-5.3-5.1h-1.7c0 3.41 2.72 6.23 6 6.72v3.28h2v-3.28c3.28-.49 6-3.31 6-6.72z"/></g><g id="shop"><path d="M16 6v-2c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2h-6v13c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-13h-6zm-6-2h4v2h-4v-2zm-1 14v-9l7.5 4-7.5 5z"/></g><g id="shopping-basket"><path d="M17.21 9l-4.38-6.56c-.19-.28-.51-.42-.83-.42-.32 0-.64.14-.83.43l-4.38 6.55h-4.79c-.55 0-1 .45-1 1 0 .09.01.18.04.27l2.54 9.27c.23.84 1 1.46 1.92 1.46h13c.92 0 1.69-.62 1.93-1.46l2.54-9.27.03-.27c0-.55-.45-1-1-1h-4.79zm-8.21 0l3-4.4 3 4.4h-6zm3 8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></g><g id="shopping-cart"><path d="M7 18c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-6-16v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2h-11.58c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1h-14.79l-.94-2h-3.27zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/></g><g id="shop-two"><path d="M3 9h-2v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2h-16v-11zm15-4v-2c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2h-5v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2v-11h-5zm-6-2h4v2h-4v-2zm0 12v-7l5.5 3-5.5 4z"/></g><g id="sort"><path d="M3 18h6v-2h-6v2zm0-12v2h18v-2h-18zm0 7h12v-2h-12v2z"/></g><g id="speaker-notes"><path d="M20 2h-16c-1.1 0-1.99.9-1.99 2l-.01 18 4-4h14c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm-12 12h-2v-2h2v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2zm7 6h-5v-2h5v2zm3-3h-8v-2h8v2zm0-3h-8v-2h8v2z"/></g><g id="spellcheck"><path d="M12.45 16h2.09l-5.11-13h-1.86l-5.11 13h2.09l1.12-3h5.64l1.14 3zm-6.02-5l2.07-5.52 2.07 5.52h-4.14zm15.16.59l-8.09 8.09-3.67-3.68-1.41 1.41 5.09 5.09 9.49-9.5-1.41-1.41z"/></g><g id="star-half"><path d="M22 9.74l-7.19-.62L12 2.5 9.19 9.13 2 9.74l5.46 4.73-1.64 7.03L12 17.77l6.18 3.73-1.63-7.03L22 9.74zM12 15.9V6.6l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.9z"/></g><g id="star-outline"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"/></g><g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></g><g id="star-rate"><path d="M12 14.3l3.71 2.7-1.42-4.36 3.71-2.64h-4.55l-1.45-4.5-1.45 4.5h-4.55l3.71 2.64-1.42 4.36z"/></g><g id="stars"><path d="M11.99 2c-5.52 0-9.99 4.48-9.99 10s4.47 10 9.99 10c5.53 0 10.01-4.48 10.01-10s-4.48-10-10.01-10zm4.24 16l-4.23-2.55-4.23 2.55 1.12-4.81-3.73-3.23 4.92-.42 1.92-4.54 1.92 4.53 4.92.42-3.73 3.23 1.12 4.82z"/></g><g id="store"><path d="M20 4h-16v2h16v-2zm1 10v-2l-1-5h-16l-1 5v2h1v6h10v-6h4v6h2v-6h1zm-9 4h-6v-4h6v4z"/></g><g id="subject"><path d="M14 17h-10v2h10v-2zm6-8h-16v2h16v-2zm-16 6h16v-2h-16v2zm0-10v2h16v-2h-16z"/></g><g id="supervisor-account"><circle cx="12" cy="13.49" r="1.5"/><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 2.5c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25 2.25-2.25-1.01-2.25-2.25 1.01-2.25 2.25-2.25zm5 10.56v2.5c-.45.41-.96.77-1.5 1.05v-.68c0-.34-.17-.65-.46-.92-.65-.62-1.89-1.02-3.04-1.02-.96 0-1.96.28-2.65.73l-.17.12-.21.17c.78.47 1.63.72 2.54.82l1.33.15c.37.04.66.36.66.75 0 .29-.16.53-.4.66-.28.15-.64.09-.95.09-.35 0-.69-.01-1.03-.05-.5-.06-.99-.17-1.46-.33-.49-.16-.97-.38-1.42-.64-.22-.13-.44-.27-.65-.43l-.31-.24c-.04-.02-.28-.18-.28-.23v-4.28c0-1.58 2.63-2.78 5-2.78s5 1.2 5 2.78v1.78z"/></g><g id="swap-horiz"><path d="M6.99 11l-3.99 4 3.99 4v-3h7.01v-2h-7.01v-3zm14.01-2l-3.99-4v3h-7.01v2h7.01v3l3.99-4z"/></g><g id="swap-vert-circle"><path d="M12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm-5.5 7l3.5-3.5 3.5 3.5h-2.5v4h-2v-4h-2.5zm11 6l-3.5 3.5-3.5-3.5h2.5v-4h2v4h2.5z"/></g><g id="swap-vert"><path d="M16 17.01v-7.01h-2v7.01h-3l4 3.99 4-3.99h-3zm-7-14.01l-4 3.99h3v7.01h2v-7.01h3l-4-3.99z"/></g><g id="system-update-tv"><path d="M12 16.5l4-4h-3v-9h-2v9h-3l4 4zm9-13h-6v1.99h6v14.03h-18v-14.03h6v-1.99h-6c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2z"/></g><g id="tab"><path d="M21 3h-18c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16h-18v-14h10v4h8v10z"/></g><g id="tab-unselected"><path d="M1 9h2v-2h-2v2zm0 4h2v-2h-2v2zm0-8h2v-2c-1.1 0-2 .9-2 2zm8 16h2v-2h-2v2zm-8-4h2v-2h-2v2zm2 4v-2h-2c0 1.1.9 2 2 2zm18-18h-8v6h10v-4c0-1.1-.9-2-2-2zm0 14h2v-2h-2v2zm-12-12h2v-2h-2v2zm-4 16h2v-2h-2v2zm0-16h2v-2h-2v2zm16 16c1.1 0 2-.9 2-2h-2v2zm0-8h2v-2h-2v2zm-8 8h2v-2h-2v2zm4 0h2v-2h-2v2z"/></g><g id="text-format"><path d="M5 17v2h14v-2h-14zm4.5-4.2h5l.9 2.2h2.1l-4.75-11h-1.5l-4.75 11h2.1l.9-2.2zm2.5-6.82l1.87 5.02h-3.74l1.87-5.02z"/></g><g id="theaters"><path d="M18 3v2h-2v-2h-8v2h-2v-2h-2v18h2v-2h2v2h8v-2h2v2h2v-18h-2zm-10 14h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2v-2h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2v-2h2v2z"/></g><g id="thumb-down"><path d="M15 3h-9c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01-.01.08c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06l1.06 1.05 6.59-6.59c.36-.36.58-.86.58-1.41v-10c0-1.1-.9-2-2-2zm4 0v12h4v-12h-4z"/></g><g id="thumbs-up-down"><path d="M12 6c0-.55-.45-1-1-1h-5.18l.66-3.18.02-.23c0-.31-.13-.59-.33-.8l-.79-.79-4.94 4.94c-.27.27-.44.65-.44 1.06v6.5c0 .83.67 1.5 1.5 1.5h6.75c.62 0 1.15-.38 1.38-.91l2.26-5.29c.07-.17.11-.36.11-.55v-1.25zm10.5 4h-6.75c-.62 0-1.15.38-1.38.91l-2.26 5.29c-.07.17-.11.36-.11.55v1.25c0 .55.45 1 1 1h5.18l-.66 3.18-.02.24c0 .31.13.59.33.8l.79.78 4.94-4.94c.27-.27.44-.65.44-1.06v-6.5c0-.83-.67-1.5-1.5-1.5z"/></g><g id="thumb-up"><path d="M1 21h4v-12h-4v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06l-1.06-1.05-6.58 6.59c-.37.36-.59.86-.59 1.41v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01.01-.08z"/></g><g id="toc"><path d="M3 9h14v-2h-14v2zm0 4h14v-2h-14v2zm0 4h14v-2h-14v2zm16 0h2v-2h-2v2zm0-10v2h2v-2h-2zm0 6h2v-2h-2v2z"/></g><g id="today"><path d="M19 3h-1v-2h-2v2h-8v-2h-2v2h-1c-1.11 0-1.99.9-1.99 2l-.01 14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-14c0-1.1-.9-2-2-2zm0 16h-14v-11h14v11zm-12-9h5v5h-5z"/></g><g id="track-changes"><path d="M19.07 4.93l-1.41 1.41c1.44 1.45 2.34 3.45 2.34 5.66 0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02c-2.84.48-5 2.94-5 5.91 0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41c.72.73 1.17 1.73 1.17 2.83 0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72v-8.28h-1c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"/></g><g id="translate"><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53h2.93v-2h-7v-2h-2v2h-7v1.99h11.17c-.67 1.93-1.73 3.76-3.17 5.36-.93-1.03-1.7-2.16-2.31-3.35h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02 1.42 1.42 5-5 3.11 3.11.76-2.04zm5.63-5.07h-2l-4.5 12h2l1.12-3h4.75l1.13 3h2l-4.5-12zm-2.62 7l1.62-4.33 1.62 4.33h-3.24z"/></g><g id="trending-down"><path d="M16 18l2.29-2.29-4.88-4.88-4 4-7.41-7.42 1.41-1.41 6 6 4-4 6.3 6.29 2.29-2.29v6z"/></g><g id="trending-neutral"><path d="M22 12l-4-4v3h-15v2h15v3z"/></g><g id="trending-up"><path d="M16 6l2.29 2.29-4.88 4.88-4-4-7.41 7.42 1.41 1.41 6-6 4 4 6.3-6.29 2.29 2.29v-6z"/></g><g id="turned-in-not"><path d="M17 3h-10c-1.1 0-1.99.9-1.99 2l-.01 16 7-3 7 3v-16c0-1.1-.9-2-2-2zm0 15l-5-2.18-5 2.18v-13h10v13z"/></g><g id="turned-in"><path d="M17 3h-10c-1.1 0-1.99.9-1.99 2l-.01 16 7-3 7 3v-16c0-1.1-.9-2-2-2z"/></g><g id="undo"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6l-3.6-3.6v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78c-1.39-4.19-5.32-7.22-9.97-7.22z"/></g><g id="unfold-less"><path d="M7.41 18.59l1.42 1.41 3.17-3.17 3.17 3.17 1.41-1.41-4.58-4.59-4.59 4.59zm9.18-13.18l-1.42-1.41-3.17 3.17-3.17-3.17-1.42 1.41 4.59 4.59 4.59-4.59z"/></g><g id="unfold-more"><path d="M12 5.83l3.17 3.17 1.41-1.41-4.58-4.59-4.59 4.59 1.42 1.41 3.17-3.17zm0 12.34l-3.17-3.17-1.41 1.41 4.58 4.59 4.59-4.59-1.42-1.41-3.17 3.17z"/></g><g id="verified-user"><path d="M12 1l-9 4v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12v-6l-9-4zm-2 16l-4-4 1.41-1.41 2.59 2.58 6.59-6.59 1.41 1.42-8 8z"/></g><g id="view-agenda"><path d="M20 13h-17c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm0-10h-17c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1z"/></g><g id="view-array"><path d="M4 18h3v-13h-3v13zm14-13v13h3v-13h-3zm-10 13h9v-13h-9v13z"/></g><g id="view-carousel"><path d="M7 19h10v-15h-10v15zm-5-2h4v-11h-4v11zm16-11v11h4v-11h-4z"/></g><g id="view-column"><path d="M10 18h5v-13h-5v13zm-6 0h5v-13h-5v13zm12-13v13h5v-13h-5z"/></g><g id="view-day"><path d="M2 21h19v-3h-19v3zm18-13h-17c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm-18-5v3h19v-3h-19z"/></g><g id="view-headline"><path d="M4 15h17v-2h-17v2zm0 4h17v-2h-17v2zm0-8h17v-2h-17v2zm0-6v2h17v-2h-17z"/></g><g id="view-list"><path d="M4 14h4v-4h-4v4zm0 5h4v-4h-4v4zm0-10h4v-4h-4v4zm5 5h12v-4h-12v4zm0 5h12v-4h-12v4zm0-14v4h12v-4h-12z"/></g><g id="view-module"><path d="M4 11h5v-6h-5v6zm0 7h5v-6h-5v6zm6 0h5v-6h-5v6zm6 0h5v-6h-5v6zm-6-7h5v-6h-5v6zm6-6v6h5v-6h-5z"/></g><g id="view-quilt"><path d="M10 18h5v-6h-5v6zm-6 0h5v-13h-5v13zm12 0h5v-6h-5v6zm-6-13v6h11v-6h-11z"/></g><g id="view-stream"><path d="M4 18h17v-6h-17v6zm0-13v6h17v-6h-17z"/></g><g id="view-week"><path d="M6 5h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-12c0-.55-.45-1-1-1zm14 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-12c0-.55-.45-1-1-1zm-7 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-12c0-.55-.45-1-1-1z"/></g><g id="visibility-off"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16c.57-.23 1.18-.36 1.83-.36zm-10-2.73l2.28 2.28.46.46c-1.66 1.29-2.96 3.01-3.74 4.99 1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42 2.93 2.92 1.27-1.27-17.73-17.73-1.27 1.27zm5.53 5.53l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/></g><g id="visibility"><path d="M12 4.5c-5 0-9.27 3.11-11 7.5 1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zm0 12.5c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></g><g id="wallet-giftcard"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68c-.54-.8-1.45-1.34-2.5-1.34-1.66 0-3 1.34-3 3 0 .35.07.69.18 1h-2.18c-1.11 0-1.99.89-1.99 2l-.01 11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-11c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-6 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15h-16v-2h16v2zm0-5h-16v-6h5.08l-2.08 2.83 1.62 1.17 2.38-3.24 1-1.36 1 1.36 2.38 3.24 1.62-1.17-2.08-2.83h5.08v6z"/></g><g id="wallet-membership"><path d="M20 2h-16c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h4v5l4-2 4 2v-5h4c1.11 0 2-.89 2-2v-11c0-1.11-.89-2-2-2zm0 13h-16v-2h16v2zm0-5h-16v-6h16v6z"/></g><g id="wallet-travel"><path d="M20 6h-3v-2c0-1.11-.89-2-2-2h-6c-1.11 0-2 .89-2 2v2h-3c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-11c0-1.11-.89-2-2-2zm-11-2h6v2h-6v-2zm11 15h-16v-2h16v2zm0-5h-16v-6h3v2h2v-2h6v2h2v-2h3v6z"/></g><g id="warning"><path d="M1 21h22l-11-19-11 19zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></g><g id="work"><path d="M24 0v24h-24v-24h24m1-1h-26v26h26v-26z"/><path d="M20 6h-4v-2c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2h-4c-1.11 0-1.99.89-1.99 2l-.01 11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2v-11c0-1.11-.89-2-2-2zm-6 0h-4v-2h4v2z"/></g></defs></svg></core-iconset-svg><polymer-element name="core-icon-button" attributes="src icon active" assetpath="../core-icon-button/"><template><style>:host{display:inline-block;box-sizing:border-box;-moz-box-sizing:border-box;user-select:none;-moz-user-select:none;-webkit-user-select:none;border-radius:2px;padding:7px;margin:2px;vertical-align:middle;font-size:1rem;cursor:pointer}:host([disabled]){opacity:.6;pointer-events:none}:host(.outline){box-shadow:0 0 0 1px rgba(0,0,0,.1)}:host(:hover:not([disabled])){box-shadow:0 1px 0 0 rgba(0,0,0,.12),0 0 0 1px rgba(0,0,0,.1)}:host(.selected:not([disabled])){background-color:rgba(0,0,0,.05);box-shadow:inset 0 1px 0 0 rgba(0,0,0,.05),0 0 0 1px rgba(0,0,0,.12)}:host(:active:not([disabled]),.selected:active:not([disabled])){background-color:rgba(0,0,0,.05);box-shadow:inset 0 1px 0 0 rgba(0,0,0,.1),0 0 0 1px rgba(0,0,0,.12)}:host(.core-dark-theme.outline){background-color:rgba(200,200,200,.05);box-shadow:0 0 0 1px rgba(200,200,200,.1)}:host(.core-dark-theme:hover){background-color:rgba(200,200,200,.05);box-shadow:0 1px 0 0 rgba(200,200,200,.12),0 0 0 1px rgba(200,200,200,.1)}:host(.core-dark-theme.selected){background-color:rgba(220,220,220,.05);box-shadow:inset 0 1px 0 0 rgba(200,200,200,.05),0 0 0 1px rgba(200,200,200,.12)}:host(.core-dark-theme:active,.core-dark-theme.selected:active){background-color:rgba(200,200,200,.05);box-shadow:inset 0 1px 0 0 rgba(200,200,200,.1),0 0 0 1px rgba(200,200,200,.12)}core-icon{pointer-events:none}:host ::content>:not(core-icon){margin-left:4px}</style><core-icon src="{{src}}" icon="{{icon}}"></core-icon><content></content></template><script>Polymer("core-icon-button",{src:"",active:false,icon:"",activeChanged:function(){this.classList.toggle("selected",this.active)}});</script></polymer-element><polymer-element name="core-toolbar" attributes="justify middleJustify bottomJustify" assetpath="../core-toolbar/"><template><style>:host{display:block;position:relative;box-sizing:border-box;-moz-box-sizing:border-box;height:64px;font-size:1.3em;background-color:#CFD8DC}:host(.animate){transition:height .18s ease-in}:host(.medium-tall){height:128px}:host(.tall){height:192px}.toolbar-tools{position:relative;height:64px;padding:0 8px;pointer-events:none}:host(.core-narrow),:host-context(.core-narrow){height:56px}polyfill-next-selector{content:':host.core-narrow.medium-tall, .core-narrow :host.medium-tall'}:host(.core-narrow.medium-tall),:host-context(.core-narrow):host(.medium-tall){height:112px}polyfill-next-selector{content:':host.core-narrow.tall, .core-narrow :host.tall'}:host(.core-narrow.tall),:host-context(.core-narrow):host(.tall){height:168px}polyfill-next-selector{content:':host.core-narrow .toolbar-tools, .core-narrow :host .toolbar-tools'}:host(.core-narrow) .toolbar-tools,:host-context(.core-narrow) .toolbar-tools{height:56px;padding:0}#middleBar{position:absolute;top:0;right:0;left:0}:host(.tall,.medium-tall) #middleBar{-webkit-transform:translateY(100%);transform:translateY(100%)}#bottomBar{position:absolute;right:0;bottom:0;left:0}polyfill-next-selector{content:'.toolbar-tools > *'}::content>*{pointer-events:auto}polyfill-next-selector{content:'.toolbar-tools > *'}::content>*{margin:0 8px}polyfill-next-selector{content:'.toolbar-tools > .fit'}::content>.fit{position:absolute;top:auto;right:0;bottom:0;left:0;width:auto;margin:0}polyfill-next-selector{content:':host .indent'}::content>.indent{margin-left:60px}</style><div id="bottomBar" class="toolbar-tools" center="" horizontal="" layout=""><content select=".bottom"></content></div><div id="middleBar" class="toolbar-tools" center="" horizontal="" layout=""><content select=".middle"></content></div><div id="topBar" class="toolbar-tools" center="" horizontal="" layout=""><content></content></div></template><script>(function(){Polymer("core-toolbar",{justify:"",middleJustify:"",bottomJustify:"",justifyChanged:function(old){this.updateBarJustify(this.$.topBar,this.justify,old)},middleJustifyChanged:function(old){this.updateBarJustify(this.$.middleBar,this.middleJustify,old)},bottomJustifyChanged:function(old){this.updateBarJustify(this.$.bottomBar,this.bottomJustify,old)},updateBarJustify:function(bar,justify,old){if(old){bar.removeAttribute(this.toLayoutAttrName(old))}if(this.justify){bar.setAttribute(this.toLayoutAttrName(justify),"")}},toLayoutAttrName:function(value){return value==="between"?"justified":value+"-justified"}})})();</script></polymer-element><polymer-element name="core-header-panel" assetpath="../core-header-panel/"><template><style>:host{display:block;position:relative}#outerContainer{position:absolute;top:0;right:0;bottom:0;left:0}#mainPanel{position:relative}#mainContainer{position:relative;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch}#dropShadow{position:absolute;top:0;left:0;right:0;height:6px;box-shadow:inset 0 5px 6px -3px rgba(0,0,0,.4)}#dropShadow.hidden{display:none}:host([mode=scroll]) #mainContainer{overflow:visible}:host([mode=scroll]) #outerContainer{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch}:host([mode=cover]) #mainPanel{position:static}:host([mode=cover]) #mainContainer{position:absolute;top:0;right:0;bottom:0;left:0}:host([mode=cover]) #dropShadow{position:static;width:100%}</style><div id="outerContainer" vertical="" layout=""><content id="headerContent" select="core-toolbar, .core-header"></content><div id="mainPanel" flex="" vertical="" layout=""><div id="mainContainer" flex?="{{mode !== 'cover'}}"><content id="mainContent" select="*"></content></div><div id="dropShadow"></div></div></div></template><script>Polymer("core-header-panel",{publish:{mode:{value:"",reflect:true},tallClass:"tall",shadow:false},animateDuration:200,modeConfigs:{shadowMode:{waterfall:1,"waterfall-tall":1},noShadow:{seamed:1,cover:1,scroll:1},tallMode:{"waterfall-tall":1},outerScroll:{scroll:1}},ready:function(){this.scrollHandler=this.scroll.bind(this);this.addListener()},detached:function(){this.removeListener(this.mode)},addListener:function(){this.scroller.addEventListener("scroll",this.scrollHandler)},removeListener:function(mode){var s=this.getScrollerForMode(mode);s.removeEventListener("scroll",this.scrollHandler)},domReady:function(){this.async("scroll")},modeChanged:function(old){var header=this.header;if(header){var configs=this.modeConfigs;if(configs.tallMode[old]&&!configs.tallMode[this.mode]){header.classList.remove(this.tallClass);this.async(function(){header.classList.remove("animate")},null,this.animateDuration)}else{header.classList.toggle("animate",configs.tallMode[this.mode])}}if(configs&&(configs.outerScroll[this.mode]||configs.outerScroll[old])){this.removeListener(old);this.addListener()}this.scroll()},get header(){return this.$.headerContent.getDistributedNodes()[0]},getScrollerForMode:function(mode){return this.modeConfigs.outerScroll[mode]?this.$.outerContainer:this.$.mainContainer},get scroller(){return this.getScrollerForMode(this.mode)},scroll:function(){var configs=this.modeConfigs;var main=this.$.mainContainer;var header=this.header;var sTop=main.scrollTop;var atTop=sTop===0;this.$.dropShadow.classList.toggle("hidden",!this.shadow&&(atTop&&configs.shadowMode[this.mode]||configs.noShadow[this.mode]));if(header&&configs.tallMode[this.mode]){header.classList.toggle(this.tallClass,atTop||header.classList.contains(this.tallClass)&&main.scrollHeight<this.$.outerContainer.offsetHeight)}this.fire("scroll",{target:this.scroller},this,false)}});</script></polymer-element><script>(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(){var out,err;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());</script><polymer-element name="marked-element" attributes="text" assetpath="../marked-element/"><script>Polymer("marked-element",{text:"",attached:function(){marked.setOptions({highlight:this.highlight.bind(this)});if(!this.text){this.text=this.innerHTML}},textChanged:function(oldVal,newVal){if(newVal){this.innerHTML=marked(this.text)}},highlight:function(code,lang){var event=this.fire("marked-js-highlight",{code:code,lang:lang});return event.detail.code||code}});</script></polymer-element><script>var IN_GLOBAL_SCOPE=true;window["PR_SHOULD_USE_CONTINUATION"]=true;var prettyPrintOne;var prettyPrint;(function(){var win=window;var FLOW_CONTROL_KEYWORDS=["break,continue,do,else,for,if,return,while"];var C_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default,"+"double,enum,extern,float,goto,inline,int,long,register,short,signed,"+"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var COMMON_KEYWORDS=[C_KEYWORDS,"catch,class,delete,false,import,"+"new,operator,private,protected,public,this,throw,true,try,typeof"];var CPP_KEYWORDS=[COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool,"+"concept,concept_map,const_cast,constexpr,decltype,delegate,"+"dynamic_cast,explicit,export,friend,generic,late_check,"+"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,"+"static_cast,template,typeid,typename,using,virtual,where"];var JAVA_KEYWORDS=[COMMON_KEYWORDS,"abstract,assert,boolean,byte,extends,final,finally,implements,import,"+"instanceof,interface,null,native,package,strictfp,super,synchronized,"+"throws,transient"];var CSHARP_KEYWORDS=[JAVA_KEYWORDS,"as,base,by,checked,decimal,delegate,descending,dynamic,event,"+"fixed,foreach,from,group,implicit,in,internal,into,is,let,"+"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,"+"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,"+"var,virtual,where"];var COFFEE_KEYWORDS="all,and,by,catch,class,else,extends,false,finally,"+"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,"+"throw,true,try,unless,until,when,while,yes";var JSCRIPT_KEYWORDS=[COMMON_KEYWORDS,"debugger,eval,export,function,get,null,set,undefined,var,with,"+"Infinity,NaN"];var PERL_KEYWORDS="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,"+"goto,if,import,last,local,my,next,no,our,print,package,redo,require,"+"sub,undef,unless,until,use,wantarray,while,BEGIN,END";var PYTHON_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"and,as,assert,class,def,del,"+"elif,except,exec,finally,from,global,import,in,is,lambda,"+"nonlocal,not,or,pass,print,raise,try,with,yield,"+"False,True,None"];var RUBY_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"alias,and,begin,case,class,"+"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,"+"rescue,retry,self,super,then,true,undef,unless,until,when,yield,"+"BEGIN,END"];var RUST_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"as,assert,const,copy,drop,"+"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,"+"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"];var SH_KEYWORDS=[FLOW_CONTROL_KEYWORDS,"case,done,elif,esac,eval,fi,"+"function,in,local,set,then,until"];var ALL_KEYWORDS=[CPP_KEYWORDS,CSHARP_KEYWORDS,JSCRIPT_KEYWORDS,PERL_KEYWORDS,PYTHON_KEYWORDS,RUBY_KEYWORDS,SH_KEYWORDS];var C_TYPES=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var PR_STRING="str";var PR_KEYWORD="kwd";var PR_COMMENT="com";var PR_TYPE="typ";var PR_LITERAL="lit";var PR_PUNCTUATION="pun";var PR_PLAIN="pln";var PR_TAG="tag";var PR_DECLARATION="dec";var PR_SOURCE="src";var PR_ATTRIB_NAME="atn";var PR_ATTRIB_VALUE="atv";var PR_NOCODE="nocode";var REGEXP_PRECEDER_PATTERN="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function combinePrefixPatterns(regexs){var capturedGroupIndex=0;var needToFoldCase=false;var ignoreCase=false;for(var i=0,n=regexs.length;i<n;++i){var regex=regexs[i];if(regex.ignoreCase){ignoreCase=true}else if(/[a-z]/i.test(regex.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){needToFoldCase=true;ignoreCase=false;break}}var escapeCharToCodeUnit={b:8,t:9,n:10,v:11,f:12,r:13};function decodeEscape(charsetPart){var cc0=charsetPart.charCodeAt(0);if(cc0!==92){return cc0}var c1=charsetPart.charAt(1);cc0=escapeCharToCodeUnit[c1];if(cc0){return cc0}else if("0"<=c1&&c1<="7"){return parseInt(charsetPart.substring(1),8)}else if(c1==="u"||c1==="x"){return parseInt(charsetPart.substring(2),16)}else{return charsetPart.charCodeAt(1)}}function encodeEscape(charCode){if(charCode<32){return(charCode<16?"\\x0":"\\x")+charCode.toString(16)}var ch=String.fromCharCode(charCode);return ch==="\\"||ch==="-"||ch==="]"||ch==="^"?"\\"+ch:ch}function caseFoldCharset(charSet){var charsetParts=charSet.substring(1,charSet.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}"+"|\\\\x[0-9A-Fa-f]{2}"+"|\\\\[0-3][0-7]{0,2}"+"|\\\\[0-7]{1,2}"+"|\\\\[\\s\\S]"+"|-"+"|[^-\\\\]","g"));var ranges=[];var inverse=charsetParts[0]==="^";var out=["["];if(inverse){out.push("^")}for(var i=inverse?1:0,n=charsetParts.length;i<n;++i){var p=charsetParts[i];if(/\\[bdsw]/i.test(p)){out.push(p)}else{var start=decodeEscape(p);var end;if(i+2<n&&"-"===charsetParts[i+1]){end=decodeEscape(charsetParts[i+2]);i+=2}else{end=start}ranges.push([start,end]);if(!(end<65||start>122)){if(!(end<65||start>90)){ranges.push([Math.max(65,start)|32,Math.min(end,90)|32])}if(!(end<97||start>122)){ranges.push([Math.max(97,start)&~32,Math.min(end,122)&~32])}}}}ranges.sort(function(a,b){return a[0]-b[0]||b[1]-a[1]});var consolidatedRanges=[];var lastRange=[];for(var i=0;i<ranges.length;++i){var range=ranges[i];if(range[0]<=lastRange[1]+1){lastRange[1]=Math.max(lastRange[1],range[1])}else{consolidatedRanges.push(lastRange=range)}}for(var i=0;i<consolidatedRanges.length;++i){var range=consolidatedRanges[i];out.push(encodeEscape(range[0]));if(range[1]>range[0]){if(range[1]+1>range[0]){out.push("-")}out.push(encodeEscape(range[1]))}}out.push("]");return out.join("")}function allowAnywhereFoldCaseAndRenumberGroups(regex){var parts=regex.source.match(new RegExp("(?:"+"\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]"+"|\\\\u[A-Fa-f0-9]{4}"+"|\\\\x[A-Fa-f0-9]{2}"+"|\\\\[0-9]+"+"|\\\\[^ux0-9]"+"|\\(\\?[:!=]"+"|[\\(\\)\\^]"+"|[^\\x5B\\x5C\\(\\)\\^]+"+")","g"));var n=parts.length;var capturedGroups=[];for(var i=0,groupIndex=0;i<n;++i){var p=parts[i];if(p==="("){++groupIndex}else if("\\"===p.charAt(0)){var decimalValue=+p.substring(1);if(decimalValue){if(decimalValue<=groupIndex){capturedGroups[decimalValue]=-1}else{parts[i]=encodeEscape(decimalValue)}}}}for(var i=1;i<capturedGroups.length;++i){if(-1===capturedGroups[i]){capturedGroups[i]=++capturedGroupIndex}}for(var i=0,groupIndex=0;i<n;++i){var p=parts[i];if(p==="("){++groupIndex;if(!capturedGroups[groupIndex]){parts[i]="(?:"}}else if("\\"===p.charAt(0)){var decimalValue=+p.substring(1);if(decimalValue&&decimalValue<=groupIndex){parts[i]="\\"+capturedGroups[decimalValue]}}}for(var i=0;i<n;++i){if("^"===parts[i]&&"^"!==parts[i+1]){parts[i]=""}}if(regex.ignoreCase&&needToFoldCase){for(var i=0;i<n;++i){var p=parts[i];var ch0=p.charAt(0);if(p.length>=2&&ch0==="["){parts[i]=caseFoldCharset(p)}else if(ch0!=="\\"){parts[i]=p.replace(/[a-zA-Z]/g,function(ch){var cc=ch.charCodeAt(0);return"["+String.fromCharCode(cc&~32,cc|32)+"]"})}}}return parts.join("")}var rewritten=[];for(var i=0,n=regexs.length;i<n;++i){var regex=regexs[i];if(regex.global||regex.multiline){throw new Error(""+regex)}rewritten.push("(?:"+allowAnywhereFoldCaseAndRenumberGroups(regex)+")")}return new RegExp(rewritten.join("|"),ignoreCase?"gi":"g")}function extractSourceSpans(node,isPreformatted){var nocode=/(?:^|\s)nocode(?:\s|$)/;var chunks=[];var length=0;var spans=[];var k=0;function walk(node){var type=node.nodeType;if(type==1){if(nocode.test(node.className)){return}for(var child=node.firstChild;child;child=child.nextSibling){walk(child)}var nodeName=node.nodeName.toLowerCase();if("br"===nodeName||"li"===nodeName){chunks[k]="\n";spans[k<<1]=length++;spans[k++<<1|1]=node}}else if(type==3||type==4){var text=node.nodeValue;if(text.length){if(!isPreformatted){text=text.replace(/[ \t\r\n]+/g," ")}else{text=text.replace(/\r\n?/g,"\n")}chunks[k]=text;spans[k<<1]=length;length+=text.length;spans[k++<<1|1]=node}}}walk(node);return{sourceCode:chunks.join("").replace(/\n$/,""),spans:spans}}function appendDecorations(basePos,sourceCode,langHandler,out){if(!sourceCode){return}var job={sourceCode:sourceCode,basePos:basePos};langHandler(job);out.push.apply(out,job.decorations)}var notWs=/\S/;function childContentWrapper(element){var wrapper=undefined;for(var c=element.firstChild;c;c=c.nextSibling){var type=c.nodeType;wrapper=type===1?wrapper?element:c:type===3?notWs.test(c.nodeValue)?element:wrapper:wrapper}return wrapper===element?undefined:wrapper}function createSimpleLexer(shortcutStylePatterns,fallthroughStylePatterns){var shortcuts={};var tokenizer;(function(){var allPatterns=shortcutStylePatterns.concat(fallthroughStylePatterns);var allRegexs=[];var regexKeys={};for(var i=0,n=allPatterns.length;i<n;++i){var patternParts=allPatterns[i];var shortcutChars=patternParts[3];if(shortcutChars){for(var c=shortcutChars.length;--c>=0;){shortcuts[shortcutChars.charAt(c)]=patternParts}}var regex=patternParts[1];var k=""+regex;if(!regexKeys.hasOwnProperty(k)){allRegexs.push(regex);regexKeys[k]=null}}allRegexs.push(/[\0-\uffff]/);tokenizer=combinePrefixPatterns(allRegexs)})();var nPatterns=fallthroughStylePatterns.length;var decorate=function(job){var sourceCode=job.sourceCode,basePos=job.basePos;var decorations=[basePos,PR_PLAIN];var pos=0;var tokens=sourceCode.match(tokenizer)||[];var styleCache={};for(var ti=0,nTokens=tokens.length;ti<nTokens;++ti){var token=tokens[ti];var style=styleCache[token];var match=void 0;var isEmbedded;if(typeof style==="string"){isEmbedded=false}else{var patternParts=shortcuts[token.charAt(0)];if(patternParts){match=token.match(patternParts[1]);style=patternParts[0]}else{for(var i=0;i<nPatterns;++i){patternParts=fallthroughStylePatterns[i];match=token.match(patternParts[1]);if(match){style=patternParts[0];break}}if(!match){style=PR_PLAIN}}isEmbedded=style.length>=5&&"lang-"===style.substring(0,5);if(isEmbedded&&!(match&&typeof match[1]==="string")){isEmbedded=false;style=PR_SOURCE}if(!isEmbedded){styleCache[token]=style}}var tokenStart=pos;pos+=token.length;if(!isEmbedded){decorations.push(basePos+tokenStart,style)}else{var embeddedSource=match[1];var embeddedSourceStart=token.indexOf(embeddedSource);var embeddedSourceEnd=embeddedSourceStart+embeddedSource.length;if(match[2]){embeddedSourceEnd=token.length-match[2].length;embeddedSourceStart=embeddedSourceEnd-embeddedSource.length}var lang=style.substring(5);appendDecorations(basePos+tokenStart,token.substring(0,embeddedSourceStart),decorate,decorations);appendDecorations(basePos+tokenStart+embeddedSourceStart,embeddedSource,langHandlerForExtension(lang,embeddedSource),decorations);appendDecorations(basePos+tokenStart+embeddedSourceEnd,token.substring(embeddedSourceEnd),decorate,decorations)}}job.decorations=decorations};return decorate}function sourceDecorator(options){var shortcutStylePatterns=[],fallthroughStylePatterns=[];if(options["tripleQuotedStrings"]){shortcutStylePatterns.push([PR_STRING,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else if(options["multiLineStrings"]){shortcutStylePatterns.push([PR_STRING,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{shortcutStylePatterns.push([PR_STRING,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}if(options["verbatimStrings"]){fallthroughStylePatterns.push([PR_STRING,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var hc=options["hashComments"];if(hc){if(options["cStyleComments"]){if(hc>1){shortcutStylePatterns.push([PR_COMMENT,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{shortcutStylePatterns.push([PR_COMMENT,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}fallthroughStylePatterns.push([PR_STRING,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{shortcutStylePatterns.push([PR_COMMENT,/^#[^\r\n]*/,null,"#"])}}if(options["cStyleComments"]){fallthroughStylePatterns.push([PR_COMMENT,/^\/\/[^\r\n]*/,null]);fallthroughStylePatterns.push([PR_COMMENT,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}var regexLiterals=options["regexLiterals"];if(regexLiterals){var regexExcls=regexLiterals>1?"":"\n\r";var regexAny=regexExcls?".":"[\\S\\s]";var REGEX_LITERAL="/(?=[^/*"+regexExcls+"])"+"(?:[^/\\x5B\\x5C"+regexExcls+"]"+"|\\x5C"+regexAny+"|\\x5B(?:[^\\x5C\\x5D"+regexExcls+"]"+"|\\x5C"+regexAny+")*(?:\\x5D|$))+"+"/";fallthroughStylePatterns.push(["lang-regex",RegExp("^"+REGEXP_PRECEDER_PATTERN+"("+REGEX_LITERAL+")")])}var types=options["types"];if(types){fallthroughStylePatterns.push([PR_TYPE,types])}var keywords=(""+options["keywords"]).replace(/^ | $/g,"");if(keywords.length){fallthroughStylePatterns.push([PR_KEYWORD,new RegExp("^(?:"+keywords.replace(/[\s,]+/g,"|")+")\\b"),null])}shortcutStylePatterns.push([PR_PLAIN,/^\s+/,null," \r\n  "]);var punctuation="^.[^\\s\\w.$@'\"`/\\\\]*";if(options["regexLiterals"]){punctuation+="(?!s*/)"}fallthroughStylePatterns.push([PR_LITERAL,/^@[a-z_$][a-z_$@0-9]*/i,null],[PR_TYPE,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[PR_PLAIN,/^[a-z_$][a-z_$@0-9]*/i,null],[PR_LITERAL,new RegExp("^(?:"+"0x[a-f0-9]+"+"|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)"+"(?:e[+\\-]?\\d+)?"+")"+"[a-z]*","i"),null,"0123456789"],[PR_PLAIN,/^\\[\s\S]?/,null],[PR_PUNCTUATION,new RegExp(punctuation),null]);return createSimpleLexer(shortcutStylePatterns,fallthroughStylePatterns)}var decorateSource=sourceDecorator({keywords:ALL_KEYWORDS,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function numberLines(node,opt_startLineNum,isPreformatted){var nocode=/(?:^|\s)nocode(?:\s|$)/;var lineBreak=/\r\n?|\n/;var document=node.ownerDocument;var li=document.createElement("li");while(node.firstChild){li.appendChild(node.firstChild)}var listItems=[li];function walk(node){var type=node.nodeType;if(type==1&&!nocode.test(node.className)){if("br"===node.nodeName){breakAfter(node);if(node.parentNode){node.parentNode.removeChild(node)}}else{for(var child=node.firstChild;child;child=child.nextSibling){walk(child)}}}else if((type==3||type==4)&&isPreformatted){var text=node.nodeValue;var match=text.match(lineBreak);if(match){var firstLine=text.substring(0,match.index);node.nodeValue=firstLine;var tail=text.substring(match.index+match[0].length);if(tail){var parent=node.parentNode;parent.insertBefore(document.createTextNode(tail),node.nextSibling)}breakAfter(node);if(!firstLine){node.parentNode.removeChild(node)}}}}function breakAfter(lineEndNode){while(!lineEndNode.nextSibling){lineEndNode=lineEndNode.parentNode;if(!lineEndNode){return}}function breakLeftOf(limit,copy){var rightSide=copy?limit.cloneNode(false):limit;var parent=limit.parentNode;if(parent){var parentClone=breakLeftOf(parent,1);var next=limit.nextSibling;parentClone.appendChild(rightSide);for(var sibling=next;sibling;sibling=next){next=sibling.nextSibling;parentClone.appendChild(sibling)}}return rightSide}var copiedListItem=breakLeftOf(lineEndNode.nextSibling,0);for(var parent;(parent=copiedListItem.parentNode)&&parent.nodeType===1;){copiedListItem=parent}listItems.push(copiedListItem)}for(var i=0;i<listItems.length;++i){walk(listItems[i])}if(opt_startLineNum===(opt_startLineNum|0)){listItems[0].setAttribute("value",opt_startLineNum)}var ol=document.createElement("ol");ol.className="linenums";var offset=Math.max(0,opt_startLineNum-1|0)||0;for(var i=0,n=listItems.length;i<n;++i){li=listItems[i];li.className="L"+(i+offset)%10;if(!li.firstChild){li.appendChild(document.createTextNode(" "))}ol.appendChild(li)}node.appendChild(ol)}function recombineTagsAndDecorations(job){var isIE8OrEarlier=/\bMSIE\s(\d+)/.exec(navigator.userAgent);isIE8OrEarlier=isIE8OrEarlier&&+isIE8OrEarlier[1]<=8;var newlineRe=/\n/g;var source=job.sourceCode;var sourceLength=source.length;var sourceIndex=0;var spans=job.spans;var nSpans=spans.length;var spanIndex=0;var decorations=job.decorations;var nDecorations=decorations.length;var decorationIndex=0;decorations[nDecorations]=sourceLength;var decPos,i;for(i=decPos=0;i<nDecorations;){if(decorations[i]!==decorations[i+2]){decorations[decPos++]=decorations[i++];decorations[decPos++]=decorations[i++]}else{i+=2}}nDecorations=decPos;for(i=decPos=0;i<nDecorations;){var startPos=decorations[i];var startDec=decorations[i+1];var end=i+2;while(end+2<=nDecorations&&decorations[end+1]===startDec){end+=2}decorations[decPos++]=startPos;decorations[decPos++]=startDec;i=end}nDecorations=decorations.length=decPos;var sourceNode=job.sourceNode;var oldDisplay;if(sourceNode){oldDisplay=sourceNode.style.display;sourceNode.style.display="none"}try{var decoration=null;while(spanIndex<nSpans){var spanStart=spans[spanIndex];var spanEnd=spans[spanIndex+2]||sourceLength;var decEnd=decorations[decorationIndex+2]||sourceLength;var end=Math.min(spanEnd,decEnd);var textNode=spans[spanIndex+1];var styledText;if(textNode.nodeType!==1&&(styledText=source.substring(sourceIndex,end))){if(isIE8OrEarlier){styledText=styledText.replace(newlineRe,"\r")}textNode.nodeValue=styledText;var document=textNode.ownerDocument;var span=document.createElement("span");span.className=decorations[decorationIndex+1];var parentNode=textNode.parentNode;parentNode.replaceChild(span,textNode);span.appendChild(textNode);if(sourceIndex<spanEnd){spans[spanIndex+1]=textNode=document.createTextNode(source.substring(end,spanEnd));parentNode.insertBefore(textNode,span.nextSibling)}}sourceIndex=end;if(sourceIndex>=spanEnd){spanIndex+=2}if(sourceIndex>=decEnd){decorationIndex+=2}}}finally{if(sourceNode){sourceNode.style.display=oldDisplay}}}var langHandlerRegistry={};function registerLangHandler(handler,fileExtensions){for(var i=fileExtensions.length;--i>=0;){var ext=fileExtensions[i];if(!langHandlerRegistry.hasOwnProperty(ext)){langHandlerRegistry[ext]=handler}else if(win["console"]){console["warn"]("cannot override language handler %s",ext)}}}function langHandlerForExtension(extension,source){if(!(extension&&langHandlerRegistry.hasOwnProperty(extension))){extension=/^\s*</.test(source)?"default-markup":"default-code"}return langHandlerRegistry[extension]}registerLangHandler(decorateSource,["default-code"]);registerLangHandler(createSimpleLexer([],[[PR_PLAIN,/^[^<?]+/],[PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);registerLangHandler(createSimpleLexer([[PR_PLAIN,/^[\s]+/,null," \r\n"],[PR_ATTRIB_VALUE,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[PR_TAG,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[PR_ATTRIB_NAME,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[PR_PUNCTUATION,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);registerLangHandler(createSimpleLexer([],[[PR_ATTRIB_VALUE,/^[\s\S]+/]]),["uq.val"]);registerLangHandler(sourceDecorator({keywords:CPP_KEYWORDS,hashComments:true,cStyleComments:true,types:C_TYPES}),["c","cc","cpp","cxx","cyc","m"]);registerLangHandler(sourceDecorator({keywords:"null,true,false"}),["json"]);registerLangHandler(sourceDecorator({keywords:CSHARP_KEYWORDS,hashComments:true,cStyleComments:true,verbatimStrings:true,types:C_TYPES}),["cs"]);registerLangHandler(sourceDecorator({keywords:JAVA_KEYWORDS,cStyleComments:true}),["java"]);registerLangHandler(sourceDecorator({keywords:SH_KEYWORDS,hashComments:true,multiLineStrings:true}),["bash","bsh","csh","sh"]);registerLangHandler(sourceDecorator({keywords:PYTHON_KEYWORDS,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py","python"]);registerLangHandler(sourceDecorator({keywords:PERL_KEYWORDS,hashComments:true,multiLineStrings:true,regexLiterals:2}),["perl","pl","pm"]);registerLangHandler(sourceDecorator({keywords:RUBY_KEYWORDS,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb","ruby"]);registerLangHandler(sourceDecorator({keywords:JSCRIPT_KEYWORDS,cStyleComments:true,regexLiterals:true}),["javascript","js"]);registerLangHandler(sourceDecorator({keywords:COFFEE_KEYWORDS,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);registerLangHandler(sourceDecorator({keywords:RUST_KEYWORDS,cStyleComments:true,multilineStrings:true}),["rc","rs","rust"]);registerLangHandler(createSimpleLexer([],[[PR_STRING,/^[\s\S]+/]]),["regex"]);function applyDecorator(job){var opt_langExtension=job.langExtension;try{var sourceAndSpans=extractSourceSpans(job.sourceNode,job.pre);var source=sourceAndSpans.sourceCode;job.sourceCode=source;job.spans=sourceAndSpans.spans;job.basePos=0;langHandlerForExtension(opt_langExtension,source)(job);recombineTagsAndDecorations(job)}catch(e){if(win["console"]){console["log"](e&&e["stack"]||e)}}}function $prettyPrintOne(sourceCodeHtml,opt_langExtension,opt_numberLines){var container=document.createElement("div");container.innerHTML="<pre>"+sourceCodeHtml+"</pre>";container=container.firstChild;if(opt_numberLines){numberLines(container,opt_numberLines,true)}var job={langExtension:opt_langExtension,numberLines:opt_numberLines,sourceNode:container,pre:1};applyDecorator(job);return container.innerHTML}function $prettyPrint(opt_whenDone,opt_root){var root=opt_root||document.body;var doc=root.ownerDocument||document;function byTagName(tn){return root.getElementsByTagName(tn)}var codeSegments=[byTagName("pre"),byTagName("code"),byTagName("xmp")];var elements=[];for(var i=0;i<codeSegments.length;++i){for(var j=0,n=codeSegments[i].length;j<n;++j){elements.push(codeSegments[i][j])}}codeSegments=null;var clock=Date;if(!clock["now"]){clock={now:function(){return+new Date}}}var k=0;var prettyPrintingJob;var langExtensionRe=/\blang(?:uage)?-([\w.]+)(?!\S)/;var prettyPrintRe=/\bprettyprint\b/;var prettyPrintedRe=/\bprettyprinted\b/;var preformattedTagNameRe=/pre|xmp/i;var codeRe=/^code$/i;var preCodeXmpRe=/^(?:pre|code|xmp)$/i;var EMPTY={};function doWork(){var endTime=win["PR_SHOULD_USE_CONTINUATION"]?clock["now"]()+250:Infinity;for(;k<elements.length&&clock["now"]()<endTime;k++){var cs=elements[k];var attrs=EMPTY;{for(var preceder=cs;preceder=preceder.previousSibling;){var nt=preceder.nodeType;var value=(nt===7||nt===8)&&preceder.nodeValue;if(value?!/^\??prettify\b/.test(value):nt!==3||/\S/.test(preceder.nodeValue)){break}if(value){attrs={};value.replace(/\b(\w+)=([\w:.%+-]+)/g,function(_,name,value){attrs[name]=value});break}}}var className=cs.className;if((attrs!==EMPTY||prettyPrintRe.test(className))&&!prettyPrintedRe.test(className)){var nested=false;for(var p=cs.parentNode;p;p=p.parentNode){var tn=p.tagName;if(preCodeXmpRe.test(tn)&&p.className&&prettyPrintRe.test(p.className)){nested=true;break}}if(!nested){cs.className+=" prettyprinted";var langExtension=attrs["lang"];if(!langExtension){langExtension=className.match(langExtensionRe);var wrapper;if(!langExtension&&(wrapper=childContentWrapper(cs))&&codeRe.test(wrapper.tagName)){langExtension=wrapper.className.match(langExtensionRe)}if(langExtension){langExtension=langExtension[1]}}var preformatted;if(preformattedTagNameRe.test(cs.tagName)){preformatted=1}else{var currentStyle=cs["currentStyle"];var defaultView=doc.defaultView;var whitespace=currentStyle?currentStyle["whiteSpace"]:defaultView&&defaultView.getComputedStyle?defaultView.getComputedStyle(cs,null).getPropertyValue("white-space"):0;preformatted=whitespace&&"pre"===whitespace.substring(0,3)}var lineNums=attrs["linenums"];if(!(lineNums=lineNums==="true"||+lineNums)){lineNums=className.match(/\blinenums\b(?::(\d+))?/);lineNums=lineNums?lineNums[1]&&lineNums[1].length?+lineNums[1]:true:false}if(lineNums){numberLines(cs,lineNums,preformatted)}prettyPrintingJob={langExtension:langExtension,sourceNode:cs,numberLines:lineNums,pre:preformatted};applyDecorator(prettyPrintingJob)}}}if(k<elements.length){setTimeout(doWork,250)}else if("function"===typeof opt_whenDone){opt_whenDone()}}doWork()}var PR=win["PR"]={createSimpleLexer:createSimpleLexer,registerLangHandler:registerLangHandler,sourceDecorator:sourceDecorator,PR_ATTRIB_NAME:PR_ATTRIB_NAME,PR_ATTRIB_VALUE:PR_ATTRIB_VALUE,PR_COMMENT:PR_COMMENT,PR_DECLARATION:PR_DECLARATION,PR_KEYWORD:PR_KEYWORD,PR_LITERAL:PR_LITERAL,PR_NOCODE:PR_NOCODE,PR_PLAIN:PR_PLAIN,PR_PUNCTUATION:PR_PUNCTUATION,PR_SOURCE:PR_SOURCE,PR_STRING:PR_STRING,PR_TAG:PR_TAG,PR_TYPE:PR_TYPE,prettyPrintOne:IN_GLOBAL_SCOPE?win["prettyPrintOne"]=$prettyPrintOne:prettyPrintOne=$prettyPrintOne,prettyPrint:prettyPrint=IN_GLOBAL_SCOPE?win["prettyPrint"]=$prettyPrint:prettyPrint=$prettyPrint};if(typeof define==="function"&&define["amd"]){define("google-code-prettify",[],function(){return PR})}})();</script><script>(function(scope){var ContextFreeParser={parse:function(text){var top={};var entities=[];var current=top;var subCurrent={};var scriptDocCommentClause="\\/\\*\\*([\\s\\S]*?)\\*\\/";var htmlDocCommentClause="<!--([\\s\\S]*?)-->";var docCommentRegex=new RegExp(scriptDocCommentClause+"|"+htmlDocCommentClause,"g");var docComments=text.match(docCommentRegex)||[];docComments.forEach(function(m){var lines=m.replace(/\r\n/g,"\n").replace(/^\s*\/\*\*|^\s*\*\/|^\s*\* ?|^\s*\<\!-\-|^s*\-\-\>/gm,"").split("\n");var pragmas=[];lines=lines.filter(function(l){var m=l.match(/\s*@([\w-]*) (.*)/);if(!m){return true}pragmas.push(m)});var code=lines.join("\n");pragmas.forEach(function(m){var pragma=m[1],content=m[2];switch(pragma){case"class":case"element":current={name:content,description:code};entities.push(current);break;case"attribute":case"property":case"method":case"event":subCurrent={name:content,description:code};var label=pragma=="property"?"properties":pragma+"s";makePragma(current,label,subCurrent);break;case"default":case"type":subCurrent[pragma]=content;break;case"param":var eventParmsRe=/\{(.+)\}\s+(\w+[.\w+]+)\s+(.*)$/;var params=content.match(eventParmsRe);if(params){var subEventObj={type:params[1],name:params[2],description:params[3]};makePragma(subCurrent,pragma+"s",subEventObj)}break;default:current[pragma]=content;break}});function makePragma(object,pragma,content){var p$=object;var p=p$[pragma];if(!p){p$[pragma]=p=[]}p.push(content)}});if(entities.length===0){entities.push({name:"Entity",description:"**Undocumented**"})}return entities}};if(typeof module!=="undefined"&&module.exports){module.exports=ContextFreeParser}else{scope.ContextFreeParser=ContextFreeParser}})(this);</script><polymer-element name="core-xhr" hidden assetpath="../core-ajax/"><script>Polymer("core-xhr",{request:function(options){var xhr=new XMLHttpRequest;var url=options.url;var method=options.method||"GET";var async=!options.sync;var params=this.toQueryString(options.params);if(params&&method=="GET"){url+=(url.indexOf("?")>0?"&":"?")+params}var xhrParams=this.isBodyMethod(method)?options.body||params:null;xhr.open(method,url,async);if(options.responseType){xhr.responseType=options.responseType}if(options.withCredentials){xhr.withCredentials=true}this.makeReadyStateHandler(xhr,options.callback);this.setRequestHeaders(xhr,options.headers);xhr.send(xhrParams);if(!async){xhr.onreadystatechange(xhr)}return xhr},toQueryString:function(params){var r=[];for(var n in params){var v=params[n];n=encodeURIComponent(n);r.push(v==null?n:n+"="+encodeURIComponent(v))}return r.join("&")},isBodyMethod:function(method){return this.bodyMethods[(method||"").toUpperCase()]},bodyMethods:{POST:1,PUT:1,DELETE:1},makeReadyStateHandler:function(xhr,callback){xhr.onreadystatechange=function(){if(xhr.readyState==4){callback&&callback.call(null,xhr.response,xhr)}}},setRequestHeaders:function(xhr,headers){if(headers){for(var name in headers){xhr.setRequestHeader(name,headers[name])}}}});</script></polymer-element><polymer-element name="core-ajax" hidden attributes="url handleAs auto params response error method headers body contentType withCredentials" assetpath="../core-ajax/"><script>Polymer("core-ajax",{url:"",handleAs:"",auto:false,params:"",response:null,error:null,method:"",headers:null,body:null,contentType:"application/x-www-form-urlencoded",withCredentials:false,xhrArgs:null,ready:function(){this.xhr=document.createElement("core-xhr")},receive:function(response,xhr){if(this.isSuccess(xhr)){this.processResponse(xhr)}else{this.processError(xhr)}this.complete(xhr)},isSuccess:function(xhr){var status=xhr.status||0;return!status||status>=200&&status<300},processResponse:function(xhr){var response=this.evalResponse(xhr);if(xhr===this.activeRequest){this.response=response}this.fire("core-response",{response:response,xhr:xhr})},processError:function(xhr){var response=xhr.status+": "+xhr.responseText;if(xhr===this.activeRequest){this.error=response}this.fire("core-error",{response:response,xhr:xhr})},complete:function(xhr){this.fire("core-complete",{response:xhr.status,xhr:xhr})},evalResponse:function(xhr){return this[(this.handleAs||"text")+"Handler"](xhr)},xmlHandler:function(xhr){return xhr.responseXML},textHandler:function(xhr){return xhr.responseText},jsonHandler:function(xhr){var r=xhr.responseText;try{return JSON.parse(r)}catch(x){console.warn("core-ajax caught an exception trying to parse response as JSON:");console.warn("url:",this.url);console.warn(x);return r}},documentHandler:function(xhr){return xhr.response},blobHandler:function(xhr){return xhr.response},arraybufferHandler:function(xhr){return xhr.response},urlChanged:function(){if(!this.handleAs){var ext=String(this.url).split(".").pop();switch(ext){case"json":this.handleAs="json";break}}this.autoGo()},paramsChanged:function(){this.autoGo()},autoChanged:function(){this.autoGo()},autoGo:function(){if(this.auto){this.goJob=this.job(this.goJob,this.go,0)}},go:function(){var args=this.xhrArgs||{};args.body=this.body||args.body;args.params=this.params||args.params;if(args.params&&typeof args.params=="string"){args.params=JSON.parse(args.params)}args.headers=this.headers||args.headers||{};if(args.headers&&typeof args.headers=="string"){args.headers=JSON.parse(args.headers)}var hasContentType=Object.keys(args.headers).some(function(header){return header.toLowerCase()==="content-type"});if(!hasContentType&&this.contentType){args.headers["Content-Type"]=this.contentType}if(this.handleAs==="arraybuffer"||this.handleAs==="blob"||this.handleAs==="document"){args.responseType=this.handleAs}args.withCredentials=this.withCredentials;args.callback=this.receive.bind(this);args.url=this.url;args.method=this.method;this.response=this.error=null;this.activeRequest=args.url&&this.xhr.request(args);return this.activeRequest}});</script></polymer-element><polymer-element name="context-free-parser" attributes="url text data" assetpath="../context-free-parser/"><template><core-ajax url="{{url}}" response="{{text}}" auto=""></core-ajax></template><script>Polymer("context-free-parser",{text:null,textChanged:function(){if(this.text){var entities=ContextFreeParser.parse(this.text);if(!entities||entities.length===0){entities=[{name:this.url.split("/").pop(),description:"**Undocumented**"}]}this.data={classes:entities}}},dataChanged:function(){this.fire("data-ready")}});</script></polymer-element><polymer-element name="core-doc-page" attributes="data" relative="" assetpath="../core-doc-viewer/elements/"><template><style>:host{display:block}#info>*{margin-right:20px}core-icon{margin-right:5px}.main{padding:0 72px;max-width:832px;margin:0 auto}marked-element{display:block}h1{color:#E91E63;font-size:52px;line-height:60px;font-weight:inherit}.box{margin-bottom:40px}.box:not(.top) .details{padding:16px}.box:not(.top) .details .params{margin-top:40px}.box:not(.top) h3{padding:16px;color:#fff;font-weight:inherit;font-size:20px;line-height:48px;margin:0}.box:not(.top) pre{padding:initial;background-color:transparent;margin:initial;font-size:12px}.box code{color:currentcolor;font-weight:500}.top pre{background-color:#fafafa;padding:16px}pre{max-width:832px;white-space:pre-wrap;overflow:hidden;border:none}.attribute-box .details{background-color:#ffcbbb;border-bottom:1px solid rgba(255,86,33,.5)}.attribute-box h3{background-color:#ff5621}.property-box .details{background-color:#fbe7b1;border-bottom:1px solid rgba(243,179,0,.5)}.property-box h3{background-color:#f3b300}.method-box .details{background-color:#a6ffea;border-bottom:1px solid rgba(0,190,164,.5)}.method-box h3{background-color:#00bea4}.event-box .details{background-color:#c5d9fb;border-bottom:1px solid rgba(65,132,243,.5)}.event-box h3{background-color:#4184f3}.badge{color:currentcolor}code,pre{color:#9f499b;font-family:"Source Code Pro",Monaco,Menlo,Consolas,"Courier New",monospace}pre .typ,pre .inline,.prettyprint .typ,.prettyprint .inline{color:#6b499f}pre .pun,.prettyprint .pun{color:#5c6bc0}pre .str,pre .string,.prettyprint .str,.prettyprint .string{color:#ff4081}pre .pln,.prettyprint .pln{color:#7986cb}pre .kwd,.prettyprint .kwd{color:#d61a7f}pre .atn,pre .attribute-name,.prettyprint .atn,.prettyprint .attribute-name{color:#6b499f}pre .atv,pre .attribute-value,.prettyprint .atv,.prettyprint .attribute-value{color:#7986cb}pre .com,pre .comment,.prettyprint .com,.prettyprint .comment{color:#8a8a8a}</style><core-header-panel id="panel" mode="waterfall" fit=""><div class="main" on-marked-js-highlight="{{hilight}}"><h1>{{data.name}}</h1><p id="info" layout="" horizontal="" center=""><span layout="" horizontal="" center=""><core-icon icon="home"></core-icon><a href="{{data | homepageFilter}}">Home Page</a></span><span layout="" horizontal="" center="" hidden?="{{!data.version}}"><core-icon icon="info-outline"></core-icon>Version: {{data.version}}</span></p><template if="{{data.extends}}"><section class="top"><h3 id="{{data.name}}.extends">Extends: <a href="#{{data.extends}}">{{data.extends}}</a></h3></section></template><template if="{{data.description}}"><section class="box top"><h3 id="{{data.name}}.summary">Summary</h3><marked-element text="{{data.description}}"></marked-element></section></template><template if="{{data.attributes.length}}"><section class="box attribute-box"><h3 id="{{data.name}}.attributes">Attributes</h3><template repeat="{{attribute in data.attributes}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.attributes.{{attribute.name}}"><p><code>{{attribute.name}}</code></p></div><div class="details-info" flex="" three=""><p layout="" horizontal="" center="" justified=""><code>&lt;<em>{{attribute.type}}</em>&gt;</code><span class="default" hidden?="{{!attribute.default}}">default: <code>{{attribute.default}}</code></span></p><marked-element text="{{attribute.description}}"></marked-element></div></div></template></section></template><template if="{{data.properties.length}}"><section class="box property-box"><h3 id="{{data.name}}.properties">Properties</h3><template repeat="{{property in data.properties}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.properties.{{property.name}}"><p><code>{{property.name}}</code></p></div><div class="details-info" flex="" three=""><p layout="" horizontal="" center="" justified=""><code>&lt;<em>{{property.type}}</em>&gt;</code><span class="default" hidden?="{{!property.default}}">default: <code>{{property.default}}</code></span></p><marked-element text="{{property.description}}"></marked-element></div></div></template></section></template><template if="{{data.events.length}}"><section class="box event-box"><h3 id="{{data.name}}.events">Events</h3><template repeat="{{event in data.events}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.events.{{event.name}}"><p><code>{{event.name}}</code></p></div><div class="details-info" flex="" three=""><marked-element text="{{event.description}}"></marked-element><template if="{{event.params.length}}"><div class="params"><p>Event details:</p><template repeat="{{param in event.params}}"><p><code>&lt;<em>{{param.type}}</em>&gt; {{param.name}}</code></p><p><span>{{param.description}}</span></p></template></div></template></div></div></template></section></template><template if="{{data.methods.length}}"><section class="box method-box"><h3 id="{{data.name}}.methods">Methods</h3><template repeat="{{method in data.methods}}"><div class="details" horizontal="" layout=""><div class="details-name" flex="" id="{{data.name}}.methods.{{method.name}}"><p><code>{{method.name}}</code></p></div><div class="details-info" flex="" three=""><marked-element text="{{method.description}}"></marked-element><template if="{{method.params.length}}"><div class="params"><p>Method parameters:</p><template repeat="{{param in method.params}}"><p><code>&lt;<em>{{param.type}}</em>&gt; {{param.name}}</code></p><p><span>{{param.description}}</span></p></template></div></template></div></div></template></section></template></div></core-header-panel></template><script>Polymer("core-doc-page",{hilight:function(event,detail,sender){detail.code=prettyPrintOne((detail.code||"").replace(/</g,"&lt;").replace(/>/g,"&gt;"))},homepageFilter:function(data){if(!data){return""}if(!data.homepage||data.homepage==="github.io"){return"//polymer.github.io/"+data.name}else{return data.homepage}},dataChanged:function(){this.async(function(){var elementToFocus=this.shadowRoot.getElementById(window.location.hash.slice(1));if(elementToFocus){elementToFocus.scrollIntoView()}})}});</script></polymer-element><polymer-element name="core-selection" attributes="multi" hidden assetpath="../core-selection/"><script>Polymer("core-selection",{multi:false,ready:function(){this.clear()},clear:function(){this.selection=[]},getSelection:function(){return this.multi?this.selection:this.selection[0]},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!==undefined&&item!==null){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}this.fire("core-select",{isSelected:isSelected,item:item})}},select:function(item){if(this.multi){this.toggle(item)}else if(this.getSelection()!==item){this.setItemSelected(this.getSelection(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}});</script></polymer-element><polymer-element name="core-selector" attributes="selected multi valueattr selectedClass selectedProperty selectedAttribute selectedItem selectedModel selectedIndex notap excludedLocalNames target itemsSelector activateEvent" assetpath="../core-selector/"><template><core-selection id="selection" multi="{{multi}}" on-core-select="{{selectionSelect}}"></core-selection><content id="items" select="*"></content></template><script>Polymer("core-selector",{selected:null,multi:false,valueattr:"name",selectedClass:"core-selected",selectedProperty:"",selectedAttribute:"active",selectedItem:null,selectedModel:null,selectedIndex:-1,excludedLocalNames:"",target:null,itemsSelector:"",activateEvent:"tap",notap:false,defaultExcludedLocalNames:"template",observe:{"selected multi":"selectedChanged"},ready:function(){this.activateListener=this.activateHandler.bind(this);this.itemFilter=this.filterItem.bind(this);this.excludedLocalNamesChanged();this.observer=new MutationObserver(this.updateSelected.bind(this));if(!this.target){this.target=this}},get items(){if(!this.target){return[]}var nodes=this.target!==this?this.itemsSelector?this.target.querySelectorAll(this.itemsSelector):this.target.children:this.$.items.getDistributedNodes();return Array.prototype.filter.call(nodes,this.itemFilter)},filterItem:function(node){return!this._excludedNames[node.localName]},excludedLocalNamesChanged:function(){this._excludedNames={};var s=this.defaultExcludedLocalNames;if(this.excludedLocalNames){s+=" "+this.excludedLocalNames}s.split(/\s+/g).forEach(function(n){this._excludedNames[n]=1},this)},targetChanged:function(old){if(old){this.removeListener(old);this.observer.disconnect();this.clearSelection()}if(this.target){this.addListener(this.target);this.observer.observe(this.target,{childList:true});this.updateSelected()}},addListener:function(node){Polymer.addEventListener(node,this.activateEvent,this.activateListener)},removeListener:function(node){Polymer.removeEventListener(node,this.activateEvent,this.activateListener)},get selection(){return this.$.selection.getSelection()},selectedChanged:function(){if(arguments.length===1){this.processSplices(arguments[0])}else{this.updateSelected()}},updateSelected:function(){this.validateSelected();if(this.multi){this.clearSelection(this.selected);this.selected&&this.selected.forEach(function(s){this.setValueSelected(s,true)},this)}else{this.valueToSelection(this.selected)}},validateSelected:function(){if(this.multi&&!Array.isArray(this.selected)&&this.selected!=null){this.selected=[this.selected]}else if(!this.multi&&Array.isArray(this.selected)){var s=this.selected[0];this.clearSelection([s]);this.selected=s}},processSplices:function(splices){for(var i=0,splice;splice=splices[i];i++){for(var j=0;j<splice.removed.length;j++){this.setValueSelected(splice.removed[j],false)}for(var j=0;j<splice.addedCount;j++){this.setValueSelected(this.selected[splice.index+j],true)}}},clearSelection:function(excludes){this.$.selection.selection.slice().forEach(function(item){var v=this.valueForNode(item)||this.items.indexOf(item);if(!excludes||excludes.indexOf(v)<0){this.$.selection.setItemSelected(item,false)}},this)},valueToSelection:function(value){var item=this.valueToItem(value);this.$.selection.select(item)},setValueSelected:function(value,isSelected){var item=this.valueToItem(value);if(isSelected^this.$.selection.isSelected(item)){this.$.selection.setItemSelected(item,isSelected)}},updateSelectedItem:function(){this.selectedItem=this.selection},selectedItemChanged:function(){if(this.selectedItem){var t=this.selectedItem.templateInstance;this.selectedModel=t?t.model:undefined}else{this.selectedModel=null}this.selectedIndex=this.selectedItem?parseInt(this.valueToIndex(this.selected)):-1},valueToItem:function(value){return value===null||value===undefined?null:this.items[this.valueToIndex(value)]},valueToIndex:function(value){for(var i=0,items=this.items,c;c=items[i];i++){if(this.valueForNode(c)==value){return i}}return value},valueForNode:function(node){return node[this.valueattr]||node.getAttribute(this.valueattr)},selectionSelect:function(e,detail){this.updateSelectedItem();if(detail.item){this.applySelection(detail.item,detail.isSelected)}},applySelection:function(item,isSelected){if(this.selectedClass){item.classList.toggle(this.selectedClass,isSelected)}if(this.selectedProperty){item[this.selectedProperty]=isSelected}if(this.selectedAttribute&&item.setAttribute){if(isSelected){item.setAttribute(this.selectedAttribute,"")}else{item.removeAttribute(this.selectedAttribute)}}},activateHandler:function(e){if(!this.notap){var i=this.findDistributedTarget(e.target,this.items);if(i>=0){var item=this.items[i];var s=this.valueForNode(item)||i;if(this.multi){if(this.selected){this.addRemoveSelected(s)}else{this.selected=[s]}}else{this.selected=s}this.asyncFire("core-activate",{item:item})}}},addRemoveSelected:function(value){var i=this.selected.indexOf(value);if(i>=0){this.selected.splice(i,1)}else{this.selected.push(value)}},findDistributedTarget:function(target,nodes){while(target&&target!=this){var i=Array.prototype.indexOf.call(nodes,target);if(i>=0){return i}target=target.parentNode}},selectIndex:function(index){var item=this.items[index];if(item){this.selected=this.valueForNode(item)||index;return item}},selectPrevious:function(wrapped){var i=wrapped&&!this.selectedIndex?this.items.length-1:this.selectedIndex-1;return this.selectIndex(i)},selectNext:function(wrapped){var i=wrapped&&this.selectedIndex>=this.items.length-1?0:this.selectedIndex+1;return this.selectIndex(i)}});</script></polymer-element><polymer-element name="core-menu" extends="core-selector" assetpath="../core-menu/"><template><style>:host{display:block;margin:12px}polyfill-next-selector{content:':host > core-item'}::content>core-item{cursor:default}</style><shadow></shadow></template><script>Polymer("core-menu");</script></polymer-element><polymer-element name="core-item" attributes="label icon src" horizontal="" center="" layout="" assetpath="../core-item/"><template><style>:host{display:block;position:relative;min-height:40px;white-space:nowrap}:host(.font-scalable){min-height:2.5em}:host(.core-selected){font-weight:700}#icon{margin:0 16px 0 4px}:host(.font-scalable) #icon{margin:0 1em 0 .25em;height:1.5em;width:1.5em}polyfill-next-selector{content:':host > a'}::content>a{position:absolute;top:0;right:0;bottom:0;left:0;background-color:rgba(0,0,0,.000001)}</style><template if="{{icon || src}}"><core-icon src="{{src}}" id="icon" icon="{{icon}}" hidden?="{{!src && !icon}}"></core-icon></template><div id="label">{{label}}</div><content></content></template><script>Polymer("core-item",{});</script></polymer-element><polymer-element name="core-doc-toc" attributes="data selected" assetpath="../core-doc-viewer/elements/"><template><style>:host{display:block;position:relative;border-right:1px solid silver}core-header-panel{position:absolute;top:0;left:0;height:100%;width:100%}core-toolbar{background-color:#eee}</style><core-header-panel mode="waterfall"><core-menu selected="{{selected}}"><template repeat="{{data}}"><core-item><a href="#{{name}}">{{name}}</a></core-item></template></core-menu></core-header-panel></template><script>Polymer("core-doc-toc",{searchAction:function(){this.$.searchBar.style.opacity=1;this.$.searchBar.style.display=""},closeSearchAction:function(){this.$.searchBar.style.opacity=0;this.$.searchBar.style.display="none"}});</script></polymer-element><polymer-element name="core-doc-viewer" attributes="sources route url" horizontal="" layout="" assetpath="../core-doc-viewer/"><template><style>core-doc-toc{display:none;width:332px;overflow-x:hidden}</style><context-free-parser url="{{url}}" on-data-ready="{{parserDataReady}}"></context-free-parser><template repeat="{{sources}}"><context-free-parser url="{{}}" on-data-ready="{{parserDataReady}}"></context-free-parser></template><core-doc-toc id="toc" data="{{classes}}" selected="{{selected}}"></core-doc-toc><core-doc-page flex="" data="{{data}}"></core-doc-page></template><script>Polymer("core-doc-viewer",{classes:[],sources:[],ready:function(){window.addEventListener("hashchange",this.parseLocationHash.bind(this));this.parseLocationHash()},parseLocationHash:function(){this.route=window.location.hash.slice(1)},routeChanged:function(){this.validateRoute()},validateRoute:function(){if(this.route){this.classes.some(function(c){if(c.name===this.route.split(".")[0]){this.data=c;this.route="";return}},this)}},selectedChanged:function(){this.data=this.classes[this.selected]},parserDataReady:function(event,detail,sender){var path="";if(this.sources.length){var path=event.target.templateInstance.model;var idx=path.lastIndexOf("/");path=idx!=-1?path.substr(0,idx):"."}else{var parts=location.pathname.split("/");parts.pop();path=parts.join("/")}var data=event.target.data;var xhr=new XMLHttpRequest;xhr.open("GET",path+"/bower.json");xhr.onerror=function(e){this.assimilateData(data)}.bind(this);xhr.onloadend=function(e){if(e.target.status==200){var version=JSON.parse(e.target.response).version;for(var i=0,c;c=data.classes[i];++i){c.version=version}}this.assimilateData(data)}.bind(this);xhr.send()},assimilateData:function(data){this.classes=this.classes.concat(data.classes);this.classes.sort(function(a,b){var na=a&&a.name.toLowerCase(),nb=b&&b.name.toLowerCase();return na<nb?-1:na==nb?0:1});if(!this.data&&!this.route&&this.classes.length){this.data=this.classes[0]}if(this.classes.length>1){this.$.toc.style.display="block"}this.validateRoute()}});</script></polymer-element></div>
-<div hidden>undefined</div>
-
-<!--
-
-Implements the default landing page for Polymer components.
-
-`<core-component-page>` can render an information page for any component.
-Polymer components use this component in `index.html` to provide the standard landing page.
-
-`<core-component-page>` is _vulcanized_, which means it contains all it's dependencies baked in.
-Therefore, this component is intended to be used only by itself in a page.
-
-This *-dev package contains the raw source and the dependency manifest necessary
-to reconstruct `core-component-page/core-component-page.html` via vulcanize. To vulcanize,
-check out the core-component-page repo alongside this repo and run build.sh. This will
-drop the vulcanize output into `core-component-page/core-component-page.html`.
-
-Note: `<core-component-page>` sets the page title automatically.
-
-@group Polymer Core Elements
-@element core-component-page
-
--->
-
-<polymer-element name="core-component-page" attributes="moduleName sources" layout="" vertical="" assetpath="../core-component-page-dev/"><template><style>:host{font-family:Arial,sans-serif;height:100vh}h2{display:inline-block;margin:8px 6px;vertical-align:middle}.choiceB,.choiceC,.choiceD{color:#fff;font-size:12px;font-weight:700;text-decoration:none;background-color:#4285F4;box-shadow:0 1px 2px 0 rgba(0,0,0,.1);box-shadow:0 0 1px 0 rgba(0,0,0,.1);border-radius:2px;cursor:pointer;display:inline-block;padding:4px 12px 5px 12px;margin:4px 0}.appbar{background-color:#E91E63;color:#fff}</style><core-toolbar class="appbar"><span>{{moduleName}}</span><a class="choiceC" target="_blank" href="../{{moduleName}}/demo.html">demo</a></core-toolbar><core-doc-viewer flex="" url="{{url}}" sources="{{sources}}"></core-doc-viewer></template><script>Polymer("core-component-page",{moduleName:"",sources:[],ready:function(){this.moduleName=this.moduleName||this.findModuleName()},moduleNameChanged:function(){document.title=this.moduleName;this.url=!this.sources.length&&this.moduleName?this.moduleName+".html":""},findModuleName:function(){var path=location.pathname.split("/");var name=path.pop()||path.pop();if(name.indexOf(".html")>=0){name=path.pop()}return name||""}});</script></polymer-element>
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/.bower.json b/chromium/third_party/catapult/tracing/third_party/components/polymer/.bower.json
deleted file mode 100644
index 5f5e0c1acfd..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/.bower.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "polymer",
- "description": "Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers.",
- "homepage": "http://www.polymer-project.org/",
- "keywords": [
- "util",
- "client",
- "browser",
- "web components",
- "web-components"
- ],
- "author": "Polymer Authors <polymer-dev@googlegroups.com>",
- "private": true,
- "dependencies": {
- "core-component-page": "Polymer/core-component-page#^0.5",
- "webcomponentsjs": "Polymer/webcomponentsjs#^0.5"
- },
- "devDependencies": {
- "tools": "Polymer/tools#master",
- "web-component-tester": "Polymer/web-component-tester#^1.4.2"
- },
- "version": "0.5.5",
- "_release": "0.5.5",
- "_resolution": {
- "type": "version",
- "tag": "0.5.5",
- "commit": "b94b680c966fc9ea86bc8f14b3af6f13d77f217a"
- },
- "_source": "git://github.com/Polymer/polymer.git",
- "_target": "~0.5.5",
- "_originalSource": "Polymer/polymer"
-} \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/README.chromium b/chromium/third_party/catapult/tracing/third_party/components/polymer/README.chromium
deleted file mode 100644
index 80aa4db6604..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/README.chromium
+++ /dev/null
@@ -1,16 +0,0 @@
-me: polymer
-Short Name: polymer
-URL: http://www.polymer-project.org/
-Version: 0.5.5
-Revision: None
-Date: Mar 24, 2015
-License: BSD
-License File: NOT_SHIPPED
-Security Critical: no
-
-Description:
-Polymer framework.
-
-Local modifications:
- - Removed comment lines with {{var_names}} from polymer.js because of
- breaking GRIT in Chromium. See #854
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/README.md b/chromium/third_party/catapult/tracing/third_party/components/polymer/README.md
deleted file mode 100644
index 2c03674f3db..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Polymer
-
-[![Polymer build status](http://www.polymer-project.org/build/polymer-dev/status.png "Polymer build status")](http://build.chromium.org/p/client.polymer/waterfall)
-
-## Brief Overview
-
-For more detailed info goto [http://polymer-project.org/](http://polymer-project.org/).
-
-Polymer is a new type of library for the web, designed to leverage the existing browser infrastructure to provide the encapsulation and extendability currently only available in JS libraries.
-
-Polymer is based on a set of future technologies, including [Shadow DOM](http://w3c.github.io/webcomponents/spec/shadow/), [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/) and Model Driven Views. Currently these technologies are implemented as polyfills or shims, but as browsers adopt these features natively, the platform code that drives Polymer evacipates, leaving only the value-adds.
-
-## Tools & Testing
-
-For running tests or building minified files, consult the [tooling information](https://www.polymer-project.org/resources/tooling-strategy.html).
-
-## Releases
-
-[Release (tagged) versions](https://github.com/Polymer/polymer/releases) of Polymer include concatenated and minified sources for your convenience.
-
-[![Analytics](https://ga-beacon.appspot.com/UA-39334307-2/Polymer/polymer/README)](https://github.com/igrigorik/ga-beacon)
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/bower.json b/chromium/third_party/catapult/tracing/third_party/components/polymer/bower.json
deleted file mode 100644
index dbc759605bf..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/bower.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "polymer",
- "description": "Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers.",
- "homepage": "http://www.polymer-project.org/",
- "keywords": [
- "util",
- "client",
- "browser",
- "web components",
- "web-components"
- ],
- "author": "Polymer Authors <polymer-dev@googlegroups.com>",
- "private": true,
- "dependencies": {
- "core-component-page": "Polymer/core-component-page#^0.5",
- "webcomponentsjs": "Polymer/webcomponentsjs#^0.5"
- },
- "devDependencies": {
- "tools": "Polymer/tools#master",
- "web-component-tester": "Polymer/web-component-tester#^1.4.2"
- },
- "version": "0.5.5"
-} \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/build.log b/chromium/third_party/catapult/tracing/third_party/components/polymer/build.log
deleted file mode 100644
index 3eef92a1232..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/build.log
+++ /dev/null
@@ -1,26 +0,0 @@
-BUILD LOG
----------
-Build Time: 2015-02-17T17:25:22
-
-NODEJS INFORMATION
-==================
-nodejs: v0.12.0
-grunt: 0.4.5
-grunt-audit: 1.0.0
-grunt-contrib-concat: 0.5.0
-grunt-contrib-copy: 0.7.0
-grunt-contrib-uglify: 0.6.0
-grunt-string-replace: 1.0.0
-web-component-tester: 1.6.2
-
-REPO REVISIONS
-==============
-polymer-expressions: f2229c2f3db2332aab5c4dba029c17f8bc3f99f2
-polymer-gestures: ccd9dfae58896dff2e4fe9ce123870d321e393d1
-polymer: f53db3fe961a3094844ad46e70e3f721604b0a2b
-
-BUILD HASHES
-============
-dist/polymer.js: 0238138d46a41de3724926295213f1babf66ed41
-dist/polymer.min.js: d5907053e8535c422393aa240e9026ffe0b5fefc
-dist/layout.html: 348d358a91712ecc2f8811efa430fcd954b4590c \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/layout.html b/chromium/third_party/catapult/tracing/third_party/components/polymer/layout.html
deleted file mode 100644
index d3b7aa76f10..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/layout.html
+++ /dev/null
@@ -1,286 +0,0 @@
-<!--
-Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--->
-<style shim-shadowdom>
-/*******************************
- Flex Layout
-*******************************/
-
-html /deep/ [layout][horizontal], html /deep/ [layout][vertical] {
- display: -ms-flexbox;
- display: -webkit-flex;
- display: flex;
-}
-
-html /deep/ [layout][horizontal][inline], html /deep/ [layout][vertical][inline] {
- display: -ms-inline-flexbox;
- display: -webkit-inline-flex;
- display: inline-flex;
-}
-
-html /deep/ [layout][horizontal] {
- -ms-flex-direction: row;
- -webkit-flex-direction: row;
- flex-direction: row;
-}
-
-html /deep/ [layout][horizontal][reverse] {
- -ms-flex-direction: row-reverse;
- -webkit-flex-direction: row-reverse;
- flex-direction: row-reverse;
-}
-
-html /deep/ [layout][vertical] {
- -ms-flex-direction: column;
- -webkit-flex-direction: column;
- flex-direction: column;
-}
-
-html /deep/ [layout][vertical][reverse] {
- -ms-flex-direction: column-reverse;
- -webkit-flex-direction: column-reverse;
- flex-direction: column-reverse;
-}
-
-html /deep/ [layout][wrap] {
- -ms-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- flex-wrap: wrap;
-}
-
-html /deep/ [layout][wrap-reverse] {
- -ms-flex-wrap: wrap-reverse;
- -webkit-flex-wrap: wrap-reverse;
- flex-wrap: wrap-reverse;
-}
-
-html /deep/ [flex] {
- -ms-flex: 1 1 0.000000001px;
- -webkit-flex: 1;
- flex: 1;
- -webkit-flex-basis: 0.000000001px;
- flex-basis: 0.000000001px;
-}
-
-html /deep/ [vertical][layout] > [flex][auto-vertical], html /deep/ [vertical][layout]::shadow [flex][auto-vertical] {
- -ms-flex: 1 1 auto;
- -webkit-flex-basis: auto;
- flex-basis: auto;
-}
-
-html /deep/ [flex][auto] {
- -ms-flex: 1 1 auto;
- -webkit-flex-basis: auto;
- flex-basis: auto;
-}
-
-html /deep/ [flex][none] {
- -ms-flex: none;
- -webkit-flex: none;
- flex: none;
-}
-
-html /deep/ [flex][one] {
- -ms-flex: 1;
- -webkit-flex: 1;
- flex: 1;
-}
-
-html /deep/ [flex][two] {
- -ms-flex: 2;
- -webkit-flex: 2;
- flex: 2;
-}
-
-html /deep/ [flex][three] {
- -ms-flex: 3;
- -webkit-flex: 3;
- flex: 3;
-}
-
-html /deep/ [flex][four] {
- -ms-flex: 4;
- -webkit-flex: 4;
- flex: 4;
-}
-
-html /deep/ [flex][five] {
- -ms-flex: 5;
- -webkit-flex: 5;
- flex: 5;
-}
-
-html /deep/ [flex][six] {
- -ms-flex: 6;
- -webkit-flex: 6;
- flex: 6;
-}
-
-html /deep/ [flex][seven] {
- -ms-flex: 7;
- -webkit-flex: 7;
- flex: 7;
-}
-
-html /deep/ [flex][eight] {
- -ms-flex: 8;
- -webkit-flex: 8;
- flex: 8;
-}
-
-html /deep/ [flex][nine] {
- -ms-flex: 9;
- -webkit-flex: 9;
- flex: 9;
-}
-
-html /deep/ [flex][ten] {
- -ms-flex: 10;
- -webkit-flex: 10;
- flex: 10;
-}
-
-html /deep/ [flex][eleven] {
- -ms-flex: 11;
- -webkit-flex: 11;
- flex: 11;
-}
-
-html /deep/ [flex][twelve] {
- -ms-flex: 12;
- -webkit-flex: 12;
- flex: 12;
-}
-
-/* alignment in cross axis */
-
-html /deep/ [layout][start] {
- -ms-flex-align: start;
- -webkit-align-items: flex-start;
- align-items: flex-start;
-}
-
-html /deep/ [layout][center], html /deep/ [layout][center-center] {
- -ms-flex-align: center;
- -webkit-align-items: center;
- align-items: center;
-}
-
-html /deep/ [layout][end] {
- -ms-flex-align: end;
- -webkit-align-items: flex-end;
- align-items: flex-end;
-}
-
-/* alignment in main axis */
-
-html /deep/ [layout][start-justified] {
- -ms-flex-pack: start;
- -webkit-justify-content: flex-start;
- justify-content: flex-start;
-}
-
-html /deep/ [layout][center-justified], html /deep/ [layout][center-center] {
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
-}
-
-html /deep/ [layout][end-justified] {
- -ms-flex-pack: end;
- -webkit-justify-content: flex-end;
- justify-content: flex-end;
-}
-
-html /deep/ [layout][around-justified] {
- -ms-flex-pack: distribute;
- -webkit-justify-content: space-around;
- justify-content: space-around;
-}
-
-html /deep/ [layout][justified] {
- -ms-flex-pack: justify;
- -webkit-justify-content: space-between;
- justify-content: space-between;
-}
-
-/* self alignment */
-
-html /deep/ [self-start] {
- -ms-align-self: flex-start;
- -webkit-align-self: flex-start;
- align-self: flex-start;
-}
-
-html /deep/ [self-center] {
- -ms-align-self: center;
- -webkit-align-self: center;
- align-self: center;
-}
-
-html /deep/ [self-end] {
- -ms-align-self: flex-end;
- -webkit-align-self: flex-end;
- align-self: flex-end;
-}
-
-html /deep/ [self-stretch] {
- -ms-align-self: stretch;
- -webkit-align-self: stretch;
- align-self: stretch;
-}
-
-/*******************************
- Other Layout
-*******************************/
-
-html /deep/ [block] {
- display: block;
-}
-
-/* ie support for hidden */
-html /deep/ [hidden] {
- display: none !important;
-}
-
-html /deep/ [relative] {
- position: relative;
-}
-
-html /deep/ [fit] {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-}
-
-body[fullbleed] {
- margin: 0;
- height: 100vh;
-}
-
-/*******************************
- Other
-*******************************/
-
-html /deep/ [segment], html /deep/ segment {
- display: block;
- position: relative;
- -webkit-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- margin: 1em 0.5em;
- padding: 1em;
- background-color: white;
- -webkit-box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
- box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
- border-radius: 5px 5px 5px 5px;
-}
-
-</style>
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.js b/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.js
deleted file mode 100644
index 3b720aab4f8..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.js
+++ /dev/null
@@ -1,11857 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-window.PolymerGestures = {};
-
-(function(scope) {
- var hasFullPath = false;
-
- // test for full event path support
- var pathTest = document.createElement('meta');
- if (pathTest.createShadowRoot) {
- var sr = pathTest.createShadowRoot();
- var s = document.createElement('span');
- sr.appendChild(s);
- pathTest.addEventListener('testpath', function(ev) {
- if (ev.path) {
- // if the span is in the event path, then path[0] is the real source for all events
- hasFullPath = ev.path[0] === s;
- }
- ev.stopPropagation();
- });
- var ev = new CustomEvent('testpath', {bubbles: true});
- // must add node to DOM to trigger event listener
- document.head.appendChild(pathTest);
- s.dispatchEvent(ev);
- pathTest.parentNode.removeChild(pathTest);
- sr = s = null;
- }
- pathTest = null;
-
- var target = {
- shadow: function(inEl) {
- if (inEl) {
- return inEl.shadowRoot || inEl.webkitShadowRoot;
- }
- },
- canTarget: function(shadow) {
- return shadow && Boolean(shadow.elementFromPoint);
- },
- targetingShadow: function(inEl) {
- var s = this.shadow(inEl);
- if (this.canTarget(s)) {
- return s;
- }
- },
- olderShadow: function(shadow) {
- var os = shadow.olderShadowRoot;
- if (!os) {
- var se = shadow.querySelector('shadow');
- if (se) {
- os = se.olderShadowRoot;
- }
- }
- return os;
- },
- allShadows: function(element) {
- var shadows = [], s = this.shadow(element);
- while(s) {
- shadows.push(s);
- s = this.olderShadow(s);
- }
- return shadows;
- },
- searchRoot: function(inRoot, x, y) {
- var t, st, sr, os;
- if (inRoot) {
- t = inRoot.elementFromPoint(x, y);
- if (t) {
- // found element, check if it has a ShadowRoot
- sr = this.targetingShadow(t);
- } else if (inRoot !== document) {
- // check for sibling roots
- sr = this.olderShadow(inRoot);
- }
- // search other roots, fall back to light dom element
- return this.searchRoot(sr, x, y) || t;
- }
- },
- owner: function(element) {
- if (!element) {
- return document;
- }
- var s = element;
- // walk up until you hit the shadow root or document
- while (s.parentNode) {
- s = s.parentNode;
- }
- // the owner element is expected to be a Document or ShadowRoot
- if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGMENT_NODE) {
- s = document;
- }
- return s;
- },
- findTarget: function(inEvent) {
- if (hasFullPath && inEvent.path && inEvent.path.length) {
- return inEvent.path[0];
- }
- var x = inEvent.clientX, y = inEvent.clientY;
- // if the listener is in the shadow root, it is much faster to start there
- var s = this.owner(inEvent.target);
- // if x, y is not in this root, fall back to document search
- if (!s.elementFromPoint(x, y)) {
- s = document;
- }
- return this.searchRoot(s, x, y);
- },
- findTouchAction: function(inEvent) {
- var n;
- if (hasFullPath && inEvent.path && inEvent.path.length) {
- var path = inEvent.path;
- for (var i = 0; i < path.length; i++) {
- n = path[i];
- if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) {
- return n.getAttribute('touch-action');
- }
- }
- } else {
- n = inEvent.target;
- while(n) {
- if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) {
- return n.getAttribute('touch-action');
- }
- n = n.parentNode || n.host;
- }
- }
- // auto is default
- return "auto";
- },
- LCA: function(a, b) {
- if (a === b) {
- return a;
- }
- if (a && !b) {
- return a;
- }
- if (b && !a) {
- return b;
- }
- if (!b && !a) {
- return document;
- }
- // fast case, a is a direct descendant of b or vice versa
- if (a.contains && a.contains(b)) {
- return a;
- }
- if (b.contains && b.contains(a)) {
- return b;
- }
- var adepth = this.depth(a);
- var bdepth = this.depth(b);
- var d = adepth - bdepth;
- if (d >= 0) {
- a = this.walk(a, d);
- } else {
- b = this.walk(b, -d);
- }
- while (a && b && a !== b) {
- a = a.parentNode || a.host;
- b = b.parentNode || b.host;
- }
- return a;
- },
- walk: function(n, u) {
- for (var i = 0; n && (i < u); i++) {
- n = n.parentNode || n.host;
- }
- return n;
- },
- depth: function(n) {
- var d = 0;
- while(n) {
- d++;
- n = n.parentNode || n.host;
- }
- return d;
- },
- deepContains: function(a, b) {
- var common = this.LCA(a, b);
- // if a is the common ancestor, it must "deeply" contain b
- return common === a;
- },
- insideNode: function(node, x, y) {
- var rect = node.getBoundingClientRect();
- return (rect.left <= x) && (x <= rect.right) && (rect.top <= y) && (y <= rect.bottom);
- },
- path: function(event) {
- var p;
- if (hasFullPath && event.path && event.path.length) {
- p = event.path;
- } else {
- p = [];
- var n = this.findTarget(event);
- while (n) {
- p.push(n);
- n = n.parentNode || n.host;
- }
- }
- return p;
- }
- };
- scope.targetFinding = target;
- /**
- * Given an event, finds the "deepest" node that could have been the original target before ShadowDOM retargetting
- *
- * @param {Event} Event An event object with clientX and clientY properties
- * @return {Element} The probable event origninator
- */
- scope.findTarget = target.findTarget.bind(target);
- /**
- * Determines if the "container" node deeply contains the "containee" node, including situations where the "containee" is contained by one or more ShadowDOM
- * roots.
- *
- * @param {Node} container
- * @param {Node} containee
- * @return {Boolean}
- */
- scope.deepContains = target.deepContains.bind(target);
-
- /**
- * Determines if the x/y position is inside the given node.
- *
- * Example:
- *
- * function upHandler(event) {
- * var innode = PolymerGestures.insideNode(event.target, event.clientX, event.clientY);
- * if (innode) {
- * // wait for tap?
- * } else {
- * // tap will never happen
- * }
- * }
- *
- * @param {Node} node
- * @param {Number} x Screen X position
- * @param {Number} y screen Y position
- * @return {Boolean}
- */
- scope.insideNode = target.insideNode;
-
-})(window.PolymerGestures);
-
-(function() {
- function shadowSelector(v) {
- return 'html /deep/ ' + selector(v);
- }
- function selector(v) {
- return '[touch-action="' + v + '"]';
- }
- function rule(v) {
- return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + ';}';
- }
- var attrib2css = [
- 'none',
- 'auto',
- 'pan-x',
- 'pan-y',
- {
- rule: 'pan-x pan-y',
- selectors: [
- 'pan-x pan-y',
- 'pan-y pan-x'
- ]
- },
- 'manipulation'
- ];
- var styles = '';
- // only install stylesheet if the browser has touch action support
- var hasTouchAction = typeof document.head.style.touchAction === 'string';
- // only add shadow selectors if shadowdom is supported
- var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot;
-
- if (hasTouchAction) {
- attrib2css.forEach(function(r) {
- if (String(r) === r) {
- styles += selector(r) + rule(r) + '\n';
- if (hasShadowRoot) {
- styles += shadowSelector(r) + rule(r) + '\n';
- }
- } else {
- styles += r.selectors.map(selector) + rule(r.rule) + '\n';
- if (hasShadowRoot) {
- styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
- }
- }
- });
-
- var el = document.createElement('style');
- el.textContent = styles;
- document.head.appendChild(el);
- }
-})();
-
-/**
- * This is the constructor for new PointerEvents.
- *
- * New Pointer Events must be given a type, and an optional dictionary of
- * initialization properties.
- *
- * Due to certain platform requirements, events returned from the constructor
- * identify as MouseEvents.
- *
- * @constructor
- * @param {String} inType The type of the event to create.
- * @param {Object} [inDict] An optional dictionary of initial event properties.
- * @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
- */
-(function(scope) {
-
- var MOUSE_PROPS = [
- 'bubbles',
- 'cancelable',
- 'view',
- 'detail',
- 'screenX',
- 'screenY',
- 'clientX',
- 'clientY',
- 'ctrlKey',
- 'altKey',
- 'shiftKey',
- 'metaKey',
- 'button',
- 'relatedTarget',
- 'pageX',
- 'pageY'
- ];
-
- var MOUSE_DEFAULTS = [
- false,
- false,
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- 0,
- 0
- ];
-
- var NOP_FACTORY = function(){ return function(){}; };
-
- var eventFactory = {
- // TODO(dfreedm): this is overridden by tap recognizer, needs review
- preventTap: NOP_FACTORY,
- makeBaseEvent: function(inType, inDict) {
- var e = document.createEvent('Event');
- e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
- e.preventTap = eventFactory.preventTap(e);
- return e;
- },
- makeGestureEvent: function(inType, inDict) {
- inDict = inDict || Object.create(null);
-
- var e = this.makeBaseEvent(inType, inDict);
- for (var i = 0, keys = Object.keys(inDict), k; i < keys.length; i++) {
- k = keys[i];
- if( k !== 'bubbles' && k !== 'cancelable' ) {
- e[k] = inDict[k];
- }
- }
- return e;
- },
- makePointerEvent: function(inType, inDict) {
- inDict = inDict || Object.create(null);
-
- var e = this.makeBaseEvent(inType, inDict);
- // define inherited MouseEvent properties
- for(var i = 2, p; i < MOUSE_PROPS.length; i++) {
- p = MOUSE_PROPS[i];
- e[p] = inDict[p] || MOUSE_DEFAULTS[i];
- }
- e.buttons = inDict.buttons || 0;
-
- // Spec requires that pointers without pressure specified use 0.5 for down
- // state and 0 for up state.
- var pressure = 0;
- if (inDict.pressure) {
- pressure = inDict.pressure;
- } else {
- pressure = e.buttons ? 0.5 : 0;
- }
-
- // add x/y properties aliased to clientX/Y
- e.x = e.clientX;
- e.y = e.clientY;
-
- // define the properties of the PointerEvent interface
- e.pointerId = inDict.pointerId || 0;
- e.width = inDict.width || 0;
- e.height = inDict.height || 0;
- e.pressure = pressure;
- e.tiltX = inDict.tiltX || 0;
- e.tiltY = inDict.tiltY || 0;
- e.pointerType = inDict.pointerType || '';
- e.hwTimestamp = inDict.hwTimestamp || 0;
- e.isPrimary = inDict.isPrimary || false;
- e._source = inDict._source || '';
- return e;
- }
- };
-
- scope.eventFactory = eventFactory;
-})(window.PolymerGestures);
-
-/**
- * This module implements an map of pointer states
- */
-(function(scope) {
- var USE_MAP = window.Map && window.Map.prototype.forEach;
- var POINTERS_FN = function(){ return this.size; };
- function PointerMap() {
- if (USE_MAP) {
- var m = new Map();
- m.pointers = POINTERS_FN;
- return m;
- } else {
- this.keys = [];
- this.values = [];
- }
- }
-
- PointerMap.prototype = {
- set: function(inId, inEvent) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.values[i] = inEvent;
- } else {
- this.keys.push(inId);
- this.values.push(inEvent);
- }
- },
- has: function(inId) {
- return this.keys.indexOf(inId) > -1;
- },
- 'delete': function(inId) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.keys.splice(i, 1);
- this.values.splice(i, 1);
- }
- },
- get: function(inId) {
- var i = this.keys.indexOf(inId);
- return this.values[i];
- },
- clear: function() {
- this.keys.length = 0;
- this.values.length = 0;
- },
- // return value, key, map
- forEach: function(callback, thisArg) {
- this.values.forEach(function(v, i) {
- callback.call(thisArg, v, this.keys[i], this);
- }, this);
- },
- pointers: function() {
- return this.keys.length;
- }
- };
-
- scope.PointerMap = PointerMap;
-})(window.PolymerGestures);
-
-(function(scope) {
- var CLONE_PROPS = [
- // MouseEvent
- 'bubbles',
- 'cancelable',
- 'view',
- 'detail',
- 'screenX',
- 'screenY',
- 'clientX',
- 'clientY',
- 'ctrlKey',
- 'altKey',
- 'shiftKey',
- 'metaKey',
- 'button',
- 'relatedTarget',
- // DOM Level 3
- 'buttons',
- // PointerEvent
- 'pointerId',
- 'width',
- 'height',
- 'pressure',
- 'tiltX',
- 'tiltY',
- 'pointerType',
- 'hwTimestamp',
- 'isPrimary',
- // event instance
- 'type',
- 'target',
- 'currentTarget',
- 'which',
- 'pageX',
- 'pageY',
- 'timeStamp',
- // gesture addons
- 'preventTap',
- 'tapPrevented',
- '_source'
- ];
-
- var CLONE_DEFAULTS = [
- // MouseEvent
- false,
- false,
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- // DOM Level 3
- 0,
- // PointerEvent
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- '',
- 0,
- false,
- // event instance
- '',
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- function(){},
- false
- ];
-
- var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
-
- var eventFactory = scope.eventFactory;
-
- // set of recognizers to run for the currently handled event
- var currentGestures;
-
- /**
- * This module is for normalizing events. Mouse and Touch events will be
- * collected here, and fire PointerEvents that have the same semantics, no
- * matter the source.
- * Events fired:
- * - pointerdown: a pointing is added
- * - pointerup: a pointer is removed
- * - pointermove: a pointer is moved
- * - pointerover: a pointer crosses into an element
- * - pointerout: a pointer leaves an element
- * - pointercancel: a pointer will no longer generate events
- */
- var dispatcher = {
- IS_IOS: false,
- pointermap: new scope.PointerMap(),
- requiredGestures: new scope.PointerMap(),
- eventMap: Object.create(null),
- // Scope objects for native events.
- // This exists for ease of testing.
- eventSources: Object.create(null),
- eventSourceList: [],
- gestures: [],
- // map gesture event -> {listeners: int, index: gestures[int]}
- dependencyMap: {
- // make sure down and up are in the map to trigger "register"
- down: {listeners: 0, index: -1},
- up: {listeners: 0, index: -1}
- },
- gestureQueue: [],
- /**
- * Add a new event source that will generate pointer events.
- *
- * `inSource` must contain an array of event names named `events`, and
- * functions with the names specified in the `events` array.
- * @param {string} name A name for the event source
- * @param {Object} source A new source of platform events.
- */
- registerSource: function(name, source) {
- var s = source;
- var newEvents = s.events;
- if (newEvents) {
- newEvents.forEach(function(e) {
- if (s[e]) {
- this.eventMap[e] = s[e].bind(s);
- }
- }, this);
- this.eventSources[name] = s;
- this.eventSourceList.push(s);
- }
- },
- registerGesture: function(name, source) {
- var obj = Object.create(null);
- obj.listeners = 0;
- obj.index = this.gestures.length;
- for (var i = 0, g; i < source.exposes.length; i++) {
- g = source.exposes[i].toLowerCase();
- this.dependencyMap[g] = obj;
- }
- this.gestures.push(source);
- },
- register: function(element, initial) {
- var l = this.eventSourceList.length;
- for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
- // call eventsource register
- es.register.call(es, element, initial);
- }
- },
- unregister: function(element) {
- var l = this.eventSourceList.length;
- for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
- // call eventsource register
- es.unregister.call(es, element);
- }
- },
- // EVENTS
- down: function(inEvent) {
- this.requiredGestures.set(inEvent.pointerId, currentGestures);
- this.fireEvent('down', inEvent);
- },
- move: function(inEvent) {
- // pipe move events into gesture queue directly
- inEvent.type = 'move';
- this.fillGestureQueue(inEvent);
- },
- up: function(inEvent) {
- this.fireEvent('up', inEvent);
- this.requiredGestures.delete(inEvent.pointerId);
- },
- cancel: function(inEvent) {
- inEvent.tapPrevented = true;
- this.fireEvent('up', inEvent);
- this.requiredGestures.delete(inEvent.pointerId);
- },
- addGestureDependency: function(node, currentGestures) {
- var gesturesWanted = node._pgEvents;
- if (gesturesWanted && currentGestures) {
- var gk = Object.keys(gesturesWanted);
- for (var i = 0, r, ri, g; i < gk.length; i++) {
- // gesture
- g = gk[i];
- if (gesturesWanted[g] > 0) {
- // lookup gesture recognizer
- r = this.dependencyMap[g];
- // recognizer index
- ri = r ? r.index : -1;
- currentGestures[ri] = true;
- }
- }
- }
- },
- // LISTENER LOGIC
- eventHandler: function(inEvent) {
- // This is used to prevent multiple dispatch of events from
- // platform events. This can happen when two elements in different scopes
- // are set up to create pointer events, which is relevant to Shadow DOM.
-
- var type = inEvent.type;
-
- // only generate the list of desired events on "down"
- if (type === 'touchstart' || type === 'mousedown' || type === 'pointerdown' || type === 'MSPointerDown') {
- if (!inEvent._handledByPG) {
- currentGestures = {};
- }
-
- // in IOS mode, there is only a listener on the document, so this is not re-entrant
- if (this.IS_IOS) {
- var ev = inEvent;
- if (type === 'touchstart') {
- var ct = inEvent.changedTouches[0];
- // set up a fake event to give to the path builder
- ev = {target: inEvent.target, clientX: ct.clientX, clientY: ct.clientY, path: inEvent.path};
- }
- // use event path if available, otherwise build a path from target finding
- var nodes = inEvent.path || scope.targetFinding.path(ev);
- for (var i = 0, n; i < nodes.length; i++) {
- n = nodes[i];
- this.addGestureDependency(n, currentGestures);
- }
- } else {
- this.addGestureDependency(inEvent.currentTarget, currentGestures);
- }
- }
-
- if (inEvent._handledByPG) {
- return;
- }
- var fn = this.eventMap && this.eventMap[type];
- if (fn) {
- fn(inEvent);
- }
- inEvent._handledByPG = true;
- },
- // set up event listeners
- listen: function(target, events) {
- for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
- this.addEvent(target, e);
- }
- },
- // remove event listeners
- unlisten: function(target, events) {
- for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
- this.removeEvent(target, e);
- }
- },
- addEvent: function(target, eventName) {
- target.addEventListener(eventName, this.boundHandler);
- },
- removeEvent: function(target, eventName) {
- target.removeEventListener(eventName, this.boundHandler);
- },
- // EVENT CREATION AND TRACKING
- /**
- * Creates a new Event of type `inType`, based on the information in
- * `inEvent`.
- *
- * @param {string} inType A string representing the type of event to create
- * @param {Event} inEvent A platform event with a target
- * @return {Event} A PointerEvent of type `inType`
- */
- makeEvent: function(inType, inEvent) {
- var e = eventFactory.makePointerEvent(inType, inEvent);
- e.preventDefault = inEvent.preventDefault;
- e.tapPrevented = inEvent.tapPrevented;
- e._target = e._target || inEvent.target;
- return e;
- },
- // make and dispatch an event in one call
- fireEvent: function(inType, inEvent) {
- var e = this.makeEvent(inType, inEvent);
- return this.dispatchEvent(e);
- },
- /**
- * Returns a snapshot of inEvent, with writable properties.
- *
- * @param {Event} inEvent An event that contains properties to copy.
- * @return {Object} An object containing shallow copies of `inEvent`'s
- * properties.
- */
- cloneEvent: function(inEvent) {
- var eventCopy = Object.create(null), p;
- for (var i = 0; i < CLONE_PROPS.length; i++) {
- p = CLONE_PROPS[i];
- eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
- // Work around SVGInstanceElement shadow tree
- // Return the <use> element that is represented by the instance for Safari, Chrome, IE.
- // This is the behavior implemented by Firefox.
- if (p === 'target' || p === 'relatedTarget') {
- if (HAS_SVG_INSTANCE && eventCopy[p] instanceof SVGElementInstance) {
- eventCopy[p] = eventCopy[p].correspondingUseElement;
- }
- }
- }
- // keep the semantics of preventDefault
- eventCopy.preventDefault = function() {
- inEvent.preventDefault();
- };
- return eventCopy;
- },
- /**
- * Dispatches the event to its target.
- *
- * @param {Event} inEvent The event to be dispatched.
- * @return {Boolean} True if an event handler returns true, false otherwise.
- */
- dispatchEvent: function(inEvent) {
- var t = inEvent._target;
- if (t) {
- t.dispatchEvent(inEvent);
- // clone the event for the gesture system to process
- // clone after dispatch to pick up gesture prevention code
- var clone = this.cloneEvent(inEvent);
- clone.target = t;
- this.fillGestureQueue(clone);
- }
- },
- gestureTrigger: function() {
- // process the gesture queue
- for (var i = 0, e, rg; i < this.gestureQueue.length; i++) {
- e = this.gestureQueue[i];
- rg = e._requiredGestures;
- if (rg) {
- for (var j = 0, g, fn; j < this.gestures.length; j++) {
- // only run recognizer if an element in the source event's path is listening for those gestures
- if (rg[j]) {
- g = this.gestures[j];
- fn = g[e.type];
- if (fn) {
- fn.call(g, e);
- }
- }
- }
- }
- }
- this.gestureQueue.length = 0;
- },
- fillGestureQueue: function(ev) {
- // only trigger the gesture queue once
- if (!this.gestureQueue.length) {
- requestAnimationFrame(this.boundGestureTrigger);
- }
- ev._requiredGestures = this.requiredGestures.get(ev.pointerId);
- this.gestureQueue.push(ev);
- }
- };
- dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
- dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher);
- scope.dispatcher = dispatcher;
-
- /**
- * Listen for `gesture` on `node` with the `handler` function
- *
- * If `handler` is the first listener for `gesture`, the underlying gesture recognizer is then enabled.
- *
- * @param {Element} node
- * @param {string} gesture
- * @return Boolean `gesture` is a valid gesture
- */
- scope.activateGesture = function(node, gesture) {
- var g = gesture.toLowerCase();
- var dep = dispatcher.dependencyMap[g];
- if (dep) {
- var recognizer = dispatcher.gestures[dep.index];
- if (!node._pgListeners) {
- dispatcher.register(node);
- node._pgListeners = 0;
- }
- // TODO(dfreedm): re-evaluate bookkeeping to avoid using attributes
- if (recognizer) {
- var touchAction = recognizer.defaultActions && recognizer.defaultActions[g];
- var actionNode;
- switch(node.nodeType) {
- case Node.ELEMENT_NODE:
- actionNode = node;
- break;
- case Node.DOCUMENT_FRAGMENT_NODE:
- actionNode = node.host;
- break;
- default:
- actionNode = null;
- break;
- }
- if (touchAction && actionNode && !actionNode.hasAttribute('touch-action')) {
- actionNode.setAttribute('touch-action', touchAction);
- }
- }
- if (!node._pgEvents) {
- node._pgEvents = {};
- }
- node._pgEvents[g] = (node._pgEvents[g] || 0) + 1;
- node._pgListeners++;
- }
- return Boolean(dep);
- };
-
- /**
- *
- * Listen for `gesture` from `node` with `handler` function.
- *
- * @param {Element} node
- * @param {string} gesture
- * @param {Function} handler
- * @param {Boolean} capture
- */
- scope.addEventListener = function(node, gesture, handler, capture) {
- if (handler) {
- scope.activateGesture(node, gesture);
- node.addEventListener(gesture, handler, capture);
- }
- };
-
- /**
- * Tears down the gesture configuration for `node`
- *
- * If `handler` is the last listener for `gesture`, the underlying gesture recognizer is disabled.
- *
- * @param {Element} node
- * @param {string} gesture
- * @return Boolean `gesture` is a valid gesture
- */
- scope.deactivateGesture = function(node, gesture) {
- var g = gesture.toLowerCase();
- var dep = dispatcher.dependencyMap[g];
- if (dep) {
- if (node._pgListeners > 0) {
- node._pgListeners--;
- }
- if (node._pgListeners === 0) {
- dispatcher.unregister(node);
- }
- if (node._pgEvents) {
- if (node._pgEvents[g] > 0) {
- node._pgEvents[g]--;
- } else {
- node._pgEvents[g] = 0;
- }
- }
- }
- return Boolean(dep);
- };
-
- /**
- * Stop listening for `gesture` from `node` with `handler` function.
- *
- * @param {Element} node
- * @param {string} gesture
- * @param {Function} handler
- * @param {Boolean} capture
- */
- scope.removeEventListener = function(node, gesture, handler, capture) {
- if (handler) {
- scope.deactivateGesture(node, gesture);
- node.removeEventListener(gesture, handler, capture);
- }
- };
-})(window.PolymerGestures);
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = dispatcher.pointermap;
- // radius around touchend that swallows mouse events
- var DEDUP_DIST = 25;
-
- var WHICH_TO_BUTTONS = [0, 1, 4, 2];
-
- var currentButtons = 0;
-
- var FIREFOX_LINUX = /Linux.*Firefox\//i;
-
- var HAS_BUTTONS = (function() {
- // firefox on linux returns spec-incorrect values for mouseup.buttons
- // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.buttons#See_also
- // https://codereview.chromium.org/727593003/#msg16
- if (FIREFOX_LINUX.test(navigator.userAgent)) {
- return false;
- }
- try {
- return new MouseEvent('test', {buttons: 1}).buttons === 1;
- } catch (e) {
- return false;
- }
- })();
-
- // handler block for native mouse events
- var mouseEvents = {
- POINTER_ID: 1,
- POINTER_TYPE: 'mouse',
- events: [
- 'mousedown',
- 'mousemove',
- 'mouseup'
- ],
- exposes: [
- 'down',
- 'up',
- 'move'
- ],
- register: function(target) {
- dispatcher.listen(target, this.events);
- },
- unregister: function(target) {
- if (target.nodeType === Node.DOCUMENT_NODE) {
- return;
- }
- dispatcher.unlisten(target, this.events);
- },
- lastTouches: [],
- // collide with the global mouse listener
- isEventSimulatedFromTouch: function(inEvent) {
- var lts = this.lastTouches;
- var x = inEvent.clientX, y = inEvent.clientY;
- for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
- // simulated mouse events will be swallowed near a primary touchend
- var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
- if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
- return true;
- }
- }
- },
- prepareEvent: function(inEvent) {
- var e = dispatcher.cloneEvent(inEvent);
- e.pointerId = this.POINTER_ID;
- e.isPrimary = true;
- e.pointerType = this.POINTER_TYPE;
- e._source = 'mouse';
- if (!HAS_BUTTONS) {
- var type = inEvent.type;
- var bit = WHICH_TO_BUTTONS[inEvent.which] || 0;
- if (type === 'mousedown') {
- currentButtons |= bit;
- } else if (type === 'mouseup') {
- currentButtons &= ~bit;
- }
- e.buttons = currentButtons;
- }
- return e;
- },
- mousedown: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var p = pointermap.has(this.POINTER_ID);
- var e = this.prepareEvent(inEvent);
- e.target = scope.findTarget(inEvent);
- pointermap.set(this.POINTER_ID, e.target);
- dispatcher.down(e);
- }
- },
- mousemove: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var target = pointermap.get(this.POINTER_ID);
- if (target) {
- var e = this.prepareEvent(inEvent);
- e.target = target;
- // handle case where we missed a mouseup
- if ((HAS_BUTTONS ? e.buttons : e.which) === 0) {
- if (!HAS_BUTTONS) {
- currentButtons = e.buttons = 0;
- }
- dispatcher.cancel(e);
- this.cleanupMouse(e.buttons);
- } else {
- dispatcher.move(e);
- }
- }
- }
- },
- mouseup: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var e = this.prepareEvent(inEvent);
- e.relatedTarget = scope.findTarget(inEvent);
- e.target = pointermap.get(this.POINTER_ID);
- dispatcher.up(e);
- this.cleanupMouse(e.buttons);
- }
- },
- cleanupMouse: function(buttons) {
- if (buttons === 0) {
- pointermap.delete(this.POINTER_ID);
- }
- }
- };
-
- scope.mouseEvents = mouseEvents;
-})(window.PolymerGestures);
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
- var pointermap = dispatcher.pointermap;
- var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
- // This should be long enough to ignore compat mouse events made by touch
- var DEDUP_TIMEOUT = 2500;
- var DEDUP_DIST = 25;
- var CLICK_COUNT_TIMEOUT = 200;
- var HYSTERESIS = 20;
- var ATTRIB = 'touch-action';
- // TODO(dfreedm): disable until http://crbug.com/399765 is resolved
- // var HAS_TOUCH_ACTION = ATTRIB in document.head.style;
- var HAS_TOUCH_ACTION = false;
-
- // handler block for native touch events
- var touchEvents = {
- IS_IOS: false,
- events: [
- 'touchstart',
- 'touchmove',
- 'touchend',
- 'touchcancel'
- ],
- exposes: [
- 'down',
- 'up',
- 'move'
- ],
- register: function(target, initial) {
- if (this.IS_IOS ? initial : !initial) {
- dispatcher.listen(target, this.events);
- }
- },
- unregister: function(target) {
- if (!this.IS_IOS) {
- dispatcher.unlisten(target, this.events);
- }
- },
- scrollTypes: {
- EMITTER: 'none',
- XSCROLLER: 'pan-x',
- YSCROLLER: 'pan-y',
- },
- touchActionToScrollType: function(touchAction) {
- var t = touchAction;
- var st = this.scrollTypes;
- if (t === st.EMITTER) {
- return 'none';
- } else if (t === st.XSCROLLER) {
- return 'X';
- } else if (t === st.YSCROLLER) {
- return 'Y';
- } else {
- return 'XY';
- }
- },
- POINTER_TYPE: 'touch',
- firstTouch: null,
- isPrimaryTouch: function(inTouch) {
- return this.firstTouch === inTouch.identifier;
- },
- setPrimaryTouch: function(inTouch) {
- // set primary touch if there no pointers, or the only pointer is the mouse
- if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointermap.has(1))) {
- this.firstTouch = inTouch.identifier;
- this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY};
- this.firstTarget = inTouch.target;
- this.scrolling = null;
- this.cancelResetClickCount();
- }
- },
- removePrimaryPointer: function(inPointer) {
- if (inPointer.isPrimary) {
- this.firstTouch = null;
- this.firstXY = null;
- this.resetClickCount();
- }
- },
- clickCount: 0,
- resetId: null,
- resetClickCount: function() {
- var fn = function() {
- this.clickCount = 0;
- this.resetId = null;
- }.bind(this);
- this.resetId = setTimeout(fn, CLICK_COUNT_TIMEOUT);
- },
- cancelResetClickCount: function() {
- if (this.resetId) {
- clearTimeout(this.resetId);
- }
- },
- typeToButtons: function(type) {
- var ret = 0;
- if (type === 'touchstart' || type === 'touchmove') {
- ret = 1;
- }
- return ret;
- },
- findTarget: function(touch, id) {
- if (this.currentTouchEvent.type === 'touchstart') {
- if (this.isPrimaryTouch(touch)) {
- var fastPath = {
- clientX: touch.clientX,
- clientY: touch.clientY,
- path: this.currentTouchEvent.path,
- target: this.currentTouchEvent.target
- };
- return scope.findTarget(fastPath);
- } else {
- return scope.findTarget(touch);
- }
- }
- // reuse target we found in touchstart
- return pointermap.get(id);
- },
- touchToPointer: function(inTouch) {
- var cte = this.currentTouchEvent;
- var e = dispatcher.cloneEvent(inTouch);
- // Spec specifies that pointerId 1 is reserved for Mouse.
- // Touch identifiers can start at 0.
- // Add 2 to the touch identifier for compatibility.
- var id = e.pointerId = inTouch.identifier + 2;
- e.target = this.findTarget(inTouch, id);
- e.bubbles = true;
- e.cancelable = true;
- e.detail = this.clickCount;
- e.buttons = this.typeToButtons(cte.type);
- e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
- e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
- e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
- e.isPrimary = this.isPrimaryTouch(inTouch);
- e.pointerType = this.POINTER_TYPE;
- e._source = 'touch';
- // forward touch preventDefaults
- var self = this;
- e.preventDefault = function() {
- self.scrolling = false;
- self.firstXY = null;
- cte.preventDefault();
- };
- return e;
- },
- processTouches: function(inEvent, inFunction) {
- var tl = inEvent.changedTouches;
- this.currentTouchEvent = inEvent;
- for (var i = 0, t, p; i < tl.length; i++) {
- t = tl[i];
- p = this.touchToPointer(t);
- if (inEvent.type === 'touchstart') {
- pointermap.set(p.pointerId, p.target);
- }
- if (pointermap.has(p.pointerId)) {
- inFunction.call(this, p);
- }
- if (inEvent.type === 'touchend' || inEvent._cancel) {
- this.cleanUpPointer(p);
- }
- }
- },
- // For single axis scrollers, determines whether the element should emit
- // pointer events or behave as a scroller
- shouldScroll: function(inEvent) {
- if (this.firstXY) {
- var ret;
- var touchAction = scope.targetFinding.findTouchAction(inEvent);
- var scrollAxis = this.touchActionToScrollType(touchAction);
- if (scrollAxis === 'none') {
- // this element is a touch-action: none, should never scroll
- ret = false;
- } else if (scrollAxis === 'XY') {
- // this element should always scroll
- ret = true;
- } else {
- var t = inEvent.changedTouches[0];
- // check the intended scroll axis, and other axis
- var a = scrollAxis;
- var oa = scrollAxis === 'Y' ? 'X' : 'Y';
- var da = Math.abs(t['client' + a] - this.firstXY[a]);
- var doa = Math.abs(t['client' + oa] - this.firstXY[oa]);
- // if delta in the scroll axis > delta other axis, scroll instead of
- // making events
- ret = da >= doa;
- }
- return ret;
- }
- },
- findTouch: function(inTL, inId) {
- for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) {
- if (t.identifier === inId) {
- return true;
- }
- }
- },
- // In some instances, a touchstart can happen without a touchend. This
- // leaves the pointermap in a broken state.
- // Therefore, on every touchstart, we remove the touches that did not fire a
- // touchend event.
- // To keep state globally consistent, we fire a
- // pointercancel for this "abandoned" touch
- vacuumTouches: function(inEvent) {
- var tl = inEvent.touches;
- // pointermap.pointers() should be < tl.length here, as the touchstart has not
- // been processed yet.
- if (pointermap.pointers() >= tl.length) {
- var d = [];
- pointermap.forEach(function(value, key) {
- // Never remove pointerId == 1, which is mouse.
- // Touch identifiers are 2 smaller than their pointerId, which is the
- // index in pointermap.
- if (key !== 1 && !this.findTouch(tl, key - 2)) {
- var p = value;
- d.push(p);
- }
- }, this);
- d.forEach(function(p) {
- this.cancel(p);
- pointermap.delete(p.pointerId);
- }, this);
- }
- },
- touchstart: function(inEvent) {
- this.vacuumTouches(inEvent);
- this.setPrimaryTouch(inEvent.changedTouches[0]);
- this.dedupSynthMouse(inEvent);
- if (!this.scrolling) {
- this.clickCount++;
- this.processTouches(inEvent, this.down);
- }
- },
- down: function(inPointer) {
- dispatcher.down(inPointer);
- },
- touchmove: function(inEvent) {
- if (HAS_TOUCH_ACTION) {
- // touchevent.cancelable == false is sent when the page is scrolling under native Touch Action in Chrome 36
- // https://groups.google.com/a/chromium.org/d/msg/input-dev/wHnyukcYBcA/b9kmtwM1jJQJ
- if (inEvent.cancelable) {
- this.processTouches(inEvent, this.move);
- }
- } else {
- if (!this.scrolling) {
- if (this.scrolling === null && this.shouldScroll(inEvent)) {
- this.scrolling = true;
- } else {
- this.scrolling = false;
- inEvent.preventDefault();
- this.processTouches(inEvent, this.move);
- }
- } else if (this.firstXY) {
- var t = inEvent.changedTouches[0];
- var dx = t.clientX - this.firstXY.X;
- var dy = t.clientY - this.firstXY.Y;
- var dd = Math.sqrt(dx * dx + dy * dy);
- if (dd >= HYSTERESIS) {
- this.touchcancel(inEvent);
- this.scrolling = true;
- this.firstXY = null;
- }
- }
- }
- },
- move: function(inPointer) {
- dispatcher.move(inPointer);
- },
- touchend: function(inEvent) {
- this.dedupSynthMouse(inEvent);
- this.processTouches(inEvent, this.up);
- },
- up: function(inPointer) {
- inPointer.relatedTarget = scope.findTarget(inPointer);
- dispatcher.up(inPointer);
- },
- cancel: function(inPointer) {
- dispatcher.cancel(inPointer);
- },
- touchcancel: function(inEvent) {
- inEvent._cancel = true;
- this.processTouches(inEvent, this.cancel);
- },
- cleanUpPointer: function(inPointer) {
- pointermap['delete'](inPointer.pointerId);
- this.removePrimaryPointer(inPointer);
- },
- // prevent synth mouse events from creating pointer events
- dedupSynthMouse: function(inEvent) {
- var lts = scope.mouseEvents.lastTouches;
- var t = inEvent.changedTouches[0];
- // only the primary finger will synth mouse events
- if (this.isPrimaryTouch(t)) {
- // remember x/y of last touch
- var lt = {x: t.clientX, y: t.clientY};
- lts.push(lt);
- var fn = (function(lts, lt){
- var i = lts.indexOf(lt);
- if (i > -1) {
- lts.splice(i, 1);
- }
- }).bind(null, lts, lt);
- setTimeout(fn, DEDUP_TIMEOUT);
- }
- }
- };
-
- // prevent "ghost clicks" that come from elements that were removed in a touch handler
- var STOP_PROP_FN = Event.prototype.stopImmediatePropagation || Event.prototype.stopPropagation;
- document.addEventListener('click', function(ev) {
- var x = ev.clientX, y = ev.clientY;
- // check if a click is within DEDUP_DIST px radius of the touchstart
- var closeTo = function(touch) {
- var dx = Math.abs(x - touch.x), dy = Math.abs(y - touch.y);
- return (dx <= DEDUP_DIST && dy <= DEDUP_DIST);
- };
- // if click coordinates are close to touch coordinates, assume the click came from a touch
- var wasTouched = scope.mouseEvents.lastTouches.some(closeTo);
- // if the click came from touch, and the touchstart target is not in the path of the click event,
- // then the touchstart target was probably removed, and the click should be "busted"
- var path = scope.targetFinding.path(ev);
- if (wasTouched) {
- for (var i = 0; i < path.length; i++) {
- if (path[i] === touchEvents.firstTarget) {
- return;
- }
- }
- ev.preventDefault();
- STOP_PROP_FN.call(ev);
- }
- }, true);
-
- scope.touchEvents = touchEvents;
-})(window.PolymerGestures);
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = dispatcher.pointermap;
- var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE === 'number';
- var msEvents = {
- events: [
- 'MSPointerDown',
- 'MSPointerMove',
- 'MSPointerUp',
- 'MSPointerCancel',
- ],
- register: function(target) {
- dispatcher.listen(target, this.events);
- },
- unregister: function(target) {
- if (target.nodeType === Node.DOCUMENT_NODE) {
- return;
- }
- dispatcher.unlisten(target, this.events);
- },
- POINTER_TYPES: [
- '',
- 'unavailable',
- 'touch',
- 'pen',
- 'mouse'
- ],
- prepareEvent: function(inEvent) {
- var e = inEvent;
- e = dispatcher.cloneEvent(inEvent);
- if (HAS_BITMAP_TYPE) {
- e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
- }
- e._source = 'ms';
- return e;
- },
- cleanup: function(id) {
- pointermap['delete'](id);
- },
- MSPointerDown: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.target = scope.findTarget(inEvent);
- pointermap.set(inEvent.pointerId, e.target);
- dispatcher.down(e);
- },
- MSPointerMove: function(inEvent) {
- var target = pointermap.get(inEvent.pointerId);
- if (target) {
- var e = this.prepareEvent(inEvent);
- e.target = target;
- dispatcher.move(e);
- }
- },
- MSPointerUp: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.relatedTarget = scope.findTarget(inEvent);
- e.target = pointermap.get(e.pointerId);
- dispatcher.up(e);
- this.cleanup(inEvent.pointerId);
- },
- MSPointerCancel: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.relatedTarget = scope.findTarget(inEvent);
- e.target = pointermap.get(e.pointerId);
- dispatcher.cancel(e);
- this.cleanup(inEvent.pointerId);
- }
- };
-
- scope.msEvents = msEvents;
-})(window.PolymerGestures);
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = dispatcher.pointermap;
- var pointerEvents = {
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel'
- ],
- prepareEvent: function(inEvent) {
- var e = dispatcher.cloneEvent(inEvent);
- e._source = 'pointer';
- return e;
- },
- register: function(target) {
- dispatcher.listen(target, this.events);
- },
- unregister: function(target) {
- if (target.nodeType === Node.DOCUMENT_NODE) {
- return;
- }
- dispatcher.unlisten(target, this.events);
- },
- cleanup: function(id) {
- pointermap['delete'](id);
- },
- pointerdown: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.target = scope.findTarget(inEvent);
- pointermap.set(e.pointerId, e.target);
- dispatcher.down(e);
- },
- pointermove: function(inEvent) {
- var target = pointermap.get(inEvent.pointerId);
- if (target) {
- var e = this.prepareEvent(inEvent);
- e.target = target;
- dispatcher.move(e);
- }
- },
- pointerup: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.relatedTarget = scope.findTarget(inEvent);
- e.target = pointermap.get(e.pointerId);
- dispatcher.up(e);
- this.cleanup(inEvent.pointerId);
- },
- pointercancel: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- e.relatedTarget = scope.findTarget(inEvent);
- e.target = pointermap.get(e.pointerId);
- dispatcher.cancel(e);
- this.cleanup(inEvent.pointerId);
- }
- };
-
- scope.pointerEvents = pointerEvents;
-})(window.PolymerGestures);
-
-/**
- * This module contains the handlers for native platform events.
- * From here, the dispatcher is called to create unified pointer events.
- * Included are touch events (v1), mouse events, and MSPointerEvents.
- */
-(function(scope) {
-
- var dispatcher = scope.dispatcher;
- var nav = window.navigator;
-
- if (window.PointerEvent) {
- dispatcher.registerSource('pointer', scope.pointerEvents);
- } else if (nav.msPointerEnabled) {
- dispatcher.registerSource('ms', scope.msEvents);
- } else {
- dispatcher.registerSource('mouse', scope.mouseEvents);
- if (window.ontouchstart !== undefined) {
- dispatcher.registerSource('touch', scope.touchEvents);
- }
- }
-
- // Work around iOS bugs https://bugs.webkit.org/show_bug.cgi?id=135628 and https://bugs.webkit.org/show_bug.cgi?id=136506
- var ua = navigator.userAgent;
- var IS_IOS = ua.match(/iPad|iPhone|iPod/) && 'ontouchstart' in window;
-
- dispatcher.IS_IOS = IS_IOS;
- scope.touchEvents.IS_IOS = IS_IOS;
-
- dispatcher.register(document, true);
-})(window.PolymerGestures);
-
-/**
- * This event denotes the beginning of a series of tracking events.
- *
- * @module PointerGestures
- * @submodule Events
- * @class trackstart
- */
-/**
- * Pixels moved in the x direction since trackstart.
- * @type Number
- * @property dx
- */
-/**
- * Pixes moved in the y direction since trackstart.
- * @type Number
- * @property dy
- */
-/**
- * Pixels moved in the x direction since the last track.
- * @type Number
- * @property ddx
- */
-/**
- * Pixles moved in the y direction since the last track.
- * @type Number
- * @property ddy
- */
-/**
- * The clientX position of the track gesture.
- * @type Number
- * @property clientX
- */
-/**
- * The clientY position of the track gesture.
- * @type Number
- * @property clientY
- */
-/**
- * The pageX position of the track gesture.
- * @type Number
- * @property pageX
- */
-/**
- * The pageY position of the track gesture.
- * @type Number
- * @property pageY
- */
-/**
- * The screenX position of the track gesture.
- * @type Number
- * @property screenX
- */
-/**
- * The screenY position of the track gesture.
- * @type Number
- * @property screenY
- */
-/**
- * The last x axis direction of the pointer.
- * @type Number
- * @property xDirection
- */
-/**
- * The last y axis direction of the pointer.
- * @type Number
- * @property yDirection
- */
-/**
- * A shared object between all tracking events.
- * @type Object
- * @property trackInfo
- */
-/**
- * The element currently under the pointer.
- * @type Element
- * @property relatedTarget
- */
-/**
- * The type of pointer that make the track gesture.
- * @type String
- * @property pointerType
- */
-/**
- *
- * This event fires for all pointer movement being tracked.
- *
- * @class track
- * @extends trackstart
- */
-/**
- * This event fires when the pointer is no longer being tracked.
- *
- * @class trackend
- * @extends trackstart
- */
-
- (function(scope) {
- var dispatcher = scope.dispatcher;
- var eventFactory = scope.eventFactory;
- var pointermap = new scope.PointerMap();
- var track = {
- events: [
- 'down',
- 'move',
- 'up',
- ],
- exposes: [
- 'trackstart',
- 'track',
- 'trackx',
- 'tracky',
- 'trackend'
- ],
- defaultActions: {
- 'track': 'none',
- 'trackx': 'pan-y',
- 'tracky': 'pan-x'
- },
- WIGGLE_THRESHOLD: 4,
- clampDir: function(inDelta) {
- return inDelta > 0 ? 1 : -1;
- },
- calcPositionDelta: function(inA, inB) {
- var x = 0, y = 0;
- if (inA && inB) {
- x = inB.pageX - inA.pageX;
- y = inB.pageY - inA.pageY;
- }
- return {x: x, y: y};
- },
- fireTrack: function(inType, inEvent, inTrackingData) {
- var t = inTrackingData;
- var d = this.calcPositionDelta(t.downEvent, inEvent);
- var dd = this.calcPositionDelta(t.lastMoveEvent, inEvent);
- if (dd.x) {
- t.xDirection = this.clampDir(dd.x);
- } else if (inType === 'trackx') {
- return;
- }
- if (dd.y) {
- t.yDirection = this.clampDir(dd.y);
- } else if (inType === 'tracky') {
- return;
- }
- var gestureProto = {
- bubbles: true,
- cancelable: true,
- trackInfo: t.trackInfo,
- relatedTarget: inEvent.relatedTarget,
- pointerType: inEvent.pointerType,
- pointerId: inEvent.pointerId,
- _source: 'track'
- };
- if (inType !== 'tracky') {
- gestureProto.x = inEvent.x;
- gestureProto.dx = d.x;
- gestureProto.ddx = dd.x;
- gestureProto.clientX = inEvent.clientX;
- gestureProto.pageX = inEvent.pageX;
- gestureProto.screenX = inEvent.screenX;
- gestureProto.xDirection = t.xDirection;
- }
- if (inType !== 'trackx') {
- gestureProto.dy = d.y;
- gestureProto.ddy = dd.y;
- gestureProto.y = inEvent.y;
- gestureProto.clientY = inEvent.clientY;
- gestureProto.pageY = inEvent.pageY;
- gestureProto.screenY = inEvent.screenY;
- gestureProto.yDirection = t.yDirection;
- }
- var e = eventFactory.makeGestureEvent(inType, gestureProto);
- t.downTarget.dispatchEvent(e);
- },
- down: function(inEvent) {
- if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.buttons === 1 : true)) {
- var p = {
- downEvent: inEvent,
- downTarget: inEvent.target,
- trackInfo: {},
- lastMoveEvent: null,
- xDirection: 0,
- yDirection: 0,
- tracking: false
- };
- pointermap.set(inEvent.pointerId, p);
- }
- },
- move: function(inEvent) {
- var p = pointermap.get(inEvent.pointerId);
- if (p) {
- if (!p.tracking) {
- var d = this.calcPositionDelta(p.downEvent, inEvent);
- var move = d.x * d.x + d.y * d.y;
- // start tracking only if finger moves more than WIGGLE_THRESHOLD
- if (move > this.WIGGLE_THRESHOLD) {
- p.tracking = true;
- p.lastMoveEvent = p.downEvent;
- this.fireTrack('trackstart', inEvent, p);
- }
- }
- if (p.tracking) {
- this.fireTrack('track', inEvent, p);
- this.fireTrack('trackx', inEvent, p);
- this.fireTrack('tracky', inEvent, p);
- }
- p.lastMoveEvent = inEvent;
- }
- },
- up: function(inEvent) {
- var p = pointermap.get(inEvent.pointerId);
- if (p) {
- if (p.tracking) {
- this.fireTrack('trackend', inEvent, p);
- }
- pointermap.delete(inEvent.pointerId);
- }
- }
- };
- dispatcher.registerGesture('track', track);
- })(window.PolymerGestures);
-
-/**
- * This event is fired when a pointer is held down for 200ms.
- *
- * @module PointerGestures
- * @submodule Events
- * @class hold
- */
-/**
- * Type of pointer that made the holding event.
- * @type String
- * @property pointerType
- */
-/**
- * Screen X axis position of the held pointer
- * @type Number
- * @property clientX
- */
-/**
- * Screen Y axis position of the held pointer
- * @type Number
- * @property clientY
- */
-/**
- * Type of pointer that made the holding event.
- * @type String
- * @property pointerType
- */
-/**
- * This event is fired every 200ms while a pointer is held down.
- *
- * @class holdpulse
- * @extends hold
- */
-/**
- * Milliseconds pointer has been held down.
- * @type Number
- * @property holdTime
- */
-/**
- * This event is fired when a held pointer is released or moved.
- *
- * @class release
- */
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var eventFactory = scope.eventFactory;
- var hold = {
- // wait at least HOLD_DELAY ms between hold and pulse events
- HOLD_DELAY: 200,
- // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold
- WIGGLE_THRESHOLD: 16,
- events: [
- 'down',
- 'move',
- 'up',
- ],
- exposes: [
- 'hold',
- 'holdpulse',
- 'release'
- ],
- heldPointer: null,
- holdJob: null,
- pulse: function() {
- var hold = Date.now() - this.heldPointer.timeStamp;
- var type = this.held ? 'holdpulse' : 'hold';
- this.fireHold(type, hold);
- this.held = true;
- },
- cancel: function() {
- clearInterval(this.holdJob);
- if (this.held) {
- this.fireHold('release');
- }
- this.held = false;
- this.heldPointer = null;
- this.target = null;
- this.holdJob = null;
- },
- down: function(inEvent) {
- if (inEvent.isPrimary && !this.heldPointer) {
- this.heldPointer = inEvent;
- this.target = inEvent.target;
- this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY);
- }
- },
- up: function(inEvent) {
- if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
- this.cancel();
- }
- },
- move: function(inEvent) {
- if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
- var x = inEvent.clientX - this.heldPointer.clientX;
- var y = inEvent.clientY - this.heldPointer.clientY;
- if ((x * x + y * y) > this.WIGGLE_THRESHOLD) {
- this.cancel();
- }
- }
- },
- fireHold: function(inType, inHoldTime) {
- var p = {
- bubbles: true,
- cancelable: true,
- pointerType: this.heldPointer.pointerType,
- pointerId: this.heldPointer.pointerId,
- x: this.heldPointer.clientX,
- y: this.heldPointer.clientY,
- _source: 'hold'
- };
- if (inHoldTime) {
- p.holdTime = inHoldTime;
- }
- var e = eventFactory.makeGestureEvent(inType, p);
- this.target.dispatchEvent(e);
- }
- };
- dispatcher.registerGesture('hold', hold);
-})(window.PolymerGestures);
-
-/**
- * This event is fired when a pointer quickly goes down and up, and is used to
- * denote activation.
- *
- * Any gesture event can prevent the tap event from being created by calling
- * `event.preventTap`.
- *
- * Any pointer event can prevent the tap by setting the `tapPrevented` property
- * on itself.
- *
- * @module PointerGestures
- * @submodule Events
- * @class tap
- */
-/**
- * X axis position of the tap.
- * @property x
- * @type Number
- */
-/**
- * Y axis position of the tap.
- * @property y
- * @type Number
- */
-/**
- * Type of the pointer that made the tap.
- * @property pointerType
- * @type String
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var eventFactory = scope.eventFactory;
- var pointermap = new scope.PointerMap();
- var tap = {
- events: [
- 'down',
- 'up'
- ],
- exposes: [
- 'tap'
- ],
- down: function(inEvent) {
- if (inEvent.isPrimary && !inEvent.tapPrevented) {
- pointermap.set(inEvent.pointerId, {
- target: inEvent.target,
- buttons: inEvent.buttons,
- x: inEvent.clientX,
- y: inEvent.clientY
- });
- }
- },
- shouldTap: function(e, downState) {
- var tap = true;
- if (e.pointerType === 'mouse') {
- // only allow left click to tap for mouse
- tap = (e.buttons ^ 1) && (downState.buttons & 1);
- }
- return tap && !e.tapPrevented;
- },
- up: function(inEvent) {
- var start = pointermap.get(inEvent.pointerId);
- if (start && this.shouldTap(inEvent, start)) {
- // up.relatedTarget is target currently under finger
- var t = scope.targetFinding.LCA(start.target, inEvent.relatedTarget);
- if (t) {
- var e = eventFactory.makeGestureEvent('tap', {
- bubbles: true,
- cancelable: true,
- x: inEvent.clientX,
- y: inEvent.clientY,
- detail: inEvent.detail,
- pointerType: inEvent.pointerType,
- pointerId: inEvent.pointerId,
- altKey: inEvent.altKey,
- ctrlKey: inEvent.ctrlKey,
- metaKey: inEvent.metaKey,
- shiftKey: inEvent.shiftKey,
- _source: 'tap'
- });
- t.dispatchEvent(e);
- }
- }
- pointermap.delete(inEvent.pointerId);
- }
- };
- // patch eventFactory to remove id from tap's pointermap for preventTap calls
- eventFactory.preventTap = function(e) {
- return function() {
- e.tapPrevented = true;
- pointermap.delete(e.pointerId);
- };
- };
- dispatcher.registerGesture('tap', tap);
-})(window.PolymerGestures);
-
-/*
- * Basic strategy: find the farthest apart points, use as diameter of circle
- * react to size change and rotation of the chord
- */
-
-/**
- * @module pointer-gestures
- * @submodule Events
- * @class pinch
- */
-/**
- * Scale of the pinch zoom gesture
- * @property scale
- * @type Number
- */
-/**
- * Center X position of pointers causing pinch
- * @property centerX
- * @type Number
- */
-/**
- * Center Y position of pointers causing pinch
- * @property centerY
- * @type Number
- */
-
-/**
- * @module pointer-gestures
- * @submodule Events
- * @class rotate
- */
-/**
- * Angle (in degrees) of rotation. Measured from starting positions of pointers.
- * @property angle
- * @type Number
- */
-/**
- * Center X position of pointers causing rotation
- * @property centerX
- * @type Number
- */
-/**
- * Center Y position of pointers causing rotation
- * @property centerY
- * @type Number
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var eventFactory = scope.eventFactory;
- var pointermap = new scope.PointerMap();
- var RAD_TO_DEG = 180 / Math.PI;
- var pinch = {
- events: [
- 'down',
- 'up',
- 'move',
- 'cancel'
- ],
- exposes: [
- 'pinchstart',
- 'pinch',
- 'pinchend',
- 'rotate'
- ],
- defaultActions: {
- 'pinch': 'none',
- 'rotate': 'none'
- },
- reference: {},
- down: function(inEvent) {
- pointermap.set(inEvent.pointerId, inEvent);
- if (pointermap.pointers() == 2) {
- var points = this.calcChord();
- var angle = this.calcAngle(points);
- this.reference = {
- angle: angle,
- diameter: points.diameter,
- target: scope.targetFinding.LCA(points.a.target, points.b.target)
- };
-
- this.firePinch('pinchstart', points.diameter, points);
- }
- },
- up: function(inEvent) {
- var p = pointermap.get(inEvent.pointerId);
- var num = pointermap.pointers();
- if (p) {
- if (num === 2) {
- // fire 'pinchend' before deleting pointer
- var points = this.calcChord();
- this.firePinch('pinchend', points.diameter, points);
- }
- pointermap.delete(inEvent.pointerId);
- }
- },
- move: function(inEvent) {
- if (pointermap.has(inEvent.pointerId)) {
- pointermap.set(inEvent.pointerId, inEvent);
- if (pointermap.pointers() > 1) {
- this.calcPinchRotate();
- }
- }
- },
- cancel: function(inEvent) {
- this.up(inEvent);
- },
- firePinch: function(type, diameter, points) {
- var zoom = diameter / this.reference.diameter;
- var e = eventFactory.makeGestureEvent(type, {
- bubbles: true,
- cancelable: true,
- scale: zoom,
- centerX: points.center.x,
- centerY: points.center.y,
- _source: 'pinch'
- });
- this.reference.target.dispatchEvent(e);
- },
- fireRotate: function(angle, points) {
- var diff = Math.round((angle - this.reference.angle) % 360);
- var e = eventFactory.makeGestureEvent('rotate', {
- bubbles: true,
- cancelable: true,
- angle: diff,
- centerX: points.center.x,
- centerY: points.center.y,
- _source: 'pinch'
- });
- this.reference.target.dispatchEvent(e);
- },
- calcPinchRotate: function() {
- var points = this.calcChord();
- var diameter = points.diameter;
- var angle = this.calcAngle(points);
- if (diameter != this.reference.diameter) {
- this.firePinch('pinch', diameter, points);
- }
- if (angle != this.reference.angle) {
- this.fireRotate(angle, points);
- }
- },
- calcChord: function() {
- var pointers = [];
- pointermap.forEach(function(p) {
- pointers.push(p);
- });
- var dist = 0;
- // start with at least two pointers
- var points = {a: pointers[0], b: pointers[1]};
- var x, y, d;
- for (var i = 0; i < pointers.length; i++) {
- var a = pointers[i];
- for (var j = i + 1; j < pointers.length; j++) {
- var b = pointers[j];
- x = Math.abs(a.clientX - b.clientX);
- y = Math.abs(a.clientY - b.clientY);
- d = x + y;
- if (d > dist) {
- dist = d;
- points = {a: a, b: b};
- }
- }
- }
- x = Math.abs(points.a.clientX + points.b.clientX) / 2;
- y = Math.abs(points.a.clientY + points.b.clientY) / 2;
- points.center = { x: x, y: y };
- points.diameter = dist;
- return points;
- },
- calcAngle: function(points) {
- var x = points.a.clientX - points.b.clientX;
- var y = points.a.clientY - points.b.clientY;
- return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
- }
- };
- dispatcher.registerGesture('pinch', pinch);
-})(window.PolymerGestures);
-
-(function (global) {
- 'use strict';
-
- var Token,
- TokenName,
- Syntax,
- Messages,
- source,
- index,
- length,
- delegate,
- lookahead,
- state;
-
- Token = {
- BooleanLiteral: 1,
- EOF: 2,
- Identifier: 3,
- Keyword: 4,
- NullLiteral: 5,
- NumericLiteral: 6,
- Punctuator: 7,
- StringLiteral: 8
- };
-
- TokenName = {};
- TokenName[Token.BooleanLiteral] = 'Boolean';
- TokenName[Token.EOF] = '<end>';
- TokenName[Token.Identifier] = 'Identifier';
- TokenName[Token.Keyword] = 'Keyword';
- TokenName[Token.NullLiteral] = 'Null';
- TokenName[Token.NumericLiteral] = 'Numeric';
- TokenName[Token.Punctuator] = 'Punctuator';
- TokenName[Token.StringLiteral] = 'String';
-
- Syntax = {
- ArrayExpression: 'ArrayExpression',
- BinaryExpression: 'BinaryExpression',
- CallExpression: 'CallExpression',
- ConditionalExpression: 'ConditionalExpression',
- EmptyStatement: 'EmptyStatement',
- ExpressionStatement: 'ExpressionStatement',
- Identifier: 'Identifier',
- Literal: 'Literal',
- LabeledStatement: 'LabeledStatement',
- LogicalExpression: 'LogicalExpression',
- MemberExpression: 'MemberExpression',
- ObjectExpression: 'ObjectExpression',
- Program: 'Program',
- Property: 'Property',
- ThisExpression: 'ThisExpression',
- UnaryExpression: 'UnaryExpression'
- };
-
- // Error messages should be identical to V8.
- Messages = {
- UnexpectedToken: 'Unexpected token %0',
- UnknownLabel: 'Undefined label \'%0\'',
- Redeclaration: '%0 \'%1\' has already been declared'
- };
-
- // Ensure the condition is true, otherwise throw an error.
- // This is only to have a better contract semantic, i.e. another safety net
- // to catch a logic error. The condition shall be fulfilled in normal case.
- // Do NOT use this to enforce a certain condition on any user input.
-
- function assert(condition, message) {
- if (!condition) {
- throw new Error('ASSERT: ' + message);
- }
- }
-
- function isDecimalDigit(ch) {
- return (ch >= 48 && ch <= 57); // 0..9
- }
-
-
- // 7.2 White Space
-
- function isWhiteSpace(ch) {
- return (ch === 32) || // space
- (ch === 9) || // tab
- (ch === 0xB) ||
- (ch === 0xC) ||
- (ch === 0xA0) ||
- (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
- }
-
- // 7.3 Line Terminators
-
- function isLineTerminator(ch) {
- return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
- }
-
- // 7.6 Identifier Names and Identifiers
-
- function isIdentifierStart(ch) {
- return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
- (ch >= 65 && ch <= 90) || // A..Z
- (ch >= 97 && ch <= 122); // a..z
- }
-
- function isIdentifierPart(ch) {
- return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
- (ch >= 65 && ch <= 90) || // A..Z
- (ch >= 97 && ch <= 122) || // a..z
- (ch >= 48 && ch <= 57); // 0..9
- }
-
- // 7.6.1.1 Keywords
-
- function isKeyword(id) {
- return (id === 'this')
- }
-
- // 7.4 Comments
-
- function skipWhitespace() {
- while (index < length && isWhiteSpace(source.charCodeAt(index))) {
- ++index;
- }
- }
-
- function getIdentifier() {
- var start, ch;
-
- start = index++;
- while (index < length) {
- ch = source.charCodeAt(index);
- if (isIdentifierPart(ch)) {
- ++index;
- } else {
- break;
- }
- }
-
- return source.slice(start, index);
- }
-
- function scanIdentifier() {
- var start, id, type;
-
- start = index;
-
- id = getIdentifier();
-
- // There is no keyword or literal with only one character.
- // Thus, it must be an identifier.
- if (id.length === 1) {
- type = Token.Identifier;
- } else if (isKeyword(id)) {
- type = Token.Keyword;
- } else if (id === 'null') {
- type = Token.NullLiteral;
- } else if (id === 'true' || id === 'false') {
- type = Token.BooleanLiteral;
- } else {
- type = Token.Identifier;
- }
-
- return {
- type: type,
- value: id,
- range: [start, index]
- };
- }
-
-
- // 7.7 Punctuators
-
- function scanPunctuator() {
- var start = index,
- code = source.charCodeAt(index),
- code2,
- ch1 = source[index],
- ch2;
-
- switch (code) {
-
- // Check for most common single-character punctuators.
- case 46: // . dot
- case 40: // ( open bracket
- case 41: // ) close bracket
- case 59: // ; semicolon
- case 44: // , comma
- case 123: // { open curly brace
- case 125: // } close curly brace
- case 91: // [
- case 93: // ]
- case 58: // :
- case 63: // ?
- ++index;
- return {
- type: Token.Punctuator,
- value: String.fromCharCode(code),
- range: [start, index]
- };
-
- default:
- code2 = source.charCodeAt(index + 1);
-
- // '=' (char #61) marks an assignment or comparison operator.
- if (code2 === 61) {
- switch (code) {
- case 37: // %
- case 38: // &
- case 42: // *:
- case 43: // +
- case 45: // -
- case 47: // /
- case 60: // <
- case 62: // >
- case 124: // |
- index += 2;
- return {
- type: Token.Punctuator,
- value: String.fromCharCode(code) + String.fromCharCode(code2),
- range: [start, index]
- };
-
- case 33: // !
- case 61: // =
- index += 2;
-
- // !== and ===
- if (source.charCodeAt(index) === 61) {
- ++index;
- }
- return {
- type: Token.Punctuator,
- value: source.slice(start, index),
- range: [start, index]
- };
- default:
- break;
- }
- }
- break;
- }
-
- // Peek more characters.
-
- ch2 = source[index + 1];
-
- // Other 2-character punctuators: && ||
-
- if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) {
- index += 2;
- return {
- type: Token.Punctuator,
- value: ch1 + ch2,
- range: [start, index]
- };
- }
-
- if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
- ++index;
- return {
- type: Token.Punctuator,
- value: ch1,
- range: [start, index]
- };
- }
-
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- // 7.8.3 Numeric Literals
- function scanNumericLiteral() {
- var number, start, ch;
-
- ch = source[index];
- assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
- 'Numeric literal must start with a decimal digit or a decimal point');
-
- start = index;
- number = '';
- if (ch !== '.') {
- number = source[index++];
- ch = source[index];
-
- // Hex number starts with '0x'.
- // Octal number starts with '0'.
- if (number === '0') {
- // decimal number starts with '0' such as '09' is illegal.
- if (ch && isDecimalDigit(ch.charCodeAt(0))) {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
- }
-
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- ch = source[index];
- }
-
- if (ch === '.') {
- number += source[index++];
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- ch = source[index];
- }
-
- if (ch === 'e' || ch === 'E') {
- number += source[index++];
-
- ch = source[index];
- if (ch === '+' || ch === '-') {
- number += source[index++];
- }
- if (isDecimalDigit(source.charCodeAt(index))) {
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- } else {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
- }
-
- if (isIdentifierStart(source.charCodeAt(index))) {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- return {
- type: Token.NumericLiteral,
- value: parseFloat(number),
- range: [start, index]
- };
- }
-
- // 7.8.4 String Literals
-
- function scanStringLiteral() {
- var str = '', quote, start, ch, octal = false;
-
- quote = source[index];
- assert((quote === '\'' || quote === '"'),
- 'String literal must starts with a quote');
-
- start = index;
- ++index;
-
- while (index < length) {
- ch = source[index++];
-
- if (ch === quote) {
- quote = '';
- break;
- } else if (ch === '\\') {
- ch = source[index++];
- if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
- switch (ch) {
- case 'n':
- str += '\n';
- break;
- case 'r':
- str += '\r';
- break;
- case 't':
- str += '\t';
- break;
- case 'b':
- str += '\b';
- break;
- case 'f':
- str += '\f';
- break;
- case 'v':
- str += '\x0B';
- break;
-
- default:
- str += ch;
- break;
- }
- } else {
- if (ch === '\r' && source[index] === '\n') {
- ++index;
- }
- }
- } else if (isLineTerminator(ch.charCodeAt(0))) {
- break;
- } else {
- str += ch;
- }
- }
-
- if (quote !== '') {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- return {
- type: Token.StringLiteral,
- value: str,
- octal: octal,
- range: [start, index]
- };
- }
-
- function isIdentifierName(token) {
- return token.type === Token.Identifier ||
- token.type === Token.Keyword ||
- token.type === Token.BooleanLiteral ||
- token.type === Token.NullLiteral;
- }
-
- function advance() {
- var ch;
-
- skipWhitespace();
-
- if (index >= length) {
- return {
- type: Token.EOF,
- range: [index, index]
- };
- }
-
- ch = source.charCodeAt(index);
-
- // Very common: ( and ) and ;
- if (ch === 40 || ch === 41 || ch === 58) {
- return scanPunctuator();
- }
-
- // String literal starts with single quote (#39) or double quote (#34).
- if (ch === 39 || ch === 34) {
- return scanStringLiteral();
- }
-
- if (isIdentifierStart(ch)) {
- return scanIdentifier();
- }
-
- // Dot (.) char #46 can also start a floating-point number, hence the need
- // to check the next character.
- if (ch === 46) {
- if (isDecimalDigit(source.charCodeAt(index + 1))) {
- return scanNumericLiteral();
- }
- return scanPunctuator();
- }
-
- if (isDecimalDigit(ch)) {
- return scanNumericLiteral();
- }
-
- return scanPunctuator();
- }
-
- function lex() {
- var token;
-
- token = lookahead;
- index = token.range[1];
-
- lookahead = advance();
-
- index = token.range[1];
-
- return token;
- }
-
- function peek() {
- var pos;
-
- pos = index;
- lookahead = advance();
- index = pos;
- }
-
- // Throw an exception
-
- function throwError(token, messageFormat) {
- var error,
- args = Array.prototype.slice.call(arguments, 2),
- msg = messageFormat.replace(
- /%(\d)/g,
- function (whole, index) {
- assert(index < args.length, 'Message reference must be in range');
- return args[index];
- }
- );
-
- error = new Error(msg);
- error.index = index;
- error.description = msg;
- throw error;
- }
-
- // Throw an exception because of the token.
-
- function throwUnexpected(token) {
- throwError(token, Messages.UnexpectedToken, token.value);
- }
-
- // Expect the next token to match the specified punctuator.
- // If not, an exception will be thrown.
-
- function expect(value) {
- var token = lex();
- if (token.type !== Token.Punctuator || token.value !== value) {
- throwUnexpected(token);
- }
- }
-
- // Return true if the next token matches the specified punctuator.
-
- function match(value) {
- return lookahead.type === Token.Punctuator && lookahead.value === value;
- }
-
- // Return true if the next token matches the specified keyword
-
- function matchKeyword(keyword) {
- return lookahead.type === Token.Keyword && lookahead.value === keyword;
- }
-
- function consumeSemicolon() {
- // Catch the very common case first: immediately a semicolon (char #59).
- if (source.charCodeAt(index) === 59) {
- lex();
- return;
- }
-
- skipWhitespace();
-
- if (match(';')) {
- lex();
- return;
- }
-
- if (lookahead.type !== Token.EOF && !match('}')) {
- throwUnexpected(lookahead);
- }
- }
-
- // 11.1.4 Array Initialiser
-
- function parseArrayInitialiser() {
- var elements = [];
-
- expect('[');
-
- while (!match(']')) {
- if (match(',')) {
- lex();
- elements.push(null);
- } else {
- elements.push(parseExpression());
-
- if (!match(']')) {
- expect(',');
- }
- }
- }
-
- expect(']');
-
- return delegate.createArrayExpression(elements);
- }
-
- // 11.1.5 Object Initialiser
-
- function parseObjectPropertyKey() {
- var token;
-
- skipWhitespace();
- token = lex();
-
- // Note: This function is called only from parseObjectProperty(), where
- // EOF and Punctuator tokens are already filtered out.
- if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
- return delegate.createLiteral(token);
- }
-
- return delegate.createIdentifier(token.value);
- }
-
- function parseObjectProperty() {
- var token, key;
-
- token = lookahead;
- skipWhitespace();
-
- if (token.type === Token.EOF || token.type === Token.Punctuator) {
- throwUnexpected(token);
- }
-
- key = parseObjectPropertyKey();
- expect(':');
- return delegate.createProperty('init', key, parseExpression());
- }
-
- function parseObjectInitialiser() {
- var properties = [];
-
- expect('{');
-
- while (!match('}')) {
- properties.push(parseObjectProperty());
-
- if (!match('}')) {
- expect(',');
- }
- }
-
- expect('}');
-
- return delegate.createObjectExpression(properties);
- }
-
- // 11.1.6 The Grouping Operator
-
- function parseGroupExpression() {
- var expr;
-
- expect('(');
-
- expr = parseExpression();
-
- expect(')');
-
- return expr;
- }
-
-
- // 11.1 Primary Expressions
-
- function parsePrimaryExpression() {
- var type, token, expr;
-
- if (match('(')) {
- return parseGroupExpression();
- }
-
- type = lookahead.type;
-
- if (type === Token.Identifier) {
- expr = delegate.createIdentifier(lex().value);
- } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
- expr = delegate.createLiteral(lex());
- } else if (type === Token.Keyword) {
- if (matchKeyword('this')) {
- lex();
- expr = delegate.createThisExpression();
- }
- } else if (type === Token.BooleanLiteral) {
- token = lex();
- token.value = (token.value === 'true');
- expr = delegate.createLiteral(token);
- } else if (type === Token.NullLiteral) {
- token = lex();
- token.value = null;
- expr = delegate.createLiteral(token);
- } else if (match('[')) {
- expr = parseArrayInitialiser();
- } else if (match('{')) {
- expr = parseObjectInitialiser();
- }
-
- if (expr) {
- return expr;
- }
-
- throwUnexpected(lex());
- }
-
- // 11.2 Left-Hand-Side Expressions
-
- function parseArguments() {
- var args = [];
-
- expect('(');
-
- if (!match(')')) {
- while (index < length) {
- args.push(parseExpression());
- if (match(')')) {
- break;
- }
- expect(',');
- }
- }
-
- expect(')');
-
- return args;
- }
-
- function parseNonComputedProperty() {
- var token;
-
- token = lex();
-
- if (!isIdentifierName(token)) {
- throwUnexpected(token);
- }
-
- return delegate.createIdentifier(token.value);
- }
-
- function parseNonComputedMember() {
- expect('.');
-
- return parseNonComputedProperty();
- }
-
- function parseComputedMember() {
- var expr;
-
- expect('[');
-
- expr = parseExpression();
-
- expect(']');
-
- return expr;
- }
-
- function parseLeftHandSideExpression() {
- var expr, args, property;
-
- expr = parsePrimaryExpression();
-
- while (true) {
- if (match('[')) {
- property = parseComputedMember();
- expr = delegate.createMemberExpression('[', expr, property);
- } else if (match('.')) {
- property = parseNonComputedMember();
- expr = delegate.createMemberExpression('.', expr, property);
- } else if (match('(')) {
- args = parseArguments();
- expr = delegate.createCallExpression(expr, args);
- } else {
- break;
- }
- }
-
- return expr;
- }
-
- // 11.3 Postfix Expressions
-
- var parsePostfixExpression = parseLeftHandSideExpression;
-
- // 11.4 Unary Operators
-
- function parseUnaryExpression() {
- var token, expr;
-
- if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
- expr = parsePostfixExpression();
- } else if (match('+') || match('-') || match('!')) {
- token = lex();
- expr = parseUnaryExpression();
- expr = delegate.createUnaryExpression(token.value, expr);
- } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
- throwError({}, Messages.UnexpectedToken);
- } else {
- expr = parsePostfixExpression();
- }
-
- return expr;
- }
-
- function binaryPrecedence(token) {
- var prec = 0;
-
- if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
- return 0;
- }
-
- switch (token.value) {
- case '||':
- prec = 1;
- break;
-
- case '&&':
- prec = 2;
- break;
-
- case '==':
- case '!=':
- case '===':
- case '!==':
- prec = 6;
- break;
-
- case '<':
- case '>':
- case '<=':
- case '>=':
- case 'instanceof':
- prec = 7;
- break;
-
- case 'in':
- prec = 7;
- break;
-
- case '+':
- case '-':
- prec = 9;
- break;
-
- case '*':
- case '/':
- case '%':
- prec = 11;
- break;
-
- default:
- break;
- }
-
- return prec;
- }
-
- // 11.5 Multiplicative Operators
- // 11.6 Additive Operators
- // 11.7 Bitwise Shift Operators
- // 11.8 Relational Operators
- // 11.9 Equality Operators
- // 11.10 Binary Bitwise Operators
- // 11.11 Binary Logical Operators
-
- function parseBinaryExpression() {
- var expr, token, prec, stack, right, operator, left, i;
-
- left = parseUnaryExpression();
-
- token = lookahead;
- prec = binaryPrecedence(token);
- if (prec === 0) {
- return left;
- }
- token.prec = prec;
- lex();
-
- right = parseUnaryExpression();
-
- stack = [left, token, right];
-
- while ((prec = binaryPrecedence(lookahead)) > 0) {
-
- // Reduce: make a binary expression from the three topmost entries.
- while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
- right = stack.pop();
- operator = stack.pop().value;
- left = stack.pop();
- expr = delegate.createBinaryExpression(operator, left, right);
- stack.push(expr);
- }
-
- // Shift.
- token = lex();
- token.prec = prec;
- stack.push(token);
- expr = parseUnaryExpression();
- stack.push(expr);
- }
-
- // Final reduce to clean-up the stack.
- i = stack.length - 1;
- expr = stack[i];
- while (i > 1) {
- expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
- i -= 2;
- }
-
- return expr;
- }
-
-
- // 11.12 Conditional Operator
-
- function parseConditionalExpression() {
- var expr, consequent, alternate;
-
- expr = parseBinaryExpression();
-
- if (match('?')) {
- lex();
- consequent = parseConditionalExpression();
- expect(':');
- alternate = parseConditionalExpression();
-
- expr = delegate.createConditionalExpression(expr, consequent, alternate);
- }
-
- return expr;
- }
-
- // Simplification since we do not support AssignmentExpression.
- var parseExpression = parseConditionalExpression;
-
- // Polymer Syntax extensions
-
- // Filter ::
- // Identifier
- // Identifier "(" ")"
- // Identifier "(" FilterArguments ")"
-
- function parseFilter() {
- var identifier, args;
-
- identifier = lex();
-
- if (identifier.type !== Token.Identifier) {
- throwUnexpected(identifier);
- }
-
- args = match('(') ? parseArguments() : [];
-
- return delegate.createFilter(identifier.value, args);
- }
-
- // Filters ::
- // "|" Filter
- // Filters "|" Filter
-
- function parseFilters() {
- while (match('|')) {
- lex();
- parseFilter();
- }
- }
-
- // TopLevel ::
- // LabelledExpressions
- // AsExpression
- // InExpression
- // FilterExpression
-
- // AsExpression ::
- // FilterExpression as Identifier
-
- // InExpression ::
- // Identifier, Identifier in FilterExpression
- // Identifier in FilterExpression
-
- // FilterExpression ::
- // Expression
- // Expression Filters
-
- function parseTopLevel() {
- skipWhitespace();
- peek();
-
- var expr = parseExpression();
- if (expr) {
- if (lookahead.value === ',' || lookahead.value == 'in' &&
- expr.type === Syntax.Identifier) {
- parseInExpression(expr);
- } else {
- parseFilters();
- if (lookahead.value === 'as') {
- parseAsExpression(expr);
- } else {
- delegate.createTopLevel(expr);
- }
- }
- }
-
- if (lookahead.type !== Token.EOF) {
- throwUnexpected(lookahead);
- }
- }
-
- function parseAsExpression(expr) {
- lex(); // as
- var identifier = lex().value;
- delegate.createAsExpression(expr, identifier);
- }
-
- function parseInExpression(identifier) {
- var indexName;
- if (lookahead.value === ',') {
- lex();
- if (lookahead.type !== Token.Identifier)
- throwUnexpected(lookahead);
- indexName = lex().value;
- }
-
- lex(); // in
- var expr = parseExpression();
- parseFilters();
- delegate.createInExpression(identifier.name, indexName, expr);
- }
-
- function parse(code, inDelegate) {
- delegate = inDelegate;
- source = code;
- index = 0;
- length = source.length;
- lookahead = null;
- state = {
- labelSet: {}
- };
-
- return parseTopLevel();
- }
-
- global.esprima = {
- parse: parse
- };
-})(this);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function (global) {
- 'use strict';
-
- function prepareBinding(expressionText, name, node, filterRegistry) {
- var expression;
- try {
- expression = getExpression(expressionText);
- if (expression.scopeIdent &&
- (node.nodeType !== Node.ELEMENT_NODE ||
- node.tagName !== 'TEMPLATE' ||
- (name !== 'bind' && name !== 'repeat'))) {
- throw Error('as and in can only be used within <template bind/repeat>');
- }
- } catch (ex) {
- console.error('Invalid expression syntax: ' + expressionText, ex);
- return;
- }
-
- return function(model, node, oneTime) {
- var binding = expression.getBinding(model, filterRegistry, oneTime);
- if (expression.scopeIdent && binding) {
- node.polymerExpressionScopeIdent_ = expression.scopeIdent;
- if (expression.indexIdent)
- node.polymerExpressionIndexIdent_ = expression.indexIdent;
- }
-
- return binding;
- }
- }
-
- // TODO(rafaelw): Implement simple LRU.
- var expressionParseCache = Object.create(null);
-
- function getExpression(expressionText) {
- var expression = expressionParseCache[expressionText];
- if (!expression) {
- var delegate = new ASTDelegate();
- esprima.parse(expressionText, delegate);
- expression = new Expression(delegate);
- expressionParseCache[expressionText] = expression;
- }
- return expression;
- }
-
- function Literal(value) {
- this.value = value;
- this.valueFn_ = undefined;
- }
-
- Literal.prototype = {
- valueFn: function() {
- if (!this.valueFn_) {
- var value = this.value;
- this.valueFn_ = function() {
- return value;
- }
- }
-
- return this.valueFn_;
- }
- }
-
- function IdentPath(name) {
- this.name = name;
- this.path = Path.get(name);
- }
-
- IdentPath.prototype = {
- valueFn: function() {
- if (!this.valueFn_) {
- var name = this.name;
- var path = this.path;
- this.valueFn_ = function(model, observer) {
- if (observer)
- observer.addPath(model, path);
-
- return path.getValueFrom(model);
- }
- }
-
- return this.valueFn_;
- },
-
- setValue: function(model, newValue) {
- if (this.path.length == 1)
- model = findScope(model, this.path[0]);
-
- return this.path.setValueFrom(model, newValue);
- }
- };
-
- function MemberExpression(object, property, accessor) {
- this.computed = accessor == '[';
-
- this.dynamicDeps = typeof object == 'function' ||
- object.dynamicDeps ||
- (this.computed && !(property instanceof Literal));
-
- this.simplePath =
- !this.dynamicDeps &&
- (property instanceof IdentPath || property instanceof Literal) &&
- (object instanceof MemberExpression || object instanceof IdentPath);
-
- this.object = this.simplePath ? object : getFn(object);
- this.property = !this.computed || this.simplePath ?
- property : getFn(property);
- }
-
- MemberExpression.prototype = {
- get fullPath() {
- if (!this.fullPath_) {
-
- var parts = this.object instanceof MemberExpression ?
- this.object.fullPath.slice() : [this.object.name];
- parts.push(this.property instanceof IdentPath ?
- this.property.name : this.property.value);
- this.fullPath_ = Path.get(parts);
- }
-
- return this.fullPath_;
- },
-
- valueFn: function() {
- if (!this.valueFn_) {
- var object = this.object;
-
- if (this.simplePath) {
- var path = this.fullPath;
-
- this.valueFn_ = function(model, observer) {
- if (observer)
- observer.addPath(model, path);
-
- return path.getValueFrom(model);
- };
- } else if (!this.computed) {
- var path = Path.get(this.property.name);
-
- this.valueFn_ = function(model, observer, filterRegistry) {
- var context = object(model, observer, filterRegistry);
-
- if (observer)
- observer.addPath(context, path);
-
- return path.getValueFrom(context);
- }
- } else {
- // Computed property.
- var property = this.property;
-
- this.valueFn_ = function(model, observer, filterRegistry) {
- var context = object(model, observer, filterRegistry);
- var propName = property(model, observer, filterRegistry);
- if (observer)
- observer.addPath(context, [propName]);
-
- return context ? context[propName] : undefined;
- };
- }
- }
- return this.valueFn_;
- },
-
- setValue: function(model, newValue) {
- if (this.simplePath) {
- this.fullPath.setValueFrom(model, newValue);
- return newValue;
- }
-
- var object = this.object(model);
- var propName = this.property instanceof IdentPath ? this.property.name :
- this.property(model);
- return object[propName] = newValue;
- }
- };
-
- function Filter(name, args) {
- this.name = name;
- this.args = [];
- for (var i = 0; i < args.length; i++) {
- this.args[i] = getFn(args[i]);
- }
- }
-
- Filter.prototype = {
- transform: function(model, observer, filterRegistry, toModelDirection,
- initialArgs) {
- var context = model;
- var fn = context[this.name];
-
- if (!fn) {
- fn = filterRegistry[this.name];
- if (!fn) {
- console.error('Cannot find function or filter: ' + this.name);
- return;
- }
- }
-
- // If toModelDirection is falsey, then the "normal" (dom-bound) direction
- // is used. Otherwise, it looks for a 'toModel' property function on the
- // object.
- if (toModelDirection) {
- fn = fn.toModel;
- } else if (typeof fn.toDOM == 'function') {
- fn = fn.toDOM;
- }
-
- if (typeof fn != 'function') {
- console.error('Cannot find function or filter: ' + this.name);
- return;
- }
-
- var args = initialArgs || [];
- for (var i = 0; i < this.args.length; i++) {
- args.push(getFn(this.args[i])(model, observer, filterRegistry));
- }
-
- return fn.apply(context, args);
- }
- };
-
- function notImplemented() { throw Error('Not Implemented'); }
-
- var unaryOperators = {
- '+': function(v) { return +v; },
- '-': function(v) { return -v; },
- '!': function(v) { return !v; }
- };
-
- var binaryOperators = {
- '+': function(l, r) { return l+r; },
- '-': function(l, r) { return l-r; },
- '*': function(l, r) { return l*r; },
- '/': function(l, r) { return l/r; },
- '%': function(l, r) { return l%r; },
- '<': function(l, r) { return l<r; },
- '>': function(l, r) { return l>r; },
- '<=': function(l, r) { return l<=r; },
- '>=': function(l, r) { return l>=r; },
- '==': function(l, r) { return l==r; },
- '!=': function(l, r) { return l!=r; },
- '===': function(l, r) { return l===r; },
- '!==': function(l, r) { return l!==r; },
- '&&': function(l, r) { return l&&r; },
- '||': function(l, r) { return l||r; },
- };
-
- function getFn(arg) {
- return typeof arg == 'function' ? arg : arg.valueFn();
- }
-
- function ASTDelegate() {
- this.expression = null;
- this.filters = [];
- this.deps = {};
- this.currentPath = undefined;
- this.scopeIdent = undefined;
- this.indexIdent = undefined;
- this.dynamicDeps = false;
- }
-
- ASTDelegate.prototype = {
- createUnaryExpression: function(op, argument) {
- if (!unaryOperators[op])
- throw Error('Disallowed operator: ' + op);
-
- argument = getFn(argument);
-
- return function(model, observer, filterRegistry) {
- return unaryOperators[op](argument(model, observer, filterRegistry));
- };
- },
-
- createBinaryExpression: function(op, left, right) {
- if (!binaryOperators[op])
- throw Error('Disallowed operator: ' + op);
-
- left = getFn(left);
- right = getFn(right);
-
- switch (op) {
- case '||':
- this.dynamicDeps = true;
- return function(model, observer, filterRegistry) {
- return left(model, observer, filterRegistry) ||
- right(model, observer, filterRegistry);
- };
- case '&&':
- this.dynamicDeps = true;
- return function(model, observer, filterRegistry) {
- return left(model, observer, filterRegistry) &&
- right(model, observer, filterRegistry);
- };
- }
-
- return function(model, observer, filterRegistry) {
- return binaryOperators[op](left(model, observer, filterRegistry),
- right(model, observer, filterRegistry));
- };
- },
-
- createConditionalExpression: function(test, consequent, alternate) {
- test = getFn(test);
- consequent = getFn(consequent);
- alternate = getFn(alternate);
-
- this.dynamicDeps = true;
-
- return function(model, observer, filterRegistry) {
- return test(model, observer, filterRegistry) ?
- consequent(model, observer, filterRegistry) :
- alternate(model, observer, filterRegistry);
- }
- },
-
- createIdentifier: function(name) {
- var ident = new IdentPath(name);
- ident.type = 'Identifier';
- return ident;
- },
-
- createMemberExpression: function(accessor, object, property) {
- var ex = new MemberExpression(object, property, accessor);
- if (ex.dynamicDeps)
- this.dynamicDeps = true;
- return ex;
- },
-
- createCallExpression: function(expression, args) {
- if (!(expression instanceof IdentPath))
- throw Error('Only identifier function invocations are allowed');
-
- var filter = new Filter(expression.name, args);
-
- return function(model, observer, filterRegistry) {
- return filter.transform(model, observer, filterRegistry, false);
- };
- },
-
- createLiteral: function(token) {
- return new Literal(token.value);
- },
-
- createArrayExpression: function(elements) {
- for (var i = 0; i < elements.length; i++)
- elements[i] = getFn(elements[i]);
-
- return function(model, observer, filterRegistry) {
- var arr = []
- for (var i = 0; i < elements.length; i++)
- arr.push(elements[i](model, observer, filterRegistry));
- return arr;
- }
- },
-
- createProperty: function(kind, key, value) {
- return {
- key: key instanceof IdentPath ? key.name : key.value,
- value: value
- };
- },
-
- createObjectExpression: function(properties) {
- for (var i = 0; i < properties.length; i++)
- properties[i].value = getFn(properties[i].value);
-
- return function(model, observer, filterRegistry) {
- var obj = {};
- for (var i = 0; i < properties.length; i++)
- obj[properties[i].key] =
- properties[i].value(model, observer, filterRegistry);
- return obj;
- }
- },
-
- createFilter: function(name, args) {
- this.filters.push(new Filter(name, args));
- },
-
- createAsExpression: function(expression, scopeIdent) {
- this.expression = expression;
- this.scopeIdent = scopeIdent;
- },
-
- createInExpression: function(scopeIdent, indexIdent, expression) {
- this.expression = expression;
- this.scopeIdent = scopeIdent;
- this.indexIdent = indexIdent;
- },
-
- createTopLevel: function(expression) {
- this.expression = expression;
- },
-
- createThisExpression: notImplemented
- }
-
- function ConstantObservable(value) {
- this.value_ = value;
- }
-
- ConstantObservable.prototype = {
- open: function() { return this.value_; },
- discardChanges: function() { return this.value_; },
- deliver: function() {},
- close: function() {},
- }
-
- function Expression(delegate) {
- this.scopeIdent = delegate.scopeIdent;
- this.indexIdent = delegate.indexIdent;
-
- if (!delegate.expression)
- throw Error('No expression found.');
-
- this.expression = delegate.expression;
- getFn(this.expression); // forces enumeration of path dependencies
-
- this.filters = delegate.filters;
- this.dynamicDeps = delegate.dynamicDeps;
- }
-
- Expression.prototype = {
- getBinding: function(model, filterRegistry, oneTime) {
- if (oneTime)
- return this.getValue(model, undefined, filterRegistry);
-
- var observer = new CompoundObserver();
- // captures deps.
- var firstValue = this.getValue(model, observer, filterRegistry);
- var firstTime = true;
- var self = this;
-
- function valueFn() {
- // deps cannot have changed on first value retrieval.
- if (firstTime) {
- firstTime = false;
- return firstValue;
- }
-
- if (self.dynamicDeps)
- observer.startReset();
-
- var value = self.getValue(model,
- self.dynamicDeps ? observer : undefined,
- filterRegistry);
- if (self.dynamicDeps)
- observer.finishReset();
-
- return value;
- }
-
- function setValueFn(newValue) {
- self.setValue(model, newValue, filterRegistry);
- return newValue;
- }
-
- return new ObserverTransform(observer, valueFn, setValueFn, true);
- },
-
- getValue: function(model, observer, filterRegistry) {
- var value = getFn(this.expression)(model, observer, filterRegistry);
- for (var i = 0; i < this.filters.length; i++) {
- value = this.filters[i].transform(model, observer, filterRegistry,
- false, [value]);
- }
-
- return value;
- },
-
- setValue: function(model, newValue, filterRegistry) {
- var count = this.filters ? this.filters.length : 0;
- while (count-- > 0) {
- newValue = this.filters[count].transform(model, undefined,
- filterRegistry, true, [newValue]);
- }
-
- if (this.expression.setValue)
- return this.expression.setValue(model, newValue);
- }
- }
-
- /**
- * Converts a style property name to a css property name. For example:
- * "WebkitUserSelect" to "-webkit-user-select"
- */
- function convertStylePropertyName(name) {
- return String(name).replace(/[A-Z]/g, function(c) {
- return '-' + c.toLowerCase();
- });
- }
-
- var parentScopeName = '@' + Math.random().toString(36).slice(2);
-
- // Single ident paths must bind directly to the appropriate scope object.
- // I.e. Pushed values in two-bindings need to be assigned to the actual model
- // object.
- function findScope(model, prop) {
- while (model[parentScopeName] &&
- !Object.prototype.hasOwnProperty.call(model, prop)) {
- model = model[parentScopeName];
- }
-
- return model;
- }
-
- function isLiteralExpression(pathString) {
- switch (pathString) {
- case '':
- return false;
-
- case 'false':
- case 'null':
- case 'true':
- return true;
- }
-
- if (!isNaN(Number(pathString)))
- return true;
-
- return false;
- };
-
- function PolymerExpressions() {}
-
- PolymerExpressions.prototype = {
- // "built-in" filters
- styleObject: function(value) {
- var parts = [];
- for (var key in value) {
- parts.push(convertStylePropertyName(key) + ': ' + value[key]);
- }
- return parts.join('; ');
- },
-
- tokenList: function(value) {
- var tokens = [];
- for (var key in value) {
- if (value[key])
- tokens.push(key);
- }
- return tokens.join(' ');
- },
-
- // binding delegate API
- prepareInstancePositionChanged: function(template) {
- var indexIdent = template.polymerExpressionIndexIdent_;
- if (!indexIdent)
- return;
-
- return function(templateInstance, index) {
- templateInstance.model[indexIdent] = index;
- };
- },
-
- prepareBinding: function(pathString, name, node) {
- var path = Path.get(pathString);
-
- if (!isLiteralExpression(pathString) && path.valid) {
- if (path.length == 1) {
- return function(model, node, oneTime) {
- if (oneTime)
- return path.getValueFrom(model);
-
- var scope = findScope(model, path[0]);
- return new PathObserver(scope, path);
- };
- }
- return; // bail out early if pathString is simple path.
- }
-
- return prepareBinding(pathString, name, node, this);
- },
-
- prepareInstanceModel: function(template) {
- var scopeName = template.polymerExpressionScopeIdent_;
- if (!scopeName)
- return;
-
- var parentScope = template.templateInstance ?
- template.templateInstance.model :
- template.model;
-
- var indexName = template.polymerExpressionIndexIdent_;
-
- return function(model) {
- return createScopeObject(parentScope, model, scopeName, indexName);
- };
- }
- };
-
- var createScopeObject = ('__proto__' in {}) ?
- function(parentScope, model, scopeName, indexName) {
- var scope = {};
- scope[scopeName] = model;
- scope[indexName] = undefined;
- scope[parentScopeName] = parentScope;
- scope.__proto__ = parentScope;
- return scope;
- } :
- function(parentScope, model, scopeName, indexName) {
- var scope = Object.create(parentScope);
- Object.defineProperty(scope, scopeName,
- { value: model, configurable: true, writable: true });
- Object.defineProperty(scope, indexName,
- { value: undefined, configurable: true, writable: true });
- Object.defineProperty(scope, parentScopeName,
- { value: parentScope, configurable: true, writable: true });
- return scope;
- };
-
- global.PolymerExpressions = PolymerExpressions;
- PolymerExpressions.getExpression = getExpression;
-})(this);
-
-Polymer = {
- version: '0.5.5'
-};
-
-// TODO(sorvell): this ensures Polymer is an object and not a function
-// Platform is currently defining it as a function to allow for async loading
-// of polymer; once we refine the loading process this likely goes away.
-if (typeof window.Polymer === 'function') {
- Polymer = {};
-}
-
-
-(function(scope) {
-
- function withDependencies(task, depends) {
- depends = depends || [];
- if (!depends.map) {
- depends = [depends];
- }
- return task.apply(this, depends.map(marshal));
- }
-
- function module(name, dependsOrFactory, moduleFactory) {
- var module;
- switch (arguments.length) {
- case 0:
- return;
- case 1:
- module = null;
- break;
- case 2:
- // dependsOrFactory is `factory` in this case
- module = dependsOrFactory.apply(this);
- break;
- default:
- // dependsOrFactory is `depends` in this case
- module = withDependencies(moduleFactory, dependsOrFactory);
- break;
- }
- modules[name] = module;
- };
-
- function marshal(name) {
- return modules[name];
- }
-
- var modules = {};
-
- function using(depends, task) {
- HTMLImports.whenImportsReady(function() {
- withDependencies(task, depends);
- });
- };
-
- // exports
-
- scope.marshal = marshal;
- // `module` confuses commonjs detectors
- scope.modularize = module;
- scope.using = using;
-
-})(window);
-
-/*
- Build only script.
-
- Ensures scripts needed for basic x-platform compatibility
- will be run when platform.js is not loaded.
- */
-if (!window.WebComponents) {
-
-/*
- On supported platforms, platform.js is not needed. To retain compatibility
- with the polyfills, we stub out minimal functionality.
- */
-if (!window.WebComponents) {
-
- WebComponents = {
- flush: function() {},
- flags: {log: {}}
- };
-
- Platform = WebComponents;
-
- CustomElements = {
- useNative: true,
- ready: true,
- takeRecords: function() {},
- instanceof: function(obj, base) {
- return obj instanceof base;
- }
- };
-
- HTMLImports = {
- useNative: true
- };
-
-
- addEventListener('HTMLImportsLoaded', function() {
- document.dispatchEvent(
- new CustomEvent('WebComponentsReady', {bubbles: true})
- );
- });
-
-
- // ShadowDOM
- ShadowDOMPolyfill = null;
- wrap = unwrap = function(n){
- return n;
- };
-
-}
-
-/*
- Create polyfill scope and feature detect native support.
-*/
-window.HTMLImports = window.HTMLImports || {flags:{}};
-
-(function(scope) {
-
-/**
- Basic setup and simple module executer. We collect modules and then execute
- the code later, only if it's necessary for polyfilling.
-*/
-var IMPORT_LINK_TYPE = 'import';
-var useNative = Boolean(IMPORT_LINK_TYPE in document.createElement('link'));
-
-/**
- Support `currentScript` on all browsers as `document._currentScript.`
-
- NOTE: We cannot polyfill `document.currentScript` because it's not possible
- both to override and maintain the ability to capture the native value.
- Therefore we choose to expose `_currentScript` both when native imports
- and the polyfill are in use.
-*/
-// NOTE: ShadowDOMPolyfill intrusion.
-var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
-var wrap = function(node) {
- return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
-};
-var rootDocument = wrap(document);
-
-var currentScriptDescriptor = {
- get: function() {
- var script = HTMLImports.currentScript || document.currentScript ||
- // NOTE: only works when called in synchronously executing code.
- // readyState should check if `loading` but IE10 is
- // interactive when scripts run so we cheat.
- (document.readyState !== 'complete' ?
- document.scripts[document.scripts.length - 1] : null);
- return wrap(script);
- },
- configurable: true
-};
-
-Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
-Object.defineProperty(rootDocument, '_currentScript', currentScriptDescriptor);
-
-/**
- Add support for the `HTMLImportsLoaded` event and the `HTMLImports.whenReady`
- method. This api is necessary because unlike the native implementation,
- script elements do not force imports to resolve. Instead, users should wrap
- code in either an `HTMLImportsLoaded` hander or after load time in an
- `HTMLImports.whenReady(callback)` call.
-
- NOTE: This module also supports these apis under the native implementation.
- Therefore, if this file is loaded, the same code can be used under both
- the polyfill and native implementation.
- */
-
-var isIE = /Trident/.test(navigator.userAgent);
-
-// call a callback when all HTMLImports in the document at call time
-// (or at least document ready) have loaded.
-// 1. ensure the document is in a ready state (has dom), then
-// 2. watch for loading of imports and call callback when done
-function whenReady(callback, doc) {
- doc = doc || rootDocument;
- // if document is loading, wait and try again
- whenDocumentReady(function() {
- watchImportsLoad(callback, doc);
- }, doc);
-}
-
-// call the callback when the document is in a ready state (has dom)
-var requiredReadyState = isIE ? 'complete' : 'interactive';
-var READY_EVENT = 'readystatechange';
-function isDocumentReady(doc) {
- return (doc.readyState === 'complete' ||
- doc.readyState === requiredReadyState);
-}
-
-// call <callback> when we ensure the document is in a ready state
-function whenDocumentReady(callback, doc) {
- if (!isDocumentReady(doc)) {
- var checkReady = function() {
- if (doc.readyState === 'complete' ||
- doc.readyState === requiredReadyState) {
- doc.removeEventListener(READY_EVENT, checkReady);
- whenDocumentReady(callback, doc);
- }
- };
- doc.addEventListener(READY_EVENT, checkReady);
- } else if (callback) {
- callback();
- }
-}
-
-function markTargetLoaded(event) {
- event.target.__loaded = true;
-}
-
-// call <callback> when we ensure all imports have loaded
-function watchImportsLoad(callback, doc) {
- var imports = doc.querySelectorAll('link[rel=import]');
- var loaded = 0, l = imports.length;
- function checkDone(d) {
- if ((loaded == l) && callback) {
- callback();
- }
- }
- function loadedImport(e) {
- markTargetLoaded(e);
- loaded++;
- checkDone();
- }
- if (l) {
- for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
- if (isImportLoaded(imp)) {
- loadedImport.call(imp, {target: imp});
- } else {
- imp.addEventListener('load', loadedImport);
- imp.addEventListener('error', loadedImport);
- }
- }
- } else {
- checkDone();
- }
-}
-
-// NOTE: test for native imports loading is based on explicitly watching
-// all imports (see below).
-// However, we cannot rely on this entirely without watching the entire document
-// for import links. For perf reasons, currently only head is watched.
-// Instead, we fallback to checking if the import property is available
-// and the document is not itself loading.
-function isImportLoaded(link) {
- return useNative ? link.__loaded ||
- (link.import && link.import.readyState !== 'loading') :
- link.__importParsed;
-}
-
-// TODO(sorvell): Workaround for
-// https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when
-// this bug is addressed.
-// (1) Install a mutation observer to see when HTMLImports have loaded
-// (2) if this script is run during document load it will watch any existing
-// imports for loading.
-//
-// NOTE: The workaround has restricted functionality: (1) it's only compatible
-// with imports that are added to document.head since the mutation observer
-// watches only head for perf reasons, (2) it requires this script
-// to run before any imports have completed loading.
-if (useNative) {
- new MutationObserver(function(mxns) {
- for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
- if (m.addedNodes) {
- handleImports(m.addedNodes);
- }
- }
- }).observe(document.head, {childList: true});
-
- function handleImports(nodes) {
- for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
- if (isImport(n)) {
- handleImport(n);
- }
- }
- }
-
- function isImport(element) {
- return element.localName === 'link' && element.rel === 'import';
- }
-
- function handleImport(element) {
- var loaded = element.import;
- if (loaded) {
- markTargetLoaded({target: element});
- } else {
- element.addEventListener('load', markTargetLoaded);
- element.addEventListener('error', markTargetLoaded);
- }
- }
-
- // make sure to catch any imports that are in the process of loading
- // when this script is run.
- (function() {
- if (document.readyState === 'loading') {
- var imports = document.querySelectorAll('link[rel=import]');
- for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) {
- handleImport(imp);
- }
- }
- })();
-
-}
-
-// Fire the 'HTMLImportsLoaded' event when imports in document at load time
-// have loaded. This event is required to simulate the script blocking
-// behavior of native imports. A main document script that needs to be sure
-// imports have loaded should wait for this event.
-whenReady(function() {
- HTMLImports.ready = true;
- HTMLImports.readyTime = new Date().getTime();
- rootDocument.dispatchEvent(
- new CustomEvent('HTMLImportsLoaded', {bubbles: true})
- );
-});
-
-// exports
-scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
-scope.useNative = useNative;
-scope.rootDocument = rootDocument;
-scope.whenReady = whenReady;
-scope.isIE = isIE;
-
-})(HTMLImports);
-
-(function(scope) {
-
- // TODO(sorvell): It's desireable to provide a default stylesheet
- // that's convenient for styling unresolved elements, but
- // it's cumbersome to have to include this manually in every page.
- // It would make sense to put inside some HTMLImport but
- // the HTMLImports polyfill does not allow loading of stylesheets
- // that block rendering. Therefore this injection is tolerated here.
- var style = document.createElement('style');
- style.textContent = ''
- + 'body {'
- + 'transition: opacity ease-in 0.2s;'
- + ' } \n'
- + 'body[unresolved] {'
- + 'opacity: 0; display: block; overflow: hidden;'
- + ' } \n'
- ;
- var head = document.querySelector('head');
- head.insertBefore(style, head.firstChild);
-
-})(Platform);
-
-/*
- Build only script.
-
- Ensures scripts needed for basic x-platform compatibility
- will be run when platform.js is not loaded.
- */
-}
-(function(global) {
- 'use strict';
-
- var testingExposeCycleCount = global.testingExposeCycleCount;
-
- // Detect and do basic sanity checking on Object/Array.observe.
- function detectObjectObserve() {
- if (typeof Object.observe !== 'function' ||
- typeof Array.observe !== 'function') {
- return false;
- }
-
- var records = [];
-
- function callback(recs) {
- records = recs;
- }
-
- var test = {};
- var arr = [];
- Object.observe(test, callback);
- Array.observe(arr, callback);
- test.id = 1;
- test.id = 2;
- delete test.id;
- arr.push(1, 2);
- arr.length = 0;
-
- Object.deliverChangeRecords(callback);
- if (records.length !== 5)
- return false;
-
- if (records[0].type != 'add' ||
- records[1].type != 'update' ||
- records[2].type != 'delete' ||
- records[3].type != 'splice' ||
- records[4].type != 'splice') {
- return false;
- }
-
- Object.unobserve(test, callback);
- Array.unobserve(arr, callback);
-
- return true;
- }
-
- var hasObserve = detectObjectObserve();
-
- function detectEval() {
- // Don't test for eval if we're running in a Chrome App environment.
- // We check for APIs set that only exist in a Chrome App context.
- if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
- return false;
- }
-
- // Firefox OS Apps do not allow eval. This feature detection is very hacky
- // but even if some other platform adds support for this function this code
- // will continue to work.
- if (typeof navigator != 'undefined' && navigator.getDeviceStorage) {
- return false;
- }
-
- try {
- var f = new Function('', 'return true;');
- return f();
- } catch (ex) {
- return false;
- }
- }
-
- var hasEval = detectEval();
-
- function isIndex(s) {
- return +s === s >>> 0 && s !== '';
- }
-
- function toNumber(s) {
- return +s;
- }
-
- function isObject(obj) {
- return obj === Object(obj);
- }
-
- var numberIsNaN = global.Number.isNaN || function(value) {
- return typeof value === 'number' && global.isNaN(value);
- }
-
- function areSameValue(left, right) {
- if (left === right)
- return left !== 0 || 1 / left === 1 / right;
- if (numberIsNaN(left) && numberIsNaN(right))
- return true;
-
- return left !== left && right !== right;
- }
-
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- var identStart = '[\$_a-zA-Z]';
- var identPart = '[\$_a-zA-Z0-9]';
- var identRegExp = new RegExp('^' + identStart + '+' + identPart + '*' + '$');
-
- function getPathCharType(char) {
- if (char === undefined)
- return 'eof';
-
- var code = char.charCodeAt(0);
-
- switch(code) {
- case 0x5B: // [
- case 0x5D: // ]
- case 0x2E: // .
- case 0x22: // "
- case 0x27: // '
- case 0x30: // 0
- return char;
-
- case 0x5F: // _
- case 0x24: // $
- return 'ident';
-
- case 0x20: // Space
- case 0x09: // Tab
- case 0x0A: // Newline
- case 0x0D: // Return
- case 0xA0: // No-break space
- case 0xFEFF: // Byte Order Mark
- case 0x2028: // Line Separator
- case 0x2029: // Paragraph Separator
- return 'ws';
- }
-
- // a-z, A-Z
- if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
- return 'ident';
-
- // 1-9
- if (0x31 <= code && code <= 0x39)
- return 'number';
-
- return 'else';
- }
-
- var pathStateMachine = {
- 'beforePath': {
- 'ws': ['beforePath'],
- 'ident': ['inIdent', 'append'],
- '[': ['beforeElement'],
- 'eof': ['afterPath']
- },
-
- 'inPath': {
- 'ws': ['inPath'],
- '.': ['beforeIdent'],
- '[': ['beforeElement'],
- 'eof': ['afterPath']
- },
-
- 'beforeIdent': {
- 'ws': ['beforeIdent'],
- 'ident': ['inIdent', 'append']
- },
-
- 'inIdent': {
- 'ident': ['inIdent', 'append'],
- '0': ['inIdent', 'append'],
- 'number': ['inIdent', 'append'],
- 'ws': ['inPath', 'push'],
- '.': ['beforeIdent', 'push'],
- '[': ['beforeElement', 'push'],
- 'eof': ['afterPath', 'push']
- },
-
- 'beforeElement': {
- 'ws': ['beforeElement'],
- '0': ['afterZero', 'append'],
- 'number': ['inIndex', 'append'],
- "'": ['inSingleQuote', 'append', ''],
- '"': ['inDoubleQuote', 'append', '']
- },
-
- 'afterZero': {
- 'ws': ['afterElement', 'push'],
- ']': ['inPath', 'push']
- },
-
- 'inIndex': {
- '0': ['inIndex', 'append'],
- 'number': ['inIndex', 'append'],
- 'ws': ['afterElement'],
- ']': ['inPath', 'push']
- },
-
- 'inSingleQuote': {
- "'": ['afterElement'],
- 'eof': ['error'],
- 'else': ['inSingleQuote', 'append']
- },
-
- 'inDoubleQuote': {
- '"': ['afterElement'],
- 'eof': ['error'],
- 'else': ['inDoubleQuote', 'append']
- },
-
- 'afterElement': {
- 'ws': ['afterElement'],
- ']': ['inPath', 'push']
- }
- }
-
- function noop() {}
-
- function parsePath(path) {
- var keys = [];
- var index = -1;
- var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath';
-
- var actions = {
- push: function() {
- if (key === undefined)
- return;
-
- keys.push(key);
- key = undefined;
- },
-
- append: function() {
- if (key === undefined)
- key = newChar
- else
- key += newChar;
- }
- };
-
- function maybeUnescapeQuote() {
- if (index >= path.length)
- return;
-
- var nextChar = path[index + 1];
- if ((mode == 'inSingleQuote' && nextChar == "'") ||
- (mode == 'inDoubleQuote' && nextChar == '"')) {
- index++;
- newChar = nextChar;
- actions.append();
- return true;
- }
- }
-
- while (mode) {
- index++;
- c = path[index];
-
- if (c == '\\' && maybeUnescapeQuote(mode))
- continue;
-
- type = getPathCharType(c);
- typeMap = pathStateMachine[mode];
- transition = typeMap[type] || typeMap['else'] || 'error';
-
- if (transition == 'error')
- return; // parse error;
-
- mode = transition[0];
- action = actions[transition[1]] || noop;
- newChar = transition[2] === undefined ? c : transition[2];
- action();
-
- if (mode === 'afterPath') {
- return keys;
- }
- }
-
- return; // parse error
- }
-
- function isIdent(s) {
- return identRegExp.test(s);
- }
-
- var constructorIsPrivate = {};
-
- function Path(parts, privateToken) {
- if (privateToken !== constructorIsPrivate)
- throw Error('Use Path.get to retrieve path objects');
-
- for (var i = 0; i < parts.length; i++) {
- this.push(String(parts[i]));
- }
-
- if (hasEval && this.length) {
- this.getValueFrom = this.compiledGetValueFromFn();
- }
- }
-
- // TODO(rafaelw): Make simple LRU cache
- var pathCache = {};
-
- function getPath(pathString) {
- if (pathString instanceof Path)
- return pathString;
-
- if (pathString == null || pathString.length == 0)
- pathString = '';
-
- if (typeof pathString != 'string') {
- if (isIndex(pathString.length)) {
- // Constructed with array-like (pre-parsed) keys
- return new Path(pathString, constructorIsPrivate);
- }
-
- pathString = String(pathString);
- }
-
- var path = pathCache[pathString];
- if (path)
- return path;
-
- var parts = parsePath(pathString);
- if (!parts)
- return invalidPath;
-
- var path = new Path(parts, constructorIsPrivate);
- pathCache[pathString] = path;
- return path;
- }
-
- Path.get = getPath;
-
- function formatAccessor(key) {
- if (isIndex(key)) {
- return '[' + key + ']';
- } else {
- return '["' + key.replace(/"/g, '\\"') + '"]';
- }
- }
-
- Path.prototype = createObject({
- __proto__: [],
- valid: true,
-
- toString: function() {
- var pathString = '';
- for (var i = 0; i < this.length; i++) {
- var key = this[i];
- if (isIdent(key)) {
- pathString += i ? '.' + key : key;
- } else {
- pathString += formatAccessor(key);
- }
- }
-
- return pathString;
- },
-
- getValueFrom: function(obj, directObserver) {
- for (var i = 0; i < this.length; i++) {
- if (obj == null)
- return;
- obj = obj[this[i]];
- }
- return obj;
- },
-
- iterateObjects: function(obj, observe) {
- for (var i = 0; i < this.length; i++) {
- if (i)
- obj = obj[this[i - 1]];
- if (!isObject(obj))
- return;
- observe(obj, this[i]);
- }
- },
-
- compiledGetValueFromFn: function() {
- var str = '';
- var pathString = 'obj';
- str += 'if (obj != null';
- var i = 0;
- var key;
- for (; i < (this.length - 1); i++) {
- key = this[i];
- pathString += isIdent(key) ? '.' + key : formatAccessor(key);
- str += ' &&\n ' + pathString + ' != null';
- }
- str += ')\n';
-
- var key = this[i];
- pathString += isIdent(key) ? '.' + key : formatAccessor(key);
-
- str += ' return ' + pathString + ';\nelse\n return undefined;';
- return new Function('obj', str);
- },
-
- setValueFrom: function(obj, value) {
- if (!this.length)
- return false;
-
- for (var i = 0; i < this.length - 1; i++) {
- if (!isObject(obj))
- return false;
- obj = obj[this[i]];
- }
-
- if (!isObject(obj))
- return false;
-
- obj[this[i]] = value;
- return true;
- }
- });
-
- var invalidPath = new Path('', constructorIsPrivate);
- invalidPath.valid = false;
- invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
-
- var MAX_DIRTY_CHECK_CYCLES = 1000;
-
- function dirtyCheck(observer) {
- var cycles = 0;
- while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
- cycles++;
- }
- if (testingExposeCycleCount)
- global.dirtyCheckCycleCount = cycles;
-
- return cycles > 0;
- }
-
- function objectIsEmpty(object) {
- for (var prop in object)
- return false;
- return true;
- }
-
- function diffIsEmpty(diff) {
- return objectIsEmpty(diff.added) &&
- objectIsEmpty(diff.removed) &&
- objectIsEmpty(diff.changed);
- }
-
- function diffObjectFromOldObject(object, oldObject) {
- var added = {};
- var removed = {};
- var changed = {};
-
- for (var prop in oldObject) {
- var newValue = object[prop];
-
- if (newValue !== undefined && newValue === oldObject[prop])
- continue;
-
- if (!(prop in object)) {
- removed[prop] = undefined;
- continue;
- }
-
- if (newValue !== oldObject[prop])
- changed[prop] = newValue;
- }
-
- for (var prop in object) {
- if (prop in oldObject)
- continue;
-
- added[prop] = object[prop];
- }
-
- if (Array.isArray(object) && object.length !== oldObject.length)
- changed.length = object.length;
-
- return {
- added: added,
- removed: removed,
- changed: changed
- };
- }
-
- var eomTasks = [];
- function runEOMTasks() {
- if (!eomTasks.length)
- return false;
-
- for (var i = 0; i < eomTasks.length; i++) {
- eomTasks[i]();
- }
- eomTasks.length = 0;
- return true;
- }
-
- var runEOM = hasObserve ? (function(){
- return function(fn) {
- return Promise.resolve().then(fn);
- }
- })() :
- (function() {
- return function(fn) {
- eomTasks.push(fn);
- };
- })();
-
- var observedObjectCache = [];
-
- function newObservedObject() {
- var observer;
- var object;
- var discardRecords = false;
- var first = true;
-
- function callback(records) {
- if (observer && observer.state_ === OPENED && !discardRecords)
- observer.check_(records);
- }
-
- return {
- open: function(obs) {
- if (observer)
- throw Error('ObservedObject in use');
-
- if (!first)
- Object.deliverChangeRecords(callback);
-
- observer = obs;
- first = false;
- },
- observe: function(obj, arrayObserve) {
- object = obj;
- if (arrayObserve)
- Array.observe(object, callback);
- else
- Object.observe(object, callback);
- },
- deliver: function(discard) {
- discardRecords = discard;
- Object.deliverChangeRecords(callback);
- discardRecords = false;
- },
- close: function() {
- observer = undefined;
- Object.unobserve(object, callback);
- observedObjectCache.push(this);
- }
- };
- }
-
- /*
- * The observedSet abstraction is a perf optimization which reduces the total
- * number of Object.observe observations of a set of objects. The idea is that
- * groups of Observers will have some object dependencies in common and this
- * observed set ensures that each object in the transitive closure of
- * dependencies is only observed once. The observedSet acts as a write barrier
- * such that whenever any change comes through, all Observers are checked for
- * changed values.
- *
- * Note that this optimization is explicitly moving work from setup-time to
- * change-time.
- *
- * TODO(rafaelw): Implement "garbage collection". In order to move work off
- * the critical path, when Observers are closed, their observed objects are
- * not Object.unobserve(d). As a result, it's possible that if the observedSet
- * is kept open, but some Observers have been closed, it could cause "leaks"
- * (prevent otherwise collectable objects from being collected). At some
- * point, we should implement incremental "gc" which keeps a list of
- * observedSets which may need clean-up and does small amounts of cleanup on a
- * timeout until all is clean.
- */
-
- function getObservedObject(observer, object, arrayObserve) {
- var dir = observedObjectCache.pop() || newObservedObject();
- dir.open(observer);
- dir.observe(object, arrayObserve);
- return dir;
- }
-
- var observedSetCache = [];
-
- function newObservedSet() {
- var observerCount = 0;
- var observers = [];
- var objects = [];
- var rootObj;
- var rootObjProps;
-
- function observe(obj, prop) {
- if (!obj)
- return;
-
- if (obj === rootObj)
- rootObjProps[prop] = true;
-
- if (objects.indexOf(obj) < 0) {
- objects.push(obj);
- Object.observe(obj, callback);
- }
-
- observe(Object.getPrototypeOf(obj), prop);
- }
-
- function allRootObjNonObservedProps(recs) {
- for (var i = 0; i < recs.length; i++) {
- var rec = recs[i];
- if (rec.object !== rootObj ||
- rootObjProps[rec.name] ||
- rec.type === 'setPrototype') {
- return false;
- }
- }
- return true;
- }
-
- function callback(recs) {
- if (allRootObjNonObservedProps(recs))
- return;
-
- var observer;
- for (var i = 0; i < observers.length; i++) {
- observer = observers[i];
- if (observer.state_ == OPENED) {
- observer.iterateObjects_(observe);
- }
- }
-
- for (var i = 0; i < observers.length; i++) {
- observer = observers[i];
- if (observer.state_ == OPENED) {
- observer.check_();
- }
- }
- }
-
- var record = {
- objects: objects,
- get rootObject() { return rootObj; },
- set rootObject(value) {
- rootObj = value;
- rootObjProps = {};
- },
- open: function(obs, object) {
- observers.push(obs);
- observerCount++;
- obs.iterateObjects_(observe);
- },
- close: function(obs) {
- observerCount--;
- if (observerCount > 0) {
- return;
- }
-
- for (var i = 0; i < objects.length; i++) {
- Object.unobserve(objects[i], callback);
- Observer.unobservedCount++;
- }
-
- observers.length = 0;
- objects.length = 0;
- rootObj = undefined;
- rootObjProps = undefined;
- observedSetCache.push(this);
- if (lastObservedSet === this)
- lastObservedSet = null;
- },
- };
-
- return record;
- }
-
- var lastObservedSet;
-
- function getObservedSet(observer, obj) {
- if (!lastObservedSet || lastObservedSet.rootObject !== obj) {
- lastObservedSet = observedSetCache.pop() || newObservedSet();
- lastObservedSet.rootObject = obj;
- }
- lastObservedSet.open(observer, obj);
- return lastObservedSet;
- }
-
- var UNOPENED = 0;
- var OPENED = 1;
- var CLOSED = 2;
- var RESETTING = 3;
-
- var nextObserverId = 1;
-
- function Observer() {
- this.state_ = UNOPENED;
- this.callback_ = undefined;
- this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
- this.directObserver_ = undefined;
- this.value_ = undefined;
- this.id_ = nextObserverId++;
- }
-
- Observer.prototype = {
- open: function(callback, target) {
- if (this.state_ != UNOPENED)
- throw Error('Observer has already been opened.');
-
- addToAll(this);
- this.callback_ = callback;
- this.target_ = target;
- this.connect_();
- this.state_ = OPENED;
- return this.value_;
- },
-
- close: function() {
- if (this.state_ != OPENED)
- return;
-
- removeFromAll(this);
- this.disconnect_();
- this.value_ = undefined;
- this.callback_ = undefined;
- this.target_ = undefined;
- this.state_ = CLOSED;
- },
-
- deliver: function() {
- if (this.state_ != OPENED)
- return;
-
- dirtyCheck(this);
- },
-
- report_: function(changes) {
- try {
- this.callback_.apply(this.target_, changes);
- } catch (ex) {
- Observer._errorThrownDuringCallback = true;
- console.error('Exception caught during observer callback: ' +
- (ex.stack || ex));
- }
- },
-
- discardChanges: function() {
- this.check_(undefined, true);
- return this.value_;
- }
- }
-
- var collectObservers = !hasObserve;
- var allObservers;
- Observer._allObserversCount = 0;
-
- if (collectObservers) {
- allObservers = [];
- }
-
- function addToAll(observer) {
- Observer._allObserversCount++;
- if (!collectObservers)
- return;
-
- allObservers.push(observer);
- }
-
- function removeFromAll(observer) {
- Observer._allObserversCount--;
- }
-
- var runningMicrotaskCheckpoint = false;
-
- global.Platform = global.Platform || {};
-
- global.Platform.performMicrotaskCheckpoint = function() {
- if (runningMicrotaskCheckpoint)
- return;
-
- if (!collectObservers)
- return;
-
- runningMicrotaskCheckpoint = true;
-
- var cycles = 0;
- var anyChanged, toCheck;
-
- do {
- cycles++;
- toCheck = allObservers;
- allObservers = [];
- anyChanged = false;
-
- for (var i = 0; i < toCheck.length; i++) {
- var observer = toCheck[i];
- if (observer.state_ != OPENED)
- continue;
-
- if (observer.check_())
- anyChanged = true;
-
- allObservers.push(observer);
- }
- if (runEOMTasks())
- anyChanged = true;
- } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
-
- if (testingExposeCycleCount)
- global.dirtyCheckCycleCount = cycles;
-
- runningMicrotaskCheckpoint = false;
- };
-
- if (collectObservers) {
- global.Platform.clearObservers = function() {
- allObservers = [];
- };
- }
-
- function ObjectObserver(object) {
- Observer.call(this);
- this.value_ = object;
- this.oldObject_ = undefined;
- }
-
- ObjectObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- arrayObserve: false,
-
- connect_: function(callback, target) {
- if (hasObserve) {
- this.directObserver_ = getObservedObject(this, this.value_,
- this.arrayObserve);
- } else {
- this.oldObject_ = this.copyObject(this.value_);
- }
-
- },
-
- copyObject: function(object) {
- var copy = Array.isArray(object) ? [] : {};
- for (var prop in object) {
- copy[prop] = object[prop];
- };
- if (Array.isArray(object))
- copy.length = object.length;
- return copy;
- },
-
- check_: function(changeRecords, skipChanges) {
- var diff;
- var oldValues;
- if (hasObserve) {
- if (!changeRecords)
- return false;
-
- oldValues = {};
- diff = diffObjectFromChangeRecords(this.value_, changeRecords,
- oldValues);
- } else {
- oldValues = this.oldObject_;
- diff = diffObjectFromOldObject(this.value_, this.oldObject_);
- }
-
- if (diffIsEmpty(diff))
- return false;
-
- if (!hasObserve)
- this.oldObject_ = this.copyObject(this.value_);
-
- this.report_([
- diff.added || {},
- diff.removed || {},
- diff.changed || {},
- function(property) {
- return oldValues[property];
- }
- ]);
-
- return true;
- },
-
- disconnect_: function() {
- if (hasObserve) {
- this.directObserver_.close();
- this.directObserver_ = undefined;
- } else {
- this.oldObject_ = undefined;
- }
- },
-
- deliver: function() {
- if (this.state_ != OPENED)
- return;
-
- if (hasObserve)
- this.directObserver_.deliver(false);
- else
- dirtyCheck(this);
- },
-
- discardChanges: function() {
- if (this.directObserver_)
- this.directObserver_.deliver(true);
- else
- this.oldObject_ = this.copyObject(this.value_);
-
- return this.value_;
- }
- });
-
- function ArrayObserver(array) {
- if (!Array.isArray(array))
- throw Error('Provided object is not an Array');
- ObjectObserver.call(this, array);
- }
-
- ArrayObserver.prototype = createObject({
-
- __proto__: ObjectObserver.prototype,
-
- arrayObserve: true,
-
- copyObject: function(arr) {
- return arr.slice();
- },
-
- check_: function(changeRecords) {
- var splices;
- if (hasObserve) {
- if (!changeRecords)
- return false;
- splices = projectArraySplices(this.value_, changeRecords);
- } else {
- splices = calcSplices(this.value_, 0, this.value_.length,
- this.oldObject_, 0, this.oldObject_.length);
- }
-
- if (!splices || !splices.length)
- return false;
-
- if (!hasObserve)
- this.oldObject_ = this.copyObject(this.value_);
-
- this.report_([splices]);
- return true;
- }
- });
-
- ArrayObserver.applySplices = function(previous, current, splices) {
- splices.forEach(function(splice) {
- var spliceArgs = [splice.index, splice.removed.length];
- var addIndex = splice.index;
- while (addIndex < splice.index + splice.addedCount) {
- spliceArgs.push(current[addIndex]);
- addIndex++;
- }
-
- Array.prototype.splice.apply(previous, spliceArgs);
- });
- };
-
- function PathObserver(object, path) {
- Observer.call(this);
-
- this.object_ = object;
- this.path_ = getPath(path);
- this.directObserver_ = undefined;
- }
-
- PathObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- get path() {
- return this.path_;
- },
-
- connect_: function() {
- if (hasObserve)
- this.directObserver_ = getObservedSet(this, this.object_);
-
- this.check_(undefined, true);
- },
-
- disconnect_: function() {
- this.value_ = undefined;
-
- if (this.directObserver_) {
- this.directObserver_.close(this);
- this.directObserver_ = undefined;
- }
- },
-
- iterateObjects_: function(observe) {
- this.path_.iterateObjects(this.object_, observe);
- },
-
- check_: function(changeRecords, skipChanges) {
- var oldValue = this.value_;
- this.value_ = this.path_.getValueFrom(this.object_);
- if (skipChanges || areSameValue(this.value_, oldValue))
- return false;
-
- this.report_([this.value_, oldValue, this]);
- return true;
- },
-
- setValue: function(newValue) {
- if (this.path_)
- this.path_.setValueFrom(this.object_, newValue);
- }
- });
-
- function CompoundObserver(reportChangesOnOpen) {
- Observer.call(this);
-
- this.reportChangesOnOpen_ = reportChangesOnOpen;
- this.value_ = [];
- this.directObserver_ = undefined;
- this.observed_ = [];
- }
-
- var observerSentinel = {};
-
- CompoundObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- connect_: function() {
- if (hasObserve) {
- var object;
- var needsDirectObserver = false;
- for (var i = 0; i < this.observed_.length; i += 2) {
- object = this.observed_[i]
- if (object !== observerSentinel) {
- needsDirectObserver = true;
- break;
- }
- }
-
- if (needsDirectObserver)
- this.directObserver_ = getObservedSet(this, object);
- }
-
- this.check_(undefined, !this.reportChangesOnOpen_);
- },
-
- disconnect_: function() {
- for (var i = 0; i < this.observed_.length; i += 2) {
- if (this.observed_[i] === observerSentinel)
- this.observed_[i + 1].close();
- }
- this.observed_.length = 0;
- this.value_.length = 0;
-
- if (this.directObserver_) {
- this.directObserver_.close(this);
- this.directObserver_ = undefined;
- }
- },
-
- addPath: function(object, path) {
- if (this.state_ != UNOPENED && this.state_ != RESETTING)
- throw Error('Cannot add paths once started.');
-
- var path = getPath(path);
- this.observed_.push(object, path);
- if (!this.reportChangesOnOpen_)
- return;
- var index = this.observed_.length / 2 - 1;
- this.value_[index] = path.getValueFrom(object);
- },
-
- addObserver: function(observer) {
- if (this.state_ != UNOPENED && this.state_ != RESETTING)
- throw Error('Cannot add observers once started.');
-
- this.observed_.push(observerSentinel, observer);
- if (!this.reportChangesOnOpen_)
- return;
- var index = this.observed_.length / 2 - 1;
- this.value_[index] = observer.open(this.deliver, this);
- },
-
- startReset: function() {
- if (this.state_ != OPENED)
- throw Error('Can only reset while open');
-
- this.state_ = RESETTING;
- this.disconnect_();
- },
-
- finishReset: function() {
- if (this.state_ != RESETTING)
- throw Error('Can only finishReset after startReset');
- this.state_ = OPENED;
- this.connect_();
-
- return this.value_;
- },
-
- iterateObjects_: function(observe) {
- var object;
- for (var i = 0; i < this.observed_.length; i += 2) {
- object = this.observed_[i]
- if (object !== observerSentinel)
- this.observed_[i + 1].iterateObjects(object, observe)
- }
- },
-
- check_: function(changeRecords, skipChanges) {
- var oldValues;
- for (var i = 0; i < this.observed_.length; i += 2) {
- var object = this.observed_[i];
- var path = this.observed_[i+1];
- var value;
- if (object === observerSentinel) {
- var observable = path;
- value = this.state_ === UNOPENED ?
- observable.open(this.deliver, this) :
- observable.discardChanges();
- } else {
- value = path.getValueFrom(object);
- }
-
- if (skipChanges) {
- this.value_[i / 2] = value;
- continue;
- }
-
- if (areSameValue(value, this.value_[i / 2]))
- continue;
-
- oldValues = oldValues || [];
- oldValues[i / 2] = this.value_[i / 2];
- this.value_[i / 2] = value;
- }
-
- if (!oldValues)
- return false;
-
- // TODO(rafaelw): Having observed_ as the third callback arg here is
- // pretty lame API. Fix.
- this.report_([this.value_, oldValues, this.observed_]);
- return true;
- }
- });
-
- function identFn(value) { return value; }
-
- function ObserverTransform(observable, getValueFn, setValueFn,
- dontPassThroughSet) {
- this.callback_ = undefined;
- this.target_ = undefined;
- this.value_ = undefined;
- this.observable_ = observable;
- this.getValueFn_ = getValueFn || identFn;
- this.setValueFn_ = setValueFn || identFn;
- // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
- // at the moment because of a bug in it's dependency tracking.
- this.dontPassThroughSet_ = dontPassThroughSet;
- }
-
- ObserverTransform.prototype = {
- open: function(callback, target) {
- this.callback_ = callback;
- this.target_ = target;
- this.value_ =
- this.getValueFn_(this.observable_.open(this.observedCallback_, this));
- return this.value_;
- },
-
- observedCallback_: function(value) {
- value = this.getValueFn_(value);
- if (areSameValue(value, this.value_))
- return;
- var oldValue = this.value_;
- this.value_ = value;
- this.callback_.call(this.target_, this.value_, oldValue);
- },
-
- discardChanges: function() {
- this.value_ = this.getValueFn_(this.observable_.discardChanges());
- return this.value_;
- },
-
- deliver: function() {
- return this.observable_.deliver();
- },
-
- setValue: function(value) {
- value = this.setValueFn_(value);
- if (!this.dontPassThroughSet_ && this.observable_.setValue)
- return this.observable_.setValue(value);
- },
-
- close: function() {
- if (this.observable_)
- this.observable_.close();
- this.callback_ = undefined;
- this.target_ = undefined;
- this.observable_ = undefined;
- this.value_ = undefined;
- this.getValueFn_ = undefined;
- this.setValueFn_ = undefined;
- }
- }
-
- var expectedRecordTypes = {
- add: true,
- update: true,
- delete: true
- };
-
- function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
- var added = {};
- var removed = {};
-
- for (var i = 0; i < changeRecords.length; i++) {
- var record = changeRecords[i];
- if (!expectedRecordTypes[record.type]) {
- console.error('Unknown changeRecord type: ' + record.type);
- console.error(record);
- continue;
- }
-
- if (!(record.name in oldValues))
- oldValues[record.name] = record.oldValue;
-
- if (record.type == 'update')
- continue;
-
- if (record.type == 'add') {
- if (record.name in removed)
- delete removed[record.name];
- else
- added[record.name] = true;
-
- continue;
- }
-
- // type = 'delete'
- if (record.name in added) {
- delete added[record.name];
- delete oldValues[record.name];
- } else {
- removed[record.name] = true;
- }
- }
-
- for (var prop in added)
- added[prop] = object[prop];
-
- for (var prop in removed)
- removed[prop] = undefined;
-
- var changed = {};
- for (var prop in oldValues) {
- if (prop in added || prop in removed)
- continue;
-
- var newValue = object[prop];
- if (oldValues[prop] !== newValue)
- changed[prop] = newValue;
- }
-
- return {
- added: added,
- removed: removed,
- changed: changed
- };
- }
-
- function newSplice(index, removed, addedCount) {
- return {
- index: index,
- removed: removed,
- addedCount: addedCount
- };
- }
-
- var EDIT_LEAVE = 0;
- var EDIT_UPDATE = 1;
- var EDIT_ADD = 2;
- var EDIT_DELETE = 3;
-
- function ArraySplice() {}
-
- ArraySplice.prototype = {
-
- // Note: This function is *based* on the computation of the Levenshtein
- // "edit" distance. The one change is that "updates" are treated as two
- // edits - not one. With Array splices, an update is really a delete
- // followed by an add. By retaining this, we optimize for "keeping" the
- // maximum array items in the original array. For example:
- //
- // 'xxxx123' -> '123yyyy'
- //
- // With 1-edit updates, the shortest path would be just to update all seven
- // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
- // leaves the substring '123' intact.
- calcEditDistances: function(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- // "Deletion" columns
- var rowCount = oldEnd - oldStart + 1;
- var columnCount = currentEnd - currentStart + 1;
- var distances = new Array(rowCount);
-
- // "Addition" rows. Initialize null column.
- for (var i = 0; i < rowCount; i++) {
- distances[i] = new Array(columnCount);
- distances[i][0] = i;
- }
-
- // Initialize null row
- for (var j = 0; j < columnCount; j++)
- distances[0][j] = j;
-
- for (var i = 1; i < rowCount; i++) {
- for (var j = 1; j < columnCount; j++) {
- if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
- distances[i][j] = distances[i - 1][j - 1];
- else {
- var north = distances[i - 1][j] + 1;
- var west = distances[i][j - 1] + 1;
- distances[i][j] = north < west ? north : west;
- }
- }
- }
-
- return distances;
- },
-
- // This starts at the final weight, and walks "backward" by finding
- // the minimum previous weight recursively until the origin of the weight
- // matrix.
- spliceOperationsFromEditDistances: function(distances) {
- var i = distances.length - 1;
- var j = distances[0].length - 1;
- var current = distances[i][j];
- var edits = [];
- while (i > 0 || j > 0) {
- if (i == 0) {
- edits.push(EDIT_ADD);
- j--;
- continue;
- }
- if (j == 0) {
- edits.push(EDIT_DELETE);
- i--;
- continue;
- }
- var northWest = distances[i - 1][j - 1];
- var west = distances[i - 1][j];
- var north = distances[i][j - 1];
-
- var min;
- if (west < north)
- min = west < northWest ? west : northWest;
- else
- min = north < northWest ? north : northWest;
-
- if (min == northWest) {
- if (northWest == current) {
- edits.push(EDIT_LEAVE);
- } else {
- edits.push(EDIT_UPDATE);
- current = northWest;
- }
- i--;
- j--;
- } else if (min == west) {
- edits.push(EDIT_DELETE);
- i--;
- current = west;
- } else {
- edits.push(EDIT_ADD);
- j--;
- current = north;
- }
- }
-
- edits.reverse();
- return edits;
- },
-
- /**
- * Splice Projection functions:
- *
- * A splice map is a representation of how a previous array of items
- * was transformed into a new array of items. Conceptually it is a list of
- * tuples of
- *
- * <index, removed, addedCount>
- *
- * which are kept in ascending index order of. The tuple represents that at
- * the |index|, |removed| sequence of items were removed, and counting forward
- * from |index|, |addedCount| items were added.
- */
-
- /**
- * Lacking individual splice mutation information, the minimal set of
- * splices can be synthesized given the previous state and final state of an
- * array. The basic approach is to calculate the edit distance matrix and
- * choose the shortest path through it.
- *
- * Complexity: O(l * p)
- * l: The length of the current array
- * p: The length of the old array
- */
- calcSplices: function(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- var prefixCount = 0;
- var suffixCount = 0;
-
- var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
- if (currentStart == 0 && oldStart == 0)
- prefixCount = this.sharedPrefix(current, old, minLength);
-
- if (currentEnd == current.length && oldEnd == old.length)
- suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
-
- currentStart += prefixCount;
- oldStart += prefixCount;
- currentEnd -= suffixCount;
- oldEnd -= suffixCount;
-
- if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
- return [];
-
- if (currentStart == currentEnd) {
- var splice = newSplice(currentStart, [], 0);
- while (oldStart < oldEnd)
- splice.removed.push(old[oldStart++]);
-
- return [ splice ];
- } else if (oldStart == oldEnd)
- return [ newSplice(currentStart, [], currentEnd - currentStart) ];
-
- var ops = this.spliceOperationsFromEditDistances(
- this.calcEditDistances(current, currentStart, currentEnd,
- old, oldStart, oldEnd));
-
- var splice = undefined;
- var splices = [];
- var index = currentStart;
- var oldIndex = oldStart;
- for (var i = 0; i < ops.length; i++) {
- switch(ops[i]) {
- case EDIT_LEAVE:
- if (splice) {
- splices.push(splice);
- splice = undefined;
- }
-
- index++;
- oldIndex++;
- break;
- case EDIT_UPDATE:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.addedCount++;
- index++;
-
- splice.removed.push(old[oldIndex]);
- oldIndex++;
- break;
- case EDIT_ADD:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.addedCount++;
- index++;
- break;
- case EDIT_DELETE:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.removed.push(old[oldIndex]);
- oldIndex++;
- break;
- }
- }
-
- if (splice) {
- splices.push(splice);
- }
- return splices;
- },
-
- sharedPrefix: function(current, old, searchLength) {
- for (var i = 0; i < searchLength; i++)
- if (!this.equals(current[i], old[i]))
- return i;
- return searchLength;
- },
-
- sharedSuffix: function(current, old, searchLength) {
- var index1 = current.length;
- var index2 = old.length;
- var count = 0;
- while (count < searchLength && this.equals(current[--index1], old[--index2]))
- count++;
-
- return count;
- },
-
- calculateSplices: function(current, previous) {
- return this.calcSplices(current, 0, current.length, previous, 0,
- previous.length);
- },
-
- equals: function(currentValue, previousValue) {
- return currentValue === previousValue;
- }
- };
-
- var arraySplice = new ArraySplice();
-
- function calcSplices(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- return arraySplice.calcSplices(current, currentStart, currentEnd,
- old, oldStart, oldEnd);
- }
-
- function intersect(start1, end1, start2, end2) {
- // Disjoint
- if (end1 < start2 || end2 < start1)
- return -1;
-
- // Adjacent
- if (end1 == start2 || end2 == start1)
- return 0;
-
- // Non-zero intersect, span1 first
- if (start1 < start2) {
- if (end1 < end2)
- return end1 - start2; // Overlap
- else
- return end2 - start2; // Contained
- } else {
- // Non-zero intersect, span2 first
- if (end2 < end1)
- return end2 - start1; // Overlap
- else
- return end1 - start1; // Contained
- }
- }
-
- function mergeSplice(splices, index, removed, addedCount) {
-
- var splice = newSplice(index, removed, addedCount);
-
- var inserted = false;
- var insertionOffset = 0;
-
- for (var i = 0; i < splices.length; i++) {
- var current = splices[i];
- current.index += insertionOffset;
-
- if (inserted)
- continue;
-
- var intersectCount = intersect(splice.index,
- splice.index + splice.removed.length,
- current.index,
- current.index + current.addedCount);
-
- if (intersectCount >= 0) {
- // Merge the two splices
-
- splices.splice(i, 1);
- i--;
-
- insertionOffset -= current.addedCount - current.removed.length;
-
- splice.addedCount += current.addedCount - intersectCount;
- var deleteCount = splice.removed.length +
- current.removed.length - intersectCount;
-
- if (!splice.addedCount && !deleteCount) {
- // merged splice is a noop. discard.
- inserted = true;
- } else {
- var removed = current.removed;
-
- if (splice.index < current.index) {
- // some prefix of splice.removed is prepended to current.removed.
- var prepend = splice.removed.slice(0, current.index - splice.index);
- Array.prototype.push.apply(prepend, removed);
- removed = prepend;
- }
-
- if (splice.index + splice.removed.length > current.index + current.addedCount) {
- // some suffix of splice.removed is appended to current.removed.
- var append = splice.removed.slice(current.index + current.addedCount - splice.index);
- Array.prototype.push.apply(removed, append);
- }
-
- splice.removed = removed;
- if (current.index < splice.index) {
- splice.index = current.index;
- }
- }
- } else if (splice.index < current.index) {
- // Insert splice here.
-
- inserted = true;
-
- splices.splice(i, 0, splice);
- i++;
-
- var offset = splice.addedCount - splice.removed.length
- current.index += offset;
- insertionOffset += offset;
- }
- }
-
- if (!inserted)
- splices.push(splice);
- }
-
- function createInitialSplices(array, changeRecords) {
- var splices = [];
-
- for (var i = 0; i < changeRecords.length; i++) {
- var record = changeRecords[i];
- switch(record.type) {
- case 'splice':
- mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
- break;
- case 'add':
- case 'update':
- case 'delete':
- if (!isIndex(record.name))
- continue;
- var index = toNumber(record.name);
- if (index < 0)
- continue;
- mergeSplice(splices, index, [record.oldValue], 1);
- break;
- default:
- console.error('Unexpected record type: ' + JSON.stringify(record));
- break;
- }
- }
-
- return splices;
- }
-
- function projectArraySplices(array, changeRecords) {
- var splices = [];
-
- createInitialSplices(array, changeRecords).forEach(function(splice) {
- if (splice.addedCount == 1 && splice.removed.length == 1) {
- if (splice.removed[0] !== array[splice.index])
- splices.push(splice);
-
- return
- };
-
- splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
- splice.removed, 0, splice.removed.length));
- });
-
- return splices;
- }
-
- // Export the observe-js object for **Node.js**, with backwards-compatibility
- // for the old `require()` API. Also ensure `exports` is not a DOM Element.
- // If we're in the browser, export as a global object.
-
- var expose = global;
-
- if (typeof exports !== 'undefined' && !exports.nodeType) {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports;
- }
- expose = exports;
- }
-
- expose.Observer = Observer;
- expose.Observer.runEOM_ = runEOM;
- expose.Observer.observerSentinel_ = observerSentinel; // for testing.
- expose.Observer.hasObjectObserve = hasObserve;
- expose.ArrayObserver = ArrayObserver;
- expose.ArrayObserver.calculateSplices = function(current, previous) {
- return arraySplice.calculateSplices(current, previous);
- };
-
- expose.ArraySplice = ArraySplice;
- expose.ObjectObserver = ObjectObserver;
- expose.PathObserver = PathObserver;
- expose.CompoundObserver = CompoundObserver;
- expose.Path = Path;
- expose.ObserverTransform = ObserverTransform;
-
-})(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function(global) {
- 'use strict';
-
- var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
-
- function getTreeScope(node) {
- while (node.parentNode) {
- node = node.parentNode;
- }
-
- return typeof node.getElementById === 'function' ? node : null;
- }
-
- Node.prototype.bind = function(name, observable) {
- console.error('Unhandled binding to Node: ', this, name, observable);
- };
-
- Node.prototype.bindFinished = function() {};
-
- function updateBindings(node, name, binding) {
- var bindings = node.bindings_;
- if (!bindings)
- bindings = node.bindings_ = {};
-
- if (bindings[name])
- binding[name].close();
-
- return bindings[name] = binding;
- }
-
- function returnBinding(node, name, binding) {
- return binding;
- }
-
- function sanitizeValue(value) {
- return value == null ? '' : value;
- }
-
- function updateText(node, value) {
- node.data = sanitizeValue(value);
- }
-
- function textBinding(node) {
- return function(value) {
- return updateText(node, value);
- };
- }
-
- var maybeUpdateBindings = returnBinding;
-
- Object.defineProperty(Platform, 'enableBindingsReflection', {
- get: function() {
- return maybeUpdateBindings === updateBindings;
- },
- set: function(enable) {
- maybeUpdateBindings = enable ? updateBindings : returnBinding;
- return enable;
- },
- configurable: true
- });
-
- Text.prototype.bind = function(name, value, oneTime) {
- if (name !== 'textContent')
- return Node.prototype.bind.call(this, name, value, oneTime);
-
- if (oneTime)
- return updateText(this, value);
-
- var observable = value;
- updateText(this, observable.open(textBinding(this)));
- return maybeUpdateBindings(this, name, observable);
- }
-
- function updateAttribute(el, name, conditional, value) {
- if (conditional) {
- if (value)
- el.setAttribute(name, '');
- else
- el.removeAttribute(name);
- return;
- }
-
- el.setAttribute(name, sanitizeValue(value));
- }
-
- function attributeBinding(el, name, conditional) {
- return function(value) {
- updateAttribute(el, name, conditional, value);
- };
- }
-
- Element.prototype.bind = function(name, value, oneTime) {
- var conditional = name[name.length - 1] == '?';
- if (conditional) {
- this.removeAttribute(name);
- name = name.slice(0, -1);
- }
-
- if (oneTime)
- return updateAttribute(this, name, conditional, value);
-
-
- var observable = value;
- updateAttribute(this, name, conditional,
- observable.open(attributeBinding(this, name, conditional)));
-
- return maybeUpdateBindings(this, name, observable);
- };
-
- var checkboxEventType;
- (function() {
- // Attempt to feature-detect which event (change or click) is fired first
- // for checkboxes.
- var div = document.createElement('div');
- var checkbox = div.appendChild(document.createElement('input'));
- checkbox.setAttribute('type', 'checkbox');
- var first;
- var count = 0;
- checkbox.addEventListener('click', function(e) {
- count++;
- first = first || 'click';
- });
- checkbox.addEventListener('change', function() {
- count++;
- first = first || 'change';
- });
-
- var event = document.createEvent('MouseEvent');
- event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
- false, false, false, 0, null);
- checkbox.dispatchEvent(event);
- // WebKit/Blink don't fire the change event if the element is outside the
- // document, so assume 'change' for that case.
- checkboxEventType = count == 1 ? 'change' : first;
- })();
-
- function getEventForInputType(element) {
- switch (element.type) {
- case 'checkbox':
- return checkboxEventType;
- case 'radio':
- case 'select-multiple':
- case 'select-one':
- return 'change';
- case 'range':
- if (/Trident|MSIE/.test(navigator.userAgent))
- return 'change';
- default:
- return 'input';
- }
- }
-
- function updateInput(input, property, value, santizeFn) {
- input[property] = (santizeFn || sanitizeValue)(value);
- }
-
- function inputBinding(input, property, santizeFn) {
- return function(value) {
- return updateInput(input, property, value, santizeFn);
- }
- }
-
- function noop() {}
-
- function bindInputEvent(input, property, observable, postEventFn) {
- var eventType = getEventForInputType(input);
-
- function eventHandler() {
- var isNum = property == 'value' && input.type == 'number';
- observable.setValue(isNum ? input.valueAsNumber : input[property]);
- observable.discardChanges();
- (postEventFn || noop)(input);
- Platform.performMicrotaskCheckpoint();
- }
- input.addEventListener(eventType, eventHandler);
-
- return {
- close: function() {
- input.removeEventListener(eventType, eventHandler);
- observable.close();
- },
-
- observable_: observable
- }
- }
-
- function booleanSanitize(value) {
- return Boolean(value);
- }
-
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
- // Returns an array containing all radio buttons other than |element| that
- // have the same |name|, either in the form that |element| belongs to or,
- // if no form, in the document tree to which |element| belongs.
- //
- // This implementation is based upon the HTML spec definition of a
- // "radio button group":
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
- //
- function getAssociatedRadioButtons(element) {
- if (element.form) {
- return filter(element.form.elements, function(el) {
- return el != element &&
- el.tagName == 'INPUT' &&
- el.type == 'radio' &&
- el.name == element.name;
- });
- } else {
- var treeScope = getTreeScope(element);
- if (!treeScope)
- return [];
- var radios = treeScope.querySelectorAll(
- 'input[type="radio"][name="' + element.name + '"]');
- return filter(radios, function(el) {
- return el != element && !el.form;
- });
- }
- }
-
- function checkedPostEvent(input) {
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // check binding manually.
- if (input.tagName === 'INPUT' &&
- input.type === 'radio') {
- getAssociatedRadioButtons(input).forEach(function(radio) {
- var checkedBinding = radio.bindings_.checked;
- if (checkedBinding) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.observable_.setValue(false);
- }
- });
- }
- }
-
- HTMLInputElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value' && name !== 'checked')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute(name);
- var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
- var postEventFn = name == 'checked' ? checkedPostEvent : noop;
-
- if (oneTime)
- return updateInput(this, name, value, sanitizeFn);
-
-
- var observable = value;
- var binding = bindInputEvent(this, name, observable, postEventFn);
- updateInput(this, name,
- observable.open(inputBinding(this, name, sanitizeFn)),
- sanitizeFn);
-
- // Checkboxes may need to update bindings of other checkboxes.
- return updateBindings(this, name, binding);
- }
-
- HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute('value');
-
- if (oneTime)
- return updateInput(this, 'value', value);
-
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
- updateInput(this, 'value',
- observable.open(inputBinding(this, 'value', sanitizeValue)));
- return maybeUpdateBindings(this, name, binding);
- }
-
- function updateOption(option, value) {
- var parentNode = option.parentNode;;
- var select;
- var selectBinding;
- var oldValue;
- if (parentNode instanceof HTMLSelectElement &&
- parentNode.bindings_ &&
- parentNode.bindings_.value) {
- select = parentNode;
- selectBinding = select.bindings_.value;
- oldValue = select.value;
- }
-
- option.value = sanitizeValue(value);
-
- if (select && select.value != oldValue) {
- selectBinding.observable_.setValue(select.value);
- selectBinding.observable_.discardChanges();
- Platform.performMicrotaskCheckpoint();
- }
- }
-
- function optionBinding(option) {
- return function(value) {
- updateOption(option, value);
- }
- }
-
- HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute('value');
-
- if (oneTime)
- return updateOption(this, value);
-
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
- updateOption(this, observable.open(optionBinding(this)));
- return maybeUpdateBindings(this, name, binding);
- }
-
- HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
- if (name === 'selectedindex')
- name = 'selectedIndex';
-
- if (name !== 'selectedIndex' && name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute(name);
-
- if (oneTime)
- return updateInput(this, name, value);
-
- var observable = value;
- var binding = bindInputEvent(this, name, observable);
- updateInput(this, name,
- observable.open(inputBinding(this, name)));
-
- // Option update events may need to access select bindings.
- return updateBindings(this, name, binding);
- }
-})(this);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function(global) {
- 'use strict';
-
- function assert(v) {
- if (!v)
- throw new Error('Assertion failed');
- }
-
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
-
- function getFragmentRoot(node) {
- var p;
- while (p = node.parentNode) {
- node = p;
- }
-
- return node;
- }
-
- function searchRefId(node, id) {
- if (!id)
- return;
-
- var ref;
- var selector = '#' + id;
- while (!ref) {
- node = getFragmentRoot(node);
-
- if (node.protoContent_)
- ref = node.protoContent_.querySelector(selector);
- else if (node.getElementById)
- ref = node.getElementById(id);
-
- if (ref || !node.templateCreator_)
- break
-
- node = node.templateCreator_;
- }
-
- return ref;
- }
-
- function getInstanceRoot(node) {
- while (node.parentNode) {
- node = node.parentNode;
- }
- return node.templateCreator_ ? node : null;
- }
-
- var Map;
- if (global.Map && typeof global.Map.prototype.forEach === 'function') {
- Map = global.Map;
- } else {
- Map = function() {
- this.keys = [];
- this.values = [];
- };
-
- Map.prototype = {
- set: function(key, value) {
- var index = this.keys.indexOf(key);
- if (index < 0) {
- this.keys.push(key);
- this.values.push(value);
- } else {
- this.values[index] = value;
- }
- },
-
- get: function(key) {
- var index = this.keys.indexOf(key);
- if (index < 0)
- return;
-
- return this.values[index];
- },
-
- delete: function(key, value) {
- var index = this.keys.indexOf(key);
- if (index < 0)
- return false;
-
- this.keys.splice(index, 1);
- this.values.splice(index, 1);
- return true;
- },
-
- forEach: function(f, opt_this) {
- for (var i = 0; i < this.keys.length; i++)
- f.call(opt_this || this, this.values[i], this.keys[i], this);
- }
- };
- }
-
- // JScript does not have __proto__. We wrap all object literals with
- // createObject which uses Object.create, Object.defineProperty and
- // Object.getOwnPropertyDescriptor to create a new object that does the exact
- // same thing. The main downside to this solution is that we have to extract
- // all those property descriptors for IE.
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- // IE does not support have Document.prototype.contains.
- if (typeof document.contains != 'function') {
- Document.prototype.contains = function(node) {
- if (node === this || node.parentNode === this)
- return true;
- return this.documentElement.contains(node);
- }
- }
-
- var BIND = 'bind';
- var REPEAT = 'repeat';
- var IF = 'if';
-
- var templateAttributeDirectives = {
- 'template': true,
- 'repeat': true,
- 'bind': true,
- 'ref': true,
- 'if': true
- };
-
- var semanticTemplateElements = {
- 'THEAD': true,
- 'TBODY': true,
- 'TFOOT': true,
- 'TH': true,
- 'TR': true,
- 'TD': true,
- 'COLGROUP': true,
- 'COL': true,
- 'CAPTION': true,
- 'OPTION': true,
- 'OPTGROUP': true
- };
-
- var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined';
- if (hasTemplateElement) {
- // TODO(rafaelw): Remove when fix for
- // https://codereview.chromium.org/164803002/
- // makes it to Chrome release.
- (function() {
- var t = document.createElement('template');
- var d = t.content.ownerDocument;
- var html = d.appendChild(d.createElement('html'));
- var head = html.appendChild(d.createElement('head'));
- var base = d.createElement('base');
- base.href = document.baseURI;
- head.appendChild(base);
- })();
- }
-
- var allTemplatesSelectors = 'template, ' +
- Object.keys(semanticTemplateElements).map(function(tagName) {
- return tagName.toLowerCase() + '[template]';
- }).join(', ');
-
- function isSVGTemplate(el) {
- return el.tagName == 'template' &&
- el.namespaceURI == 'http://www.w3.org/2000/svg';
- }
-
- function isHTMLTemplate(el) {
- return el.tagName == 'TEMPLATE' &&
- el.namespaceURI == 'http://www.w3.org/1999/xhtml';
- }
-
- function isAttributeTemplate(el) {
- return Boolean(semanticTemplateElements[el.tagName] &&
- el.hasAttribute('template'));
- }
-
- function isTemplate(el) {
- if (el.isTemplate_ === undefined)
- el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el);
-
- return el.isTemplate_;
- }
-
- // FIXME: Observe templates being added/removed from documents
- // FIXME: Expose imperative API to decorate and observe templates in
- // "disconnected tress" (e.g. ShadowRoot)
- document.addEventListener('DOMContentLoaded', function(e) {
- bootstrapTemplatesRecursivelyFrom(document);
- // FIXME: Is this needed? Seems like it shouldn't be.
- Platform.performMicrotaskCheckpoint();
- }, false);
-
- function forAllTemplatesFrom(node, fn) {
- var subTemplates = node.querySelectorAll(allTemplatesSelectors);
-
- if (isTemplate(node))
- fn(node)
- forEach(subTemplates, fn);
- }
-
- function bootstrapTemplatesRecursivelyFrom(node) {
- function bootstrap(template) {
- if (!HTMLTemplateElement.decorate(template))
- bootstrapTemplatesRecursivelyFrom(template.content);
- }
-
- forAllTemplatesFrom(node, bootstrap);
- }
-
- if (!hasTemplateElement) {
- /**
- * This represents a <template> element.
- * @constructor
- * @extends {HTMLElement}
- */
- global.HTMLTemplateElement = function() {
- throw TypeError('Illegal constructor');
- };
- }
-
- var hasProto = '__proto__' in {};
-
- function mixin(to, from) {
- Object.getOwnPropertyNames(from).forEach(function(name) {
- Object.defineProperty(to, name,
- Object.getOwnPropertyDescriptor(from, name));
- });
- }
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- function getOrCreateTemplateContentsOwner(template) {
- var doc = template.ownerDocument
- if (!doc.defaultView)
- return doc;
- var d = doc.templateContentsOwner_;
- if (!d) {
- // TODO(arv): This should either be a Document or HTMLDocument depending
- // on doc.
- d = doc.implementation.createHTMLDocument('');
- while (d.lastChild) {
- d.removeChild(d.lastChild);
- }
- doc.templateContentsOwner_ = d;
- }
- return d;
- }
-
- function getTemplateStagingDocument(template) {
- if (!template.stagingDocument_) {
- var owner = template.ownerDocument;
- if (!owner.stagingDocument_) {
- owner.stagingDocument_ = owner.implementation.createHTMLDocument('');
- owner.stagingDocument_.isStagingDocument = true;
- // TODO(rafaelw): Remove when fix for
- // https://codereview.chromium.org/164803002/
- // makes it to Chrome release.
- var base = owner.stagingDocument_.createElement('base');
- base.href = document.baseURI;
- owner.stagingDocument_.head.appendChild(base);
-
- owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_;
- }
-
- template.stagingDocument_ = owner.stagingDocument_;
- }
-
- return template.stagingDocument_;
- }
-
- // For non-template browsers, the parser will disallow <template> in certain
- // locations, so we allow "attribute templates" which combine the template
- // element with the top-level container node of the content, e.g.
- //
- // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
- //
- // becomes
- //
- // <template repeat="{{ foo }}">
- // + #document-fragment
- // + <tr class="bar">
- // + <td>Bar</td>
- //
- function extractTemplateFromAttributeTemplate(el) {
- var template = el.ownerDocument.createElement('template');
- el.parentNode.insertBefore(template, el);
-
- var attribs = el.attributes;
- var count = attribs.length;
- while (count-- > 0) {
- var attrib = attribs[count];
- if (templateAttributeDirectives[attrib.name]) {
- if (attrib.name !== 'template')
- template.setAttribute(attrib.name, attrib.value);
- el.removeAttribute(attrib.name);
- }
- }
-
- return template;
- }
-
- function extractTemplateFromSVGTemplate(el) {
- var template = el.ownerDocument.createElement('template');
- el.parentNode.insertBefore(template, el);
-
- var attribs = el.attributes;
- var count = attribs.length;
- while (count-- > 0) {
- var attrib = attribs[count];
- template.setAttribute(attrib.name, attrib.value);
- el.removeAttribute(attrib.name);
- }
-
- el.parentNode.removeChild(el);
- return template;
- }
-
- function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) {
- var content = template.content;
- if (useRoot) {
- content.appendChild(el);
- return;
- }
-
- var child;
- while (child = el.firstChild) {
- content.appendChild(child);
- }
- }
-
- var templateObserver;
- if (typeof MutationObserver == 'function') {
- templateObserver = new MutationObserver(function(records) {
- for (var i = 0; i < records.length; i++) {
- records[i].target.refChanged_();
- }
- });
- }
-
- /**
- * Ensures proper API and content model for template elements.
- * @param {HTMLTemplateElement} opt_instanceRef The template element which
- * |el| template element will return as the value of its ref(), and whose
- * content will be used as source when createInstance() is invoked.
- */
- HTMLTemplateElement.decorate = function(el, opt_instanceRef) {
- if (el.templateIsDecorated_)
- return false;
-
- var templateElement = el;
- templateElement.templateIsDecorated_ = true;
-
- var isNativeHTMLTemplate = isHTMLTemplate(templateElement) &&
- hasTemplateElement;
- var bootstrapContents = isNativeHTMLTemplate;
- var liftContents = !isNativeHTMLTemplate;
- var liftRoot = false;
-
- if (!isNativeHTMLTemplate) {
- if (isAttributeTemplate(templateElement)) {
- assert(!opt_instanceRef);
- templateElement = extractTemplateFromAttributeTemplate(el);
- templateElement.templateIsDecorated_ = true;
- isNativeHTMLTemplate = hasTemplateElement;
- liftRoot = true;
- } else if (isSVGTemplate(templateElement)) {
- templateElement = extractTemplateFromSVGTemplate(el);
- templateElement.templateIsDecorated_ = true;
- isNativeHTMLTemplate = hasTemplateElement;
- }
- }
-
- if (!isNativeHTMLTemplate) {
- fixTemplateElementPrototype(templateElement);
- var doc = getOrCreateTemplateContentsOwner(templateElement);
- templateElement.content_ = doc.createDocumentFragment();
- }
-
- if (opt_instanceRef) {
- // template is contained within an instance, its direct content must be
- // empty
- templateElement.instanceRef_ = opt_instanceRef;
- } else if (liftContents) {
- liftNonNativeTemplateChildrenIntoContent(templateElement,
- el,
- liftRoot);
- } else if (bootstrapContents) {
- bootstrapTemplatesRecursivelyFrom(templateElement.content);
- }
-
- return true;
- };
-
- // TODO(rafaelw): This used to decorate recursively all templates from a given
- // node. This happens by default on 'DOMContentLoaded', but may be needed
- // in subtrees not descendent from document (e.g. ShadowRoot).
- // Review whether this is the right public API.
- HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom;
-
- var htmlElement = global.HTMLUnknownElement || HTMLElement;
-
- var contentDescriptor = {
- get: function() {
- return this.content_;
- },
- enumerable: true,
- configurable: true
- };
-
- if (!hasTemplateElement) {
- // Gecko is more picky with the prototype than WebKit. Make sure to use the
- // same prototype as created in the constructor.
- HTMLTemplateElement.prototype = Object.create(htmlElement.prototype);
-
- Object.defineProperty(HTMLTemplateElement.prototype, 'content',
- contentDescriptor);
- }
-
- function fixTemplateElementPrototype(el) {
- if (hasProto)
- el.__proto__ = HTMLTemplateElement.prototype;
- else
- mixin(el, HTMLTemplateElement.prototype);
- }
-
- function ensureSetModelScheduled(template) {
- if (!template.setModelFn_) {
- template.setModelFn_ = function() {
- template.setModelFnScheduled_ = false;
- var map = getBindings(template,
- template.delegate_ && template.delegate_.prepareBinding);
- processBindings(template, map, template.model_);
- };
- }
-
- if (!template.setModelFnScheduled_) {
- template.setModelFnScheduled_ = true;
- Observer.runEOM_(template.setModelFn_);
- }
- }
-
- mixin(HTMLTemplateElement.prototype, {
- bind: function(name, value, oneTime) {
- if (name != 'ref')
- return Element.prototype.bind.call(this, name, value, oneTime);
-
- var self = this;
- var ref = oneTime ? value : value.open(function(ref) {
- self.setAttribute('ref', ref);
- self.refChanged_();
- });
-
- this.setAttribute('ref', ref);
- this.refChanged_();
- if (oneTime)
- return;
-
- if (!this.bindings_) {
- this.bindings_ = { ref: value };
- } else {
- this.bindings_.ref = value;
- }
-
- return value;
- },
-
- processBindingDirectives_: function(directives) {
- if (this.iterator_)
- this.iterator_.closeDeps();
-
- if (!directives.if && !directives.bind && !directives.repeat) {
- if (this.iterator_) {
- this.iterator_.close();
- this.iterator_ = undefined;
- }
-
- return;
- }
-
- if (!this.iterator_) {
- this.iterator_ = new TemplateIterator(this);
- }
-
- this.iterator_.updateDependencies(directives, this.model_);
-
- if (templateObserver) {
- templateObserver.observe(this, { attributes: true,
- attributeFilter: ['ref'] });
- }
-
- return this.iterator_;
- },
-
- createInstance: function(model, bindingDelegate, delegate_) {
- if (bindingDelegate)
- delegate_ = this.newDelegate_(bindingDelegate);
- else if (!delegate_)
- delegate_ = this.delegate_;
-
- if (!this.refContent_)
- this.refContent_ = this.ref_.content;
- var content = this.refContent_;
- if (content.firstChild === null)
- return emptyInstance;
-
- var map = getInstanceBindingMap(content, delegate_);
- var stagingDocument = getTemplateStagingDocument(this);
- var instance = stagingDocument.createDocumentFragment();
- instance.templateCreator_ = this;
- instance.protoContent_ = content;
- instance.bindings_ = [];
- instance.terminator_ = null;
- var instanceRecord = instance.templateInstance_ = {
- firstNode: null,
- lastNode: null,
- model: model
- };
-
- var i = 0;
- var collectTerminator = false;
- for (var child = content.firstChild; child; child = child.nextSibling) {
- // The terminator of the instance is the clone of the last child of the
- // content. If the last child is an active template, it may produce
- // instances as a result of production, so simply collecting the last
- // child of the instance after it has finished producing may be wrong.
- if (child.nextSibling === null)
- collectTerminator = true;
-
- var clone = cloneAndBindInstance(child, instance, stagingDocument,
- map.children[i++],
- model,
- delegate_,
- instance.bindings_);
- clone.templateInstance_ = instanceRecord;
- if (collectTerminator)
- instance.terminator_ = clone;
- }
-
- instanceRecord.firstNode = instance.firstChild;
- instanceRecord.lastNode = instance.lastChild;
- instance.templateCreator_ = undefined;
- instance.protoContent_ = undefined;
- return instance;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- ensureSetModelScheduled(this);
- },
-
- get bindingDelegate() {
- return this.delegate_ && this.delegate_.raw;
- },
-
- refChanged_: function() {
- if (!this.iterator_ || this.refContent_ === this.ref_.content)
- return;
-
- this.refContent_ = undefined;
- this.iterator_.valueChanged();
- this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue());
- },
-
- clear: function() {
- this.model_ = undefined;
- this.delegate_ = undefined;
- if (this.bindings_ && this.bindings_.ref)
- this.bindings_.ref.close()
- this.refContent_ = undefined;
- if (!this.iterator_)
- return;
- this.iterator_.valueChanged();
- this.iterator_.close()
- this.iterator_ = undefined;
- },
-
- setDelegate_: function(delegate) {
- this.delegate_ = delegate;
- this.bindingMap_ = undefined;
- if (this.iterator_) {
- this.iterator_.instancePositionChangedFn_ = undefined;
- this.iterator_.instanceModelFn_ = undefined;
- }
- },
-
- newDelegate_: function(bindingDelegate) {
- if (!bindingDelegate)
- return;
-
- function delegateFn(name) {
- var fn = bindingDelegate && bindingDelegate[name];
- if (typeof fn != 'function')
- return;
-
- return function() {
- return fn.apply(bindingDelegate, arguments);
- };
- }
-
- return {
- bindingMaps: {},
- raw: bindingDelegate,
- prepareBinding: delegateFn('prepareBinding'),
- prepareInstanceModel: delegateFn('prepareInstanceModel'),
- prepareInstancePositionChanged:
- delegateFn('prepareInstancePositionChanged')
- };
- },
-
- set bindingDelegate(bindingDelegate) {
- if (this.delegate_) {
- throw Error('Template must be cleared before a new bindingDelegate ' +
- 'can be assigned');
- }
-
- this.setDelegate_(this.newDelegate_(bindingDelegate));
- },
-
- get ref_() {
- var ref = searchRefId(this, this.getAttribute('ref'));
- if (!ref)
- ref = this.instanceRef_;
-
- if (!ref)
- return this;
-
- var nextRef = ref.ref_;
- return nextRef ? nextRef : ref;
- }
- });
-
- // Returns
- // a) undefined if there are no mustaches.
- // b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one mustache.
- function parseMustaches(s, name, node, prepareBindingFn) {
- if (!s || !s.length)
- return;
-
- var tokens;
- var length = s.length;
- var startIndex = 0, lastIndex = 0, endIndex = 0;
- var onlyOneTime = true;
- while (lastIndex < length) {
- var startIndex = s.indexOf('{{', lastIndex);
- var oneTimeStart = s.indexOf('[[', lastIndex);
- var oneTime = false;
- var terminator = '}}';
-
- if (oneTimeStart >= 0 &&
- (startIndex < 0 || oneTimeStart < startIndex)) {
- startIndex = oneTimeStart;
- oneTime = true;
- terminator = ']]';
- }
-
- endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2);
-
- if (endIndex < 0) {
- if (!tokens)
- return;
-
- tokens.push(s.slice(lastIndex)); // TEXT
- break;
- }
-
- tokens = tokens || [];
- tokens.push(s.slice(lastIndex, startIndex)); // TEXT
- var pathString = s.slice(startIndex + 2, endIndex).trim();
- tokens.push(oneTime); // ONE_TIME?
- onlyOneTime = onlyOneTime && oneTime;
- var delegateFn = prepareBindingFn &&
- prepareBindingFn(pathString, name, node);
- // Don't try to parse the expression if there's a prepareBinding function
- if (delegateFn == null) {
- tokens.push(Path.get(pathString)); // PATH
- } else {
- tokens.push(null);
- }
- tokens.push(delegateFn); // DELEGATE_FN
- lastIndex = endIndex + 2;
- }
-
- if (lastIndex === length)
- tokens.push(''); // TEXT
-
- tokens.hasOnePath = tokens.length === 5;
- tokens.isSimplePath = tokens.hasOnePath &&
- tokens[0] == '' &&
- tokens[4] == '';
- tokens.onlyOneTime = onlyOneTime;
-
- tokens.combinator = function(values) {
- var newValue = tokens[0];
-
- for (var i = 1; i < tokens.length; i += 4) {
- var value = tokens.hasOnePath ? values : values[(i - 1) / 4];
- if (value !== undefined)
- newValue += value;
- newValue += tokens[i + 3];
- }
-
- return newValue;
- }
-
- return tokens;
- };
-
- function processOneTimeBinding(name, tokens, node, model) {
- if (tokens.hasOnePath) {
- var delegateFn = tokens[3];
- var value = delegateFn ? delegateFn(model, node, true) :
- tokens[2].getValueFrom(model);
- return tokens.isSimplePath ? value : tokens.combinator(value);
- }
-
- var values = [];
- for (var i = 1; i < tokens.length; i += 4) {
- var delegateFn = tokens[i + 2];
- values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) :
- tokens[i + 1].getValueFrom(model);
- }
-
- return tokens.combinator(values);
- }
-
- function processSinglePathBinding(name, tokens, node, model) {
- var delegateFn = tokens[3];
- var observer = delegateFn ? delegateFn(model, node, false) :
- new PathObserver(model, tokens[2]);
-
- return tokens.isSimplePath ? observer :
- new ObserverTransform(observer, tokens.combinator);
- }
-
- function processBinding(name, tokens, node, model) {
- if (tokens.onlyOneTime)
- return processOneTimeBinding(name, tokens, node, model);
-
- if (tokens.hasOnePath)
- return processSinglePathBinding(name, tokens, node, model);
-
- var observer = new CompoundObserver();
-
- for (var i = 1; i < tokens.length; i += 4) {
- var oneTime = tokens[i];
- var delegateFn = tokens[i + 2];
-
- if (delegateFn) {
- var value = delegateFn(model, node, oneTime);
- if (oneTime)
- observer.addPath(value)
- else
- observer.addObserver(value);
- continue;
- }
-
- var path = tokens[i + 1];
- if (oneTime)
- observer.addPath(path.getValueFrom(model))
- else
- observer.addPath(model, path);
- }
-
- return new ObserverTransform(observer, tokens.combinator);
- }
-
- function processBindings(node, bindings, model, instanceBindings) {
- for (var i = 0; i < bindings.length; i += 2) {
- var name = bindings[i]
- var tokens = bindings[i + 1];
- var value = processBinding(name, tokens, node, model);
- var binding = node.bind(name, value, tokens.onlyOneTime);
- if (binding && instanceBindings)
- instanceBindings.push(binding);
- }
-
- node.bindFinished();
- if (!bindings.isTemplate)
- return;
-
- node.model_ = model;
- var iter = node.processBindingDirectives_(bindings);
- if (instanceBindings && iter)
- instanceBindings.push(iter);
- }
-
- function parseWithDefault(el, name, prepareBindingFn) {
- var v = el.getAttribute(name);
- return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn);
- }
-
- function parseAttributeBindings(element, prepareBindingFn) {
- assert(element);
-
- var bindings = [];
- var ifFound = false;
- var bindFound = false;
-
- for (var i = 0; i < element.attributes.length; i++) {
- var attr = element.attributes[i];
- var name = attr.name;
- var value = attr.value;
-
- // Allow bindings expressed in attributes to be prefixed with underbars.
- // We do this to allow correct semantics for browsers that don't implement
- // <template> where certain attributes might trigger side-effects -- and
- // for IE which sanitizes certain attributes, disallowing mustache
- // replacements in their text.
- while (name[0] === '_') {
- name = name.substring(1);
- }
-
- if (isTemplate(element) &&
- (name === IF || name === BIND || name === REPEAT)) {
- continue;
- }
-
- var tokens = parseMustaches(value, name, element,
- prepareBindingFn);
- if (!tokens)
- continue;
-
- bindings.push(name, tokens);
- }
-
- if (isTemplate(element)) {
- bindings.isTemplate = true;
- bindings.if = parseWithDefault(element, IF, prepareBindingFn);
- bindings.bind = parseWithDefault(element, BIND, prepareBindingFn);
- bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn);
-
- if (bindings.if && !bindings.bind && !bindings.repeat)
- bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn);
- }
-
- return bindings;
- }
-
- function getBindings(node, prepareBindingFn) {
- if (node.nodeType === Node.ELEMENT_NODE)
- return parseAttributeBindings(node, prepareBindingFn);
-
- if (node.nodeType === Node.TEXT_NODE) {
- var tokens = parseMustaches(node.data, 'textContent', node,
- prepareBindingFn);
- if (tokens)
- return ['textContent', tokens];
- }
-
- return [];
- }
-
- function cloneAndBindInstance(node, parent, stagingDocument, bindings, model,
- delegate,
- instanceBindings,
- instanceRecord) {
- var clone = parent.appendChild(stagingDocument.importNode(node, false));
-
- var i = 0;
- for (var child = node.firstChild; child; child = child.nextSibling) {
- cloneAndBindInstance(child, clone, stagingDocument,
- bindings.children[i++],
- model,
- delegate,
- instanceBindings);
- }
-
- if (bindings.isTemplate) {
- HTMLTemplateElement.decorate(clone, node);
- if (delegate)
- clone.setDelegate_(delegate);
- }
-
- processBindings(clone, bindings, model, instanceBindings);
- return clone;
- }
-
- function createInstanceBindingMap(node, prepareBindingFn) {
- var map = getBindings(node, prepareBindingFn);
- map.children = {};
- var index = 0;
- for (var child = node.firstChild; child; child = child.nextSibling) {
- map.children[index++] = createInstanceBindingMap(child, prepareBindingFn);
- }
-
- return map;
- }
-
- var contentUidCounter = 1;
-
- // TODO(rafaelw): Setup a MutationObserver on content which clears the id
- // so that bindingMaps regenerate when the template.content changes.
- function getContentUid(content) {
- var id = content.id_;
- if (!id)
- id = content.id_ = contentUidCounter++;
- return id;
- }
-
- // Each delegate is associated with a set of bindingMaps, one for each
- // content which may be used by a template. The intent is that each binding
- // delegate gets the opportunity to prepare the instance (via the prepare*
- // delegate calls) once across all uses.
- // TODO(rafaelw): Separate out the parse map from the binding map. In the
- // current implementation, if two delegates need a binding map for the same
- // content, the second will have to reparse.
- function getInstanceBindingMap(content, delegate_) {
- var contentId = getContentUid(content);
- if (delegate_) {
- var map = delegate_.bindingMaps[contentId];
- if (!map) {
- map = delegate_.bindingMaps[contentId] =
- createInstanceBindingMap(content, delegate_.prepareBinding) || [];
- }
- return map;
- }
-
- var map = content.bindingMap_;
- if (!map) {
- map = content.bindingMap_ =
- createInstanceBindingMap(content, undefined) || [];
- }
- return map;
- }
-
- Object.defineProperty(Node.prototype, 'templateInstance', {
- get: function() {
- var instance = this.templateInstance_;
- return instance ? instance :
- (this.parentNode ? this.parentNode.templateInstance : undefined);
- }
- });
-
- var emptyInstance = document.createDocumentFragment();
- emptyInstance.bindings_ = [];
- emptyInstance.terminator_ = null;
-
- function TemplateIterator(templateElement) {
- this.closed = false;
- this.templateElement_ = templateElement;
- this.instances = [];
- this.deps = undefined;
- this.iteratedValue = [];
- this.presentValue = undefined;
- this.arrayObserver = undefined;
- }
-
- TemplateIterator.prototype = {
- closeDeps: function() {
- var deps = this.deps;
- if (deps) {
- if (deps.ifOneTime === false)
- deps.ifValue.close();
- if (deps.oneTime === false)
- deps.value.close();
- }
- },
-
- updateDependencies: function(directives, model) {
- this.closeDeps();
-
- var deps = this.deps = {};
- var template = this.templateElement_;
-
- var ifValue = true;
- if (directives.if) {
- deps.hasIf = true;
- deps.ifOneTime = directives.if.onlyOneTime;
- deps.ifValue = processBinding(IF, directives.if, template, model);
-
- ifValue = deps.ifValue;
-
- // oneTime if & predicate is false. nothing else to do.
- if (deps.ifOneTime && !ifValue) {
- this.valueChanged();
- return;
- }
-
- if (!deps.ifOneTime)
- ifValue = ifValue.open(this.updateIfValue, this);
- }
-
- if (directives.repeat) {
- deps.repeat = true;
- deps.oneTime = directives.repeat.onlyOneTime;
- deps.value = processBinding(REPEAT, directives.repeat, template, model);
- } else {
- deps.repeat = false;
- deps.oneTime = directives.bind.onlyOneTime;
- deps.value = processBinding(BIND, directives.bind, template, model);
- }
-
- var value = deps.value;
- if (!deps.oneTime)
- value = value.open(this.updateIteratedValue, this);
-
- if (!ifValue) {
- this.valueChanged();
- return;
- }
-
- this.updateValue(value);
- },
-
- /**
- * Gets the updated value of the bind/repeat. This can potentially call
- * user code (if a bindingDelegate is set up) so we try to avoid it if we
- * already have the value in hand (from Observer.open).
- */
- getUpdatedValue: function() {
- var value = this.deps.value;
- if (!this.deps.oneTime)
- value = value.discardChanges();
- return value;
- },
-
- updateIfValue: function(ifValue) {
- if (!ifValue) {
- this.valueChanged();
- return;
- }
-
- this.updateValue(this.getUpdatedValue());
- },
-
- updateIteratedValue: function(value) {
- if (this.deps.hasIf) {
- var ifValue = this.deps.ifValue;
- if (!this.deps.ifOneTime)
- ifValue = ifValue.discardChanges();
- if (!ifValue) {
- this.valueChanged();
- return;
- }
- }
-
- this.updateValue(value);
- },
-
- updateValue: function(value) {
- if (!this.deps.repeat)
- value = [value];
- var observe = this.deps.repeat &&
- !this.deps.oneTime &&
- Array.isArray(value);
- this.valueChanged(value, observe);
- },
-
- valueChanged: function(value, observeValue) {
- if (!Array.isArray(value))
- value = [];
-
- if (value === this.iteratedValue)
- return;
-
- this.unobserve();
- this.presentValue = value;
- if (observeValue) {
- this.arrayObserver = new ArrayObserver(this.presentValue);
- this.arrayObserver.open(this.handleSplices, this);
- }
-
- this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,
- this.iteratedValue));
- },
-
- getLastInstanceNode: function(index) {
- if (index == -1)
- return this.templateElement_;
- var instance = this.instances[index];
- var terminator = instance.terminator_;
- if (!terminator)
- return this.getLastInstanceNode(index - 1);
-
- if (terminator.nodeType !== Node.ELEMENT_NODE ||
- this.templateElement_ === terminator) {
- return terminator;
- }
-
- var subtemplateIterator = terminator.iterator_;
- if (!subtemplateIterator)
- return terminator;
-
- return subtemplateIterator.getLastTemplateNode();
- },
-
- getLastTemplateNode: function() {
- return this.getLastInstanceNode(this.instances.length - 1);
- },
-
- insertInstanceAt: function(index, fragment) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
- var parent = this.templateElement_.parentNode;
- this.instances.splice(index, 0, fragment);
-
- parent.insertBefore(fragment, previousInstanceLast.nextSibling);
- },
-
- extractInstanceAt: function(index) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
- var lastNode = this.getLastInstanceNode(index);
- var parent = this.templateElement_.parentNode;
- var instance = this.instances.splice(index, 1)[0];
-
- while (lastNode !== previousInstanceLast) {
- var node = previousInstanceLast.nextSibling;
- if (node == lastNode)
- lastNode = previousInstanceLast;
-
- instance.appendChild(parent.removeChild(node));
- }
-
- return instance;
- },
-
- getDelegateFn: function(fn) {
- fn = fn && fn(this.templateElement_);
- return typeof fn === 'function' ? fn : null;
- },
-
- handleSplices: function(splices) {
- if (this.closed || !splices.length)
- return;
-
- var template = this.templateElement_;
-
- if (!template.parentNode) {
- this.close();
- return;
- }
-
- ArrayObserver.applySplices(this.iteratedValue, this.presentValue,
- splices);
-
- var delegate = template.delegate_;
- if (this.instanceModelFn_ === undefined) {
- this.instanceModelFn_ =
- this.getDelegateFn(delegate && delegate.prepareInstanceModel);
- }
-
- if (this.instancePositionChangedFn_ === undefined) {
- this.instancePositionChangedFn_ =
- this.getDelegateFn(delegate &&
- delegate.prepareInstancePositionChanged);
- }
-
- // Instance Removals
- var instanceCache = new Map;
- var removeDelta = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- var removed = splice.removed;
- for (var j = 0; j < removed.length; j++) {
- var model = removed[j];
- var instance = this.extractInstanceAt(splice.index + removeDelta);
- if (instance !== emptyInstance) {
- instanceCache.set(model, instance);
- }
- }
-
- removeDelta -= splice.addedCount;
- }
-
- // Instance Insertions
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- var addIndex = splice.index;
- for (; addIndex < splice.index + splice.addedCount; addIndex++) {
- var model = this.iteratedValue[addIndex];
- var instance = instanceCache.get(model);
- if (instance) {
- instanceCache.delete(model);
- } else {
- if (this.instanceModelFn_) {
- model = this.instanceModelFn_(model);
- }
-
- if (model === undefined) {
- instance = emptyInstance;
- } else {
- instance = template.createInstance(model, undefined, delegate);
- }
- }
-
- this.insertInstanceAt(addIndex, instance);
- }
- }
-
- instanceCache.forEach(function(instance) {
- this.closeInstanceBindings(instance);
- }, this);
-
- if (this.instancePositionChangedFn_)
- this.reportInstancesMoved(splices);
- },
-
- reportInstanceMoved: function(index) {
- var instance = this.instances[index];
- if (instance === emptyInstance)
- return;
-
- this.instancePositionChangedFn_(instance.templateInstance_, index);
- },
-
- reportInstancesMoved: function(splices) {
- var index = 0;
- var offset = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- if (offset != 0) {
- while (index < splice.index) {
- this.reportInstanceMoved(index);
- index++;
- }
- } else {
- index = splice.index;
- }
-
- while (index < splice.index + splice.addedCount) {
- this.reportInstanceMoved(index);
- index++;
- }
-
- offset += splice.addedCount - splice.removed.length;
- }
-
- if (offset == 0)
- return;
-
- var length = this.instances.length;
- while (index < length) {
- this.reportInstanceMoved(index);
- index++;
- }
- },
-
- closeInstanceBindings: function(instance) {
- var bindings = instance.bindings_;
- for (var i = 0; i < bindings.length; i++) {
- bindings[i].close();
- }
- },
-
- unobserve: function() {
- if (!this.arrayObserver)
- return;
-
- this.arrayObserver.close();
- this.arrayObserver = undefined;
- },
-
- close: function() {
- if (this.closed)
- return;
- this.unobserve();
- for (var i = 0; i < this.instances.length; i++) {
- this.closeInstanceBindings(this.instances[i]);
- }
-
- this.instances.length = 0;
- this.closeDeps();
- this.templateElement_.iterator_ = undefined;
- this.closed = true;
- }
- };
-
- // Polyfill-specific API.
- HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom;
-})(this);
-
-(function(scope) {
- 'use strict';
-
- // feature detect for URL constructor
- var hasWorkingUrl = false;
- if (!scope.forceJURL) {
- try {
- var u = new URL('b', 'http://a');
- u.pathname = 'c%20d';
- hasWorkingUrl = u.href === 'http://a/c%20d';
- } catch(e) {}
- }
-
- if (hasWorkingUrl)
- return;
-
- var relative = Object.create(null);
- relative['ftp'] = 21;
- relative['file'] = 0;
- relative['gopher'] = 70;
- relative['http'] = 80;
- relative['https'] = 443;
- relative['ws'] = 80;
- relative['wss'] = 443;
-
- var relativePathDotMapping = Object.create(null);
- relativePathDotMapping['%2e'] = '.';
- relativePathDotMapping['.%2e'] = '..';
- relativePathDotMapping['%2e.'] = '..';
- relativePathDotMapping['%2e%2e'] = '..';
-
- function isRelativeScheme(scheme) {
- return relative[scheme] !== undefined;
- }
-
- function invalid() {
- clear.call(this);
- this._isInvalid = true;
- }
-
- function IDNAToASCII(h) {
- if ('' == h) {
- invalid.call(this)
- }
- // XXX
- return h.toLowerCase()
- }
-
- function percentEscape(c) {
- var unicode = c.charCodeAt(0);
- if (unicode > 0x20 &&
- unicode < 0x7F &&
- // " # < > ? `
- [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- function percentEscapeQuery(c) {
- // XXX This actually needs to encode c using encoding and then
- // convert the bytes one-by-one.
-
- var unicode = c.charCodeAt(0);
- if (unicode > 0x20 &&
- unicode < 0x7F &&
- // " # < > ` (do not escape '?')
- [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- var EOF = undefined,
- ALPHA = /[a-zA-Z]/,
- ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
-
- function parse(input, stateOverride, base) {
- function err(message) {
- errors.push(message)
- }
-
- var state = stateOverride || 'scheme start',
- cursor = 0,
- buffer = '',
- seenAt = false,
- seenBracket = false,
- errors = [];
-
- loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
- var c = input[cursor];
- switch (state) {
- case 'scheme start':
- if (c && ALPHA.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- state = 'scheme';
- } else if (!stateOverride) {
- buffer = '';
- state = 'no scheme';
- continue;
- } else {
- err('Invalid scheme.');
- break loop;
- }
- break;
-
- case 'scheme':
- if (c && ALPHANUMERIC.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- } else if (':' == c) {
- this._scheme = buffer;
- buffer = '';
- if (stateOverride) {
- break loop;
- }
- if (isRelativeScheme(this._scheme)) {
- this._isRelative = true;
- }
- if ('file' == this._scheme) {
- state = 'relative';
- } else if (this._isRelative && base && base._scheme == this._scheme) {
- state = 'relative or authority';
- } else if (this._isRelative) {
- state = 'authority first slash';
- } else {
- state = 'scheme data';
- }
- } else if (!stateOverride) {
- buffer = '';
- cursor = 0;
- state = 'no scheme';
- continue;
- } else if (EOF == c) {
- break loop;
- } else {
- err('Code point not allowed in scheme: ' + c)
- break loop;
- }
- break;
-
- case 'scheme data':
- if ('?' == c) {
- query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else {
- // XXX error handling
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._schemeData += percentEscape(c);
- }
- }
- break;
-
- case 'no scheme':
- if (!base || !(isRelativeScheme(base._scheme))) {
- err('Missing scheme.');
- invalid.call(this);
- } else {
- state = 'relative';
- continue;
- }
- break;
-
- case 'relative or authority':
- if ('/' == c && '/' == input[cursor+1]) {
- state = 'authority ignore slashes';
- } else {
- err('Expected /, got: ' + c);
- state = 'relative';
- continue
- }
- break;
-
- case 'relative':
- this._isRelative = true;
- if ('file' != this._scheme)
- this._scheme = base._scheme;
- if (EOF == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- break loop;
- } else if ('/' == c || '\\' == c) {
- if ('\\' == c)
- err('\\ is an invalid code point.');
- state = 'relative slash';
- } else if ('?' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- this._fragment = '#';
- state = 'fragment';
- } else {
- var nextC = input[cursor+1]
- var nextNextC = input[cursor+2]
- if (
- 'file' != this._scheme || !ALPHA.test(c) ||
- (nextC != ':' && nextC != '|') ||
- (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._path.pop();
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'relative slash':
- if ('/' == c || '\\' == c) {
- if ('\\' == c) {
- err('\\ is an invalid code point.');
- }
- if ('file' == this._scheme) {
- state = 'file host';
- } else {
- state = 'authority ignore slashes';
- }
- } else {
- if ('file' != this._scheme) {
- this._host = base._host;
- this._port = base._port;
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'authority first slash':
- if ('/' == c) {
- state = 'authority second slash';
- } else {
- err("Expected '/', got: " + c);
- state = 'authority ignore slashes';
- continue;
- }
- break;
-
- case 'authority second slash':
- state = 'authority ignore slashes';
- if ('/' != c) {
- err("Expected '/', got: " + c);
- continue;
- }
- break;
-
- case 'authority ignore slashes':
- if ('/' != c && '\\' != c) {
- state = 'authority';
- continue;
- } else {
- err('Expected authority, got: ' + c);
- }
- break;
-
- case 'authority':
- if ('@' == c) {
- if (seenAt) {
- err('@ already seen.');
- buffer += '%40';
- }
- seenAt = true;
- for (var i = 0; i < buffer.length; i++) {
- var cp = buffer[i];
- if ('\t' == cp || '\n' == cp || '\r' == cp) {
- err('Invalid whitespace in authority.');
- continue;
- }
- // XXX check URL code points
- if (':' == cp && null === this._password) {
- this._password = '';
- continue;
- }
- var tempC = percentEscape(cp);
- (null !== this._password) ? this._password += tempC : this._username += tempC;
- }
- buffer = '';
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- cursor -= buffer.length;
- buffer = '';
- state = 'host';
- continue;
- } else {
- buffer += c;
- }
- break;
-
- case 'file host':
- if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
- state = 'relative path';
- } else if (buffer.length == 0) {
- state = 'relative path start';
- } else {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- }
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid whitespace in file host.');
- } else {
- buffer += c;
- }
- break;
-
- case 'host':
- case 'hostname':
- if (':' == c && !seenBracket) {
- // XXX host parsing
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'port';
- if ('hostname' == stateOverride) {
- break loop;
- }
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- if (stateOverride) {
- break loop;
- }
- continue;
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- if ('[' == c) {
- seenBracket = true;
- } else if (']' == c) {
- seenBracket = false;
- }
- buffer += c;
- } else {
- err('Invalid code point in host/hostname: ' + c);
- }
- break;
-
- case 'port':
- if (/[0-9]/.test(c)) {
- buffer += c;
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
- if ('' != buffer) {
- var temp = parseInt(buffer, 10);
- if (temp != relative[this._scheme]) {
- this._port = temp + '';
- }
- buffer = '';
- }
- if (stateOverride) {
- break loop;
- }
- state = 'relative path start';
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid code point in port: ' + c);
- } else {
- invalid.call(this);
- }
- break;
-
- case 'relative path start':
- if ('\\' == c)
- err("'\\' not allowed in path.");
- state = 'relative path';
- if ('/' != c && '\\' != c) {
- continue;
- }
- break;
-
- case 'relative path':
- if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
- if ('\\' == c) {
- err('\\ not allowed in relative path.');
- }
- var tmp;
- if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
- buffer = tmp;
- }
- if ('..' == buffer) {
- this._path.pop();
- if ('/' != c && '\\' != c) {
- this._path.push('');
- }
- } else if ('.' == buffer && '/' != c && '\\' != c) {
- this._path.push('');
- } else if ('.' != buffer) {
- if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
- buffer = buffer[0] + ':';
- }
- this._path.push(buffer);
- }
- buffer = '';
- if ('?' == c) {
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- }
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- buffer += percentEscape(c);
- }
- break;
-
- case 'query':
- if (!stateOverride && '#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._query += percentEscapeQuery(c);
- }
- break;
-
- case 'fragment':
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._fragment += c;
- }
- break;
- }
-
- cursor++;
- }
- }
-
- function clear() {
- this._scheme = '';
- this._schemeData = '';
- this._username = '';
- this._password = null;
- this._host = '';
- this._port = '';
- this._path = [];
- this._query = '';
- this._fragment = '';
- this._isInvalid = false;
- this._isRelative = false;
- }
-
- // Does not process domain names or IP addresses.
- // Does not handle encoding for the query parameter.
- function jURL(url, base /* , encoding */) {
- if (base !== undefined && !(base instanceof jURL))
- base = new jURL(String(base));
-
- this._url = url;
- clear.call(this);
-
- var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
- // encoding = encoding || 'utf-8'
-
- parse.call(this, input, null, base);
- }
-
- jURL.prototype = {
- get href() {
- if (this._isInvalid)
- return this._url;
-
- var authority = '';
- if ('' != this._username || null != this._password) {
- authority = this._username +
- (null != this._password ? ':' + this._password : '') + '@';
- }
-
- return this.protocol +
- (this._isRelative ? '//' + authority + this.host : '') +
- this.pathname + this._query + this._fragment;
- },
- set href(href) {
- clear.call(this);
- parse.call(this, href);
- },
-
- get protocol() {
- return this._scheme + ':';
- },
- set protocol(protocol) {
- if (this._isInvalid)
- return;
- parse.call(this, protocol + ':', 'scheme start');
- },
-
- get host() {
- return this._isInvalid ? '' : this._port ?
- this._host + ':' + this._port : this._host;
- },
- set host(host) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, host, 'host');
- },
-
- get hostname() {
- return this._host;
- },
- set hostname(hostname) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, hostname, 'hostname');
- },
-
- get port() {
- return this._port;
- },
- set port(port) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, port, 'port');
- },
-
- get pathname() {
- return this._isInvalid ? '' : this._isRelative ?
- '/' + this._path.join('/') : this._schemeData;
- },
- set pathname(pathname) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._path = [];
- parse.call(this, pathname, 'relative path start');
- },
-
- get search() {
- return this._isInvalid || !this._query || '?' == this._query ?
- '' : this._query;
- },
- set search(search) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._query = '?';
- if ('?' == search[0])
- search = search.slice(1);
- parse.call(this, search, 'query');
- },
-
- get hash() {
- return this._isInvalid || !this._fragment || '#' == this._fragment ?
- '' : this._fragment;
- },
- set hash(hash) {
- if (this._isInvalid)
- return;
- this._fragment = '#';
- if ('#' == hash[0])
- hash = hash.slice(1);
- parse.call(this, hash, 'fragment');
- },
-
- get origin() {
- var host;
- if (this._isInvalid || !this._scheme) {
- return '';
- }
- // javascript: Gecko returns String(""), WebKit/Blink String("null")
- // Gecko throws error for "data://"
- // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
- // Gecko returns String("") for file: mailto:
- // WebKit/Blink returns String("SCHEME://") for file: mailto:
- switch (this._scheme) {
- case 'data':
- case 'file':
- case 'javascript':
- case 'mailto':
- return 'null';
- }
- host = this.host;
- if (!host) {
- return '';
- }
- return this._scheme + '://' + host;
- }
- };
-
- // Copy over the static methods
- var OriginalURL = scope.URL;
- if (OriginalURL) {
- jURL.createObjectURL = function(blob) {
- // IE extension allows a second optional options argument.
- // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
- return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
- };
- jURL.revokeObjectURL = function(url) {
- OriginalURL.revokeObjectURL(url);
- };
- }
-
- scope.URL = jURL;
-
-})(this);
-
-(function(scope) {
-
-var iterations = 0;
-var callbacks = [];
-var twiddle = document.createTextNode('');
-
-function endOfMicrotask(callback) {
- twiddle.textContent = iterations++;
- callbacks.push(callback);
-}
-
-function atEndOfMicrotask() {
- while (callbacks.length) {
- callbacks.shift()();
- }
-}
-
-new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask)
- .observe(twiddle, {characterData: true})
- ;
-
-// exports
-scope.endOfMicrotask = endOfMicrotask;
-// bc
-Platform.endOfMicrotask = endOfMicrotask;
-
-})(Polymer);
-
-
-(function(scope) {
-
-/**
- * @class Polymer
- */
-
-// imports
-var endOfMicrotask = scope.endOfMicrotask;
-
-// logging
-var log = window.WebComponents ? WebComponents.flags.log : {};
-
-// inject style sheet
-var style = document.createElement('style');
-style.textContent = 'template {display: none !important;} /* injected by platform.js */';
-var head = document.querySelector('head');
-head.insertBefore(style, head.firstChild);
-
-
-/**
- * Force any pending data changes to be observed before
- * the next task. Data changes are processed asynchronously but are guaranteed
- * to be processed, for example, before painting. This method should rarely be
- * needed. It does nothing when Object.observe is available;
- * when Object.observe is not available, Polymer automatically flushes data
- * changes approximately every 1/10 second.
- * Therefore, `flush` should only be used when a data mutation should be
- * observed sooner than this.
- *
- * @method flush
- */
-// flush (with logging)
-var flushing;
-function flush() {
- if (!flushing) {
- flushing = true;
- endOfMicrotask(function() {
- flushing = false;
- log.data && console.group('flush');
- Platform.performMicrotaskCheckpoint();
- log.data && console.groupEnd();
- });
- }
-};
-
-// polling dirty checker
-// flush periodically if platform does not have object observe.
-if (!Observer.hasObjectObserve) {
- var FLUSH_POLL_INTERVAL = 125;
- window.addEventListener('WebComponentsReady', function() {
- flush();
- // watch document visiblity to toggle dirty-checking
- var visibilityHandler = function() {
- // only flush if the page is visibile
- if (document.visibilityState === 'hidden') {
- if (scope.flushPoll) {
- clearInterval(scope.flushPoll);
- }
- } else {
- scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL);
- }
- };
- if (typeof document.visibilityState === 'string') {
- document.addEventListener('visibilitychange', visibilityHandler);
- }
- visibilityHandler();
- });
-} else {
- // make flush a no-op when we have Object.observe
- flush = function() {};
-}
-
-if (window.CustomElements && !CustomElements.useNative) {
- var originalImportNode = Document.prototype.importNode;
- Document.prototype.importNode = function(node, deep) {
- var imported = originalImportNode.call(this, node, deep);
- CustomElements.upgradeAll(imported);
- return imported;
- };
-}
-
-// exports
-scope.flush = flush;
-// bc
-Platform.flush = flush;
-
-})(window.Polymer);
-
-
-(function(scope) {
-
-var urlResolver = {
- resolveDom: function(root, url) {
- url = url || baseUrl(root);
- this.resolveAttributes(root, url);
- this.resolveStyles(root, url);
- // handle template.content
- var templates = root.querySelectorAll('template');
- if (templates) {
- for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i++) {
- if (t.content) {
- this.resolveDom(t.content, url);
- }
- }
- }
- },
- resolveTemplate: function(template) {
- this.resolveDom(template.content, baseUrl(template));
- },
- resolveStyles: function(root, url) {
- var styles = root.querySelectorAll('style');
- if (styles) {
- for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) {
- this.resolveStyle(s, url);
- }
- }
- },
- resolveStyle: function(style, url) {
- url = url || baseUrl(style);
- style.textContent = this.resolveCssText(style.textContent, url);
- },
- resolveCssText: function(cssText, baseUrl, keepAbsolute) {
- cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEXP);
- return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEXP);
- },
- resolveAttributes: function(root, url) {
- if (root.hasAttributes && root.hasAttributes()) {
- this.resolveElementAttributes(root, url);
- }
- // search for attributes that host urls
- var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR);
- if (nodes) {
- for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) {
- this.resolveElementAttributes(n, url);
- }
- }
- },
- resolveElementAttributes: function(node, url) {
- url = url || baseUrl(node);
- URL_ATTRS.forEach(function(v) {
- var attr = node.attributes[v];
- var value = attr && attr.value;
- var replacement;
- if (value && value.search(URL_TEMPLATE_SEARCH) < 0) {
- if (v === 'style') {
- replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP);
- } else {
- replacement = resolveRelativeUrl(url, value);
- }
- attr.value = replacement;
- }
- });
- }
-};
-
-var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
-var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
-var URL_ATTRS = ['href', 'src', 'action', 'style', 'url'];
-var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']';
-var URL_TEMPLATE_SEARCH = '{{.*}}';
-var URL_HASH = '#';
-
-function baseUrl(node) {
- var u = new URL(node.ownerDocument.baseURI);
- u.search = '';
- u.hash = '';
- return u;
-}
-
-function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) {
- return cssText.replace(regexp, function(m, pre, url, post) {
- var urlPath = url.replace(/["']/g, '');
- urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute);
- return pre + '\'' + urlPath + '\'' + post;
- });
-}
-
-function resolveRelativeUrl(baseUrl, url, keepAbsolute) {
- // do not resolve '/' absolute urls
- if (url && url[0] === '/') {
- return url;
- }
- // do not resolve '#' links, they are used for routing
- if (url && url[0] === '#') {
- return url;
- }
- var u = new URL(url, baseUrl);
- return keepAbsolute ? u.href : makeDocumentRelPath(u.href);
-}
-
-function makeDocumentRelPath(url) {
- var root = baseUrl(document.documentElement);
- var u = new URL(url, root);
- if (u.host === root.host && u.port === root.port &&
- u.protocol === root.protocol) {
- return makeRelPath(root, u);
- } else {
- return url;
- }
-}
-
-// make a relative path from source to target
-function makeRelPath(sourceUrl, targetUrl) {
- var source = sourceUrl.pathname;
- var target = targetUrl.pathname;
- var s = source.split('/');
- var t = target.split('/');
- while (s.length && s[0] === t[0]){
- s.shift();
- t.shift();
- }
- for (var i = 0, l = s.length - 1; i < l; i++) {
- t.unshift('..');
- }
- // empty '#' is discarded but we need to preserve it.
- var hash = (targetUrl.href.slice(-1) === URL_HASH) ? URL_HASH : targetUrl.hash;
- return t.join('/') + targetUrl.search + hash;
-}
-
-// exports
-scope.urlResolver = urlResolver;
-
-})(Polymer);
-
-(function(scope) {
- var endOfMicrotask = Polymer.endOfMicrotask;
-
- // Generic url loader
- function Loader(regex) {
- this.cache = Object.create(null);
- this.map = Object.create(null);
- this.requests = 0;
- this.regex = regex;
- }
- Loader.prototype = {
-
- // TODO(dfreedm): there may be a better factoring here
- // extract absolute urls from the text (full of relative urls)
- extractUrls: function(text, base) {
- var matches = [];
- var matched, u;
- while ((matched = this.regex.exec(text))) {
- u = new URL(matched[1], base);
- matches.push({matched: matched[0], url: u.href});
- }
- return matches;
- },
- // take a text blob, a root url, and a callback and load all the urls found within the text
- // returns a map of absolute url to text
- process: function(text, root, callback) {
- var matches = this.extractUrls(text, root);
-
- // every call to process returns all the text this loader has ever received
- var done = callback.bind(null, this.map);
- this.fetch(matches, done);
- },
- // build a mapping of url -> text from matches
- fetch: function(matches, callback) {
- var inflight = matches.length;
-
- // return early if there is no fetching to be done
- if (!inflight) {
- return callback();
- }
-
- // wait for all subrequests to return
- var done = function() {
- if (--inflight === 0) {
- callback();
- }
- };
-
- // start fetching all subrequests
- var m, req, url;
- for (var i = 0; i < inflight; i++) {
- m = matches[i];
- url = m.url;
- req = this.cache[url];
- // if this url has already been requested, skip requesting it again
- if (!req) {
- req = this.xhr(url);
- req.match = m;
- this.cache[url] = req;
- }
- // wait for the request to process its subrequests
- req.wait(done);
- }
- },
- handleXhr: function(request) {
- var match = request.match;
- var url = match.url;
-
- // handle errors with an empty string
- var response = request.response || request.responseText || '';
- this.map[url] = response;
- this.fetch(this.extractUrls(response, url), request.resolve);
- },
- xhr: function(url) {
- this.requests++;
- var request = new XMLHttpRequest();
- request.open('GET', url, true);
- request.send();
- request.onerror = request.onload = this.handleXhr.bind(this, request);
-
- // queue of tasks to run after XHR returns
- request.pending = [];
- request.resolve = function() {
- var pending = request.pending;
- for(var i = 0; i < pending.length; i++) {
- pending[i]();
- }
- request.pending = null;
- };
-
- // if we have already resolved, pending is null, async call the callback
- request.wait = function(fn) {
- if (request.pending) {
- request.pending.push(fn);
- } else {
- endOfMicrotask(fn);
- }
- };
-
- return request;
- }
- };
-
- scope.Loader = Loader;
-})(Polymer);
-
-(function(scope) {
-
-var urlResolver = scope.urlResolver;
-var Loader = scope.Loader;
-
-function StyleResolver() {
- this.loader = new Loader(this.regex);
-}
-StyleResolver.prototype = {
- regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,
- // Recursively replace @imports with the text at that url
- resolve: function(text, url, callback) {
- var done = function(map) {
- callback(this.flatten(text, url, map));
- }.bind(this);
- this.loader.process(text, url, done);
- },
- // resolve the textContent of a style node
- resolveNode: function(style, url, callback) {
- var text = style.textContent;
- var done = function(text) {
- style.textContent = text;
- callback(style);
- };
- this.resolve(text, url, done);
- },
- // flatten all the @imports to text
- flatten: function(text, base, map) {
- var matches = this.loader.extractUrls(text, base);
- var match, url, intermediate;
- for (var i = 0; i < matches.length; i++) {
- match = matches[i];
- url = match.url;
- // resolve any css text to be relative to the importer, keep absolute url
- intermediate = urlResolver.resolveCssText(map[url], url, true);
- // flatten intermediate @imports
- intermediate = this.flatten(intermediate, base, map);
- text = text.replace(match.matched, intermediate);
- }
- return text;
- },
- loadStyles: function(styles, base, callback) {
- var loaded=0, l = styles.length;
- // called in the context of the style
- function loadedStyle(style) {
- loaded++;
- if (loaded === l && callback) {
- callback();
- }
- }
- for (var i=0, s; (i<l) && (s=styles[i]); i++) {
- this.resolveNode(s, base, loadedStyle);
- }
- }
-};
-
-var styleResolver = new StyleResolver();
-
-// exports
-scope.styleResolver = styleResolver;
-
-})(Polymer);
-
-(function(scope) {
-
- // copy own properties from 'api' to 'prototype, with name hinting for 'super'
- function extend(prototype, api) {
- if (prototype && api) {
- // use only own properties of 'api'
- Object.getOwnPropertyNames(api).forEach(function(n) {
- // acquire property descriptor
- var pd = Object.getOwnPropertyDescriptor(api, n);
- if (pd) {
- // clone property via descriptor
- Object.defineProperty(prototype, n, pd);
- // cache name-of-method for 'super' engine
- if (typeof pd.value == 'function') {
- // hint the 'super' engine
- pd.value.nom = n;
- }
- }
- });
- }
- return prototype;
- }
-
-
- // mixin
-
- // copy all properties from inProps (et al) to inObj
- function mixin(inObj/*, inProps, inMoreProps, ...*/) {
- var obj = inObj || {};
- for (var i = 1; i < arguments.length; i++) {
- var p = arguments[i];
- try {
- for (var n in p) {
- copyProperty(n, p, obj);
- }
- } catch(x) {
- }
- }
- return obj;
- }
-
- // copy property inName from inSource object to inTarget object
- function copyProperty(inName, inSource, inTarget) {
- var pd = getPropertyDescriptor(inSource, inName);
- Object.defineProperty(inTarget, inName, pd);
- }
-
- // get property descriptor for inName on inObject, even if
- // inName exists on some link in inObject's prototype chain
- function getPropertyDescriptor(inObject, inName) {
- if (inObject) {
- var pd = Object.getOwnPropertyDescriptor(inObject, inName);
- return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);
- }
- }
-
- // exports
-
- scope.extend = extend;
- scope.mixin = mixin;
-
- // for bc
- Platform.mixin = mixin;
-
-})(Polymer);
-
-(function(scope) {
-
- // usage
-
- // invoke cb.call(this) in 100ms, unless the job is re-registered,
- // which resets the timer
- //
- // this.myJob = this.job(this.myJob, cb, 100)
- //
- // returns a job handle which can be used to re-register a job
-
- var Job = function(inContext) {
- this.context = inContext;
- this.boundComplete = this.complete.bind(this)
- };
- Job.prototype = {
- go: function(callback, wait) {
- this.callback = callback;
- var h;
- if (!wait) {
- h = requestAnimationFrame(this.boundComplete);
- this.handle = function() {
- cancelAnimationFrame(h);
- }
- } else {
- h = setTimeout(this.boundComplete, wait);
- this.handle = function() {
- clearTimeout(h);
- }
- }
- },
- stop: function() {
- if (this.handle) {
- this.handle();
- this.handle = null;
- }
- },
- complete: function() {
- if (this.handle) {
- this.stop();
- this.callback.call(this.context);
- }
- }
- };
-
- function job(job, callback, wait) {
- if (job) {
- job.stop();
- } else {
- job = new Job(this);
- }
- job.go(callback, wait);
- return job;
- }
-
- // exports
-
- scope.job = job;
-
-})(Polymer);
-
-(function(scope) {
-
- // dom polyfill, additions, and utility methods
-
- var registry = {};
-
- HTMLElement.register = function(tag, prototype) {
- registry[tag] = prototype;
- };
-
- // get prototype mapped to node <tag>
- HTMLElement.getPrototypeForTag = function(tag) {
- var prototype = !tag ? HTMLElement.prototype : registry[tag];
- // TODO(sjmiles): creating <tag> is likely to have wasteful side-effects
- return prototype || Object.getPrototypeOf(document.createElement(tag));
- };
-
- // we have to flag propagation stoppage for the event dispatcher
- var originalStopPropagation = Event.prototype.stopPropagation;
- Event.prototype.stopPropagation = function() {
- this.cancelBubble = true;
- originalStopPropagation.apply(this, arguments);
- };
-
-
- // polyfill DOMTokenList
- // * add/remove: allow these methods to take multiple classNames
- // * toggle: add a 2nd argument which forces the given state rather
- // than toggling.
-
- var add = DOMTokenList.prototype.add;
- var remove = DOMTokenList.prototype.remove;
- DOMTokenList.prototype.add = function() {
- for (var i = 0; i < arguments.length; i++) {
- add.call(this, arguments[i]);
- }
- };
- DOMTokenList.prototype.remove = function() {
- for (var i = 0; i < arguments.length; i++) {
- remove.call(this, arguments[i]);
- }
- };
- DOMTokenList.prototype.toggle = function(name, bool) {
- if (arguments.length == 1) {
- bool = !this.contains(name);
- }
- bool ? this.add(name) : this.remove(name);
- };
- DOMTokenList.prototype.switch = function(oldName, newName) {
- oldName && this.remove(oldName);
- newName && this.add(newName);
- };
-
- // add array() to NodeList, NamedNodeMap, HTMLCollection
-
- var ArraySlice = function() {
- return Array.prototype.slice.call(this);
- };
-
- var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {});
-
- NodeList.prototype.array = ArraySlice;
- namedNodeMap.prototype.array = ArraySlice;
- HTMLCollection.prototype.array = ArraySlice;
-
- // utility
-
- function createDOM(inTagOrNode, inHTML, inAttrs) {
- var dom = typeof inTagOrNode == 'string' ?
- document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true);
- dom.innerHTML = inHTML;
- if (inAttrs) {
- for (var n in inAttrs) {
- dom.setAttribute(n, inAttrs[n]);
- }
- }
- return dom;
- }
-
- // exports
-
- scope.createDOM = createDOM;
-
-})(Polymer);
-
-(function(scope) {
- // super
-
- // `arrayOfArgs` is an optional array of args like one might pass
- // to `Function.apply`
-
- // TODO(sjmiles):
- // $super must be installed on an instance or prototype chain
- // as `super`, and invoked via `this`, e.g.
- // `this.super();`
-
- // will not work if function objects are not unique, for example,
- // when using mixins.
- // The memoization strategy assumes each function exists on only one
- // prototype chain i.e. we use the function object for memoizing)
- // perhaps we can bookkeep on the prototype itself instead
- function $super(arrayOfArgs) {
- // since we are thunking a method call, performance is important here:
- // memoize all lookups, once memoized the fast path calls no other
- // functions
- //
- // find the caller (cannot be `strict` because of 'caller')
- var caller = $super.caller;
- // memoized 'name of method'
- var nom = caller.nom;
- // memoized next implementation prototype
- var _super = caller._super;
- if (!_super) {
- if (!nom) {
- nom = caller.nom = nameInThis.call(this, caller);
- }
- if (!nom) {
- console.warn('called super() on a method not installed declaratively (has no .nom property)');
- }
- // super prototype is either cached or we have to find it
- // by searching __proto__ (at the 'top')
- // invariant: because we cache _super on fn below, we never reach
- // here from inside a series of calls to super(), so it's ok to
- // start searching from the prototype of 'this' (at the 'top')
- // we must never memoize a null super for this reason
- _super = memoizeSuper(caller, nom, getPrototypeOf(this));
- }
- // our super function
- var fn = _super[nom];
- if (fn) {
- // memoize information so 'fn' can call 'super'
- if (!fn._super) {
- // must not memoize null, or we lose our invariant above
- memoizeSuper(fn, nom, _super);
- }
- // invoke the inherited method
- // if 'fn' is not function valued, this will throw
- return fn.apply(this, arrayOfArgs || []);
- }
- }
-
- function nameInThis(value) {
- var p = this.__proto__;
- while (p && p !== HTMLElement.prototype) {
- // TODO(sjmiles): getOwnPropertyNames is absurdly expensive
- var n$ = Object.getOwnPropertyNames(p);
- for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) {
- var d = Object.getOwnPropertyDescriptor(p, n);
- if (typeof d.value === 'function' && d.value === value) {
- return n;
- }
- }
- p = p.__proto__;
- }
- }
-
- function memoizeSuper(method, name, proto) {
- // find and cache next prototype containing `name`
- // we need the prototype so we can do another lookup
- // from here
- var s = nextSuper(proto, name, method);
- if (s[name]) {
- // `s` is a prototype, the actual method is `s[name]`
- // tag super method with it's name for quicker lookups
- s[name].nom = name;
- }
- return method._super = s;
- }
-
- function nextSuper(proto, name, caller) {
- // look for an inherited prototype that implements name
- while (proto) {
- if ((proto[name] !== caller) && proto[name]) {
- return proto;
- }
- proto = getPrototypeOf(proto);
- }
- // must not return null, or we lose our invariant above
- // in this case, a super() call was invoked where no superclass
- // method exists
- // TODO(sjmiles): thow an exception?
- return Object;
- }
-
- // NOTE: In some platforms (IE10) the prototype chain is faked via
- // __proto__. Therefore, always get prototype via __proto__ instead of
- // the more standard Object.getPrototypeOf.
- function getPrototypeOf(prototype) {
- return prototype.__proto__;
- }
-
- // utility function to precompute name tags for functions
- // in a (unchained) prototype
- function hintSuper(prototype) {
- // tag functions with their prototype name to optimize
- // super call invocations
- for (var n in prototype) {
- var pd = Object.getOwnPropertyDescriptor(prototype, n);
- if (pd && typeof pd.value === 'function') {
- pd.value.nom = n;
- }
- }
- }
-
- // exports
-
- scope.super = $super;
-
-})(Polymer);
-
-(function(scope) {
-
- function noopHandler(value) {
- return value;
- }
-
- // helper for deserializing properties of various types to strings
- var typeHandlers = {
- string: noopHandler,
- 'undefined': noopHandler,
- date: function(value) {
- return new Date(Date.parse(value) || Date.now());
- },
- boolean: function(value) {
- if (value === '') {
- return true;
- }
- return value === 'false' ? false : !!value;
- },
- number: function(value) {
- var n = parseFloat(value);
- // hex values like "0xFFFF" parseFloat as 0
- if (n === 0) {
- n = parseInt(value);
- }
- return isNaN(n) ? value : n;
- // this code disabled because encoded values (like "0xFFFF")
- // do not round trip to their original format
- //return (String(floatVal) === value) ? floatVal : value;
- },
- object: function(value, currentValue) {
- if (currentValue === null) {
- return value;
- }
- try {
- // If the string is an object, we can parse is with the JSON library.
- // include convenience replace for single-quotes. If the author omits
- // quotes altogether, parse will fail.
- return JSON.parse(value.replace(/'/g, '"'));
- } catch(e) {
- // The object isn't valid JSON, return the raw value
- return value;
- }
- },
- // avoid deserialization of functions
- 'function': function(value, currentValue) {
- return currentValue;
- }
- };
-
- function deserializeValue(value, currentValue) {
- // attempt to infer type from default value
- var inferredType = typeof currentValue;
- // invent 'date' type value for Date
- if (currentValue instanceof Date) {
- inferredType = 'date';
- }
- // delegate deserialization via type string
- return typeHandlers[inferredType](value, currentValue);
- }
-
- // exports
-
- scope.deserializeValue = deserializeValue;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var extend = scope.extend;
-
- // module
-
- var api = {};
-
- api.declaration = {};
- api.instance = {};
-
- api.publish = function(apis, prototype) {
- for (var n in apis) {
- extend(prototype, apis[n]);
- }
- };
-
- // exports
-
- scope.api = api;
-
-})(Polymer);
-
-(function(scope) {
-
- /**
- * @class polymer-base
- */
-
- var utils = {
-
- /**
- * Invokes a function asynchronously. The context of the callback
- * function is bound to 'this' automatically. Returns a handle which may
- * be passed to <a href="#cancelAsync">cancelAsync</a> to cancel the
- * asynchronous call.
- *
- * @method async
- * @param {Function|String} method
- * @param {any|Array} args
- * @param {number} timeout
- */
- async: function(method, args, timeout) {
- // when polyfilling Object.observe, ensure changes
- // propagate before executing the async method
- Polymer.flush();
- // second argument to `apply` must be an array
- args = (args && args.length) ? args : [args];
- // function to invoke
- var fn = function() {
- (this[method] || method).apply(this, args);
- }.bind(this);
- // execute `fn` sooner or later
- var handle = timeout ? setTimeout(fn, timeout) :
- requestAnimationFrame(fn);
- // NOTE: switch on inverting handle to determine which time is used.
- return timeout ? handle : ~handle;
- },
-
- /**
- * Cancels a pending callback that was scheduled via
- * <a href="#async">async</a>.
- *
- * @method cancelAsync
- * @param {handle} handle Handle of the `async` to cancel.
- */
- cancelAsync: function(handle) {
- if (handle < 0) {
- cancelAnimationFrame(~handle);
- } else {
- clearTimeout(handle);
- }
- },
-
- /**
- * Fire an event.
- *
- * @method fire
- * @returns {Object} event
- * @param {string} type An event name.
- * @param {any} detail
- * @param {Node} onNode Target node.
- * @param {Boolean} bubbles Set false to prevent bubbling, defaults to true
- * @param {Boolean} cancelable Set false to prevent cancellation, defaults to true
- */
- fire: function(type, detail, onNode, bubbles, cancelable) {
- var node = onNode || this;
- var detail = detail === null || detail === undefined ? {} : detail;
- var event = new CustomEvent(type, {
- bubbles: bubbles !== undefined ? bubbles : true,
- cancelable: cancelable !== undefined ? cancelable : true,
- detail: detail
- });
- node.dispatchEvent(event);
- return event;
- },
-
- /**
- * Fire an event asynchronously.
- *
- * @method asyncFire
- * @param {string} type An event name.
- * @param detail
- * @param {Node} toNode Target node.
- */
- asyncFire: function(/*inType, inDetail*/) {
- this.async("fire", arguments);
- },
-
- /**
- * Remove class from old, add class to anew, if they exist.
- *
- * @param classFollows
- * @param anew A node.
- * @param old A node
- * @param className
- */
- classFollows: function(anew, old, className) {
- if (old) {
- old.classList.remove(className);
- }
- if (anew) {
- anew.classList.add(className);
- }
- },
-
- /**
- * Inject HTML which contains markup bound to this element into
- * a target element (replacing target element content).
- *
- * @param String html to inject
- * @param Element target element
- */
- injectBoundHTML: function(html, element) {
- var template = document.createElement('template');
- template.innerHTML = html;
- var fragment = this.instanceTemplate(template);
- if (element) {
- element.textContent = '';
- element.appendChild(fragment);
- }
- return fragment;
- }
- };
-
- // no-operation function for handy stubs
- var nop = function() {};
-
- // null-object for handy stubs
- var nob = {};
-
- // deprecated
-
- utils.asyncMethod = utils.async;
-
- // exports
-
- scope.api.instance.utils = utils;
- scope.nop = nop;
- scope.nob = nob;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
- var EVENT_PREFIX = 'on-';
-
- // instance events api
- var events = {
- // read-only
- EVENT_PREFIX: EVENT_PREFIX,
- // event listeners on host
- addHostListeners: function() {
- var events = this.eventDelegates;
- log.events && (Object.keys(events).length > 0) && console.log('[%s] addHostListeners:', this.localName, events);
- // NOTE: host events look like bindings but really are not;
- // (1) we don't want the attribute to be set and (2) we want to support
- // multiple event listeners ('host' and 'instance') and Node.bind
- // by default supports 1 thing being bound.
- for (var type in events) {
- var methodName = events[type];
- PolymerGestures.addEventListener(this, type, this.element.getEventHandler(this, this, methodName));
- }
- },
- // call 'method' or function method on 'obj' with 'args', if the method exists
- dispatchMethod: function(obj, method, args) {
- if (obj) {
- log.events && console.group('[%s] dispatch [%s]', obj.localName, method);
- var fn = typeof method === 'function' ? method : obj[method];
- if (fn) {
- fn[args ? 'apply' : 'call'](obj, args);
- }
- log.events && console.groupEnd();
- // NOTE: dirty check right after calling method to ensure
- // changes apply quickly; in a very complicated app using high
- // frequency events, this can be a perf concern; in this case,
- // imperative handlers can be used to avoid flushing.
- Polymer.flush();
- }
- }
- };
-
- // exports
-
- scope.api.instance.events = events;
-
- /**
- * @class Polymer
- */
-
- /**
- * Add a gesture aware event handler to the given `node`. Can be used
- * in place of `element.addEventListener` and ensures gestures will function
- * as expected on mobile platforms. Please note that Polymer's declarative
- * event handlers include this functionality by default.
- *
- * @method addEventListener
- * @param {Node} node node on which to listen
- * @param {String} eventType name of the event
- * @param {Function} handlerFn event handler function
- * @param {Boolean} capture set to true to invoke event capturing
- * @type Function
- */
- // alias PolymerGestures event listener logic
- scope.addEventListener = function(node, eventType, handlerFn, capture) {
- PolymerGestures.addEventListener(wrap(node), eventType, handlerFn, capture);
- };
-
- /**
- * Remove a gesture aware event handler on the given `node`. To remove an
- * event listener, the exact same arguments are required that were passed
- * to `Polymer.addEventListener`.
- *
- * @method removeEventListener
- * @param {Node} node node on which to listen
- * @param {String} eventType name of the event
- * @param {Function} handlerFn event handler function
- * @param {Boolean} capture set to true to invoke event capturing
- * @type Function
- */
- scope.removeEventListener = function(node, eventType, handlerFn, capture) {
- PolymerGestures.removeEventListener(wrap(node), eventType, handlerFn, capture);
- };
-
-})(Polymer);
-
-(function(scope) {
-
- // instance api for attributes
-
- var attributes = {
- // copy attributes defined in the element declaration to the instance
- // e.g. <polymer-element name="x-foo" tabIndex="0"> tabIndex is copied
- // to the element instance here.
- copyInstanceAttributes: function () {
- var a$ = this._instanceAttributes;
- for (var k in a$) {
- if (!this.hasAttribute(k)) {
- this.setAttribute(k, a$[k]);
- }
- }
- },
- // for each attribute on this, deserialize value to property as needed
- takeAttributes: function() {
- // if we have no publish lookup table, we have no attributes to take
- // TODO(sjmiles): ad hoc
- if (this._publishLC) {
- for (var i=0, a$=this.attributes, l=a$.length, a; (a=a$[i]) && i<l; i++) {
- this.attributeToProperty(a.name, a.value);
- }
- }
- },
- // if attribute 'name' is mapped to a property, deserialize
- // 'value' into that property
- attributeToProperty: function(name, value) {
- // try to match this attribute to a property (attributes are
- // all lower-case, so this is case-insensitive search)
- var name = this.propertyForAttribute(name);
- if (name) {
- // filter out 'mustached' values, these are to be
- // replaced with bound-data and are not yet values
- // themselves
- if (value && value.search(scope.bindPattern) >= 0) {
- return;
- }
- // get original value
- var currentValue = this[name];
- // deserialize Boolean or Number values from attribute
- var value = this.deserializeValue(value, currentValue);
- // only act if the value has changed
- if (value !== currentValue) {
- // install new value (has side-effects)
- this[name] = value;
- }
- }
- },
- // return the published property matching name, or undefined
- propertyForAttribute: function(name) {
- var match = this._publishLC && this._publishLC[name];
- return match;
- },
- // convert representation of `stringValue` based on type of `currentValue`
- deserializeValue: function(stringValue, currentValue) {
- return scope.deserializeValue(stringValue, currentValue);
- },
- // convert to a string value based on the type of `inferredType`
- serializeValue: function(value, inferredType) {
- if (inferredType === 'boolean') {
- return value ? '' : undefined;
- } else if (inferredType !== 'object' && inferredType !== 'function'
- && value !== undefined) {
- return value;
- }
- },
- // serializes `name` property value and updates the corresponding attribute
- // note that reflection is opt-in.
- reflectPropertyToAttribute: function(name) {
- var inferredType = typeof this[name];
- // try to intelligently serialize property value
- var serializedValue = this.serializeValue(this[name], inferredType);
- // boolean properties must reflect as boolean attributes
- if (serializedValue !== undefined) {
- this.setAttribute(name, serializedValue);
- // TODO(sorvell): we should remove attr for all properties
- // that have undefined serialization; however, we will need to
- // refine the attr reflection system to achieve this; pica, for example,
- // relies on having inferredType object properties not removed as
- // attrs.
- } else if (inferredType === 'boolean') {
- this.removeAttribute(name);
- }
- }
- };
-
- // exports
-
- scope.api.instance.attributes = attributes;
-
-})(Polymer);
-
-(function(scope) {
-
- /**
- * @class polymer-base
- */
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
-
- // magic words
-
- var OBSERVE_SUFFIX = 'Changed';
-
- // element api
-
- var empty = [];
-
- var updateRecord = {
- object: undefined,
- type: 'update',
- name: undefined,
- oldValue: undefined
- };
-
- var numberIsNaN = Number.isNaN || function(value) {
- return typeof value === 'number' && isNaN(value);
- };
-
- function areSameValue(left, right) {
- if (left === right)
- return left !== 0 || 1 / left === 1 / right;
- if (numberIsNaN(left) && numberIsNaN(right))
- return true;
- return left !== left && right !== right;
- }
-
- // capture A's value if B's value is null or undefined,
- // otherwise use B's value
- function resolveBindingValue(oldValue, value) {
- if (value === undefined && oldValue === null) {
- return value;
- }
- return (value === null || value === undefined) ? oldValue : value;
- }
-
- var properties = {
-
- // creates a CompoundObserver to observe property changes
- // NOTE, this is only done there are any properties in the `observe` object
- createPropertyObserver: function() {
- var n$ = this._observeNames;
- if (n$ && n$.length) {
- var o = this._propertyObserver = new CompoundObserver(true);
- this.registerObserver(o);
- // TODO(sorvell): may not be kosher to access the value here (this[n]);
- // previously we looked at the descriptor on the prototype
- // this doesn't work for inheritance and not for accessors without
- // a value property
- for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
- o.addPath(this, n);
- this.observeArrayValue(n, this[n], null);
- }
- }
- },
-
- // start observing property changes
- openPropertyObserver: function() {
- if (this._propertyObserver) {
- this._propertyObserver.open(this.notifyPropertyChanges, this);
- }
- },
-
- // handler for property changes; routes changes to observing methods
- // note: array valued properties are observed for array splices
- notifyPropertyChanges: function(newValues, oldValues, paths) {
- var name, method, called = {};
- for (var i in oldValues) {
- // note: paths is of form [object, path, object, path]
- name = paths[2 * i + 1];
- method = this.observe[name];
- if (method) {
- var ov = oldValues[i], nv = newValues[i];
- // observes the value if it is an array
- this.observeArrayValue(name, nv, ov);
- if (!called[method]) {
- // only invoke change method if one of ov or nv is not (undefined | null)
- if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !== null)) {
- called[method] = true;
- // TODO(sorvell): call method with the set of values it's expecting;
- // e.g. 'foo bar': 'invalidate' expects the new and old values for
- // foo and bar. Currently we give only one of these and then
- // deliver all the arguments.
- this.invokeMethod(method, [ov, nv, arguments]);
- }
- }
- }
- }
- },
-
- // call method iff it exists.
- invokeMethod: function(method, args) {
- var fn = this[method] || method;
- if (typeof fn === 'function') {
- fn.apply(this, args);
- }
- },
-
- /**
- * Force any pending property changes to synchronously deliver to
- * handlers specified in the `observe` object.
- * Note, normally changes are processed at microtask time.
- *
- * @method deliverChanges
- */
- deliverChanges: function() {
- if (this._propertyObserver) {
- this._propertyObserver.deliver();
- }
- },
-
- observeArrayValue: function(name, value, old) {
- // we only care if there are registered side-effects
- var callbackName = this.observe[name];
- if (callbackName) {
- // if we are observing the previous value, stop
- if (Array.isArray(old)) {
- log.observe && console.log('[%s] observeArrayValue: unregister observer [%s]', this.localName, name);
- this.closeNamedObserver(name + '__array');
- }
- // if the new value is an array, being observing it
- if (Array.isArray(value)) {
- log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
- var observer = new ArrayObserver(value);
- observer.open(function(splices) {
- this.invokeMethod(callbackName, [splices]);
- }, this);
- this.registerNamedObserver(name + '__array', observer);
- }
- }
- },
-
- emitPropertyChangeRecord: function(name, value, oldValue) {
- var object = this;
- if (areSameValue(value, oldValue)) {
- return;
- }
- // invoke property change side effects
- this._propertyChanged(name, value, oldValue);
- // emit change record
- if (!Observer.hasObjectObserve) {
- return;
- }
- var notifier = this._objectNotifier;
- if (!notifier) {
- notifier = this._objectNotifier = Object.getNotifier(this);
- }
- updateRecord.object = this;
- updateRecord.name = name;
- updateRecord.oldValue = oldValue;
- notifier.notify(updateRecord);
- },
-
- _propertyChanged: function(name, value, oldValue) {
- if (this.reflect[name]) {
- this.reflectPropertyToAttribute(name);
- }
- },
-
- // creates a property binding (called via bind) to a published property.
- bindProperty: function(property, observable, oneTime) {
- if (oneTime) {
- this[property] = observable;
- return;
- }
- var computed = this.element.prototype.computed;
- // Binding an "out-only" value to a computed property. Note that
- // since this observer isn't opened, it doesn't need to be closed on
- // cleanup.
- if (computed && computed[property]) {
- var privateComputedBoundValue = property + 'ComputedBoundObservable_';
- this[privateComputedBoundValue] = observable;
- return;
- }
- return this.bindToAccessor(property, observable, resolveBindingValue);
- },
-
- // NOTE property `name` must be published. This makes it an accessor.
- bindToAccessor: function(name, observable, resolveFn) {
- var privateName = name + '_';
- var privateObservable = name + 'Observable_';
- // Present for properties which are computed and published and have a
- // bound value.
- var privateComputedBoundValue = name + 'ComputedBoundObservable_';
- this[privateObservable] = observable;
- var oldValue = this[privateName];
- // observable callback
- var self = this;
- function updateValue(value, oldValue) {
- self[privateName] = value;
- var setObserveable = self[privateComputedBoundValue];
- if (setObserveable && typeof setObserveable.setValue == 'function') {
- setObserveable.setValue(value);
- }
- self.emitPropertyChangeRecord(name, value, oldValue);
- }
- // resolve initial value
- var value = observable.open(updateValue);
- if (resolveFn && !areSameValue(oldValue, value)) {
- var resolvedValue = resolveFn(oldValue, value);
- if (!areSameValue(value, resolvedValue)) {
- value = resolvedValue;
- if (observable.setValue) {
- observable.setValue(value);
- }
- }
- }
- updateValue(value, oldValue);
- // register and return observable
- var observer = {
- close: function() {
- observable.close();
- self[privateObservable] = undefined;
- self[privateComputedBoundValue] = undefined;
- }
- };
- this.registerObserver(observer);
- return observer;
- },
-
- createComputedProperties: function() {
- if (!this._computedNames) {
- return;
- }
- for (var i = 0; i < this._computedNames.length; i++) {
- var name = this._computedNames[i];
- var expressionText = this.computed[name];
- try {
- var expression = PolymerExpressions.getExpression(expressionText);
- var observable = expression.getBinding(this, this.element.syntax);
- this.bindToAccessor(name, observable);
- } catch (ex) {
- console.error('Failed to create computed property', ex);
- }
- }
- },
-
- // property bookkeeping
- registerObserver: function(observer) {
- if (!this._observers) {
- this._observers = [observer];
- return;
- }
- this._observers.push(observer);
- },
-
- closeObservers: function() {
- if (!this._observers) {
- return;
- }
- // observer array items are arrays of observers.
- var observers = this._observers;
- for (var i = 0; i < observers.length; i++) {
- var observer = observers[i];
- if (observer && typeof observer.close == 'function') {
- observer.close();
- }
- }
- this._observers = [];
- },
-
- // bookkeeping observers for memory management
- registerNamedObserver: function(name, observer) {
- var o$ = this._namedObservers || (this._namedObservers = {});
- o$[name] = observer;
- },
-
- closeNamedObserver: function(name) {
- var o$ = this._namedObservers;
- if (o$ && o$[name]) {
- o$[name].close();
- o$[name] = null;
- return true;
- }
- },
-
- closeNamedObservers: function() {
- if (this._namedObservers) {
- for (var i in this._namedObservers) {
- this.closeNamedObserver(i);
- }
- this._namedObservers = {};
- }
- }
-
- };
-
- // logging
- var LOG_OBSERVE = '[%s] watching [%s]';
- var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
- var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';
-
- // exports
-
- scope.api.instance.properties = properties;
-
-})(Polymer);
-
-(function(scope) {
-
- /**
- * @class polymer-base
- */
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
-
- // element api supporting mdv
- var mdv = {
-
- /**
- * Creates dom cloned from the given template, instantiating bindings
- * with this element as the template model and `PolymerExpressions` as the
- * binding delegate.
- *
- * @method instanceTemplate
- * @param {Template} template source template from which to create dom.
- */
- instanceTemplate: function(template) {
- // ensure template is decorated (lets' things like <tr template ...> work)
- HTMLTemplateElement.decorate(template);
- // ensure a default bindingDelegate
- var syntax = this.syntax || (!template.bindingDelegate &&
- this.element.syntax);
- var dom = template.createInstance(this, syntax);
- var observers = dom.bindings_;
- for (var i = 0; i < observers.length; i++) {
- this.registerObserver(observers[i]);
- }
- return dom;
- },
-
- // Called by TemplateBinding/NodeBind to setup a binding to the given
- // property. It's overridden here to support property bindings
- // in addition to attribute bindings that are supported by default.
- bind: function(name, observable, oneTime) {
- var property = this.propertyForAttribute(name);
- if (!property) {
- // TODO(sjmiles): this mixin method must use the special form
- // of `super` installed by `mixinMethod` in declaration/prototype.js
- return this.mixinSuper(arguments);
- } else {
- // use n-way Polymer binding
- var observer = this.bindProperty(property, observable, oneTime);
- // NOTE: reflecting binding information is typically required only for
- // tooling. It has a performance cost so it's opt-in in Node.bind.
- if (Platform.enableBindingsReflection && observer) {
- observer.path = observable.path_;
- this._recordBinding(property, observer);
- }
- if (this.reflect[property]) {
- this.reflectPropertyToAttribute(property);
- }
- return observer;
- }
- },
-
- _recordBinding: function(name, observer) {
- this.bindings_ = this.bindings_ || {};
- this.bindings_[name] = observer;
- },
-
- // Called by TemplateBinding when all bindings on an element have been
- // executed. This signals that all element inputs have been gathered
- // and it's safe to ready the element, create shadow-root and start
- // data-observation.
- bindFinished: function() {
- this.makeElementReady();
- },
-
- // called at detached time to signal that an element's bindings should be
- // cleaned up. This is done asynchronously so that users have the chance
- // to call `cancelUnbindAll` to prevent unbinding.
- asyncUnbindAll: function() {
- if (!this._unbound) {
- log.unbind && console.log('[%s] asyncUnbindAll', this.localName);
- this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0);
- }
- },
-
- /**
- * This method should rarely be used and only if
- * <a href="#cancelUnbindAll">`cancelUnbindAll`</a> has been called to
- * prevent element unbinding. In this case, the element's bindings will
- * not be automatically cleaned up and it cannot be garbage collected
- * by the system. If memory pressure is a concern or a
- * large amount of elements need to be managed in this way, `unbindAll`
- * can be called to deactivate the element's bindings and allow its
- * memory to be reclaimed.
- *
- * @method unbindAll
- */
- unbindAll: function() {
- if (!this._unbound) {
- this.closeObservers();
- this.closeNamedObservers();
- this._unbound = true;
- }
- },
-
- /**
- * Call in `detached` to prevent the element from unbinding when it is
- * detached from the dom. The element is unbound as a cleanup step that
- * allows its memory to be reclaimed.
- * If `cancelUnbindAll` is used, consider calling
- * <a href="#unbindAll">`unbindAll`</a> when the element is no longer
- * needed. This will allow its memory to be reclaimed.
- *
- * @method cancelUnbindAll
- */
- cancelUnbindAll: function() {
- if (this._unbound) {
- log.unbind && console.warn('[%s] already unbound, cannot cancel unbindAll', this.localName);
- return;
- }
- log.unbind && console.log('[%s] cancelUnbindAll', this.localName);
- if (this._unbindAllJob) {
- this._unbindAllJob = this._unbindAllJob.stop();
- }
- }
-
- };
-
- function unbindNodeTree(node) {
- forNodeTree(node, _nodeUnbindAll);
- }
-
- function _nodeUnbindAll(node) {
- node.unbindAll();
- }
-
- function forNodeTree(node, callback) {
- if (node) {
- callback(node);
- for (var child = node.firstChild; child; child = child.nextSibling) {
- forNodeTree(child, callback);
- }
- }
- }
-
- var mustachePattern = /\{\{([^{}]*)}}/;
-
- // exports
-
- scope.bindPattern = mustachePattern;
- scope.api.instance.mdv = mdv;
-
-})(Polymer);
-
-(function(scope) {
-
- /**
- * Common prototype for all Polymer Elements.
- *
- * @class polymer-base
- * @homepage polymer.github.io
- */
- var base = {
- /**
- * Tags this object as the canonical Base prototype.
- *
- * @property PolymerBase
- * @type boolean
- * @default true
- */
- PolymerBase: true,
-
- /**
- * Debounce signals.
- *
- * Call `job` to defer a named signal, and all subsequent matching signals,
- * until a wait time has elapsed with no new signal.
- *
- * debouncedClickAction: function(e) {
- * // processClick only when it's been 100ms since the last click
- * this.job('click', function() {
- * this.processClick;
- * }, 100);
- * }
- *
- * @method job
- * @param String {String} job A string identifier for the job to debounce.
- * @param Function {Function} callback A function that is called (with `this` context) when the wait time elapses.
- * @param Number {Number} wait Time in milliseconds (ms) after the last signal that must elapse before invoking `callback`
- * @type Handle
- */
- job: function(job, callback, wait) {
- if (typeof job === 'string') {
- var n = '___' + job;
- this[n] = Polymer.job.call(this, this[n], callback, wait);
- } else {
- // TODO(sjmiles): suggest we deprecate this call signature
- return Polymer.job.call(this, job, callback, wait);
- }
- },
-
- /**
- * Invoke a superclass method.
- *
- * Use `super()` to invoke the most recently overridden call to the
- * currently executing function.
- *
- * To pass arguments through, use the literal `arguments` as the parameter
- * to `super()`.
- *
- * nextPageAction: function(e) {
- * // invoke the superclass version of `nextPageAction`
- * this.super(arguments);
- * }
- *
- * To pass custom arguments, arrange them in an array.
- *
- * appendSerialNo: function(value, serial) {
- * // prefix the superclass serial number with our lot # before
- * // invoking the superlcass
- * return this.super([value, this.lotNo + serial])
- * }
- *
- * @method super
- * @type Any
- * @param {args) An array of arguments to use when calling the superclass method, or null.
- */
- super: Polymer.super,
-
- /**
- * Lifecycle method called when the element is instantiated.
- *
- * Override `created` to perform custom create-time tasks. No need to call
- * super-class `created` unless you are extending another Polymer element.
- * Created is called before the element creates `shadowRoot` or prepares
- * data-observation.
- *
- * @method created
- * @type void
- */
- created: function() {
- },
-
- /**
- * Lifecycle method called when the element has populated it's `shadowRoot`,
- * prepared data-observation, and made itself ready for API interaction.
- *
- * @method ready
- * @type void
- */
- ready: function() {
- },
-
- /**
- * Low-level lifecycle method called as part of standard Custom Elements
- * operation. Polymer implements this method to provide basic default
- * functionality. For custom create-time tasks, implement `created`
- * instead, which is called immediately after `createdCallback`.
- *
- * @method createdCallback
- */
- createdCallback: function() {
- if (this.templateInstance && this.templateInstance.model) {
- console.warn('Attributes on ' + this.localName + ' were data bound ' +
- 'prior to Polymer upgrading the element. This may result in ' +
- 'incorrect binding types.');
- }
- this.created();
- this.prepareElement();
- if (!this.ownerDocument.isStagingDocument) {
- this.makeElementReady();
- }
- },
-
- // system entry point, do not override
- prepareElement: function() {
- if (this._elementPrepared) {
- console.warn('Element already prepared', this.localName);
- return;
- }
- this._elementPrepared = true;
- // storage for shadowRoots info
- this.shadowRoots = {};
- // install property observers
- this.createPropertyObserver();
- this.openPropertyObserver();
- // install boilerplate attributes
- this.copyInstanceAttributes();
- // process input attributes
- this.takeAttributes();
- // add event listeners
- this.addHostListeners();
- },
-
- // system entry point, do not override
- makeElementReady: function() {
- if (this._readied) {
- return;
- }
- this._readied = true;
- this.createComputedProperties();
- this.parseDeclarations(this.__proto__);
- // NOTE: Support use of the `unresolved` attribute to help polyfill
- // custom elements' `:unresolved` feature.
- this.removeAttribute('unresolved');
- // user entry point
- this.ready();
- },
-
- /**
- * Low-level lifecycle method called as part of standard Custom Elements
- * operation. Polymer implements this method to provide basic default
- * functionality. For custom tasks in your element, implement `attributeChanged`
- * instead, which is called immediately after `attributeChangedCallback`.
- *
- * @method attributeChangedCallback
- */
- attributeChangedCallback: function(name, oldValue) {
- // TODO(sjmiles): adhoc filter
- if (name !== 'class' && name !== 'style') {
- this.attributeToProperty(name, this.getAttribute(name));
- }
- if (this.attributeChanged) {
- this.attributeChanged.apply(this, arguments);
- }
- },
-
- /**
- * Low-level lifecycle method called as part of standard Custom Elements
- * operation. Polymer implements this method to provide basic default
- * functionality. For custom create-time tasks, implement `attached`
- * instead, which is called immediately after `attachedCallback`.
- *
- * @method attachedCallback
- */
- attachedCallback: function() {
- // when the element is attached, prevent it from unbinding.
- this.cancelUnbindAll();
- // invoke user action
- if (this.attached) {
- this.attached();
- }
- if (!this.hasBeenAttached) {
- this.hasBeenAttached = true;
- if (this.domReady) {
- this.async('domReady');
- }
- }
- },
-
- /**
- * Implement to access custom elements in dom descendants, ancestors,
- * or siblings. Because custom elements upgrade in document order,
- * elements accessed in `ready` or `attached` may not be upgraded. When
- * `domReady` is called, all registered custom elements are guaranteed
- * to have been upgraded.
- *
- * @method domReady
- */
-
- /**
- * Low-level lifecycle method called as part of standard Custom Elements
- * operation. Polymer implements this method to provide basic default
- * functionality. For custom create-time tasks, implement `detached`
- * instead, which is called immediately after `detachedCallback`.
- *
- * @method detachedCallback
- */
- detachedCallback: function() {
- if (!this.preventDispose) {
- this.asyncUnbindAll();
- }
- // invoke user action
- if (this.detached) {
- this.detached();
- }
- // TODO(sorvell): bc
- if (this.leftView) {
- this.leftView();
- }
- },
-
- /**
- * Walks the prototype-chain of this element and allows specific
- * classes a chance to process static declarations.
- *
- * In particular, each polymer-element has it's own `template`.
- * `parseDeclarations` is used to accumulate all element `template`s
- * from an inheritance chain.
- *
- * `parseDeclaration` static methods implemented in the chain are called
- * recursively, oldest first, with the `<polymer-element>` associated
- * with the current prototype passed as an argument.
- *
- * An element may override this method to customize shadow-root generation.
- *
- * @method parseDeclarations
- */
- parseDeclarations: function(p) {
- if (p && p.element) {
- this.parseDeclarations(p.__proto__);
- p.parseDeclaration.call(this, p.element);
- }
- },
-
- /**
- * Perform init-time actions based on static information in the
- * `<polymer-element>` instance argument.
- *
- * For example, the standard implementation locates the template associated
- * with the given `<polymer-element>` and stamps it into a shadow-root to
- * implement shadow inheritance.
- *
- * An element may override this method for custom behavior.
- *
- * @method parseDeclaration
- */
- parseDeclaration: function(elementElement) {
- var template = this.fetchTemplate(elementElement);
- if (template) {
- var root = this.shadowFromTemplate(template);
- this.shadowRoots[elementElement.name] = root;
- }
- },
-
- /**
- * Given a `<polymer-element>`, find an associated template (if any) to be
- * used for shadow-root generation.
- *
- * An element may override this method for custom behavior.
- *
- * @method fetchTemplate
- */
- fetchTemplate: function(elementElement) {
- return elementElement.querySelector('template');
- },
-
- /**
- * Create a shadow-root in this host and stamp `template` as it's
- * content.
- *
- * An element may override this method for custom behavior.
- *
- * @method shadowFromTemplate
- */
- shadowFromTemplate: function(template) {
- if (template) {
- // make a shadow root
- var root = this.createShadowRoot();
- // stamp template
- // which includes parsing and applying MDV bindings before being
- // inserted (to avoid {{}} in attribute values).
- var dom = this.instanceTemplate(template);
- // append to shadow dom
- root.appendChild(dom);
- // perform post-construction initialization tasks on shadow root
- this.shadowRootReady(root, template);
- // return the created shadow root
- return root;
- }
- },
-
- // utility function that stamps a <template> into light-dom
- lightFromTemplate: function(template, refNode) {
- if (template) {
- // TODO(sorvell): mark this element as an eventController so that
- // event listeners on bound nodes inside it will be called on it.
- // Note, the expectation here is that events on all descendants
- // should be handled by this element.
- this.eventController = this;
- // stamp template
- // which includes parsing and applying MDV bindings before being
- // inserted (to avoid {{}} in attribute values).
- var dom = this.instanceTemplate(template);
- // append to shadow dom
- if (refNode) {
- this.insertBefore(dom, refNode);
- } else {
- this.appendChild(dom);
- }
- // perform post-construction initialization tasks on ahem, light root
- this.shadowRootReady(this);
- // return the created shadow root
- return dom;
- }
- },
-
- shadowRootReady: function(root) {
- // locate nodes with id and store references to them in this.$ hash
- this.marshalNodeReferences(root);
- },
-
- // locate nodes with id and store references to them in this.$ hash
- marshalNodeReferences: function(root) {
- // establish $ instance variable
- var $ = this.$ = this.$ || {};
- // populate $ from nodes with ID from the LOCAL tree
- if (root) {
- var n$ = root.querySelectorAll("[id]");
- for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
- $[n.id] = n;
- };
- }
- },
-
- /**
- * Register a one-time callback when a child-list or sub-tree mutation
- * occurs on node.
- *
- * For persistent callbacks, call onMutation from your listener.
- *
- * @method onMutation
- * @param Node {Node} node Node to watch for mutations.
- * @param Function {Function} listener Function to call on mutation. The function is invoked as `listener.call(this, observer, mutations);` where `observer` is the MutationObserver that triggered the notification, and `mutations` is the native mutation list.
- */
- onMutation: function(node, listener) {
- var observer = new MutationObserver(function(mutations) {
- listener.call(this, observer, mutations);
- observer.disconnect();
- }.bind(this));
- observer.observe(node, {childList: true, subtree: true});
- }
- };
-
- /**
- * @class Polymer
- */
-
- /**
- * Returns true if the object includes <a href="#polymer-base">polymer-base</a> in it's prototype chain.
- *
- * @method isBase
- * @param Object {Object} object Object to test.
- * @type Boolean
- */
- function isBase(object) {
- return object.hasOwnProperty('PolymerBase')
- }
-
- // name a base constructor for dev tools
-
- /**
- * The Polymer base-class constructor.
- *
- * @property Base
- * @type Function
- */
- function PolymerBase() {};
- PolymerBase.prototype = base;
- base.constructor = PolymerBase;
-
- // exports
-
- scope.Base = PolymerBase;
- scope.isBase = isBase;
- scope.api.instance.base = base;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
- var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
-
- // magic words
-
- var STYLE_SCOPE_ATTRIBUTE = 'element';
- var STYLE_CONTROLLER_SCOPE = 'controller';
-
- var styles = {
- STYLE_SCOPE_ATTRIBUTE: STYLE_SCOPE_ATTRIBUTE,
- /**
- * Installs external stylesheets and <style> elements with the attribute
- * polymer-scope='controller' into the scope of element. This is intended
- * to be a called during custom element construction.
- */
- installControllerStyles: function() {
- // apply controller styles, but only if they are not yet applied
- var scope = this.findStyleScope();
- if (scope && !this.scopeHasNamedStyle(scope, this.localName)) {
- // allow inherited controller styles
- var proto = getPrototypeOf(this), cssText = '';
- while (proto && proto.element) {
- cssText += proto.element.cssTextForScope(STYLE_CONTROLLER_SCOPE);
- proto = getPrototypeOf(proto);
- }
- if (cssText) {
- this.installScopeCssText(cssText, scope);
- }
- }
- },
- installScopeStyle: function(style, name, scope) {
- var scope = scope || this.findStyleScope(), name = name || '';
- if (scope && !this.scopeHasNamedStyle(scope, this.localName + name)) {
- var cssText = '';
- if (style instanceof Array) {
- for (var i=0, l=style.length, s; (i<l) && (s=style[i]); i++) {
- cssText += s.textContent + '\n\n';
- }
- } else {
- cssText = style.textContent;
- }
- this.installScopeCssText(cssText, scope, name);
- }
- },
- installScopeCssText: function(cssText, scope, name) {
- scope = scope || this.findStyleScope();
- name = name || '';
- if (!scope) {
- return;
- }
- if (hasShadowDOMPolyfill) {
- cssText = shimCssText(cssText, scope.host);
- }
- var style = this.element.cssTextToScopeStyle(cssText,
- STYLE_CONTROLLER_SCOPE);
- Polymer.applyStyleToScope(style, scope);
- // cache that this style has been applied
- this.styleCacheForScope(scope)[this.localName + name] = true;
- },
- findStyleScope: function(node) {
- // find the shadow root that contains this element
- var n = node || this;
- while (n.parentNode) {
- n = n.parentNode;
- }
- return n;
- },
- scopeHasNamedStyle: function(scope, name) {
- var cache = this.styleCacheForScope(scope);
- return cache[name];
- },
- styleCacheForScope: function(scope) {
- if (hasShadowDOMPolyfill) {
- var scopeName = scope.host ? scope.host.localName : scope.localName;
- return polyfillScopeStyleCache[scopeName] || (polyfillScopeStyleCache[scopeName] = {});
- } else {
- return scope._scopeStyles = (scope._scopeStyles || {});
- }
- }
- };
-
- var polyfillScopeStyleCache = {};
-
- // NOTE: use raw prototype traversal so that we ensure correct traversal
- // on platforms where the protoype chain is simulated via __proto__ (IE10)
- function getPrototypeOf(prototype) {
- return prototype.__proto__;
- }
-
- function shimCssText(cssText, host) {
- var name = '', is = false;
- if (host) {
- name = host.localName;
- is = host.hasAttribute('is');
- }
- var selector = WebComponents.ShadowCSS.makeScopeSelector(name, is);
- return WebComponents.ShadowCSS.shimCssText(cssText, selector);
- }
-
- // exports
-
- scope.api.instance.styles = styles;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var extend = scope.extend;
- var api = scope.api;
-
- // imperative implementation: Polymer()
-
- // specify an 'own' prototype for tag `name`
- function element(name, prototype) {
- if (typeof name !== 'string') {
- var script = prototype || document._currentScript;
- prototype = name;
- name = script && script.parentNode && script.parentNode.getAttribute ?
- script.parentNode.getAttribute('name') : '';
- if (!name) {
- throw 'Element name could not be inferred.';
- }
- }
- if (getRegisteredPrototype(name)) {
- throw 'Already registered (Polymer) prototype for element ' + name;
- }
- // cache the prototype
- registerPrototype(name, prototype);
- // notify the registrar waiting for 'name', if any
- notifyPrototype(name);
- }
-
- // async prototype source
-
- function waitingForPrototype(name, client) {
- waitPrototype[name] = client;
- }
-
- var waitPrototype = {};
-
- function notifyPrototype(name) {
- if (waitPrototype[name]) {
- waitPrototype[name].registerWhenReady();
- delete waitPrototype[name];
- }
- }
-
- // utility and bookkeeping
-
- // maps tag names to prototypes, as registered with
- // Polymer. Prototypes associated with a tag name
- // using document.registerElement are available from
- // HTMLElement.getPrototypeForTag().
- // If an element was fully registered by Polymer, then
- // Polymer.getRegisteredPrototype(name) ===
- // HTMLElement.getPrototypeForTag(name)
-
- var prototypesByName = {};
-
- function registerPrototype(name, prototype) {
- return prototypesByName[name] = prototype || {};
- }
-
- function getRegisteredPrototype(name) {
- return prototypesByName[name];
- }
-
- function instanceOfType(element, type) {
- if (typeof type !== 'string') {
- return false;
- }
- var proto = HTMLElement.getPrototypeForTag(type);
- var ctor = proto && proto.constructor;
- if (!ctor) {
- return false;
- }
- if (CustomElements.instanceof) {
- return CustomElements.instanceof(element, ctor);
- }
- return element instanceof ctor;
- }
-
- // exports
-
- scope.getRegisteredPrototype = getRegisteredPrototype;
- scope.waitingForPrototype = waitingForPrototype;
- scope.instanceOfType = instanceOfType;
-
- // namespace shenanigans so we can expose our scope on the registration
- // function
-
- // make window.Polymer reference `element()`
-
- window.Polymer = element;
-
- // TODO(sjmiles): find a way to do this that is less terrible
- // copy window.Polymer properties onto `element()`
-
- extend(Polymer, scope);
-
- // Under the HTMLImports polyfill, scripts in the main document
- // do not block on imports; we want to allow calls to Polymer in the main
- // document. WebComponents collects those calls until we can process them, which
- // we do here.
-
- if (WebComponents.consumeDeclarations) {
- WebComponents.consumeDeclarations(function(declarations) {
- if (declarations) {
- for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i++) {
- element.apply(null, d);
- }
- }
- });
- }
-
-})(Polymer);
-
-(function(scope) {
-
-/**
- * @class polymer-base
- */
-
- /**
- * Resolve a url path to be relative to a `base` url. If unspecified, `base`
- * defaults to the element's ownerDocument url. Can be used to resolve
- * paths from element's in templates loaded in HTMLImports to be relative
- * to the document containing the element. Polymer automatically does this for
- * url attributes in element templates; however, if a url, for
- * example, contains a binding, then `resolvePath` can be used to ensure it is
- * relative to the element document. For example, in an element's template,
- *
- * <a href="{{resolvePath(path)}}">Resolved</a>
- *
- * @method resolvePath
- * @param {String} url Url path to resolve.
- * @param {String} base Optional base url against which to resolve, defaults
- * to the element's ownerDocument url.
- * returns {String} resolved url.
- */
-
-var path = {
- resolveElementPaths: function(node) {
- Polymer.urlResolver.resolveDom(node);
- },
- addResolvePathApi: function() {
- // let assetpath attribute modify the resolve path
- var assetPath = this.getAttribute('assetpath') || '';
- var root = new URL(assetPath, this.ownerDocument.baseURI);
- this.prototype.resolvePath = function(urlPath, base) {
- var u = new URL(urlPath, base || root);
- return u.href;
- };
- }
-};
-
-// exports
-scope.api.declaration.path = path;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
- var api = scope.api.instance.styles;
- var STYLE_SCOPE_ATTRIBUTE = api.STYLE_SCOPE_ATTRIBUTE;
-
- var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
-
- // magic words
-
- var STYLE_SELECTOR = 'style';
- var STYLE_LOADABLE_MATCH = '@import';
- var SHEET_SELECTOR = 'link[rel=stylesheet]';
- var STYLE_GLOBAL_SCOPE = 'global';
- var SCOPE_ATTR = 'polymer-scope';
-
- var styles = {
- // returns true if resources are loading
- loadStyles: function(callback) {
- var template = this.fetchTemplate();
- var content = template && this.templateContent();
- if (content) {
- this.convertSheetsToStyles(content);
- var styles = this.findLoadableStyles(content);
- if (styles.length) {
- var templateUrl = template.ownerDocument.baseURI;
- return Polymer.styleResolver.loadStyles(styles, templateUrl, callback);
- }
- }
- if (callback) {
- callback();
- }
- },
- convertSheetsToStyles: function(root) {
- var s$ = root.querySelectorAll(SHEET_SELECTOR);
- for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) {
- c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI),
- this.ownerDocument);
- this.copySheetAttributes(c, s);
- s.parentNode.replaceChild(c, s);
- }
- },
- copySheetAttributes: function(style, link) {
- for (var i=0, a$=link.attributes, l=a$.length, a; (a=a$[i]) && i<l; i++) {
- if (a.name !== 'rel' && a.name !== 'href') {
- style.setAttribute(a.name, a.value);
- }
- }
- },
- findLoadableStyles: function(root) {
- var loadables = [];
- if (root) {
- var s$ = root.querySelectorAll(STYLE_SELECTOR);
- for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) {
- if (s.textContent.match(STYLE_LOADABLE_MATCH)) {
- loadables.push(s);
- }
- }
- }
- return loadables;
- },
- /**
- * Install external stylesheets loaded in <polymer-element> elements into the
- * element's template.
- * @param elementElement The <element> element to style.
- */
- installSheets: function() {
- this.cacheSheets();
- this.cacheStyles();
- this.installLocalSheets();
- this.installGlobalStyles();
- },
- /**
- * Remove all sheets from element and store for later use.
- */
- cacheSheets: function() {
- this.sheets = this.findNodes(SHEET_SELECTOR);
- this.sheets.forEach(function(s) {
- if (s.parentNode) {
- s.parentNode.removeChild(s);
- }
- });
- },
- cacheStyles: function() {
- this.styles = this.findNodes(STYLE_SELECTOR + '[' + SCOPE_ATTR + ']');
- this.styles.forEach(function(s) {
- if (s.parentNode) {
- s.parentNode.removeChild(s);
- }
- });
- },
- /**
- * Takes external stylesheets loaded in an <element> element and moves
- * their content into a <style> element inside the <element>'s template.
- * The sheet is then removed from the <element>. This is done only so
- * that if the element is loaded in the main document, the sheet does
- * not become active.
- * Note, ignores sheets with the attribute 'polymer-scope'.
- * @param elementElement The <element> element to style.
- */
- installLocalSheets: function () {
- var sheets = this.sheets.filter(function(s) {
- return !s.hasAttribute(SCOPE_ATTR);
- });
- var content = this.templateContent();
- if (content) {
- var cssText = '';
- sheets.forEach(function(sheet) {
- cssText += cssTextFromSheet(sheet) + '\n';
- });
- if (cssText) {
- var style = createStyleElement(cssText, this.ownerDocument);
- content.insertBefore(style, content.firstChild);
- }
- }
- },
- findNodes: function(selector, matcher) {
- var nodes = this.querySelectorAll(selector).array();
- var content = this.templateContent();
- if (content) {
- var templateNodes = content.querySelectorAll(selector).array();
- nodes = nodes.concat(templateNodes);
- }
- return matcher ? nodes.filter(matcher) : nodes;
- },
- /**
- * Promotes external stylesheets and <style> elements with the attribute
- * polymer-scope='global' into global scope.
- * This is particularly useful for defining @keyframe rules which
- * currently do not function in scoped or shadow style elements.
- * (See wkb.ug/72462)
- * @param elementElement The <element> element to style.
- */
- // TODO(sorvell): remove when wkb.ug/72462 is addressed.
- installGlobalStyles: function() {
- var style = this.styleForScope(STYLE_GLOBAL_SCOPE);
- applyStyleToScope(style, document.head);
- },
- cssTextForScope: function(scopeDescriptor) {
- var cssText = '';
- // handle stylesheets
- var selector = '[' + SCOPE_ATTR + '=' + scopeDescriptor + ']';
- var matcher = function(s) {
- return matchesSelector(s, selector);
- };
- var sheets = this.sheets.filter(matcher);
- sheets.forEach(function(sheet) {
- cssText += cssTextFromSheet(sheet) + '\n\n';
- });
- // handle cached style elements
- var styles = this.styles.filter(matcher);
- styles.forEach(function(style) {
- cssText += style.textContent + '\n\n';
- });
- return cssText;
- },
- styleForScope: function(scopeDescriptor) {
- var cssText = this.cssTextForScope(scopeDescriptor);
- return this.cssTextToScopeStyle(cssText, scopeDescriptor);
- },
- cssTextToScopeStyle: function(cssText, scopeDescriptor) {
- if (cssText) {
- var style = createStyleElement(cssText);
- style.setAttribute(STYLE_SCOPE_ATTRIBUTE, this.getAttribute('name') +
- '-' + scopeDescriptor);
- return style;
- }
- }
- };
-
- function importRuleForSheet(sheet, baseUrl) {
- var href = new URL(sheet.getAttribute('href'), baseUrl).href;
- return '@import \'' + href + '\';';
- }
-
- function applyStyleToScope(style, scope) {
- if (style) {
- if (scope === document) {
- scope = document.head;
- }
- if (hasShadowDOMPolyfill) {
- scope = document.head;
- }
- // TODO(sorvell): necessary for IE
- // see https://connect.microsoft.com/IE/feedback/details/790212/
- // cloning-a-style-element-and-adding-to-document-produces
- // -unexpected-result#details
- // var clone = style.cloneNode(true);
- var clone = createStyleElement(style.textContent);
- var attr = style.getAttribute(STYLE_SCOPE_ATTRIBUTE);
- if (attr) {
- clone.setAttribute(STYLE_SCOPE_ATTRIBUTE, attr);
- }
- // TODO(sorvell): probably too brittle; try to figure out
- // where to put the element.
- var refNode = scope.firstElementChild;
- if (scope === document.head) {
- var selector = 'style[' + STYLE_SCOPE_ATTRIBUTE + ']';
- var s$ = document.head.querySelectorAll(selector);
- if (s$.length) {
- refNode = s$[s$.length-1].nextElementSibling;
- }
- }
- scope.insertBefore(clone, refNode);
- }
- }
-
- function createStyleElement(cssText, scope) {
- scope = scope || document;
- scope = scope.createElement ? scope : scope.ownerDocument;
- var style = scope.createElement('style');
- style.textContent = cssText;
- return style;
- }
-
- function cssTextFromSheet(sheet) {
- return (sheet && sheet.__resource) || '';
- }
-
- function matchesSelector(node, inSelector) {
- if (matches) {
- return matches.call(node, inSelector);
- }
- }
- var p = HTMLElement.prototype;
- var matches = p.matches || p.matchesSelector || p.webkitMatchesSelector
- || p.mozMatchesSelector;
-
- // exports
-
- scope.api.declaration.styles = styles;
- scope.applyStyleToScope = applyStyleToScope;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var log = window.WebComponents ? WebComponents.flags.log : {};
- var api = scope.api.instance.events;
- var EVENT_PREFIX = api.EVENT_PREFIX;
-
- var mixedCaseEventTypes = {};
- [
- 'webkitAnimationStart',
- 'webkitAnimationEnd',
- 'webkitTransitionEnd',
- 'DOMFocusOut',
- 'DOMFocusIn',
- 'DOMMouseScroll'
- ].forEach(function(e) {
- mixedCaseEventTypes[e.toLowerCase()] = e;
- });
-
- // polymer-element declarative api: events feature
- var events = {
- parseHostEvents: function() {
- // our delegates map
- var delegates = this.prototype.eventDelegates;
- // extract data from attributes into delegates
- this.addAttributeDelegates(delegates);
- },
- addAttributeDelegates: function(delegates) {
- // for each attribute
- for (var i=0, a; a=this.attributes[i]; i++) {
- // does it have magic marker identifying it as an event delegate?
- if (this.hasEventPrefix(a.name)) {
- // if so, add the info to delegates
- delegates[this.removeEventPrefix(a.name)] = a.value.replace('{{', '')
- .replace('}}', '').trim();
- }
- }
- },
- // starts with 'on-'
- hasEventPrefix: function (n) {
- return n && (n[0] === 'o') && (n[1] === 'n') && (n[2] === '-');
- },
- removeEventPrefix: function(n) {
- return n.slice(prefixLength);
- },
- findController: function(node) {
- while (node.parentNode) {
- if (node.eventController) {
- return node.eventController;
- }
- node = node.parentNode;
- }
- return node.host;
- },
- getEventHandler: function(controller, target, method) {
- var events = this;
- return function(e) {
- if (!controller || !controller.PolymerBase) {
- controller = events.findController(target);
- }
-
- var args = [e, e.detail, e.currentTarget];
- controller.dispatchMethod(controller, method, args);
- };
- },
- prepareEventBinding: function(pathString, name, node) {
- if (!this.hasEventPrefix(name))
- return;
-
- var eventType = this.removeEventPrefix(name);
- eventType = mixedCaseEventTypes[eventType] || eventType;
-
- var events = this;
-
- return function(model, node, oneTime) {
- var handler = events.getEventHandler(undefined, node, pathString);
- PolymerGestures.addEventListener(node, eventType, handler);
-
- if (oneTime)
- return;
-
- // TODO(rafaelw): This is really pointless work. Aside from the cost
- // of these allocations, NodeBind is going to setAttribute back to its
- // current value. Fixing this would mean changing the TemplateBinding
- // binding delegate API.
- function bindingValue() {
- return '{{ ' + pathString + ' }}';
- }
-
- return {
- open: bindingValue,
- discardChanges: bindingValue,
- close: function() {
- PolymerGestures.removeEventListener(node, eventType, handler);
- }
- };
- };
- }
- };
-
- var prefixLength = EVENT_PREFIX.length;
-
- // exports
- scope.api.declaration.events = events;
-
-})(Polymer);
-
-(function(scope) {
-
- // element api
-
- var observationBlacklist = ['attribute'];
-
- var properties = {
- inferObservers: function(prototype) {
- // called before prototype.observe is chained to inherited object
- var observe = prototype.observe, property;
- for (var n in prototype) {
- if (n.slice(-7) === 'Changed') {
- property = n.slice(0, -7);
- if (this.canObserveProperty(property)) {
- if (!observe) {
- observe = (prototype.observe = {});
- }
- observe[property] = observe[property] || n;
- }
- }
- }
- },
- canObserveProperty: function(property) {
- return (observationBlacklist.indexOf(property) < 0);
- },
- explodeObservers: function(prototype) {
- // called before prototype.observe is chained to inherited object
- var o = prototype.observe;
- if (o) {
- var exploded = {};
- for (var n in o) {
- var names = n.split(' ');
- for (var i=0, ni; ni=names[i]; i++) {
- exploded[ni] = o[n];
- }
- }
- prototype.observe = exploded;
- }
- },
- optimizePropertyMaps: function(prototype) {
- if (prototype.observe) {
- // construct name list
- var a = prototype._observeNames = [];
- for (var n in prototype.observe) {
- var names = n.split(' ');
- for (var i=0, ni; ni=names[i]; i++) {
- a.push(ni);
- }
- }
- }
- if (prototype.publish) {
- // construct name list
- var a = prototype._publishNames = [];
- for (var n in prototype.publish) {
- a.push(n);
- }
- }
- if (prototype.computed) {
- // construct name list
- var a = prototype._computedNames = [];
- for (var n in prototype.computed) {
- a.push(n);
- }
- }
- },
- publishProperties: function(prototype, base) {
- // if we have any properties to publish
- var publish = prototype.publish;
- if (publish) {
- // transcribe `publish` entries onto own prototype
- this.requireProperties(publish, prototype, base);
- // warn and remove accessor names that are broken on some browsers
- this.filterInvalidAccessorNames(publish);
- // construct map of lower-cased property names
- prototype._publishLC = this.lowerCaseMap(publish);
- }
- var computed = prototype.computed;
- if (computed) {
- // warn and remove accessor names that are broken on some browsers
- this.filterInvalidAccessorNames(computed);
- }
- },
- // Publishing/computing a property where the name might conflict with a
- // browser property is not currently supported to help users of Polymer
- // avoid browser bugs:
- //
- // https://code.google.com/p/chromium/issues/detail?id=43394
- // https://bugs.webkit.org/show_bug.cgi?id=49739
- //
- // We can lift this restriction when those bugs are fixed.
- filterInvalidAccessorNames: function(propertyNames) {
- for (var name in propertyNames) {
- // Check if the name is in our blacklist.
- if (this.propertyNameBlacklist[name]) {
- console.warn('Cannot define property "' + name + '" for element "' +
- this.name + '" because it has the same name as an HTMLElement ' +
- 'property, and not all browsers support overriding that. ' +
- 'Consider giving it a different name.');
- // Remove the invalid accessor from the list.
- delete propertyNames[name];
- }
- }
- },
- //
- // `name: value` entries in the `publish` object may need to generate
- // matching properties on the prototype.
- //
- // Values that are objects may have a `reflect` property, which
- // signals that the value describes property control metadata.
- // In metadata objects, the prototype default value (if any)
- // is encoded in the `value` property.
- //
- // publish: {
- // foo: 5,
- // bar: {value: true, reflect: true},
- // zot: {}
- // }
- //
- // `reflect` metadata property controls whether changes to the property
- // are reflected back to the attribute (default false).
- //
- // A value is stored on the prototype unless it's === `undefined`,
- // in which case the base chain is checked for a value.
- // If the basal value is also undefined, `null` is stored on the prototype.
- //
- // The reflection data is stored on another prototype object, `reflect`
- // which also can be specified directly.
- //
- // reflect: {
- // foo: true
- // }
- //
- requireProperties: function(propertyInfos, prototype, base) {
- // per-prototype storage for reflected properties
- prototype.reflect = prototype.reflect || {};
- // ensure a prototype value for each property
- // and update the property's reflect to attribute status
- for (var n in propertyInfos) {
- var value = propertyInfos[n];
- // value has metadata if it has a `reflect` property
- if (value && value.reflect !== undefined) {
- prototype.reflect[n] = Boolean(value.reflect);
- value = value.value;
- }
- // only set a value if one is specified
- if (value !== undefined) {
- prototype[n] = value;
- }
- }
- },
- lowerCaseMap: function(properties) {
- var map = {};
- for (var n in properties) {
- map[n.toLowerCase()] = n;
- }
- return map;
- },
- createPropertyAccessor: function(name, ignoreWrites) {
- var proto = this.prototype;
-
- var privateName = name + '_';
- var privateObservable = name + 'Observable_';
- proto[privateName] = proto[name];
-
- Object.defineProperty(proto, name, {
- get: function() {
- var observable = this[privateObservable];
- if (observable)
- observable.deliver();
-
- return this[privateName];
- },
- set: function(value) {
- if (ignoreWrites) {
- return this[privateName];
- }
-
- var observable = this[privateObservable];
- if (observable) {
- observable.setValue(value);
- return;
- }
-
- var oldValue = this[privateName];
- this[privateName] = value;
- this.emitPropertyChangeRecord(name, value, oldValue);
-
- return value;
- },
- configurable: true
- });
- },
- createPropertyAccessors: function(prototype) {
- var n$ = prototype._computedNames;
- if (n$ && n$.length) {
- for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
- this.createPropertyAccessor(n, true);
- }
- }
- var n$ = prototype._publishNames;
- if (n$ && n$.length) {
- for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
- // If the property is computed and published, the accessor is created
- // above.
- if (!prototype.computed || !prototype.computed[n]) {
- this.createPropertyAccessor(n);
- }
- }
- }
- },
- // This list contains some property names that people commonly want to use,
- // but won't work because of Chrome/Safari bugs. It isn't an exhaustive
- // list. In particular it doesn't contain any property names found on
- // subtypes of HTMLElement (e.g. name, value). Rather it attempts to catch
- // some common cases.
- propertyNameBlacklist: {
- children: 1,
- 'class': 1,
- id: 1,
- hidden: 1,
- style: 1,
- title: 1,
- }
- };
-
- // exports
-
- scope.api.declaration.properties = properties;
-
-})(Polymer);
-
-(function(scope) {
-
- // magic words
-
- var ATTRIBUTES_ATTRIBUTE = 'attributes';
- var ATTRIBUTES_REGEX = /\s|,/;
-
- // attributes api
-
- var attributes = {
-
- inheritAttributesObjects: function(prototype) {
- // chain our lower-cased publish map to the inherited version
- this.inheritObject(prototype, 'publishLC');
- // chain our instance attributes map to the inherited version
- this.inheritObject(prototype, '_instanceAttributes');
- },
-
- publishAttributes: function(prototype, base) {
- // merge names from 'attributes' attribute into the 'publish' object
- var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE);
- if (attributes) {
- // create a `publish` object if needed.
- // the `publish` object is only relevant to this prototype, the
- // publishing logic in `declaration/properties.js` is responsible for
- // managing property values on the prototype chain.
- // TODO(sjmiles): the `publish` object is later chained to it's
- // ancestor object, presumably this is only for
- // reflection or other non-library uses.
- var publish = prototype.publish || (prototype.publish = {});
- // names='a b c' or names='a,b,c'
- var names = attributes.split(ATTRIBUTES_REGEX);
- // record each name for publishing
- for (var i=0, l=names.length, n; i<l; i++) {
- // remove excess ws
- n = names[i].trim();
- // looks weird, but causes n to exist on `publish` if it does not;
- // a more careful test would need expensive `in` operator
- if (n && publish[n] === undefined) {
- publish[n] = undefined;
- }
- }
- }
- },
-
- // record clonable attributes from <element>
- accumulateInstanceAttributes: function() {
- // inherit instance attributes
- var clonable = this.prototype._instanceAttributes;
- // merge attributes from element
- var a$ = this.attributes;
- for (var i=0, l=a$.length, a; (i<l) && (a=a$[i]); i++) {
- if (this.isInstanceAttribute(a.name)) {
- clonable[a.name] = a.value;
- }
- }
- },
-
- isInstanceAttribute: function(name) {
- return !this.blackList[name] && name.slice(0,3) !== 'on-';
- },
-
- // do not clone these attributes onto instances
- blackList: {
- name: 1,
- 'extends': 1,
- constructor: 1,
- noscript: 1,
- assetpath: 1,
- 'cache-csstext': 1
- }
-
- };
-
- // add ATTRIBUTES_ATTRIBUTE to the blacklist
- attributes.blackList[ATTRIBUTES_ATTRIBUTE] = 1;
-
- // exports
-
- scope.api.declaration.attributes = attributes;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
- var events = scope.api.declaration.events;
-
- var syntax = new PolymerExpressions();
- var prepareBinding = syntax.prepareBinding;
-
- // Polymer takes a first crack at the binding to see if it's a declarative
- // event handler.
- syntax.prepareBinding = function(pathString, name, node) {
- return events.prepareEventBinding(pathString, name, node) ||
- prepareBinding.call(syntax, pathString, name, node);
- };
-
- // declaration api supporting mdv
- var mdv = {
- syntax: syntax,
- fetchTemplate: function() {
- return this.querySelector('template');
- },
- templateContent: function() {
- var template = this.fetchTemplate();
- return template && template.content;
- },
- installBindingDelegate: function(template) {
- if (template) {
- template.bindingDelegate = this.syntax;
- }
- }
- };
-
- // exports
- scope.api.declaration.mdv = mdv;
-
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var api = scope.api;
- var isBase = scope.isBase;
- var extend = scope.extend;
-
- var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
-
- // prototype api
-
- var prototype = {
-
- register: function(name, extendeeName) {
- // build prototype combining extendee, Polymer base, and named api
- this.buildPrototype(name, extendeeName);
- // register our custom element with the platform
- this.registerPrototype(name, extendeeName);
- // reference constructor in a global named by 'constructor' attribute
- this.publishConstructor();
- },
-
- buildPrototype: function(name, extendeeName) {
- // get our custom prototype (before chaining)
- var extension = scope.getRegisteredPrototype(name);
- // get basal prototype
- var base = this.generateBasePrototype(extendeeName);
- // implement declarative features
- this.desugarBeforeChaining(extension, base);
- // join prototypes
- this.prototype = this.chainPrototypes(extension, base);
- // more declarative features
- this.desugarAfterChaining(name, extendeeName);
- },
-
- desugarBeforeChaining: function(prototype, base) {
- // back reference declaration element
- // TODO(sjmiles): replace `element` with `elementElement` or `declaration`
- prototype.element = this;
- // transcribe `attributes` declarations onto own prototype's `publish`
- this.publishAttributes(prototype, base);
- // `publish` properties to the prototype and to attribute watch
- this.publishProperties(prototype, base);
- // infer observers for `observe` list based on method names
- this.inferObservers(prototype);
- // desugar compound observer syntax, e.g. 'a b c'
- this.explodeObservers(prototype);
- },
-
- chainPrototypes: function(prototype, base) {
- // chain various meta-data objects to inherited versions
- this.inheritMetaData(prototype, base);
- // chain custom api to inherited
- var chained = this.chainObject(prototype, base);
- // x-platform fixup
- ensurePrototypeTraversal(chained);
- return chained;
- },
-
- inheritMetaData: function(prototype, base) {
- // chain observe object to inherited
- this.inheritObject('observe', prototype, base);
- // chain publish object to inherited
- this.inheritObject('publish', prototype, base);
- // chain reflect object to inherited
- this.inheritObject('reflect', prototype, base);
- // chain our lower-cased publish map to the inherited version
- this.inheritObject('_publishLC', prototype, base);
- // chain our instance attributes map to the inherited version
- this.inheritObject('_instanceAttributes', prototype, base);
- // chain our event delegates map to the inherited version
- this.inheritObject('eventDelegates', prototype, base);
- },
-
- // implement various declarative features
- desugarAfterChaining: function(name, extendee) {
- // build side-chained lists to optimize iterations
- this.optimizePropertyMaps(this.prototype);
- this.createPropertyAccessors(this.prototype);
- // install mdv delegate on template
- this.installBindingDelegate(this.fetchTemplate());
- // install external stylesheets as if they are inline
- this.installSheets();
- // adjust any paths in dom from imports
- this.resolveElementPaths(this);
- // compile list of attributes to copy to instances
- this.accumulateInstanceAttributes();
- // parse on-* delegates declared on `this` element
- this.parseHostEvents();
- //
- // install a helper method this.resolvePath to aid in
- // setting resource urls. e.g.
- // this.$.image.src = this.resolvePath('images/foo.png')
- this.addResolvePathApi();
- // under ShadowDOMPolyfill, transforms to approximate missing CSS features
- if (hasShadowDOMPolyfill) {
- WebComponents.ShadowCSS.shimStyling(this.templateContent(), name,
- extendee);
- }
- // allow custom element access to the declarative context
- if (this.prototype.registerCallback) {
- this.prototype.registerCallback(this);
- }
- },
-
- // if a named constructor is requested in element, map a reference
- // to the constructor to the given symbol
- publishConstructor: function() {
- var symbol = this.getAttribute('constructor');
- if (symbol) {
- window[symbol] = this.ctor;
- }
- },
-
- // build prototype combining extendee, Polymer base, and named api
- generateBasePrototype: function(extnds) {
- var prototype = this.findBasePrototype(extnds);
- if (!prototype) {
- // create a prototype based on tag-name extension
- var prototype = HTMLElement.getPrototypeForTag(extnds);
- // insert base api in inheritance chain (if needed)
- prototype = this.ensureBaseApi(prototype);
- // memoize this base
- memoizedBases[extnds] = prototype;
- }
- return prototype;
- },
-
- findBasePrototype: function(name) {
- return memoizedBases[name];
- },
-
- // install Polymer instance api into prototype chain, as needed
- ensureBaseApi: function(prototype) {
- if (prototype.PolymerBase) {
- return prototype;
- }
- var extended = Object.create(prototype);
- // we need a unique copy of base api for each base prototype
- // therefore we 'extend' here instead of simply chaining
- api.publish(api.instance, extended);
- // TODO(sjmiles): sharing methods across prototype chains is
- // not supported by 'super' implementation which optimizes
- // by memoizing prototype relationships.
- // Probably we should have a version of 'extend' that is
- // share-aware: it could study the text of each function,
- // look for usage of 'super', and wrap those functions in
- // closures.
- // As of now, there is only one problematic method, so
- // we just patch it manually.
- // To avoid re-entrancy problems, the special super method
- // installed is called `mixinSuper` and the mixin method
- // must use this method instead of the default `super`.
- this.mixinMethod(extended, prototype, api.instance.mdv, 'bind');
- // return buffed-up prototype
- return extended;
- },
-
- mixinMethod: function(extended, prototype, api, name) {
- var $super = function(args) {
- return prototype[name].apply(this, args);
- };
- extended[name] = function() {
- this.mixinSuper = $super;
- return api[name].apply(this, arguments);
- }
- },
-
- // ensure prototype[name] inherits from a prototype.prototype[name]
- inheritObject: function(name, prototype, base) {
- // require an object
- var source = prototype[name] || {};
- // chain inherited properties onto a new object
- prototype[name] = this.chainObject(source, base[name]);
- },
-
- // register 'prototype' to custom element 'name', store constructor
- registerPrototype: function(name, extendee) {
- var info = {
- prototype: this.prototype
- }
- // native element must be specified in extends
- var typeExtension = this.findTypeExtension(extendee);
- if (typeExtension) {
- info.extends = typeExtension;
- }
- // register the prototype with HTMLElement for name lookup
- HTMLElement.register(name, this.prototype);
- // register the custom type
- this.ctor = document.registerElement(name, info);
- },
-
- findTypeExtension: function(name) {
- if (name && name.indexOf('-') < 0) {
- return name;
- } else {
- var p = this.findBasePrototype(name);
- if (p.element) {
- return this.findTypeExtension(p.element.extends);
- }
- }
- }
-
- };
-
- // memoize base prototypes
- var memoizedBases = {};
-
- // implementation of 'chainObject' depends on support for __proto__
- if (Object.__proto__) {
- prototype.chainObject = function(object, inherited) {
- if (object && inherited && object !== inherited) {
- object.__proto__ = inherited;
- }
- return object;
- }
- } else {
- prototype.chainObject = function(object, inherited) {
- if (object && inherited && object !== inherited) {
- var chained = Object.create(inherited);
- object = extend(chained, object);
- }
- return object;
- }
- }
-
- // On platforms that do not support __proto__ (versions of IE), the prototype
- // chain of a custom element is simulated via installation of __proto__.
- // Although custom elements manages this, we install it here so it's
- // available during desugaring.
- function ensurePrototypeTraversal(prototype) {
- if (!Object.__proto__) {
- var ancestor = Object.getPrototypeOf(prototype);
- prototype.__proto__ = ancestor;
- if (isBase(ancestor)) {
- ancestor.__proto__ = Object.getPrototypeOf(ancestor);
- }
- }
- }
-
- // exports
-
- api.declaration.prototype = prototype;
-
-})(Polymer);
-
-(function(scope) {
-
- /*
-
- Elements are added to a registration queue so that they register in
- the proper order at the appropriate time. We do this for a few reasons:
-
- * to enable elements to load resources (like stylesheets)
- asynchronously. We need to do this until the platform provides an efficient
- alternative. One issue is that remote @import stylesheets are
- re-fetched whenever stamped into a shadowRoot.
-
- * to ensure elements loaded 'at the same time' (e.g. via some set of
- imports) are registered as a batch. This allows elements to be enured from
- upgrade ordering as long as they query the dom tree 1 task after
- upgrade (aka domReady). This is a performance tradeoff. On the one hand,
- elements that could register while imports are loading are prevented from
- doing so. On the other, grouping upgrades into a single task means less
- incremental work (for example style recalcs), Also, we can ensure the
- document is in a known state at the single quantum of time when
- elements upgrade.
-
- */
- var queue = {
-
- // tell the queue to wait for an element to be ready
- wait: function(element) {
- if (!element.__queue) {
- element.__queue = {};
- elements.push(element);
- }
- },
-
- // enqueue an element to the next spot in the queue.
- enqueue: function(element, check, go) {
- var shouldAdd = element.__queue && !element.__queue.check;
- if (shouldAdd) {
- queueForElement(element).push(element);
- element.__queue.check = check;
- element.__queue.go = go;
- }
- return (this.indexOf(element) !== 0);
- },
-
- indexOf: function(element) {
- var i = queueForElement(element).indexOf(element);
- if (i >= 0 && document.contains(element)) {
- i += (HTMLImports.useNative || HTMLImports.ready) ?
- importQueue.length : 1e9;
- }
- return i;
- },
-
- // tell the queue an element is ready to be registered
- go: function(element) {
- var readied = this.remove(element);
- if (readied) {
- element.__queue.flushable = true;
- this.addToFlushQueue(readied);
- this.check();
- }
- },
-
- remove: function(element) {
- var i = this.indexOf(element);
- if (i !== 0) {
- //console.warn('queue order wrong', i);
- return;
- }
- return queueForElement(element).shift();
- },
-
- check: function() {
- // next
- var element = this.nextElement();
- if (element) {
- element.__queue.check.call(element);
- }
- if (this.canReady()) {
- this.ready();
- return true;
- }
- },
-
- nextElement: function() {
- return nextQueued();
- },
-
- canReady: function() {
- return !this.waitToReady && this.isEmpty();
- },
-
- isEmpty: function() {
- for (var i=0, l=elements.length, e; (i<l) &&
- (e=elements[i]); i++) {
- if (e.__queue && !e.__queue.flushable) {
- return;
- }
- }
- return true;
- },
-
- addToFlushQueue: function(element) {
- flushQueue.push(element);
- },
-
- flush: function() {
- // prevent re-entrance
- if (this.flushing) {
- return;
- }
- this.flushing = true;
- var element;
- while (flushQueue.length) {
- element = flushQueue.shift();
- element.__queue.go.call(element);
- element.__queue = null;
- }
- this.flushing = false;
- },
-
- ready: function() {
- // TODO(sorvell): As an optimization, turn off CE polyfill upgrading
- // while registering. This way we avoid having to upgrade each document
- // piecemeal per registration and can instead register all elements
- // and upgrade once in a batch. Without this optimization, upgrade time
- // degrades significantly when SD polyfill is used. This is mainly because
- // querying the document tree for elements is slow under the SD polyfill.
- var polyfillWasReady = CustomElements.ready;
- CustomElements.ready = false;
- this.flush();
- if (!CustomElements.useNative) {
- CustomElements.upgradeDocumentTree(document);
- }
- CustomElements.ready = polyfillWasReady;
- Polymer.flush();
- requestAnimationFrame(this.flushReadyCallbacks);
- },
-
- addReadyCallback: function(callback) {
- if (callback) {
- readyCallbacks.push(callback);
- }
- },
-
- flushReadyCallbacks: function() {
- if (readyCallbacks) {
- var fn;
- while (readyCallbacks.length) {
- fn = readyCallbacks.shift();
- fn();
- }
- }
- },
-
- /**
- Returns a list of elements that have had polymer-elements created but
- are not yet ready to register. The list is an array of element definitions.
- */
- waitingFor: function() {
- var e$ = [];
- for (var i=0, l=elements.length, e; (i<l) &&
- (e=elements[i]); i++) {
- if (e.__queue && !e.__queue.flushable) {
- e$.push(e);
- }
- }
- return e$;
- },
-
- waitToReady: true
-
- };
-
- var elements = [];
- var flushQueue = [];
- var importQueue = [];
- var mainQueue = [];
- var readyCallbacks = [];
-
- function queueForElement(element) {
- return document.contains(element) ? mainQueue : importQueue;
- }
-
- function nextQueued() {
- return importQueue.length ? importQueue[0] : mainQueue[0];
- }
-
- function whenReady(callback) {
- queue.waitToReady = true;
- Polymer.endOfMicrotask(function() {
- HTMLImports.whenReady(function() {
- queue.addReadyCallback(callback);
- queue.waitToReady = false;
- queue.check();
- });
- });
- }
-
- /**
- Forces polymer to register any pending elements. Can be used to abort
- waiting for elements that are partially defined.
- @param timeout {Integer} Optional timeout in milliseconds
- */
- function forceReady(timeout) {
- if (timeout === undefined) {
- queue.ready();
- return;
- }
- var handle = setTimeout(function() {
- queue.ready();
- }, timeout);
- Polymer.whenReady(function() {
- clearTimeout(handle);
- });
- }
-
- // exports
- scope.elements = elements;
- scope.waitingFor = queue.waitingFor.bind(queue);
- scope.forceReady = forceReady;
- scope.queue = queue;
- scope.whenReady = scope.whenPolymerReady = whenReady;
-})(Polymer);
-
-(function(scope) {
-
- // imports
-
- var extend = scope.extend;
- var api = scope.api;
- var queue = scope.queue;
- var whenReady = scope.whenReady;
- var getRegisteredPrototype = scope.getRegisteredPrototype;
- var waitingForPrototype = scope.waitingForPrototype;
-
- // declarative implementation: <polymer-element>
-
- var prototype = extend(Object.create(HTMLElement.prototype), {
-
- createdCallback: function() {
- if (this.getAttribute('name')) {
- this.init();
- }
- },
-
- init: function() {
- // fetch declared values
- this.name = this.getAttribute('name');
- this.extends = this.getAttribute('extends');
- queue.wait(this);
- // initiate any async resource fetches
- this.loadResources();
- // register when all constraints are met
- this.registerWhenReady();
- },
-
- // TODO(sorvell): we currently queue in the order the prototypes are
- // registered, but we should queue in the order that polymer-elements
- // are registered. We are currently blocked from doing this based on
- // crbug.com/395686.
- registerWhenReady: function() {
- if (this.registered
- || this.waitingForPrototype(this.name)
- || this.waitingForQueue()
- || this.waitingForResources()) {
- return;
- }
- queue.go(this);
- },
-
- _register: function() {
- //console.log('registering', this.name);
- // warn if extending from a custom element not registered via Polymer
- if (isCustomTag(this.extends) && !isRegistered(this.extends)) {
- console.warn('%s is attempting to extend %s, an unregistered element ' +
- 'or one that was not registered with Polymer.', this.name,
- this.extends);
- }
- this.register(this.name, this.extends);
- this.registered = true;
- },
-
- waitingForPrototype: function(name) {
- if (!getRegisteredPrototype(name)) {
- // then wait for a prototype
- waitingForPrototype(name, this);
- // emulate script if user is not supplying one
- this.handleNoScript(name);
- // prototype not ready yet
- return true;
- }
- },
-
- handleNoScript: function(name) {
- // if explicitly marked as 'noscript'
- if (this.hasAttribute('noscript') && !this.noscript) {
- this.noscript = true;
- // imperative element registration
- Polymer(name);
- }
- },
-
- waitingForResources: function() {
- return this._needsResources;
- },
-
- // NOTE: Elements must be queued in proper order for inheritance/composition
- // dependency resolution. Previously this was enforced for inheritance,
- // and by rule for composition. It's now entirely by rule.
- waitingForQueue: function() {
- return queue.enqueue(this, this.registerWhenReady, this._register);
- },
-
- loadResources: function() {
- this._needsResources = true;
- this.loadStyles(function() {
- this._needsResources = false;
- this.registerWhenReady();
- }.bind(this));
- }
-
- });
-
- // semi-pluggable APIs
-
- // TODO(sjmiles): should be fully pluggable (aka decoupled, currently
- // the various plugins are allowed to depend on each other directly)
- api.publish(api.declaration, prototype);
-
- // utility and bookkeeping
-
- function isRegistered(name) {
- return Boolean(HTMLElement.getPrototypeForTag(name));
- }
-
- function isCustomTag(name) {
- return (name && name.indexOf('-') >= 0);
- }
-
- // boot tasks
-
- whenReady(function() {
- document.body.removeAttribute('unresolved');
- document.dispatchEvent(
- new CustomEvent('polymer-ready', {bubbles: true})
- );
- });
-
- // register polymer-element with document
-
- document.registerElement('polymer-element', {prototype: prototype});
-
-})(Polymer);
-
-(function(scope) {
-
-/**
- * @class Polymer
- */
-
-var whenReady = scope.whenReady;
-
-/**
- * Loads the set of HTMLImports contained in `node`. Notifies when all
- * the imports have loaded by calling the `callback` function argument.
- * This method can be used to lazily load imports. For example, given a
- * template:
- *
- * <template>
- * <link rel="import" href="my-import1.html">
- * <link rel="import" href="my-import2.html">
- * </template>
- *
- * Polymer.importElements(template.content, function() {
- * console.log('imports lazily loaded');
- * });
- *
- * @method importElements
- * @param {Node} node Node containing the HTMLImports to load.
- * @param {Function} callback Callback called when all imports have loaded.
- */
-function importElements(node, callback) {
- if (node) {
- document.head.appendChild(node);
- whenReady(callback);
- } else if (callback) {
- callback();
- }
-}
-
-/**
- * Loads an HTMLImport for each url specified in the `urls` array.
- * Notifies when all the imports have loaded by calling the `callback`
- * function argument. This method can be used to lazily load imports.
- * For example,
- *
- * Polymer.import(['my-import1.html', 'my-import2.html'], function() {
- * console.log('imports lazily loaded');
- * });
- *
- * @method import
- * @param {Array} urls Array of urls to load as HTMLImports.
- * @param {Function} callback Callback called when all imports have loaded.
- */
-function _import(urls, callback) {
- if (urls && urls.length) {
- var frag = document.createDocumentFragment();
- for (var i=0, l=urls.length, url, link; (i<l) && (url=urls[i]); i++) {
- link = document.createElement('link');
- link.rel = 'import';
- link.href = url;
- frag.appendChild(link);
- }
- importElements(frag, callback);
- } else if (callback) {
- callback();
- }
-}
-
-// exports
-scope.import = _import;
-scope.importElements = importElements;
-
-})(Polymer);
-
-/**
- * The `auto-binding` element extends the template element. It provides a quick
- * and easy way to do data binding without the need to setup a model.
- * The `auto-binding` element itself serves as the model and controller for the
- * elements it contains. Both data and event handlers can be bound.
- *
- * The `auto-binding` element acts just like a template that is bound to
- * a model. It stamps its content in the dom adjacent to itself. When the
- * content is stamped, the `template-bound` event is fired.
- *
- * Example:
- *
- * <template is="auto-binding">
- * <div>Say something: <input value="{{value}}"></div>
- * <div>You said: {{value}}</div>
- * <button on-tap="{{buttonTap}}">Tap me!</button>
- * </template>
- * <script>
- * var template = document.querySelector('template');
- * template.value = 'something';
- * template.buttonTap = function() {
- * console.log('tap!');
- * };
- * </script>
- *
- * @module Polymer
- * @status stable
-*/
-
-(function() {
-
- var element = document.createElement('polymer-element');
- element.setAttribute('name', 'auto-binding');
- element.setAttribute('extends', 'template');
- element.init();
-
- Polymer('auto-binding', {
-
- createdCallback: function() {
- this.syntax = this.bindingDelegate = this.makeSyntax();
- // delay stamping until polymer-ready so that auto-binding is not
- // required to load last.
- Polymer.whenPolymerReady(function() {
- this.model = this;
- this.setAttribute('bind', '');
- // we don't bother with an explicit signal here, we could ust a MO
- // if necessary
- this.async(function() {
- // note: this will marshall *all* the elements in the parentNode
- // rather than just stamped ones. We'd need to use createInstance
- // to fix this or something else fancier.
- this.marshalNodeReferences(this.parentNode);
- // template stamping is asynchronous so stamping isn't complete
- // by polymer-ready; fire an event so users can use stamped elements
- this.fire('template-bound');
- });
- }.bind(this));
- },
-
- makeSyntax: function() {
- var events = Object.create(Polymer.api.declaration.events);
- var self = this;
- events.findController = function() { return self.model; };
-
- var syntax = new PolymerExpressions();
- var prepareBinding = syntax.prepareBinding;
- syntax.prepareBinding = function(pathString, name, node) {
- return events.prepareEventBinding(pathString, name, node) ||
- prepareBinding.call(syntax, pathString, name, node);
- };
- return syntax;
- }
-
- });
-
-})();
diff --git a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.min.js b/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.min.js
deleted file mode 100644
index dcd0bd6763f..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/polymer/polymer.min.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-window.PolymerGestures={},function(a){var b=!1,c=document.createElement("meta");if(c.createShadowRoot){var d=c.createShadowRoot(),e=document.createElement("span");d.appendChild(e),c.addEventListener("testpath",function(a){a.path&&(b=a.path[0]===e),a.stopPropagation()});var f=new CustomEvent("testpath",{bubbles:!0});document.head.appendChild(c),e.dispatchEvent(f),c.parentNode.removeChild(c),d=e=null}c=null;var g={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);return this.canTarget(b)?b:void 0},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){var d,e;return a?(d=a.elementFromPoint(b,c),d?e=this.targetingShadow(d):a!==document&&(e=this.olderShadow(a)),this.searchRoot(e,b,c)||d):void 0},owner:function(a){if(!a)return document;for(var b=a;b.parentNode;)b=b.parentNode;return b.nodeType!=Node.DOCUMENT_NODE&&b.nodeType!=Node.DOCUMENT_FRAGMENT_NODE&&(b=document),b},findTarget:function(a){if(b&&a.path&&a.path.length)return a.path[0];var c=a.clientX,d=a.clientY,e=this.owner(a.target);return e.elementFromPoint(c,d)||(e=document),this.searchRoot(e,c,d)},findTouchAction:function(a){var c;if(b&&a.path&&a.path.length){for(var d=a.path,e=0;e<d.length;e++)if(c=d[e],c.nodeType===Node.ELEMENT_NODE&&c.hasAttribute("touch-action"))return c.getAttribute("touch-action")}else for(c=a.target;c;){if(c.nodeType===Node.ELEMENT_NODE&&c.hasAttribute("touch-action"))return c.getAttribute("touch-action");c=c.parentNode||c.host}return"auto"},LCA:function(a,b){if(a===b)return a;if(a&&!b)return a;if(b&&!a)return b;if(!b&&!a)return document;if(a.contains&&a.contains(b))return a;if(b.contains&&b.contains(a))return b;var c=this.depth(a),d=this.depth(b),e=c-d;for(e>=0?a=this.walk(a,e):b=this.walk(b,-e);a&&b&&a!==b;)a=a.parentNode||a.host,b=b.parentNode||b.host;return a},walk:function(a,b){for(var c=0;a&&b>c;c++)a=a.parentNode||a.host;return a},depth:function(a){for(var b=0;a;)b++,a=a.parentNode||a.host;return b},deepContains:function(a,b){var c=this.LCA(a,b);return c===a},insideNode:function(a,b,c){var d=a.getBoundingClientRect();return d.left<=b&&b<=d.right&&d.top<=c&&c<=d.bottom},path:function(a){var c;if(b&&a.path&&a.path.length)c=a.path;else{c=[];for(var d=this.findTarget(a);d;)c.push(d),d=d.parentNode||d.host}return c}};a.targetFinding=g,a.findTarget=g.findTarget.bind(g),a.deepContains=g.deepContains.bind(g),a.insideNode=g.insideNode}(window.PolymerGestures),function(){function a(a){return"html /deep/ "+b(a)}function b(a){return'[touch-action="'+a+'"]'}function c(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+";}"}var d=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]},"manipulation"],e="",f="string"==typeof document.head.style.touchAction,g=!window.ShadowDOMPolyfill&&document.head.createShadowRoot;if(f){d.forEach(function(d){String(d)===d?(e+=b(d)+c(d)+"\n",g&&(e+=a(d)+c(d)+"\n")):(e+=d.selectors.map(b)+c(d.rule)+"\n",g&&(e+=d.selectors.map(a)+c(d.rule)+"\n"))});var h=document.createElement("style");h.textContent=e,document.head.appendChild(h)}}(),function(a){var b=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","pageX","pageY"],c=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0],d=function(){return function(){}},e={preventTap:d,makeBaseEvent:function(a,b){var c=document.createEvent("Event");return c.initEvent(a,b.bubbles||!1,b.cancelable||!1),c.preventTap=e.preventTap(c),c},makeGestureEvent:function(a,b){b=b||Object.create(null);for(var c,d=this.makeBaseEvent(a,b),e=0,f=Object.keys(b);e<f.length;e++)c=f[e],"bubbles"!==c&&"cancelable"!==c&&(d[c]=b[c]);return d},makePointerEvent:function(a,d){d=d||Object.create(null);for(var e,f=this.makeBaseEvent(a,d),g=2;g<b.length;g++)e=b[g],f[e]=d[e]||c[g];f.buttons=d.buttons||0;var h=0;return h=d.pressure?d.pressure:f.buttons?.5:0,f.x=f.clientX,f.y=f.clientY,f.pointerId=d.pointerId||0,f.width=d.width||0,f.height=d.height||0,f.pressure=h,f.tiltX=d.tiltX||0,f.tiltY=d.tiltY||0,f.pointerType=d.pointerType||"",f.hwTimestamp=d.hwTimestamp||0,f.isPrimary=d.isPrimary||!1,f._source=d._source||"",f}};a.eventFactory=e}(window.PolymerGestures),function(a){function b(){if(c){var a=new Map;return a.pointers=d,a}this.keys=[],this.values=[]}var c=window.Map&&window.Map.prototype.forEach,d=function(){return this.size};b.prototype={set:function(a,b){var c=this.keys.indexOf(a);c>-1?this.values[c]=b:(this.keys.push(a),this.values.push(b))},has:function(a){return this.keys.indexOf(a)>-1},"delete":function(a){var b=this.keys.indexOf(a);b>-1&&(this.keys.splice(b,1),this.values.splice(b,1))},get:function(a){var b=this.keys.indexOf(a);return this.values[b]},clear:function(){this.keys.length=0,this.values.length=0},forEach:function(a,b){this.values.forEach(function(c,d){a.call(b,c,this.keys[d],this)},this)},pointers:function(){return this.keys.length}},a.PointerMap=b}(window.PolymerGestures),function(a){var b,c=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","which","pageX","pageY","timeStamp","preventTap","tapPrevented","_source"],d=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0,0,0,0,function(){},!1],e="undefined"!=typeof SVGElementInstance,f=a.eventFactory,g={IS_IOS:!1,pointermap:new a.PointerMap,requiredGestures:new a.PointerMap,eventMap:Object.create(null),eventSources:Object.create(null),eventSourceList:[],gestures:[],dependencyMap:{down:{listeners:0,index:-1},up:{listeners:0,index:-1}},gestureQueue:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},registerGesture:function(a,b){var c=Object.create(null);c.listeners=0,c.index=this.gestures.length;for(var d,e=0;e<b.exposes.length;e++)d=b.exposes[e].toLowerCase(),this.dependencyMap[d]=c;this.gestures.push(b)},register:function(a,b){for(var c,d=this.eventSourceList.length,e=0;d>e&&(c=this.eventSourceList[e]);e++)c.register.call(c,a,b)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.unregister.call(b,a)},down:function(a){this.requiredGestures.set(a.pointerId,b),this.fireEvent("down",a)},move:function(a){a.type="move",this.fillGestureQueue(a)},up:function(a){this.fireEvent("up",a),this.requiredGestures["delete"](a.pointerId)},cancel:function(a){a.tapPrevented=!0,this.fireEvent("up",a),this.requiredGestures["delete"](a.pointerId)},addGestureDependency:function(a,b){var c=a._pgEvents;if(c&&b)for(var d,e,f,g=Object.keys(c),h=0;h<g.length;h++)f=g[h],c[f]>0&&(d=this.dependencyMap[f],e=d?d.index:-1,b[e]=!0)},eventHandler:function(c){var d=c.type;if("touchstart"===d||"mousedown"===d||"pointerdown"===d||"MSPointerDown"===d)if(c._handledByPG||(b={}),this.IS_IOS){var e=c;if("touchstart"===d){var f=c.changedTouches[0];e={target:c.target,clientX:f.clientX,clientY:f.clientY,path:c.path}}for(var g,h=c.path||a.targetFinding.path(e),i=0;i<h.length;i++)g=h[i],this.addGestureDependency(g,b)}else this.addGestureDependency(c.currentTarget,b);if(!c._handledByPG){var j=this.eventMap&&this.eventMap[d];j&&j(c),c._handledByPG=!0}},listen:function(a,b){for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.addEvent(a,c)},unlisten:function(a,b){for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.removeEvent(a,c)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(a,b){var c=f.makePointerEvent(a,b);return c.preventDefault=b.preventDefault,c.tapPrevented=b.tapPrevented,c._target=c._target||b.target,c},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){for(var b,f=Object.create(null),g=0;g<c.length;g++)b=c[g],f[b]=a[b]||d[g],("target"===b||"relatedTarget"===b)&&e&&f[b]instanceof SVGElementInstance&&(f[b]=f[b].correspondingUseElement);return f.preventDefault=function(){a.preventDefault()},f},dispatchEvent:function(a){var b=a._target;if(b){b.dispatchEvent(a);var c=this.cloneEvent(a);c.target=b,this.fillGestureQueue(c)}},gestureTrigger:function(){for(var a,b,c=0;c<this.gestureQueue.length;c++)if(a=this.gestureQueue[c],b=a._requiredGestures)for(var d,e,f=0;f<this.gestures.length;f++)b[f]&&(d=this.gestures[f],e=d[a.type],e&&e.call(d,a));this.gestureQueue.length=0},fillGestureQueue:function(a){this.gestureQueue.length||requestAnimationFrame(this.boundGestureTrigger),a._requiredGestures=this.requiredGestures.get(a.pointerId),this.gestureQueue.push(a)}};g.boundHandler=g.eventHandler.bind(g),g.boundGestureTrigger=g.gestureTrigger.bind(g),a.dispatcher=g,a.activateGesture=function(a,b){var c=b.toLowerCase(),d=g.dependencyMap[c];if(d){var e=g.gestures[d.index];if(a._pgListeners||(g.register(a),a._pgListeners=0),e){var f,h=e.defaultActions&&e.defaultActions[c];switch(a.nodeType){case Node.ELEMENT_NODE:f=a;break;case Node.DOCUMENT_FRAGMENT_NODE:f=a.host;break;default:f=null}h&&f&&!f.hasAttribute("touch-action")&&f.setAttribute("touch-action",h)}a._pgEvents||(a._pgEvents={}),a._pgEvents[c]=(a._pgEvents[c]||0)+1,a._pgListeners++}return Boolean(d)},a.addEventListener=function(b,c,d,e){d&&(a.activateGesture(b,c),b.addEventListener(c,d,e))},a.deactivateGesture=function(a,b){var c=b.toLowerCase(),d=g.dependencyMap[c];return d&&(a._pgListeners>0&&a._pgListeners--,0===a._pgListeners&&g.unregister(a),a._pgEvents&&(a._pgEvents[c]>0?a._pgEvents[c]--:a._pgEvents[c]=0)),Boolean(d)},a.removeEventListener=function(b,c,d,e){d&&(a.deactivateGesture(b,c),b.removeEventListener(c,d,e))}}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d=25,e=[0,1,4,2],f=0,g=/Linux.*Firefox\//i,h=function(){if(g.test(navigator.userAgent))return!1;try{return 1===new MouseEvent("test",{buttons:1}).buttons}catch(a){return!1}}(),i={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup"],exposes:["down","up","move"],register:function(a){b.listen(a,this.events)},unregister:function(a){a.nodeType!==Node.DOCUMENT_NODE&&b.unlisten(a,this.events)},lastTouches:[],isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,e=a.clientX,f=a.clientY,g=0,h=c.length;h>g&&(b=c[g]);g++){var i=Math.abs(e-b.x),j=Math.abs(f-b.y);if(d>=i&&d>=j)return!0}},prepareEvent:function(a){var c=b.cloneEvent(a);if(c.pointerId=this.POINTER_ID,c.isPrimary=!0,c.pointerType=this.POINTER_TYPE,c._source="mouse",!h){var d=a.type,g=e[a.which]||0;"mousedown"===d?f|=g:"mouseup"===d&&(f&=~g),c.buttons=f}return c},mousedown:function(d){if(!this.isEventSimulatedFromTouch(d)){var e=(c.has(this.POINTER_ID),this.prepareEvent(d));e.target=a.findTarget(d),c.set(this.POINTER_ID,e.target),b.down(e)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.get(this.POINTER_ID);if(d){var e=this.prepareEvent(a);e.target=d,0===(h?e.buttons:e.which)?(h||(f=e.buttons=0),b.cancel(e),this.cleanupMouse(e.buttons)):b.move(e)}}},mouseup:function(d){if(!this.isEventSimulatedFromTouch(d)){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(this.POINTER_ID),b.up(e),this.cleanupMouse(e.buttons)}},cleanupMouse:function(a){0===a&&c["delete"](this.POINTER_ID)}};a.mouseEvents=i}(window.PolymerGestures),function(a){var b=a.dispatcher,c=(a.targetFinding.allShadows.bind(a.targetFinding),b.pointermap),d=(Array.prototype.map.call.bind(Array.prototype.map),2500),e=25,f=200,g=20,h=!1,i={IS_IOS:!1,events:["touchstart","touchmove","touchend","touchcancel"],exposes:["down","up","move"],register:function(a,c){(this.IS_IOS?c:!c)&&b.listen(a,this.events)},unregister:function(a){this.IS_IOS||b.unlisten(a,this.events)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y"},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return b===c.EMITTER?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":"XY"},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){(0===c.pointers()||1===c.pointers()&&c.has(1))&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.firstTarget=a.target,this.scrolling=null,this.cancelResetClickCount())},removePrimaryPointer:function(a){a.isPrimary&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,f)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},typeToButtons:function(a){var b=0;return("touchstart"===a||"touchmove"===a)&&(b=1),b},findTarget:function(b,d){if("touchstart"===this.currentTouchEvent.type){if(this.isPrimaryTouch(b)){var e={clientX:b.clientX,clientY:b.clientY,path:this.currentTouchEvent.path,target:this.currentTouchEvent.target};return a.findTarget(e)}return a.findTarget(b)}return c.get(d)},touchToPointer:function(a){var c=this.currentTouchEvent,d=b.cloneEvent(a),e=d.pointerId=a.identifier+2;d.target=this.findTarget(a,e),d.bubbles=!0,d.cancelable=!0,d.detail=this.clickCount,d.buttons=this.typeToButtons(c.type),d.width=a.webkitRadiusX||a.radiusX||0,d.height=a.webkitRadiusY||a.radiusY||0,d.pressure=a.webkitForce||a.force||.5,d.isPrimary=this.isPrimaryTouch(a),d.pointerType=this.POINTER_TYPE,d._source="touch";var f=this;return d.preventDefault=function(){f.scrolling=!1,f.firstXY=null,c.preventDefault()},d},processTouches:function(a,b){var d=a.changedTouches;this.currentTouchEvent=a;for(var e,f,g=0;g<d.length;g++)e=d[g],f=this.touchToPointer(e),"touchstart"===a.type&&c.set(f.pointerId,f.target),c.has(f.pointerId)&&b.call(this,f),("touchend"===a.type||a._cancel)&&this.cleanUpPointer(f)},shouldScroll:function(b){if(this.firstXY){var c,d=a.targetFinding.findTouchAction(b),e=this.touchActionToScrollType(d);if("none"===e)c=!1;else if("XY"===e)c=!0;else{var f=b.changedTouches[0],g=e,h="Y"===e?"X":"Y",i=Math.abs(f["client"+g]-this.firstXY[g]),j=Math.abs(f["client"+h]-this.firstXY[h]);c=i>=j}return c}},findTouch:function(a,b){for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)if(c.identifier===b)return!0},vacuumTouches:function(a){var b=a.touches;if(c.pointers()>=b.length){var d=[];c.forEach(function(a,c){if(1!==c&&!this.findTouch(b,c-2)){var e=a;d.push(e)}},this),d.forEach(function(a){this.cancel(a),c["delete"](a.pointerId)},this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.down))},down:function(a){b.down(a)},touchmove:function(a){if(h)a.cancelable&&this.processTouches(a,this.move);else if(this.scrolling){if(this.firstXY){var b=a.changedTouches[0],c=b.clientX-this.firstXY.X,d=b.clientY-this.firstXY.Y,e=Math.sqrt(c*c+d*d);e>=g&&(this.touchcancel(a),this.scrolling=!0,this.firstXY=null)}}else null===this.scrolling&&this.shouldScroll(a)?this.scrolling=!0:(this.scrolling=!1,a.preventDefault(),this.processTouches(a,this.move))},move:function(a){b.move(a)},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.up)},up:function(c){c.relatedTarget=a.findTarget(c),b.up(c)},cancel:function(a){b.cancel(a)},touchcancel:function(a){a._cancel=!0,this.processTouches(a,this.cancel)},cleanUpPointer:function(a){c["delete"](a.pointerId),this.removePrimaryPointer(a)},dedupSynthMouse:function(b){var c=a.mouseEvents.lastTouches,e=b.changedTouches[0];if(this.isPrimaryTouch(e)){var f={x:e.clientX,y:e.clientY};c.push(f);var g=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,c,f);setTimeout(g,d)}}},j=Event.prototype.stopImmediatePropagation||Event.prototype.stopPropagation;document.addEventListener("click",function(b){var c=b.clientX,d=b.clientY,f=function(a){var b=Math.abs(c-a.x),f=Math.abs(d-a.y);return e>=b&&e>=f},g=a.mouseEvents.lastTouches.some(f),h=a.targetFinding.path(b);if(g){for(var k=0;k<h.length;k++)if(h[k]===i.firstTarget)return;b.preventDefault(),j.call(b)}},!0),a.touchEvents=i}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,e={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerCancel"],register:function(a){b.listen(a,this.events)},unregister:function(a){a.nodeType!==Node.DOCUMENT_NODE&&b.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var c=a;return c=b.cloneEvent(a),d&&(c.pointerType=this.POINTER_TYPES[a.pointerType]),c._source="ms",c},cleanup:function(a){c["delete"](a)},MSPointerDown:function(d){var e=this.prepareEvent(d);e.target=a.findTarget(d),c.set(d.pointerId,e.target),b.down(e)},MSPointerMove:function(a){var d=c.get(a.pointerId);if(d){var e=this.prepareEvent(a);e.target=d,b.move(e)}},MSPointerUp:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.up(e),this.cleanup(d.pointerId)},MSPointerCancel:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.cancel(e),this.cleanup(d.pointerId)}};a.msEvents=e}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],prepareEvent:function(a){var c=b.cloneEvent(a);return c._source="pointer",c},register:function(a){b.listen(a,this.events)},unregister:function(a){a.nodeType!==Node.DOCUMENT_NODE&&b.unlisten(a,this.events)},cleanup:function(a){c["delete"](a)},pointerdown:function(d){var e=this.prepareEvent(d);e.target=a.findTarget(d),c.set(e.pointerId,e.target),b.down(e)},pointermove:function(a){var d=c.get(a.pointerId);if(d){var e=this.prepareEvent(a);e.target=d,b.move(e)}},pointerup:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.up(e),this.cleanup(d.pointerId)},pointercancel:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.cancel(e),this.cleanup(d.pointerId)}};a.pointerEvents=d}(window.PolymerGestures),function(a){var b=a.dispatcher,c=window.navigator;window.PointerEvent?b.registerSource("pointer",a.pointerEvents):c.msPointerEnabled?b.registerSource("ms",a.msEvents):(b.registerSource("mouse",a.mouseEvents),void 0!==window.ontouchstart&&b.registerSource("touch",a.touchEvents));var d=navigator.userAgent,e=d.match(/iPad|iPhone|iPod/)&&"ontouchstart"in window;b.IS_IOS=e,a.touchEvents.IS_IOS=e,b.register(document,!0)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d=new a.PointerMap,e={events:["down","move","up"],exposes:["trackstart","track","trackx","tracky","trackend"],defaultActions:{track:"none",trackx:"pan-y",tracky:"pan-x"},WIGGLE_THRESHOLD:4,clampDir:function(a){return a>0?1:-1},calcPositionDelta:function(a,b){var c=0,d=0;return a&&b&&(c=b.pageX-a.pageX,d=b.pageY-a.pageY),{x:c,y:d}},fireTrack:function(a,b,d){var e=d,f=this.calcPositionDelta(e.downEvent,b),g=this.calcPositionDelta(e.lastMoveEvent,b);if(g.x)e.xDirection=this.clampDir(g.x);else if("trackx"===a)return;if(g.y)e.yDirection=this.clampDir(g.y);else if("tracky"===a)return;var h={bubbles:!0,cancelable:!0,trackInfo:e.trackInfo,relatedTarget:b.relatedTarget,pointerType:b.pointerType,pointerId:b.pointerId,_source:"track"};"tracky"!==a&&(h.x=b.x,h.dx=f.x,h.ddx=g.x,h.clientX=b.clientX,h.pageX=b.pageX,h.screenX=b.screenX,h.xDirection=e.xDirection),"trackx"!==a&&(h.dy=f.y,h.ddy=g.y,h.y=b.y,h.clientY=b.clientY,h.pageY=b.pageY,h.screenY=b.screenY,h.yDirection=e.yDirection);var i=c.makeGestureEvent(a,h);e.downTarget.dispatchEvent(i)},down:function(a){if(a.isPrimary&&("mouse"===a.pointerType?1===a.buttons:!0)){var b={downEvent:a,downTarget:a.target,trackInfo:{},lastMoveEvent:null,xDirection:0,yDirection:0,tracking:!1};d.set(a.pointerId,b)}},move:function(a){var b=d.get(a.pointerId);if(b){if(!b.tracking){var c=this.calcPositionDelta(b.downEvent,a),e=c.x*c.x+c.y*c.y;e>this.WIGGLE_THRESHOLD&&(b.tracking=!0,b.lastMoveEvent=b.downEvent,this.fireTrack("trackstart",a,b))}b.tracking&&(this.fireTrack("track",a,b),this.fireTrack("trackx",a,b),this.fireTrack("tracky",a,b)),b.lastMoveEvent=a}},up:function(a){var b=d.get(a.pointerId);b&&(b.tracking&&this.fireTrack("trackend",a,b),d["delete"](a.pointerId))}};b.registerGesture("track",e)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d={HOLD_DELAY:200,WIGGLE_THRESHOLD:16,events:["down","move","up"],exposes:["hold","holdpulse","release"],heldPointer:null,holdJob:null,pulse:function(){var a=Date.now()-this.heldPointer.timeStamp,b=this.held?"holdpulse":"hold";this.fireHold(b,a),this.held=!0},cancel:function(){clearInterval(this.holdJob),this.held&&this.fireHold("release"),this.held=!1,this.heldPointer=null,this.target=null,this.holdJob=null},down:function(a){a.isPrimary&&!this.heldPointer&&(this.heldPointer=a,this.target=a.target,this.holdJob=setInterval(this.pulse.bind(this),this.HOLD_DELAY))},up:function(a){this.heldPointer&&this.heldPointer.pointerId===a.pointerId&&this.cancel()},move:function(a){if(this.heldPointer&&this.heldPointer.pointerId===a.pointerId){var b=a.clientX-this.heldPointer.clientX,c=a.clientY-this.heldPointer.clientY;b*b+c*c>this.WIGGLE_THRESHOLD&&this.cancel()}},fireHold:function(a,b){var d={bubbles:!0,cancelable:!0,pointerType:this.heldPointer.pointerType,pointerId:this.heldPointer.pointerId,x:this.heldPointer.clientX,y:this.heldPointer.clientY,_source:"hold"};b&&(d.holdTime=b);var e=c.makeGestureEvent(a,d);this.target.dispatchEvent(e)}};b.registerGesture("hold",d)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d=new a.PointerMap,e={events:["down","up"],exposes:["tap"],down:function(a){a.isPrimary&&!a.tapPrevented&&d.set(a.pointerId,{target:a.target,buttons:a.buttons,x:a.clientX,y:a.clientY})},shouldTap:function(a,b){var c=!0;return"mouse"===a.pointerType&&(c=1^a.buttons&&1&b.buttons),c&&!a.tapPrevented},up:function(b){var e=d.get(b.pointerId);if(e&&this.shouldTap(b,e)){var f=a.targetFinding.LCA(e.target,b.relatedTarget);if(f){var g=c.makeGestureEvent("tap",{bubbles:!0,cancelable:!0,x:b.clientX,y:b.clientY,detail:b.detail,pointerType:b.pointerType,pointerId:b.pointerId,altKey:b.altKey,ctrlKey:b.ctrlKey,metaKey:b.metaKey,shiftKey:b.shiftKey,_source:"tap"});f.dispatchEvent(g)}}d["delete"](b.pointerId)}};c.preventTap=function(a){return function(){a.tapPrevented=!0,d["delete"](a.pointerId)}},b.registerGesture("tap",e)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d=new a.PointerMap,e=180/Math.PI,f={events:["down","up","move","cancel"],exposes:["pinchstart","pinch","pinchend","rotate"],defaultActions:{pinch:"none",rotate:"none"},reference:{},down:function(b){if(d.set(b.pointerId,b),2==d.pointers()){var c=this.calcChord(),e=this.calcAngle(c);this.reference={angle:e,diameter:c.diameter,target:a.targetFinding.LCA(c.a.target,c.b.target)},this.firePinch("pinchstart",c.diameter,c)}},up:function(a){var b=d.get(a.pointerId),c=d.pointers();if(b){if(2===c){var e=this.calcChord();this.firePinch("pinchend",e.diameter,e)}d["delete"](a.pointerId)}},move:function(a){d.has(a.pointerId)&&(d.set(a.pointerId,a),d.pointers()>1&&this.calcPinchRotate())},cancel:function(a){this.up(a)},firePinch:function(a,b,d){var e=b/this.reference.diameter,f=c.makeGestureEvent(a,{bubbles:!0,cancelable:!0,scale:e,centerX:d.center.x,centerY:d.center.y,_source:"pinch"});this.reference.target.dispatchEvent(f)},fireRotate:function(a,b){var d=Math.round((a-this.reference.angle)%360),e=c.makeGestureEvent("rotate",{bubbles:!0,cancelable:!0,angle:d,centerX:b.center.x,centerY:b.center.y,_source:"pinch"});this.reference.target.dispatchEvent(e)},calcPinchRotate:function(){var a=this.calcChord(),b=a.diameter,c=this.calcAngle(a);b!=this.reference.diameter&&this.firePinch("pinch",b,a),c!=this.reference.angle&&this.fireRotate(c,a)},calcChord:function(){var a=[];d.forEach(function(b){a.push(b)});for(var b,c,e,f=0,g={a:a[0],b:a[1]},h=0;h<a.length;h++)for(var i=a[h],j=h+1;j<a.length;j++){var k=a[j];b=Math.abs(i.clientX-k.clientX),c=Math.abs(i.clientY-k.clientY),e=b+c,e>f&&(f=e,g={a:i,b:k})}return b=Math.abs(g.a.clientX+g.b.clientX)/2,c=Math.abs(g.a.clientY+g.b.clientY)/2,g.center={x:b,y:c},g.diameter=f,g},calcAngle:function(a){var b=a.a.clientX-a.b.clientX,c=a.a.clientY-a.b.clientY;return(360+Math.atan2(c,b)*e)%360}};b.registerGesture("pinch",f)}(window.PolymerGestures),function(a){"use strict";function b(a,b){if(!a)throw new Error("ASSERT: "+b)}function c(a){return a>=48&&57>=a}function d(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&" ᠎              ".indexOf(String.fromCharCode(a))>0}function e(a){return 10===a||13===a||8232===a||8233===a}function f(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a}function g(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a}function h(a){return"this"===a}function i(){for(;Y>X&&d(W.charCodeAt(X));)++X}function j(){var a,b;for(a=X++;Y>X&&(b=W.charCodeAt(X),g(b));)++X;return W.slice(a,X)}function k(){var a,b,c;return a=X,b=j(),c=1===b.length?S.Identifier:h(b)?S.Keyword:"null"===b?S.NullLiteral:"true"===b||"false"===b?S.BooleanLiteral:S.Identifier,{type:c,value:b,range:[a,X]}}function l(){var a,b,c=X,d=W.charCodeAt(X),e=W[X];switch(d){case 46:case 40:case 41:case 59:case 44:case 123:case 125:case 91:case 93:case 58:case 63:return++X,{type:S.Punctuator,value:String.fromCharCode(d),range:[c,X]};default:if(a=W.charCodeAt(X+1),61===a)switch(d){case 37:case 38:case 42:case 43:case 45:case 47:case 60:case 62:case 124:return X+=2,{type:S.Punctuator,value:String.fromCharCode(d)+String.fromCharCode(a),range:[c,X]};case 33:case 61:return X+=2,61===W.charCodeAt(X)&&++X,{type:S.Punctuator,value:W.slice(c,X),range:[c,X]}}}return b=W[X+1],e===b&&"&|".indexOf(e)>=0?(X+=2,{type:S.Punctuator,value:e+b,range:[c,X]}):"<>=!+-*%&|^/".indexOf(e)>=0?(++X,{type:S.Punctuator,value:e,range:[c,X]}):void s({},V.UnexpectedToken,"ILLEGAL")}function m(){var a,d,e;if(e=W[X],b(c(e.charCodeAt(0))||"."===e,"Numeric literal must start with a decimal digit or a decimal point"),d=X,a="","."!==e){for(a=W[X++],e=W[X],"0"===a&&e&&c(e.charCodeAt(0))&&s({},V.UnexpectedToken,"ILLEGAL");c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("."===e){for(a+=W[X++];c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("e"===e||"E"===e)if(a+=W[X++],e=W[X],("+"===e||"-"===e)&&(a+=W[X++]),c(W.charCodeAt(X)))for(;c(W.charCodeAt(X));)a+=W[X++];else s({},V.UnexpectedToken,"ILLEGAL");return f(W.charCodeAt(X))&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.NumericLiteral,value:parseFloat(a),range:[d,X]}}function n(){var a,c,d,f="",g=!1;for(a=W[X],b("'"===a||'"'===a,"String literal must starts with a quote"),c=X,++X;Y>X;){if(d=W[X++],d===a){a="";break}if("\\"===d)if(d=W[X++],d&&e(d.charCodeAt(0)))"\r"===d&&"\n"===W[X]&&++X;else switch(d){case"n":f+="\n";break;case"r":f+="\r";break;case"t":f+=" ";break;case"b":f+="\b";break;case"f":f+="\f";break;case"v":f+=" ";break;default:f+=d}else{if(e(d.charCodeAt(0)))break;f+=d}}return""!==a&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.StringLiteral,value:f,octal:g,range:[c,X]}}function o(a){return a.type===S.Identifier||a.type===S.Keyword||a.type===S.BooleanLiteral||a.type===S.NullLiteral}function p(){var a;return i(),X>=Y?{type:S.EOF,range:[X,X]}:(a=W.charCodeAt(X),40===a||41===a||58===a?l():39===a||34===a?n():f(a)?k():46===a?c(W.charCodeAt(X+1))?m():l():c(a)?m():l())}function q(){var a;return a=$,X=a.range[1],$=p(),X=a.range[1],a}function r(){var a;a=X,$=p(),X=a}function s(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(c<e.length,"Message reference must be in range"),e[c]});throw d=new Error(f),d.index=X,d.description=f,d}function t(a){s(a,V.UnexpectedToken,a.value)}function u(a){var b=q();(b.type!==S.Punctuator||b.value!==a)&&t(b)}function v(a){return $.type===S.Punctuator&&$.value===a}function w(a){return $.type===S.Keyword&&$.value===a}function x(){var a=[];for(u("[");!v("]");)v(",")?(q(),a.push(null)):(a.push(bb()),v("]")||u(","));return u("]"),Z.createArrayExpression(a)}function y(){var a;return i(),a=q(),a.type===S.StringLiteral||a.type===S.NumericLiteral?Z.createLiteral(a):Z.createIdentifier(a.value)}function z(){var a,b;return a=$,i(),(a.type===S.EOF||a.type===S.Punctuator)&&t(a),b=y(),u(":"),Z.createProperty("init",b,bb())}function A(){var a=[];for(u("{");!v("}");)a.push(z()),v("}")||u(",");return u("}"),Z.createObjectExpression(a)}function B(){var a;return u("("),a=bb(),u(")"),a}function C(){var a,b,c;return v("(")?B():(a=$.type,a===S.Identifier?c=Z.createIdentifier(q().value):a===S.StringLiteral||a===S.NumericLiteral?c=Z.createLiteral(q()):a===S.Keyword?w("this")&&(q(),c=Z.createThisExpression()):a===S.BooleanLiteral?(b=q(),b.value="true"===b.value,c=Z.createLiteral(b)):a===S.NullLiteral?(b=q(),b.value=null,c=Z.createLiteral(b)):v("[")?c=x():v("{")&&(c=A()),c?c:void t(q()))}function D(){var a=[];if(u("("),!v(")"))for(;Y>X&&(a.push(bb()),!v(")"));)u(",");return u(")"),a}function E(){var a;return a=q(),o(a)||t(a),Z.createIdentifier(a.value)}function F(){return u("."),E()}function G(){var a;return u("["),a=bb(),u("]"),a}function H(){var a,b,c;for(a=C();;)if(v("["))c=G(),a=Z.createMemberExpression("[",a,c);else if(v("."))c=F(),a=Z.createMemberExpression(".",a,c);else{if(!v("("))break;b=D(),a=Z.createCallExpression(a,b)}return a}function I(){var a,b;return $.type!==S.Punctuator&&$.type!==S.Keyword?b=ab():v("+")||v("-")||v("!")?(a=q(),b=I(),b=Z.createUnaryExpression(a.value,b)):w("delete")||w("void")||w("typeof")?s({},V.UnexpectedToken):b=ab(),b}function J(a){var b=0;if(a.type!==S.Punctuator&&a.type!==S.Keyword)return 0;switch(a.value){case"||":b=1;break;case"&&":b=2;break;case"==":case"!=":case"===":case"!==":b=6;break;case"<":case">":case"<=":case">=":case"instanceof":b=7;break;case"in":b=7;break;case"+":case"-":b=9;break;case"*":case"/":case"%":b=11}return b}function K(){var a,b,c,d,e,f,g,h;if(g=I(),b=$,c=J(b),0===c)return g;for(b.prec=c,q(),e=I(),d=[g,b,e];(c=J($))>0;){for(;d.length>2&&c<=d[d.length-2].prec;)e=d.pop(),f=d.pop().value,g=d.pop(),a=Z.createBinaryExpression(f,g,e),d.push(a);b=q(),b.prec=c,d.push(b),a=I(),d.push(a)}for(h=d.length-1,a=d[h];h>1;)a=Z.createBinaryExpression(d[h-1].value,d[h-2],a),h-=2;return a}function L(){var a,b,c;return a=K(),v("?")&&(q(),b=L(),u(":"),c=L(),a=Z.createConditionalExpression(a,b,c)),a}function M(){var a,b;return a=q(),a.type!==S.Identifier&&t(a),b=v("(")?D():[],Z.createFilter(a.value,b)}function N(){for(;v("|");)q(),M()}function O(){i(),r();var a=bb();a&&(","===$.value||"in"==$.value&&a.type===U.Identifier?Q(a):(N(),"as"===$.value?P(a):Z.createTopLevel(a))),$.type!==S.EOF&&t($)}function P(a){q();var b=q().value;Z.createAsExpression(a,b)}function Q(a){var b;","===$.value&&(q(),$.type!==S.Identifier&&t($),b=q().value),q();var c=bb();N(),Z.createInExpression(a.name,b,c)}function R(a,b){return Z=b,W=a,X=0,Y=W.length,$=null,_={labelSet:{}},O()}var S,T,U,V,W,X,Y,Z,$,_;S={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},T={},T[S.BooleanLiteral]="Boolean",T[S.EOF]="<end>",T[S.Identifier]="Identifier",T[S.Keyword]="Keyword",T[S.NullLiteral]="Null",T[S.NumericLiteral]="Numeric",T[S.Punctuator]="Punctuator",T[S.StringLiteral]="String",U={ArrayExpression:"ArrayExpression",BinaryExpression:"BinaryExpression",CallExpression:"CallExpression",ConditionalExpression:"ConditionalExpression",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",Identifier:"Identifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ThisExpression:"ThisExpression",UnaryExpression:"UnaryExpression"},V={UnexpectedToken:"Unexpected token %0",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared"};
-var ab=H,bb=L;a.esprima={parse:R}}(this),function(a){"use strict";function b(a,b,d,e){var f;try{if(f=c(a),f.scopeIdent&&(d.nodeType!==Node.ELEMENT_NODE||"TEMPLATE"!==d.tagName||"bind"!==b&&"repeat"!==b))throw Error("as and in can only be used within <template bind/repeat>")}catch(g){return void console.error("Invalid expression syntax: "+a,g)}return function(a,b,c){var d=f.getBinding(a,e,c);return f.scopeIdent&&d&&(b.polymerExpressionScopeIdent_=f.scopeIdent,f.indexIdent&&(b.polymerExpressionIndexIdent_=f.indexIdent)),d}}function c(a){var b=q[a];if(!b){var c=new j;esprima.parse(a,c),b=new l(c),q[a]=b}return b}function d(a){this.value=a,this.valueFn_=void 0}function e(a){this.name=a,this.path=Path.get(a)}function f(a,b,c){this.computed="["==c,this.dynamicDeps="function"==typeof a||a.dynamicDeps||this.computed&&!(b instanceof d),this.simplePath=!this.dynamicDeps&&(b instanceof e||b instanceof d)&&(a instanceof f||a instanceof e),this.object=this.simplePath?a:i(a),this.property=!this.computed||this.simplePath?b:i(b)}function g(a,b){this.name=a,this.args=[];for(var c=0;c<b.length;c++)this.args[c]=i(b[c])}function h(){throw Error("Not Implemented")}function i(a){return"function"==typeof a?a:a.valueFn()}function j(){this.expression=null,this.filters=[],this.deps={},this.currentPath=void 0,this.scopeIdent=void 0,this.indexIdent=void 0,this.dynamicDeps=!1}function k(a){this.value_=a}function l(a){if(this.scopeIdent=a.scopeIdent,this.indexIdent=a.indexIdent,!a.expression)throw Error("No expression found.");this.expression=a.expression,i(this.expression),this.filters=a.filters,this.dynamicDeps=a.dynamicDeps}function m(a){return String(a).replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()})}function n(a,b){for(;a[t]&&!Object.prototype.hasOwnProperty.call(a,b);)a=a[t];return a}function o(a){switch(a){case"":return!1;case"false":case"null":case"true":return!0}return isNaN(Number(a))?!1:!0}function p(){}var q=Object.create(null);d.prototype={valueFn:function(){if(!this.valueFn_){var a=this.value;this.valueFn_=function(){return a}}return this.valueFn_}},e.prototype={valueFn:function(){if(!this.valueFn_){var a=(this.name,this.path);this.valueFn_=function(b,c){return c&&c.addPath(b,a),a.getValueFrom(b)}}return this.valueFn_},setValue:function(a,b){return 1==this.path.length&&(a=n(a,this.path[0])),this.path.setValueFrom(a,b)}},f.prototype={get fullPath(){if(!this.fullPath_){var a=this.object instanceof f?this.object.fullPath.slice():[this.object.name];a.push(this.property instanceof e?this.property.name:this.property.value),this.fullPath_=Path.get(a)}return this.fullPath_},valueFn:function(){if(!this.valueFn_){var a=this.object;if(this.simplePath){var b=this.fullPath;this.valueFn_=function(a,c){return c&&c.addPath(a,b),b.getValueFrom(a)}}else if(this.computed){var c=this.property;this.valueFn_=function(b,d,e){var f=a(b,d,e),g=c(b,d,e);return d&&d.addPath(f,[g]),f?f[g]:void 0}}else{var b=Path.get(this.property.name);this.valueFn_=function(c,d,e){var f=a(c,d,e);return d&&d.addPath(f,b),b.getValueFrom(f)}}}return this.valueFn_},setValue:function(a,b){if(this.simplePath)return this.fullPath.setValueFrom(a,b),b;var c=this.object(a),d=this.property instanceof e?this.property.name:this.property(a);return c[d]=b}},g.prototype={transform:function(a,b,c,d,e){var f=a,g=f[this.name];if(!g&&(g=c[this.name],!g))return void console.error("Cannot find function or filter: "+this.name);if(d?g=g.toModel:"function"==typeof g.toDOM&&(g=g.toDOM),"function"!=typeof g)return void console.error("Cannot find function or filter: "+this.name);for(var h=e||[],j=0;j<this.args.length;j++)h.push(i(this.args[j])(a,b,c));return g.apply(f,h)}};var r={"+":function(a){return+a},"-":function(a){return-a},"!":function(a){return!a}},s={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"*":function(a,b){return a*b},"/":function(a,b){return a/b},"%":function(a,b){return a%b},"<":function(a,b){return b>a},">":function(a,b){return a>b},"<=":function(a,b){return b>=a},">=":function(a,b){return a>=b},"==":function(a,b){return a==b},"!=":function(a,b){return a!=b},"===":function(a,b){return a===b},"!==":function(a,b){return a!==b},"&&":function(a,b){return a&&b},"||":function(a,b){return a||b}};j.prototype={createUnaryExpression:function(a,b){if(!r[a])throw Error("Disallowed operator: "+a);return b=i(b),function(c,d,e){return r[a](b(c,d,e))}},createBinaryExpression:function(a,b,c){if(!s[a])throw Error("Disallowed operator: "+a);switch(b=i(b),c=i(c),a){case"||":return this.dynamicDeps=!0,function(a,d,e){return b(a,d,e)||c(a,d,e)};case"&&":return this.dynamicDeps=!0,function(a,d,e){return b(a,d,e)&&c(a,d,e)}}return function(d,e,f){return s[a](b(d,e,f),c(d,e,f))}},createConditionalExpression:function(a,b,c){return a=i(a),b=i(b),c=i(c),this.dynamicDeps=!0,function(d,e,f){return a(d,e,f)?b(d,e,f):c(d,e,f)}},createIdentifier:function(a){var b=new e(a);return b.type="Identifier",b},createMemberExpression:function(a,b,c){var d=new f(b,c,a);return d.dynamicDeps&&(this.dynamicDeps=!0),d},createCallExpression:function(a,b){if(!(a instanceof e))throw Error("Only identifier function invocations are allowed");var c=new g(a.name,b);return function(a,b,d){return c.transform(a,b,d,!1)}},createLiteral:function(a){return new d(a.value)},createArrayExpression:function(a){for(var b=0;b<a.length;b++)a[b]=i(a[b]);return function(b,c,d){for(var e=[],f=0;f<a.length;f++)e.push(a[f](b,c,d));return e}},createProperty:function(a,b,c){return{key:b instanceof e?b.name:b.value,value:c}},createObjectExpression:function(a){for(var b=0;b<a.length;b++)a[b].value=i(a[b].value);return function(b,c,d){for(var e={},f=0;f<a.length;f++)e[a[f].key]=a[f].value(b,c,d);return e}},createFilter:function(a,b){this.filters.push(new g(a,b))},createAsExpression:function(a,b){this.expression=a,this.scopeIdent=b},createInExpression:function(a,b,c){this.expression=c,this.scopeIdent=a,this.indexIdent=b},createTopLevel:function(a){this.expression=a},createThisExpression:h},k.prototype={open:function(){return this.value_},discardChanges:function(){return this.value_},deliver:function(){},close:function(){}},l.prototype={getBinding:function(a,b,c){function d(){if(h)return h=!1,g;i.dynamicDeps&&f.startReset();var c=i.getValue(a,i.dynamicDeps?f:void 0,b);return i.dynamicDeps&&f.finishReset(),c}function e(c){return i.setValue(a,c,b),c}if(c)return this.getValue(a,void 0,b);var f=new CompoundObserver,g=this.getValue(a,f,b),h=!0,i=this;return new ObserverTransform(f,d,e,!0)},getValue:function(a,b,c){for(var d=i(this.expression)(a,b,c),e=0;e<this.filters.length;e++)d=this.filters[e].transform(a,b,c,!1,[d]);return d},setValue:function(a,b,c){for(var d=this.filters?this.filters.length:0;d-->0;)b=this.filters[d].transform(a,void 0,c,!0,[b]);return this.expression.setValue?this.expression.setValue(a,b):void 0}};var t="@"+Math.random().toString(36).slice(2);p.prototype={styleObject:function(a){var b=[];for(var c in a)b.push(m(c)+": "+a[c]);return b.join("; ")},tokenList:function(a){var b=[];for(var c in a)a[c]&&b.push(c);return b.join(" ")},prepareInstancePositionChanged:function(a){var b=a.polymerExpressionIndexIdent_;if(b)return function(a,c){a.model[b]=c}},prepareBinding:function(a,c,d){var e=Path.get(a);{if(o(a)||!e.valid)return b(a,c,d,this);if(1==e.length)return function(a,b,c){if(c)return e.getValueFrom(a);var d=n(a,e[0]);return new PathObserver(d,e)}}},prepareInstanceModel:function(a){var b=a.polymerExpressionScopeIdent_;if(b){var c=a.templateInstance?a.templateInstance.model:a.model,d=a.polymerExpressionIndexIdent_;return function(a){return u(c,a,b,d)}}}};var u="__proto__"in{}?function(a,b,c,d){var e={};return e[c]=b,e[d]=void 0,e[t]=a,e.__proto__=a,e}:function(a,b,c,d){var e=Object.create(a);return Object.defineProperty(e,c,{value:b,configurable:!0,writable:!0}),Object.defineProperty(e,d,{value:void 0,configurable:!0,writable:!0}),Object.defineProperty(e,t,{value:a,configurable:!0,writable:!0}),e};a.PolymerExpressions=p,p.getExpression=c}(this),Polymer={version:"0.5.5"},"function"==typeof window.Polymer&&(Polymer={}),function(a){function b(a,b){return b=b||[],b.map||(b=[b]),a.apply(this,b.map(d))}function c(a,c,d){var e;switch(arguments.length){case 0:return;case 1:e=null;break;case 2:e=c.apply(this);break;default:e=b(d,c)}f[a]=e}function d(a){return f[a]}function e(a,c){HTMLImports.whenImportsReady(function(){b(c,a)})}var f={};a.marshal=d,a.modularize=c,a.using=e}(window),window.WebComponents||(window.WebComponents||(WebComponents={flush:function(){},flags:{log:{}}},Platform=WebComponents,CustomElements={useNative:!0,ready:!0,takeRecords:function(){},"instanceof":function(a,b){return a instanceof b}},HTMLImports={useNative:!0},addEventListener("HTMLImportsLoaded",function(){document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))}),ShadowDOMPolyfill=null,wrap=unwrap=function(a){return a}),window.HTMLImports=window.HTMLImports||{flags:{}},function(a){function b(a,b){b=b||o,d(function(){f(a,b)},b)}function c(a){return"complete"===a.readyState||a.readyState===r}function d(a,b){if(c(b))a&&a();else{var e=function(){("complete"===b.readyState||b.readyState===r)&&(b.removeEventListener(s,e),d(a,b))};b.addEventListener(s,e)}}function e(a){a.target.__loaded=!0}function f(a,b){function c(){h==i&&a&&a()}function d(a){e(a),h++,c()}var f=b.querySelectorAll("link[rel=import]"),h=0,i=f.length;if(i)for(var j,k=0;i>k&&(j=f[k]);k++)g(j)?d.call(j,{target:j}):(j.addEventListener("load",d),j.addEventListener("error",d));else c()}function g(a){return l?a.__loaded||a["import"]&&"loading"!==a["import"].readyState:a.__importParsed}function h(a){for(var b,c=0,d=a.length;d>c&&(b=a[c]);c++)i(b)&&j(b)}function i(a){return"link"===a.localName&&"import"===a.rel}function j(a){var b=a["import"];b?e({target:a}):(a.addEventListener("load",e),a.addEventListener("error",e))}var k="import",l=Boolean(k in document.createElement("link")),m=Boolean(window.ShadowDOMPolyfill),n=function(a){return m?ShadowDOMPolyfill.wrapIfNeeded(a):a},o=n(document),p={get:function(){var a=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return n(a)},configurable:!0};Object.defineProperty(document,"_currentScript",p),Object.defineProperty(o,"_currentScript",p);var q=/Trident/.test(navigator.userAgent),r=q?"complete":"interactive",s="readystatechange";l&&(new MutationObserver(function(a){for(var b,c=0,d=a.length;d>c&&(b=a[c]);c++)b.addedNodes&&h(b.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var a,b=document.querySelectorAll("link[rel=import]"),c=0,d=b.length;d>c&&(a=b[c]);c++)j(a)}()),b(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime(),o.dispatchEvent(new CustomEvent("HTMLImportsLoaded",{bubbles:!0}))}),a.IMPORT_LINK_TYPE=k,a.useNative=l,a.rootDocument=o,a.whenReady=b,a.isIE=q}(HTMLImports),function(){var a=document.createElement("style");a.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; } \n";var b=document.querySelector("head");b.insertBefore(a,b.firstChild)}(Platform)),function(a){"use strict";function b(){function a(a){b=a}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=[],c={},d=[];return Object.observe(c,a),Array.observe(d,a),c.id=1,c.id=2,delete c.id,d.push(1,2),d.length=0,Object.deliverChangeRecords(a),5!==b.length?!1:"add"!=b[0].type||"update"!=b[1].type||"delete"!=b[2].type||"splice"!=b[3].type||"splice"!=b[4].type?!1:(Object.unobserve(c,a),Array.unobserve(d,a),!0)}function c(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if("undefined"!=typeof navigator&&navigator.getDeviceStorage)return!1;try{var a=new Function("","return true;");return a()}catch(b){return!1}}function d(a){return+a===a>>>0&&""!==a}function e(a){return+a}function f(a){return a===Object(a)}function g(a,b){return a===b?0!==a||1/a===1/b:R(a)&&R(b)?!0:a!==a&&b!==b}function h(a){if(void 0===a)return"eof";var b=a.charCodeAt(0);switch(b){case 91:case 93:case 46:case 34:case 39:case 48:return a;case 95:case 36:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return b>=97&&122>=b||b>=65&&90>=b?"ident":b>=49&&57>=b?"number":"else"}function i(){}function j(a){function b(){if(!(m>=a.length)){var b=a[m+1];return"inSingleQuote"==n&&"'"==b||"inDoubleQuote"==n&&'"'==b?(m++,d=b,o.append(),!0):void 0}}for(var c,d,e,f,g,j,k,l=[],m=-1,n="beforePath",o={push:function(){void 0!==e&&(l.push(e),e=void 0)},append:function(){void 0===e?e=d:e+=d}};n;)if(m++,c=a[m],"\\"!=c||!b(n)){if(f=h(c),k=W[n],g=k[f]||k["else"]||"error","error"==g)return;if(n=g[0],j=o[g[1]]||i,d=void 0===g[2]?c:g[2],j(),"afterPath"===n)return l}}function k(a){return V.test(a)}function l(a,b){if(b!==X)throw Error("Use Path.get to retrieve path objects");for(var c=0;c<a.length;c++)this.push(String(a[c]));Q&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn())}function m(a){if(a instanceof l)return a;if((null==a||0==a.length)&&(a=""),"string"!=typeof a){if(d(a.length))return new l(a,X);a=String(a)}var b=Y[a];if(b)return b;var c=j(a);if(!c)return Z;var b=new l(c,X);return Y[a]=b,b}function n(a){return d(a)?"["+a+"]":'["'+a.replace(/"/g,'\\"')+'"]'}function o(b){for(var c=0;_>c&&b.check_();)c++;return O&&(a.dirtyCheckCycleCount=c),c>0}function p(a){for(var b in a)return!1;return!0}function q(a){return p(a.added)&&p(a.removed)&&p(a.changed)}function r(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function s(){if(!ab.length)return!1;for(var a=0;a<ab.length;a++)ab[a]();return ab.length=0,!0}function t(){function a(a){b&&b.state_===fb&&!d&&b.check_(a)}var b,c,d=!1,e=!0;return{open:function(c){if(b)throw Error("ObservedObject in use");e||Object.deliverChangeRecords(a),b=c,e=!1},observe:function(b,d){c=b,d?Array.observe(c,a):Object.observe(c,a)},deliver:function(b){d=b,Object.deliverChangeRecords(a),d=!1},close:function(){b=void 0,Object.unobserve(c,a),cb.push(this)}}}function u(a,b,c){var d=cb.pop()||t();return d.open(a),d.observe(b,c),d}function v(){function a(b,f){b&&(b===d&&(e[f]=!0),h.indexOf(b)<0&&(h.push(b),Object.observe(b,c)),a(Object.getPrototypeOf(b),f))}function b(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.object!==d||e[c.name]||"setPrototype"===c.type)return!1}return!0}function c(c){if(!b(c)){for(var d,e=0;e<g.length;e++)d=g[e],d.state_==fb&&d.iterateObjects_(a);for(var e=0;e<g.length;e++)d=g[e],d.state_==fb&&d.check_()}}var d,e,f=0,g=[],h=[],i={objects:h,get rootObject(){return d},set rootObject(a){d=a,e={}},open:function(b){g.push(b),f++,b.iterateObjects_(a)},close:function(){if(f--,!(f>0)){for(var a=0;a<h.length;a++)Object.unobserve(h[a],c),x.unobservedCount++;g.length=0,h.length=0,d=void 0,e=void 0,db.push(this),$===this&&($=null)}}};return i}function w(a,b){return $&&$.rootObject===b||($=db.pop()||v(),$.rootObject=b),$.open(a,b),$}function x(){this.state_=eb,this.callback_=void 0,this.target_=void 0,this.directObserver_=void 0,this.value_=void 0,this.id_=ib++}function y(a){x._allObserversCount++,kb&&jb.push(a)}function z(){x._allObserversCount--}function A(a){x.call(this),this.value_=a,this.oldObject_=void 0}function B(a){if(!Array.isArray(a))throw Error("Provided object is not an Array");A.call(this,a)}function C(a,b){x.call(this),this.object_=a,this.path_=m(b),this.directObserver_=void 0}function D(a){x.call(this),this.reportChangesOnOpen_=a,this.value_=[],this.directObserver_=void 0,this.observed_=[]}function E(a){return a}function F(a,b,c,d){this.callback_=void 0,this.target_=void 0,this.value_=void 0,this.observable_=a,this.getValueFn_=b||E,this.setValueFn_=c||E,this.dontPassThroughSet_=d}function G(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];nb[g.type]?(g.name in c||(c[g.name]=g.oldValue),"update"!=g.type&&("add"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}function H(a,b,c){return{index:a,removed:b,addedCount:c}}function I(){}function J(a,b,c,d,e,f){return sb.calcSplices(a,b,c,d,e,f)}function K(a,b,c,d){return c>b||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function L(a,b,c,d){for(var e=H(b,c,d),f=!1,g=0,h=0;h<a.length;h++){var i=a[h];if(i.index+=g,!f){var j=K(e.index,e.index+e.removed.length,i.index,i.index+i.addedCount);if(j>=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.index<i.index){var l=e.removed.slice(0,i.index-e.index);Array.prototype.push.apply(l,c),c=l}if(e.index+e.removed.length>i.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.index<e.index&&(e.index=i.index)}else f=!0}else if(e.index<i.index){f=!0,a.splice(h,0,e),h++;var n=e.addedCount-e.removed.length;i.index+=n,g+=n}}}f||a.push(e)}function M(a,b){for(var c=[],f=0;f<b.length;f++){var g=b[f];switch(g.type){case"splice":L(c,g.index,g.removed.slice(),g.addedCount);break;case"add":case"update":case"delete":if(!d(g.name))continue;var h=e(g.name);if(0>h)continue;L(c,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return c}function N(a,b){var c=[];return M(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?void(b.removed[0]!==a[b.index]&&c.push(b)):void(c=c.concat(J(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)))}),c}var O=a.testingExposeCycleCount,P=b(),Q=c(),R=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},S="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},T="[$_a-zA-Z]",U="[$_a-zA-Z0-9]",V=new RegExp("^"+T+"+"+U+"*$"),W={beforePath:{ws:["beforePath"],ident:["inIdent","append"],"[":["beforeElement"],eof:["afterPath"]},inPath:{ws:["inPath"],".":["beforeIdent"],"[":["beforeElement"],eof:["afterPath"]},beforeIdent:{ws:["beforeIdent"],ident:["inIdent","append"]},inIdent:{ident:["inIdent","append"],0:["inIdent","append"],number:["inIdent","append"],ws:["inPath","push"],".":["beforeIdent","push"],"[":["beforeElement","push"],eof:["afterPath","push"]},beforeElement:{ws:["beforeElement"],0:["afterZero","append"],number:["inIndex","append"],"'":["inSingleQuote","append",""],'"':["inDoubleQuote","append",""]},afterZero:{ws:["afterElement","push"],"]":["inPath","push"]},inIndex:{0:["inIndex","append"],number:["inIndex","append"],ws:["afterElement"],"]":["inPath","push"]},inSingleQuote:{"'":["afterElement"],eof:["error"],"else":["inSingleQuote","append"]},inDoubleQuote:{'"':["afterElement"],eof:["error"],"else":["inDoubleQuote","append"]},afterElement:{ws:["afterElement"],"]":["inPath","push"]}},X={},Y={};l.get=m,l.prototype=S({__proto__:[],valid:!0,toString:function(){for(var a="",b=0;b<this.length;b++){var c=this[b];a+=k(c)?b?"."+c:c:n(c)}return a},getValueFrom:function(a){for(var b=0;b<this.length;b++){if(null==a)return;a=a[this[b]]}return a},iterateObjects:function(a,b){for(var c=0;c<this.length;c++){if(c&&(a=a[this[c-1]]),!f(a))return;b(a,this[c])}},compiledGetValueFromFn:function(){var a="",b="obj";a+="if (obj != null";for(var c,d=0;d<this.length-1;d++)c=this[d],b+=k(c)?"."+c:n(c),a+=" &&\n "+b+" != null";a+=")\n";var c=this[d];return b+=k(c)?"."+c:n(c),a+=" return "+b+";\nelse\n return undefined;",new Function("obj",a)},setValueFrom:function(a,b){if(!this.length)return!1;for(var c=0;c<this.length-1;c++){if(!f(a))return!1;a=a[this[c]]}return f(a)?(a[this[c]]=b,!0):!1}});var Z=new l("",X);Z.valid=!1,Z.getValueFrom=Z.setValueFrom=function(){};var $,_=1e3,ab=[],bb=P?function(){return function(a){return Promise.resolve().then(a)}}():function(){return function(a){ab.push(a)}}(),cb=[],db=[],eb=0,fb=1,gb=2,hb=3,ib=1;x.prototype={open:function(a,b){if(this.state_!=eb)throw Error("Observer has already been opened.");return y(this),this.callback_=a,this.target_=b,this.connect_(),this.state_=fb,this.value_},close:function(){this.state_==fb&&(z(this),this.disconnect_(),this.value_=void 0,this.callback_=void 0,this.target_=void 0,this.state_=gb)},deliver:function(){this.state_==fb&&o(this)},report_:function(a){try{this.callback_.apply(this.target_,a)}catch(b){x._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+(b.stack||b))}},discardChanges:function(){return this.check_(void 0,!0),this.value_}};var jb,kb=!P;x._allObserversCount=0,kb&&(jb=[]);var lb=!1;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!lb&&kb){lb=!0;var b,c,d=0;do{d++,c=jb,jb=[],b=!1;for(var e=0;e<c.length;e++){var f=c[e];f.state_==fb&&(f.check_()&&(b=!0),jb.push(f))}s()&&(b=!0)}while(_>d&&b);O&&(a.dirtyCheckCycleCount=d),lb=!1}},kb&&(a.Platform.clearObservers=function(){jb=[]}),A.prototype=S({__proto__:x.prototype,arrayObserve:!1,connect_:function(){P?this.directObserver_=u(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(P){if(!a)return!1;c={},b=G(this.value_,a,c)}else c=this.oldObject_,b=r(this.value_,this.oldObject_);return q(b)?!1:(P||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){P?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==fb&&(P?this.directObserver_.deliver(!1):o(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}}),B.prototype=S({__proto__:A.prototype,arrayObserve:!0,copyObject:function(a){return a.slice()},check_:function(a){var b;if(P){if(!a)return!1;b=N(this.value_,a)}else b=J(this.value_,0,this.value_.length,this.oldObject_,0,this.oldObject_.length);return b&&b.length?(P||(this.oldObject_=this.copyObject(this.value_)),this.report_([b]),!0):!1}}),B.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;e<c.index+c.addedCount;)d.push(b[e]),e++;Array.prototype.splice.apply(a,d)})},C.prototype=S({__proto__:x.prototype,get path(){return this.path_},connect_:function(){P&&(this.directObserver_=w(this,this.object_)),this.check_(void 0,!0)},disconnect_:function(){this.value_=void 0,this.directObserver_&&(this.directObserver_.close(this),this.directObserver_=void 0)},iterateObjects_:function(a){this.path_.iterateObjects(this.object_,a)},check_:function(a,b){var c=this.value_;return this.value_=this.path_.getValueFrom(this.object_),b||g(this.value_,c)?!1:(this.report_([this.value_,c,this]),!0)},setValue:function(a){this.path_&&this.path_.setValueFrom(this.object_,a)}});var mb={};D.prototype=S({__proto__:x.prototype,connect_:function(){if(P){for(var a,b=!1,c=0;c<this.observed_.length;c+=2)if(a=this.observed_[c],a!==mb){b=!0;break}b&&(this.directObserver_=w(this,a))}this.check_(void 0,!this.reportChangesOnOpen_)},disconnect_:function(){for(var a=0;a<this.observed_.length;a+=2)this.observed_[a]===mb&&this.observed_[a+1].close();this.observed_.length=0,this.value_.length=0,this.directObserver_&&(this.directObserver_.close(this),this.directObserver_=void 0)},addPath:function(a,b){if(this.state_!=eb&&this.state_!=hb)throw Error("Cannot add paths once started.");var b=m(b);if(this.observed_.push(a,b),this.reportChangesOnOpen_){var c=this.observed_.length/2-1;this.value_[c]=b.getValueFrom(a)}},addObserver:function(a){if(this.state_!=eb&&this.state_!=hb)throw Error("Cannot add observers once started.");if(this.observed_.push(mb,a),this.reportChangesOnOpen_){var b=this.observed_.length/2-1;this.value_[b]=a.open(this.deliver,this)}},startReset:function(){if(this.state_!=fb)throw Error("Can only reset while open");this.state_=hb,this.disconnect_()},finishReset:function(){if(this.state_!=hb)throw Error("Can only finishReset after startReset");return this.state_=fb,this.connect_(),this.value_},iterateObjects_:function(a){for(var b,c=0;c<this.observed_.length;c+=2)b=this.observed_[c],b!==mb&&this.observed_[c+1].iterateObjects(b,a)},check_:function(a,b){for(var c,d=0;d<this.observed_.length;d+=2){var e,f=this.observed_[d],h=this.observed_[d+1];if(f===mb){var i=h;e=this.state_===eb?i.open(this.deliver,this):i.discardChanges()}else e=h.getValueFrom(f);b?this.value_[d/2]=e:g(e,this.value_[d/2])||(c=c||[],c[d/2]=this.value_[d/2],this.value_[d/2]=e)}return c?(this.report_([this.value_,c,this.observed_]),!0):!1}}),F.prototype={open:function(a,b){return this.callback_=a,this.target_=b,this.value_=this.getValueFn_(this.observable_.open(this.observedCallback_,this)),this.value_},observedCallback_:function(a){if(a=this.getValueFn_(a),!g(a,this.value_)){var b=this.value_;this.value_=a,this.callback_.call(this.target_,this.value_,b)}},discardChanges:function(){return this.value_=this.getValueFn_(this.observable_.discardChanges()),this.value_},deliver:function(){return this.observable_.deliver()},setValue:function(a){return a=this.setValueFn_(a),!this.dontPassThroughSet_&&this.observable_.setValue?this.observable_.setValue(a):void 0},close:function(){this.observable_&&this.observable_.close(),this.callback_=void 0,this.target_=void 0,this.observable_=void 0,this.value_=void 0,this.getValueFn_=void 0,this.setValueFn_=void 0}};var nb={add:!0,update:!0,"delete":!0},ob=0,pb=1,qb=2,rb=3;I.prototype={calcEditDistances:function(a,b,c,d,e,f){for(var g=f-e+1,h=c-b+1,i=new Array(g),j=0;g>j;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(this.equals(a[b+k-1],d[e+j-1]))i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i},spliceOperationsFromEditDistances:function(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(ob):(e.push(pb),d=g),b--,c--):f==h?(e.push(rb),b--,d=h):(e.push(qb),c--,d=i)}else e.push(rb),b--;else e.push(qb),c--;return e.reverse(),e},calcSplices:function(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=this.sharedPrefix(a,d,i)),c==a.length&&f==d.length&&(h=this.sharedSuffix(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,c-b==0&&f-e==0)return[];if(b==c){for(var j=H(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[H(b,[],c-b)];for(var k=this.spliceOperationsFromEditDistances(this.calcEditDistances(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;o<k.length;o++)switch(k[o]){case ob:j&&(l.push(j),j=void 0),m++,n++;break;case pb:j||(j=H(m,[],0)),j.addedCount++,m++,j.removed.push(d[n]),n++;break;case qb:j||(j=H(m,[],0)),j.addedCount++,m++;break;case rb:j||(j=H(m,[],0)),j.removed.push(d[n]),n++}return j&&l.push(j),l},sharedPrefix:function(a,b,c){for(var d=0;c>d;d++)if(!this.equals(a[d],b[d]))return d;return c},sharedSuffix:function(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&this.equals(a[--d],b[--e]);)f++;return f},calculateSplices:function(a,b){return this.calcSplices(a,0,a.length,b,0,b.length)},equals:function(a,b){return a===b}};var sb=new I,tb=a;"undefined"==typeof exports||exports.nodeType||("undefined"!=typeof module&&module.exports&&(exports=module.exports),tb=exports),tb.Observer=x,tb.Observer.runEOM_=bb,tb.Observer.observerSentinel_=mb,tb.Observer.hasObjectObserve=P,tb.ArrayObserver=B,tb.ArrayObserver.calculateSplices=function(a,b){return sb.calculateSplices(a,b)},tb.ArraySplice=I,tb.ObjectObserver=A,tb.PathObserver=C,tb.CompoundObserver=D,tb.Path=l,tb.ObserverTransform=F}("undefined"!=typeof global&&global&&"undefined"!=typeof module&&module?global:this||window),function(){"use strict";function a(a){for(;a.parentNode;)a=a.parentNode;return"function"==typeof a.getElementById?a:null}function b(a,b,c){var d=a.bindings_;return d||(d=a.bindings_={}),d[b]&&c[b].close(),d[b]=c}function c(a,b,c){return c}function d(a){return null==a?"":a}function e(a,b){a.data=d(b)}function f(a){return function(b){return e(a,b)}}function g(a,b,c,e){return c?void(e?a.setAttribute(b,""):a.removeAttribute(b)):void a.setAttribute(b,d(e))}function h(a,b,c){return function(d){g(a,b,c,d)}}function i(a){switch(a.type){case"checkbox":return u;case"radio":case"select-multiple":case"select-one":return"change";case"range":if(/Trident|MSIE/.test(navigator.userAgent))return"change";default:return"input"}}function j(a,b,c,e){a[b]=(e||d)(c)}function k(a,b,c){return function(d){return j(a,b,d,c)}}function l(){}function m(a,b,c,d){function e(){var e="value"==b&&"number"==a.type;c.setValue(e?a.valueAsNumber:a[b]),c.discardChanges(),(d||l)(a),Platform.performMicrotaskCheckpoint()}var f=i(a);return a.addEventListener(f,e),{close:function(){a.removeEventListener(f,e),c.close()},observable_:c}}function n(a){return Boolean(a)}function o(b){if(b.form)return s(b.form.elements,function(a){return a!=b&&"INPUT"==a.tagName&&"radio"==a.type&&a.name==b.name});var c=a(b);if(!c)return[];var d=c.querySelectorAll('input[type="radio"][name="'+b.name+'"]');return s(d,function(a){return a!=b&&!a.form})}function p(a){"INPUT"===a.tagName&&"radio"===a.type&&o(a).forEach(function(a){var b=a.bindings_.checked;b&&b.observable_.setValue(!1)})}function q(a,b){var c,e,f,g=a.parentNode;g instanceof HTMLSelectElement&&g.bindings_&&g.bindings_.value&&(c=g,e=c.bindings_.value,f=c.value),a.value=d(b),c&&c.value!=f&&(e.observable_.setValue(c.value),e.observable_.discardChanges(),Platform.performMicrotaskCheckpoint())}function r(a){return function(b){q(a,b)}}var s=Array.prototype.filter.call.bind(Array.prototype.filter);Node.prototype.bind=function(a,b){console.error("Unhandled binding to Node: ",this,a,b)},Node.prototype.bindFinished=function(){};var t=c;Object.defineProperty(Platform,"enableBindingsReflection",{get:function(){return t===b},set:function(a){return t=a?b:c,a},configurable:!0}),Text.prototype.bind=function(a,b,c){if("textContent"!==a)return Node.prototype.bind.call(this,a,b,c);if(c)return e(this,b);var d=b;return e(this,d.open(f(this))),t(this,a,d)},Element.prototype.bind=function(a,b,c){var d="?"==a[a.length-1];if(d&&(this.removeAttribute(a),a=a.slice(0,-1)),c)return g(this,a,d,b);var e=b;return g(this,a,d,e.open(h(this,a,d))),t(this,a,e)};var u;!function(){var a=document.createElement("div"),b=a.appendChild(document.createElement("input"));b.setAttribute("type","checkbox");var c,d=0;b.addEventListener("click",function(){d++,c=c||"click"}),b.addEventListener("change",function(){d++,c=c||"change"});var e=document.createEvent("MouseEvent");e.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),b.dispatchEvent(e),u=1==d?"change":c}(),HTMLInputElement.prototype.bind=function(a,c,e){if("value"!==a&&"checked"!==a)return HTMLElement.prototype.bind.call(this,a,c,e);this.removeAttribute(a);var f="checked"==a?n:d,g="checked"==a?p:l;if(e)return j(this,a,c,f);var h=c,i=m(this,a,h,g);return j(this,a,h.open(k(this,a,f)),f),b(this,a,i)},HTMLTextAreaElement.prototype.bind=function(a,b,c){if("value"!==a)return HTMLElement.prototype.bind.call(this,a,b,c);if(this.removeAttribute("value"),c)return j(this,"value",b);var e=b,f=m(this,"value",e);return j(this,"value",e.open(k(this,"value",d))),t(this,a,f)},HTMLOptionElement.prototype.bind=function(a,b,c){if("value"!==a)return HTMLElement.prototype.bind.call(this,a,b,c);if(this.removeAttribute("value"),c)return q(this,b);var d=b,e=m(this,"value",d);
-return q(this,d.open(r(this))),t(this,a,e)},HTMLSelectElement.prototype.bind=function(a,c,d){if("selectedindex"===a&&(a="selectedIndex"),"selectedIndex"!==a&&"value"!==a)return HTMLElement.prototype.bind.call(this,a,c,d);if(this.removeAttribute(a),d)return j(this,a,c);var e=c,f=m(this,a,e);return j(this,a,e.open(k(this,a))),b(this,a,f)}}(this),function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a){for(var b;b=a.parentNode;)a=b;return a}function d(a,b){if(b){for(var d,e="#"+b;!d&&(a=c(a),a.protoContent_?d=a.protoContent_.querySelector(e):a.getElementById&&(d=a.getElementById(b)),!d&&a.templateCreator_);)a=a.templateCreator_;return d}}function e(a){return"template"==a.tagName&&"http://www.w3.org/2000/svg"==a.namespaceURI}function f(a){return"TEMPLATE"==a.tagName&&"http://www.w3.org/1999/xhtml"==a.namespaceURI}function g(a){return Boolean(L[a.tagName]&&a.hasAttribute("template"))}function h(a){return void 0===a.isTemplate_&&(a.isTemplate_="TEMPLATE"==a.tagName||g(a)),a.isTemplate_}function i(a,b){var c=a.querySelectorAll(N);h(a)&&b(a),G(c,b)}function j(a){function b(a){HTMLTemplateElement.decorate(a)||j(a.content)}i(a,b)}function k(a,b){Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))})}function l(a){var b=a.ownerDocument;if(!b.defaultView)return b;var c=b.templateContentsOwner_;if(!c){for(c=b.implementation.createHTMLDocument("");c.lastChild;)c.removeChild(c.lastChild);b.templateContentsOwner_=c}return c}function m(a){if(!a.stagingDocument_){var b=a.ownerDocument;if(!b.stagingDocument_){b.stagingDocument_=b.implementation.createHTMLDocument(""),b.stagingDocument_.isStagingDocument=!0;var c=b.stagingDocument_.createElement("base");c.href=document.baseURI,b.stagingDocument_.head.appendChild(c),b.stagingDocument_.stagingDocument_=b.stagingDocument_}a.stagingDocument_=b.stagingDocument_}return a.stagingDocument_}function n(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];K[e.name]&&("template"!==e.name&&b.setAttribute(e.name,e.value),a.removeAttribute(e.name))}return b}function o(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];b.setAttribute(e.name,e.value),a.removeAttribute(e.name)}return a.parentNode.removeChild(a),b}function p(a,b,c){var d=a.content;if(c)return void d.appendChild(b);for(var e;e=b.firstChild;)d.appendChild(e)}function q(a){P?a.__proto__=HTMLTemplateElement.prototype:k(a,HTMLTemplateElement.prototype)}function r(a){a.setModelFn_||(a.setModelFn_=function(){a.setModelFnScheduled_=!1;var b=z(a,a.delegate_&&a.delegate_.prepareBinding);w(a,b,a.model_)}),a.setModelFnScheduled_||(a.setModelFnScheduled_=!0,Observer.runEOM_(a.setModelFn_))}function s(a,b,c,d){if(a&&a.length){for(var e,f=a.length,g=0,h=0,i=0,j=!0;f>h;){var g=a.indexOf("{{",h),k=a.indexOf("[[",h),l=!1,m="}}";if(k>=0&&(0>g||g>k)&&(g=k,l=!0,m="]]"),i=0>g?-1:a.indexOf(m,g+2),0>i){if(!e)return;e.push(a.slice(h));break}e=e||[],e.push(a.slice(h,g));var n=a.slice(g+2,i).trim();e.push(l),j=j&&l;var o=d&&d(n,b,c);e.push(null==o?Path.get(n):null),e.push(o),h=i+2}return h===f&&e.push(""),e.hasOnePath=5===e.length,e.isSimplePath=e.hasOnePath&&""==e[0]&&""==e[4],e.onlyOneTime=j,e.combinator=function(a){for(var b=e[0],c=1;c<e.length;c+=4){var d=e.hasOnePath?a:a[(c-1)/4];void 0!==d&&(b+=d),b+=e[c+3]}return b},e}}function t(a,b,c,d){if(b.hasOnePath){var e=b[3],f=e?e(d,c,!0):b[2].getValueFrom(d);return b.isSimplePath?f:b.combinator(f)}for(var g=[],h=1;h<b.length;h+=4){var e=b[h+2];g[(h-1)/4]=e?e(d,c):b[h+1].getValueFrom(d)}return b.combinator(g)}function u(a,b,c,d){var e=b[3],f=e?e(d,c,!1):new PathObserver(d,b[2]);return b.isSimplePath?f:new ObserverTransform(f,b.combinator)}function v(a,b,c,d){if(b.onlyOneTime)return t(a,b,c,d);if(b.hasOnePath)return u(a,b,c,d);for(var e=new CompoundObserver,f=1;f<b.length;f+=4){var g=b[f],h=b[f+2];if(h){var i=h(d,c,g);g?e.addPath(i):e.addObserver(i)}else{var j=b[f+1];g?e.addPath(j.getValueFrom(d)):e.addPath(d,j)}}return new ObserverTransform(e,b.combinator)}function w(a,b,c,d){for(var e=0;e<b.length;e+=2){var f=b[e],g=b[e+1],h=v(f,g,a,c),i=a.bind(f,h,g.onlyOneTime);i&&d&&d.push(i)}if(a.bindFinished(),b.isTemplate){a.model_=c;var j=a.processBindingDirectives_(b);d&&j&&d.push(j)}}function x(a,b,c){var d=a.getAttribute(b);return s(""==d?"{{}}":d,b,a,c)}function y(a,c){b(a);for(var d=[],e=0;e<a.attributes.length;e++){for(var f=a.attributes[e],g=f.name,i=f.value;"_"===g[0];)g=g.substring(1);if(!h(a)||g!==J&&g!==H&&g!==I){var j=s(i,g,a,c);j&&d.push(g,j)}}return h(a)&&(d.isTemplate=!0,d["if"]=x(a,J,c),d.bind=x(a,H,c),d.repeat=x(a,I,c),!d["if"]||d.bind||d.repeat||(d.bind=s("{{}}",H,a,c))),d}function z(a,b){if(a.nodeType===Node.ELEMENT_NODE)return y(a,b);if(a.nodeType===Node.TEXT_NODE){var c=s(a.data,"textContent",a,b);if(c)return["textContent",c]}return[]}function A(a,b,c,d,e,f,g){for(var h=b.appendChild(c.importNode(a,!1)),i=0,j=a.firstChild;j;j=j.nextSibling)A(j,h,c,d.children[i++],e,f,g);return d.isTemplate&&(HTMLTemplateElement.decorate(h,a),f&&h.setDelegate_(f)),w(h,d,e,g),h}function B(a,b){var c=z(a,b);c.children={};for(var d=0,e=a.firstChild;e;e=e.nextSibling)c.children[d++]=B(e,b);return c}function C(a){var b=a.id_;return b||(b=a.id_=S++),b}function D(a,b){var c=C(a);if(b){var d=b.bindingMaps[c];return d||(d=b.bindingMaps[c]=B(a,b.prepareBinding)||[]),d}var d=a.bindingMap_;return d||(d=a.bindingMap_=B(a,void 0)||[]),d}function E(a){this.closed=!1,this.templateElement_=a,this.instances=[],this.deps=void 0,this.iteratedValue=[],this.presentValue=void 0,this.arrayObserver=void 0}var F,G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.Map&&"function"==typeof a.Map.prototype.forEach?F=a.Map:(F=function(){this.keys=[],this.values=[]},F.prototype={set:function(a,b){var c=this.keys.indexOf(a);0>c?(this.keys.push(a),this.values.push(b)):this.values[c]=b},get:function(a){var b=this.keys.indexOf(a);if(!(0>b))return this.values[b]},"delete":function(a){var b=this.keys.indexOf(a);return 0>b?!1:(this.keys.splice(b,1),this.values.splice(b,1),!0)},forEach:function(a,b){for(var c=0;c<this.keys.length;c++)a.call(b||this,this.values[c],this.keys[c],this)}});"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)});var H="bind",I="repeat",J="if",K={template:!0,repeat:!0,bind:!0,ref:!0,"if":!0},L={THEAD:!0,TBODY:!0,TFOOT:!0,TH:!0,TR:!0,TD:!0,COLGROUP:!0,COL:!0,CAPTION:!0,OPTION:!0,OPTGROUP:!0},M="undefined"!=typeof HTMLTemplateElement;M&&!function(){var a=document.createElement("template"),b=a.content.ownerDocument,c=b.appendChild(b.createElement("html")),d=c.appendChild(b.createElement("head")),e=b.createElement("base");e.href=document.baseURI,d.appendChild(e)}();var N="template, "+Object.keys(L).map(function(a){return a.toLowerCase()+"[template]"}).join(", ");document.addEventListener("DOMContentLoaded",function(){j(document),Platform.performMicrotaskCheckpoint()},!1),M||(a.HTMLTemplateElement=function(){throw TypeError("Illegal constructor")});var O,P="__proto__"in{};"function"==typeof MutationObserver&&(O=new MutationObserver(function(a){for(var b=0;b<a.length;b++)a[b].target.refChanged_()})),HTMLTemplateElement.decorate=function(a,c){if(a.templateIsDecorated_)return!1;var d=a;d.templateIsDecorated_=!0;var h=f(d)&&M,i=h,k=!h,m=!1;if(h||(g(d)?(b(!c),d=n(a),d.templateIsDecorated_=!0,h=M,m=!0):e(d)&&(d=o(a),d.templateIsDecorated_=!0,h=M)),!h){q(d);var r=l(d);d.content_=r.createDocumentFragment()}return c?d.instanceRef_=c:k?p(d,a,m):i&&j(d.content),!0},HTMLTemplateElement.bootstrap=j;var Q=a.HTMLUnknownElement||HTMLElement,R={get:function(){return this.content_},enumerable:!0,configurable:!0};M||(HTMLTemplateElement.prototype=Object.create(Q.prototype),Object.defineProperty(HTMLTemplateElement.prototype,"content",R)),k(HTMLTemplateElement.prototype,{bind:function(a,b,c){if("ref"!=a)return Element.prototype.bind.call(this,a,b,c);var d=this,e=c?b:b.open(function(a){d.setAttribute("ref",a),d.refChanged_()});return this.setAttribute("ref",e),this.refChanged_(),c?void 0:(this.bindings_?this.bindings_.ref=b:this.bindings_={ref:b},b)},processBindingDirectives_:function(a){return this.iterator_&&this.iterator_.closeDeps(),a["if"]||a.bind||a.repeat?(this.iterator_||(this.iterator_=new E(this)),this.iterator_.updateDependencies(a,this.model_),O&&O.observe(this,{attributes:!0,attributeFilter:["ref"]}),this.iterator_):void(this.iterator_&&(this.iterator_.close(),this.iterator_=void 0))},createInstance:function(a,b,c){b?c=this.newDelegate_(b):c||(c=this.delegate_),this.refContent_||(this.refContent_=this.ref_.content);var d=this.refContent_;if(null===d.firstChild)return T;var e=D(d,c),f=m(this),g=f.createDocumentFragment();g.templateCreator_=this,g.protoContent_=d,g.bindings_=[],g.terminator_=null;for(var h=g.templateInstance_={firstNode:null,lastNode:null,model:a},i=0,j=!1,k=d.firstChild;k;k=k.nextSibling){null===k.nextSibling&&(j=!0);var l=A(k,g,f,e.children[i++],a,c,g.bindings_);l.templateInstance_=h,j&&(g.terminator_=l)}return h.firstNode=g.firstChild,h.lastNode=g.lastChild,g.templateCreator_=void 0,g.protoContent_=void 0,g},get model(){return this.model_},set model(a){this.model_=a,r(this)},get bindingDelegate(){return this.delegate_&&this.delegate_.raw},refChanged_:function(){this.iterator_&&this.refContent_!==this.ref_.content&&(this.refContent_=void 0,this.iterator_.valueChanged(),this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue()))},clear:function(){this.model_=void 0,this.delegate_=void 0,this.bindings_&&this.bindings_.ref&&this.bindings_.ref.close(),this.refContent_=void 0,this.iterator_&&(this.iterator_.valueChanged(),this.iterator_.close(),this.iterator_=void 0)},setDelegate_:function(a){this.delegate_=a,this.bindingMap_=void 0,this.iterator_&&(this.iterator_.instancePositionChangedFn_=void 0,this.iterator_.instanceModelFn_=void 0)},newDelegate_:function(a){function b(b){var c=a&&a[b];if("function"==typeof c)return function(){return c.apply(a,arguments)}}if(a)return{bindingMaps:{},raw:a,prepareBinding:b("prepareBinding"),prepareInstanceModel:b("prepareInstanceModel"),prepareInstancePositionChanged:b("prepareInstancePositionChanged")}},set bindingDelegate(a){if(this.delegate_)throw Error("Template must be cleared before a new bindingDelegate can be assigned");this.setDelegate_(this.newDelegate_(a))},get ref_(){var a=d(this,this.getAttribute("ref"));if(a||(a=this.instanceRef_),!a)return this;var b=a.ref_;return b?b:a}});var S=1;Object.defineProperty(Node.prototype,"templateInstance",{get:function(){var a=this.templateInstance_;return a?a:this.parentNode?this.parentNode.templateInstance:void 0}});var T=document.createDocumentFragment();T.bindings_=[],T.terminator_=null,E.prototype={closeDeps:function(){var a=this.deps;a&&(a.ifOneTime===!1&&a.ifValue.close(),a.oneTime===!1&&a.value.close())},updateDependencies:function(a,b){this.closeDeps();var c=this.deps={},d=this.templateElement_,e=!0;if(a["if"]){if(c.hasIf=!0,c.ifOneTime=a["if"].onlyOneTime,c.ifValue=v(J,a["if"],d,b),e=c.ifValue,c.ifOneTime&&!e)return void this.valueChanged();c.ifOneTime||(e=e.open(this.updateIfValue,this))}a.repeat?(c.repeat=!0,c.oneTime=a.repeat.onlyOneTime,c.value=v(I,a.repeat,d,b)):(c.repeat=!1,c.oneTime=a.bind.onlyOneTime,c.value=v(H,a.bind,d,b));var f=c.value;return c.oneTime||(f=f.open(this.updateIteratedValue,this)),e?void this.updateValue(f):void this.valueChanged()},getUpdatedValue:function(){var a=this.deps.value;return this.deps.oneTime||(a=a.discardChanges()),a},updateIfValue:function(a){return a?void this.updateValue(this.getUpdatedValue()):void this.valueChanged()},updateIteratedValue:function(a){if(this.deps.hasIf){var b=this.deps.ifValue;if(this.deps.ifOneTime||(b=b.discardChanges()),!b)return void this.valueChanged()}this.updateValue(a)},updateValue:function(a){this.deps.repeat||(a=[a]);var b=this.deps.repeat&&!this.deps.oneTime&&Array.isArray(a);this.valueChanged(a,b)},valueChanged:function(a,b){Array.isArray(a)||(a=[]),a!==this.iteratedValue&&(this.unobserve(),this.presentValue=a,b&&(this.arrayObserver=new ArrayObserver(this.presentValue),this.arrayObserver.open(this.handleSplices,this)),this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,this.iteratedValue)))},getLastInstanceNode:function(a){if(-1==a)return this.templateElement_;var b=this.instances[a],c=b.terminator_;if(!c)return this.getLastInstanceNode(a-1);if(c.nodeType!==Node.ELEMENT_NODE||this.templateElement_===c)return c;var d=c.iterator_;return d?d.getLastTemplateNode():c},getLastTemplateNode:function(){return this.getLastInstanceNode(this.instances.length-1)},insertInstanceAt:function(a,b){var c=this.getLastInstanceNode(a-1),d=this.templateElement_.parentNode;this.instances.splice(a,0,b),d.insertBefore(b,c.nextSibling)},extractInstanceAt:function(a){for(var b=this.getLastInstanceNode(a-1),c=this.getLastInstanceNode(a),d=this.templateElement_.parentNode,e=this.instances.splice(a,1)[0];c!==b;){var f=b.nextSibling;f==c&&(c=b),e.appendChild(d.removeChild(f))}return e},getDelegateFn:function(a){return a=a&&a(this.templateElement_),"function"==typeof a?a:null},handleSplices:function(a){if(!this.closed&&a.length){var b=this.templateElement_;if(!b.parentNode)return void this.close();ArrayObserver.applySplices(this.iteratedValue,this.presentValue,a);var c=b.delegate_;void 0===this.instanceModelFn_&&(this.instanceModelFn_=this.getDelegateFn(c&&c.prepareInstanceModel)),void 0===this.instancePositionChangedFn_&&(this.instancePositionChangedFn_=this.getDelegateFn(c&&c.prepareInstancePositionChanged));for(var d=new F,e=0,f=0;f<a.length;f++){for(var g=a[f],h=g.removed,i=0;i<h.length;i++){var j=h[i],k=this.extractInstanceAt(g.index+e);k!==T&&d.set(j,k)}e-=g.addedCount}for(var f=0;f<a.length;f++)for(var g=a[f],l=g.index;l<g.index+g.addedCount;l++){var j=this.iteratedValue[l],k=d.get(j);k?d["delete"](j):(this.instanceModelFn_&&(j=this.instanceModelFn_(j)),k=void 0===j?T:b.createInstance(j,void 0,c)),this.insertInstanceAt(l,k)}d.forEach(function(a){this.closeInstanceBindings(a)},this),this.instancePositionChangedFn_&&this.reportInstancesMoved(a)}},reportInstanceMoved:function(a){var b=this.instances[a];b!==T&&this.instancePositionChangedFn_(b.templateInstance_,a)},reportInstancesMoved:function(a){for(var b=0,c=0,d=0;d<a.length;d++){var e=a[d];if(0!=c)for(;b<e.index;)this.reportInstanceMoved(b),b++;else b=e.index;for(;b<e.index+e.addedCount;)this.reportInstanceMoved(b),b++;c+=e.addedCount-e.removed.length}if(0!=c)for(var f=this.instances.length;f>b;)this.reportInstanceMoved(b),b++},closeInstanceBindings:function(a){for(var b=a.bindings_,c=0;c<b.length;c++)b[c].close()},unobserve:function(){this.arrayObserver&&(this.arrayObserver.close(),this.arrayObserver=void 0)},close:function(){if(!this.closed){this.unobserve();for(var a=0;a<this.instances.length;a++)this.closeInstanceBindings(this.instances[a]);this.instances.length=0,this.closeDeps(),this.templateElement_.iterator_=void 0,this.closed=!0}}},HTMLTemplateElement.forAllTemplatesFrom_=i}(this),function(a){"use strict";function b(a){return void 0!==m[a]}function c(){h.call(this),this._isInvalid=!0}function d(a){return""==a&&c.call(this),a.toLowerCase()}function e(a){var b=a.charCodeAt(0);return b>32&&127>b&&-1==[34,35,60,62,63,96].indexOf(b)?a:encodeURIComponent(a)}function f(a){var b=a.charCodeAt(0);return b>32&&127>b&&-1==[34,35,60,62,96].indexOf(b)?a:encodeURIComponent(a)}function g(a,g,h){function i(a){t.push(a)}var j=g||"scheme start",k=0,l="",r=!1,s=!1,t=[];a:for(;(a[k-1]!=o||0==k)&&!this._isInvalid;){var u=a[k];switch(j){case"scheme start":if(!u||!p.test(u)){if(g){i("Invalid scheme.");break a}l="",j="no scheme";continue}l+=u.toLowerCase(),j="scheme";break;case"scheme":if(u&&q.test(u))l+=u.toLowerCase();else{if(":"!=u){if(g){if(o==u)break a;i("Code point not allowed in scheme: "+u);break a}l="",k=0,j="no scheme";continue}if(this._scheme=l,l="",g)break a;b(this._scheme)&&(this._isRelative=!0),j="file"==this._scheme?"relative":this._isRelative&&h&&h._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==u?(query="?",j="query"):"#"==u?(this._fragment="#",j="fragment"):o!=u&&" "!=u&&"\n"!=u&&"\r"!=u&&(this._schemeData+=e(u));break;case"no scheme":if(h&&b(h._scheme)){j="relative";continue}i("Missing scheme."),c.call(this);break;case"relative or authority":if("/"!=u||"/"!=a[k+1]){i("Expected /, got: "+u),j="relative";continue}j="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=h._scheme),o==u){this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query=h._query;break a}if("/"==u||"\\"==u)"\\"==u&&i("\\ is an invalid code point."),j="relative slash";else if("?"==u)this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query="?",j="query";else{if("#"!=u){var v=a[k+1],w=a[k+2];("file"!=this._scheme||!p.test(u)||":"!=v&&"|"!=v||o!=w&&"/"!=w&&"\\"!=w&&"?"!=w&&"#"!=w)&&(this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._path.pop()),j="relative path";continue}this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query=h._query,this._fragment="#",j="fragment"}break;case"relative slash":if("/"!=u&&"\\"!=u){"file"!=this._scheme&&(this._host=h._host,this._port=h._port),j="relative path";continue}"\\"==u&&i("\\ is an invalid code point."),j="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=u){i("Expected '/', got: "+u),j="authority ignore slashes";continue}j="authority second slash";break;case"authority second slash":if(j="authority ignore slashes","/"!=u){i("Expected '/', got: "+u);continue}break;case"authority ignore slashes":if("/"!=u&&"\\"!=u){j="authority";continue}i("Expected authority, got: "+u);break;case"authority":if("@"==u){r&&(i("@ already seen."),l+="%40"),r=!0;for(var x=0;x<l.length;x++){var y=l[x];if(" "!=y&&"\n"!=y&&"\r"!=y)if(":"!=y||null!==this._password){var z=e(y);null!==this._password?this._password+=z:this._username+=z}else this._password="";else i("Invalid whitespace in authority.")}l=""}else{if(o==u||"/"==u||"\\"==u||"?"==u||"#"==u){k-=l.length,l="",j="host";continue}l+=u}break;case"file host":if(o==u||"/"==u||"\\"==u||"?"==u||"#"==u){2!=l.length||!p.test(l[0])||":"!=l[1]&&"|"!=l[1]?0==l.length?j="relative path start":(this._host=d.call(this,l),l="",j="relative path start"):j="relative path";continue}" "==u||"\n"==u||"\r"==u?i("Invalid whitespace in file host."):l+=u;break;case"host":case"hostname":if(":"!=u||s){if(o==u||"/"==u||"\\"==u||"?"==u||"#"==u){if(this._host=d.call(this,l),l="",j="relative path start",g)break a;continue}" "!=u&&"\n"!=u&&"\r"!=u?("["==u?s=!0:"]"==u&&(s=!1),l+=u):i("Invalid code point in host/hostname: "+u)}else if(this._host=d.call(this,l),l="",j="port","hostname"==g)break a;break;case"port":if(/[0-9]/.test(u))l+=u;else{if(o==u||"/"==u||"\\"==u||"?"==u||"#"==u||g){if(""!=l){var A=parseInt(l,10);A!=m[this._scheme]&&(this._port=A+""),l=""}if(g)break a;j="relative path start";continue}" "==u||"\n"==u||"\r"==u?i("Invalid code point in port: "+u):c.call(this)}break;case"relative path start":if("\\"==u&&i("'\\' not allowed in path."),j="relative path","/"!=u&&"\\"!=u)continue;break;case"relative path":if(o!=u&&"/"!=u&&"\\"!=u&&(g||"?"!=u&&"#"!=u))" "!=u&&"\n"!=u&&"\r"!=u&&(l+=e(u));else{"\\"==u&&i("\\ not allowed in relative path.");var B;(B=n[l.toLowerCase()])&&(l=B),".."==l?(this._path.pop(),"/"!=u&&"\\"!=u&&this._path.push("")):"."==l&&"/"!=u&&"\\"!=u?this._path.push(""):"."!=l&&("file"==this._scheme&&0==this._path.length&&2==l.length&&p.test(l[0])&&"|"==l[1]&&(l=l[0]+":"),this._path.push(l)),l="","?"==u?(this._query="?",j="query"):"#"==u&&(this._fragment="#",j="fragment")}break;case"query":g||"#"!=u?o!=u&&" "!=u&&"\n"!=u&&"\r"!=u&&(this._query+=f(u)):(this._fragment="#",j="fragment");break;case"fragment":o!=u&&" "!=u&&"\n"!=u&&"\r"!=u&&(this._fragment+=u)}k++}}function h(){this._scheme="",this._schemeData="",this._username="",this._password=null,this._host="",this._port="",this._path=[],this._query="",this._fragment="",this._isInvalid=!1,this._isRelative=!1}function i(a,b){void 0===b||b instanceof i||(b=new i(String(b))),this._url=a,h.call(this);var c=a.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g,"");g.call(this,c,null,b)}var j=!1;if(!a.forceJURL)try{var k=new URL("b","http://a");k.pathname="c%20d",j="http://a/c%20d"===k.href}catch(l){}if(!j){var m=Object.create(null);m.ftp=21,m.file=0,m.gopher=70,m.http=80,m.https=443,m.ws=80,m.wss=443;var n=Object.create(null);n["%2e"]=".",n[".%2e"]="..",n["%2e."]="..",n["%2e%2e"]="..";var o=void 0,p=/[a-zA-Z]/,q=/[a-zA-Z0-9\+\-\.]/;i.prototype={get href(){if(this._isInvalid)return this._url;var a="";return(""!=this._username||null!=this._password)&&(a=this._username+(null!=this._password?":"+this._password:"")+"@"),this.protocol+(this._isRelative?"//"+a+this.host:"")+this.pathname+this._query+this._fragment},set href(a){h.call(this),g.call(this,a)},get protocol(){return this._scheme+":"},set protocol(a){this._isInvalid||g.call(this,a+":","scheme start")},get host(){return this._isInvalid?"":this._port?this._host+":"+this._port:this._host},set host(a){!this._isInvalid&&this._isRelative&&g.call(this,a,"host")},get hostname(){return this._host},set hostname(a){!this._isInvalid&&this._isRelative&&g.call(this,a,"hostname")},get port(){return this._port},set port(a){!this._isInvalid&&this._isRelative&&g.call(this,a,"port")},get pathname(){return this._isInvalid?"":this._isRelative?"/"+this._path.join("/"):this._schemeData},set pathname(a){!this._isInvalid&&this._isRelative&&(this._path=[],g.call(this,a,"relative path start"))},get search(){return this._isInvalid||!this._query||"?"==this._query?"":this._query},set search(a){!this._isInvalid&&this._isRelative&&(this._query="?","?"==a[0]&&(a=a.slice(1)),g.call(this,a,"query"))},get hash(){return this._isInvalid||!this._fragment||"#"==this._fragment?"":this._fragment},set hash(a){this._isInvalid||(this._fragment="#","#"==a[0]&&(a=a.slice(1)),g.call(this,a,"fragment"))},get origin(){var a;if(this._isInvalid||!this._scheme)return"";switch(this._scheme){case"data":case"file":case"javascript":case"mailto":return"null"}return a=this.host,a?this._scheme+"://"+a:""}};var r=a.URL;r&&(i.createObjectURL=function(){return r.createObjectURL.apply(r,arguments)},i.revokeObjectURL=function(a){r.revokeObjectURL(a)}),a.URL=i}}(this),function(a){function b(a){f.textContent=d++,e.push(a)}function c(){for(;e.length;)e.shift()()}var d=0,e=[],f=document.createTextNode("");new(window.MutationObserver||JsMutationObserver)(c).observe(f,{characterData:!0}),a.endOfMicrotask=b,Platform.endOfMicrotask=b}(Polymer),function(a){function b(){g||(g=!0,c(function(){g=!1,d.data&&console.group("flush"),Platform.performMicrotaskCheckpoint(),d.data&&console.groupEnd()}))}var c=a.endOfMicrotask,d=window.WebComponents?WebComponents.flags.log:{},e=document.createElement("style");e.textContent="template {display: none !important;} /* injected by platform.js */";var f=document.querySelector("head");f.insertBefore(e,f.firstChild);var g;if(Observer.hasObjectObserve)b=function(){};else{var h=125;window.addEventListener("WebComponentsReady",function(){b();var c=function(){"hidden"===document.visibilityState?a.flushPoll&&clearInterval(a.flushPoll):a.flushPoll=setInterval(b,h)};"string"==typeof document.visibilityState&&document.addEventListener("visibilitychange",c),c()})}if(window.CustomElements&&!CustomElements.useNative){var i=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=i.call(this,a,b);return CustomElements.upgradeAll(c),c}}a.flush=b,Platform.flush=b}(window.Polymer),function(a){function b(a){var b=new URL(a.ownerDocument.baseURI);return b.search="",b.hash="",b}function c(a,b,c,e){return a.replace(e,function(a,e,f,g){var h=f.replace(/["']/g,"");return h=d(b,h,c),e+"'"+h+"'"+g})}function d(a,b,c){if(b&&"/"===b[0])return b;if(b&&"#"===b[0])return b;var d=new URL(b,a);return c?d.href:e(d.href)}function e(a){var c=b(document.documentElement),d=new URL(a,c);return d.host===c.host&&d.port===c.port&&d.protocol===c.protocol?f(c,d):a}function f(a,b){for(var c=a.pathname,d=b.pathname,e=c.split("/"),f=d.split("/");e.length&&e[0]===f[0];)e.shift(),f.shift();for(var g=0,h=e.length-1;h>g;g++)f.unshift("..");var i=b.href.slice(-1)===m?m:b.hash;return f.join("/")+b.search+i}var g={resolveDom:function(a,c){c=c||b(a),this.resolveAttributes(a,c),this.resolveStyles(a,c);var d=a.querySelectorAll("template");if(d)for(var e,f=0,g=d.length;g>f&&(e=d[f]);f++)e.content&&this.resolveDom(e.content,c)},resolveTemplate:function(a){this.resolveDom(a.content,b(a))},resolveStyles:function(a,b){var c=a.querySelectorAll("style");if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveStyle(d,b)},resolveStyle:function(a,c){c=c||b(a),a.textContent=this.resolveCssText(a.textContent,c)},resolveCssText:function(a,b,d){return a=c(a,b,d,h),c(a,b,d,i)},resolveAttributes:function(a,b){a.hasAttributes&&a.hasAttributes()&&this.resolveElementAttributes(a,b);var c=a&&a.querySelectorAll(k);if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveElementAttributes(d,b)},resolveElementAttributes:function(a,e){e=e||b(a),j.forEach(function(b){var f,g=a.attributes[b],i=g&&g.value;i&&i.search(l)<0&&(f="style"===b?c(i,e,!1,h):d(e,i),g.value=f)})}},h=/(url\()([^)]*)(\))/g,i=/(@import[\s]+(?!url\())([^;]*)(;)/g,j=["href","src","action","style","url"],k="["+j.join("],[")+"]",l="{{.*}}",m="#";a.urlResolver=g}(Polymer),function(a){function b(a){this.cache=Object.create(null),this.map=Object.create(null),this.requests=0,this.regex=a}var c=Polymer.endOfMicrotask;b.prototype={extractUrls:function(a,b){for(var c,d,e=[];c=this.regex.exec(a);)d=new URL(c[1],b),e.push({matched:c[0],url:d.href});return e},process:function(a,b,c){var d=this.extractUrls(a,b),e=c.bind(null,this.map);this.fetch(d,e)},fetch:function(a,b){var c=a.length;if(!c)return b();for(var d,e,f,g=function(){0===--c&&b()},h=0;c>h;h++)d=a[h],f=d.url,e=this.cache[f],e||(e=this.xhr(f),e.match=d,this.cache[f]=e),e.wait(g)},handleXhr:function(a){var b=a.match,c=b.url,d=a.response||a.responseText||"";this.map[c]=d,this.fetch(this.extractUrls(d,c),a.resolve)},xhr:function(a){this.requests++;var b=new XMLHttpRequest;return b.open("GET",a,!0),b.send(),b.onerror=b.onload=this.handleXhr.bind(this,b),b.pending=[],b.resolve=function(){for(var a=b.pending,c=0;c<a.length;c++)a[c]();b.pending=null},b.wait=function(a){b.pending?b.pending.push(a):c(a)},b}},a.Loader=b}(Polymer),function(a){function b(){this.loader=new d(this.regex)}var c=a.urlResolver,d=a.Loader;b.prototype={regex:/@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,resolve:function(a,b,c){var d=function(d){c(this.flatten(a,b,d))}.bind(this);this.loader.process(a,b,d)},resolveNode:function(a,b,c){var d=a.textContent,e=function(b){a.textContent=b,c(a)};this.resolve(d,b,e)},flatten:function(a,b,d){for(var e,f,g,h=this.loader.extractUrls(a,b),i=0;i<h.length;i++)e=h[i],f=e.url,g=c.resolveCssText(d[f],f,!0),g=this.flatten(g,b,d),a=a.replace(e.matched,g);return a},loadStyles:function(a,b,c){function d(){f++,f===g&&c&&c()}for(var e,f=0,g=a.length,h=0;g>h&&(e=a[h]);h++)this.resolveNode(e,b,d)}};var e=new b;a.styleResolver=e}(Polymer),function(a){function b(a,b){return a&&b&&Object.getOwnPropertyNames(b).forEach(function(c){var d=Object.getOwnPropertyDescriptor(b,c);d&&(Object.defineProperty(a,c,d),"function"==typeof d.value&&(d.value.nom=c))}),a}function c(a){for(var b=a||{},c=1;c<arguments.length;c++){var e=arguments[c];try{for(var f in e)d(f,e,b)}catch(g){}}return b}function d(a,b,c){var d=e(b,a);Object.defineProperty(c,a,d)}function e(a,b){if(a){var c=Object.getOwnPropertyDescriptor(a,b);return c||e(Object.getPrototypeOf(a),b)}}a.extend=b,a.mixin=c,Platform.mixin=c}(Polymer),function(a){function b(a,b,d){return a?a.stop():a=new c(this),a.go(b,d),a}var c=function(a){this.context=a,this.boundComplete=this.complete.bind(this)};c.prototype={go:function(a,b){this.callback=a;var c;b?(c=setTimeout(this.boundComplete,b),this.handle=function(){clearTimeout(c)}):(c=requestAnimationFrame(this.boundComplete),this.handle=function(){cancelAnimationFrame(c)})},stop:function(){this.handle&&(this.handle(),this.handle=null)},complete:function(){this.handle&&(this.stop(),this.callback.call(this.context))}},a.job=b}(Polymer),function(a){function b(a,b,c){var d="string"==typeof a?document.createElement(a):a.cloneNode(!0);if(d.innerHTML=b,c)for(var e in c)d.setAttribute(e,c[e]);return d}var c={};HTMLElement.register=function(a,b){c[a]=b},HTMLElement.getPrototypeForTag=function(a){var b=a?c[a]:HTMLElement.prototype;return b||Object.getPrototypeOf(document.createElement(a))};var d=Event.prototype.stopPropagation;Event.prototype.stopPropagation=function(){this.cancelBubble=!0,d.apply(this,arguments)};var e=DOMTokenList.prototype.add,f=DOMTokenList.prototype.remove;DOMTokenList.prototype.add=function(){for(var a=0;a<arguments.length;a++)e.call(this,arguments[a])},DOMTokenList.prototype.remove=function(){for(var a=0;a<arguments.length;a++)f.call(this,arguments[a])},DOMTokenList.prototype.toggle=function(a,b){1==arguments.length&&(b=!this.contains(a)),b?this.add(a):this.remove(a)},DOMTokenList.prototype["switch"]=function(a,b){a&&this.remove(a),b&&this.add(b)};var g=function(){return Array.prototype.slice.call(this)},h=window.NamedNodeMap||window.MozNamedAttrMap||{};NodeList.prototype.array=g,h.prototype.array=g,HTMLCollection.prototype.array=g,a.createDOM=b}(Polymer),function(a){function b(a){var e=b.caller,g=e.nom,h=e._super;h||(g||(g=e.nom=c.call(this,e)),g||console.warn("called super() on a method not installed declaratively (has no .nom property)"),h=d(e,g,f(this)));var i=h[g];return i?(i._super||d(i,g,h),i.apply(this,a||[])):void 0}function c(a){for(var b=this.__proto__;b&&b!==HTMLElement.prototype;){for(var c,d=Object.getOwnPropertyNames(b),e=0,f=d.length;f>e&&(c=d[e]);e++){var g=Object.getOwnPropertyDescriptor(b,c);if("function"==typeof g.value&&g.value===a)return c}b=b.__proto__}}function d(a,b,c){var d=e(c,b,a);return d[b]&&(d[b].nom=b),a._super=d}function e(a,b,c){for(;a;){if(a[b]!==c&&a[b])return a;a=f(a)}return Object}function f(a){return a.__proto__}a["super"]=b}(Polymer),function(a){function b(a){return a}function c(a,b){var c=typeof b;return b instanceof Date&&(c="date"),d[c](a,b)}var d={string:b,undefined:b,date:function(a){return new Date(Date.parse(a)||Date.now())},"boolean":function(a){return""===a?!0:"false"===a?!1:!!a},number:function(a){var b=parseFloat(a);return 0===b&&(b=parseInt(a)),isNaN(b)?a:b},object:function(a,b){if(null===b)return a;try{return JSON.parse(a.replace(/'/g,'"'))}catch(c){return a}},"function":function(a,b){return b}};a.deserializeValue=c}(Polymer),function(a){var b=a.extend,c={};c.declaration={},c.instance={},c.publish=function(a,c){for(var d in a)b(c,a[d])},a.api=c}(Polymer),function(a){var b={async:function(a,b,c){Polymer.flush(),b=b&&b.length?b:[b];var d=function(){(this[a]||a).apply(this,b)}.bind(this),e=c?setTimeout(d,c):requestAnimationFrame(d);return c?e:~e},cancelAsync:function(a){0>a?cancelAnimationFrame(~a):clearTimeout(a)},fire:function(a,b,c,d,e){var f=c||this,b=null===b||void 0===b?{}:b,g=new CustomEvent(a,{bubbles:void 0!==d?d:!0,cancelable:void 0!==e?e:!0,detail:b});return f.dispatchEvent(g),g},asyncFire:function(){this.async("fire",arguments)},classFollows:function(a,b,c){b&&b.classList.remove(c),a&&a.classList.add(c)},injectBoundHTML:function(a,b){var c=document.createElement("template");c.innerHTML=a;var d=this.instanceTemplate(c);return b&&(b.textContent="",b.appendChild(d)),d}},c=function(){},d={};b.asyncMethod=b.async,a.api.instance.utils=b,a.nop=c,a.nob=d}(Polymer),function(a){var b=window.WebComponents?WebComponents.flags.log:{},c="on-",d={EVENT_PREFIX:c,addHostListeners:function(){var a=this.eventDelegates;
-b.events&&Object.keys(a).length>0&&console.log("[%s] addHostListeners:",this.localName,a);for(var c in a){var d=a[c];PolymerGestures.addEventListener(this,c,this.element.getEventHandler(this,this,d))}},dispatchMethod:function(a,c,d){if(a){b.events&&console.group("[%s] dispatch [%s]",a.localName,c);var e="function"==typeof c?c:a[c];e&&e[d?"apply":"call"](a,d),b.events&&console.groupEnd(),Polymer.flush()}}};a.api.instance.events=d,a.addEventListener=function(a,b,c,d){PolymerGestures.addEventListener(wrap(a),b,c,d)},a.removeEventListener=function(a,b,c,d){PolymerGestures.removeEventListener(wrap(a),b,c,d)}}(Polymer),function(a){var b={copyInstanceAttributes:function(){var a=this._instanceAttributes;for(var b in a)this.hasAttribute(b)||this.setAttribute(b,a[b])},takeAttributes:function(){if(this._publishLC)for(var a,b=0,c=this.attributes,d=c.length;(a=c[b])&&d>b;b++)this.attributeToProperty(a.name,a.value)},attributeToProperty:function(b,c){var b=this.propertyForAttribute(b);if(b){if(c&&c.search(a.bindPattern)>=0)return;var d=this[b],c=this.deserializeValue(c,d);c!==d&&(this[b]=c)}},propertyForAttribute:function(a){var b=this._publishLC&&this._publishLC[a];return b},deserializeValue:function(b,c){return a.deserializeValue(b,c)},serializeValue:function(a,b){return"boolean"===b?a?"":void 0:"object"!==b&&"function"!==b&&void 0!==a?a:void 0},reflectPropertyToAttribute:function(a){var b=typeof this[a],c=this.serializeValue(this[a],b);void 0!==c?this.setAttribute(a,c):"boolean"===b&&this.removeAttribute(a)}};a.api.instance.attributes=b}(Polymer),function(a){function b(a,b){return a===b?0!==a||1/a===1/b:f(a)&&f(b)?!0:a!==a&&b!==b}function c(a,b){return void 0===b&&null===a?b:null===b||void 0===b?a:b}var d=window.WebComponents?WebComponents.flags.log:{},e={object:void 0,type:"update",name:void 0,oldValue:void 0},f=Number.isNaN||function(a){return"number"==typeof a&&isNaN(a)},g={createPropertyObserver:function(){var a=this._observeNames;if(a&&a.length){var b=this._propertyObserver=new CompoundObserver(!0);this.registerObserver(b);for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)b.addPath(this,c),this.observeArrayValue(c,this[c],null)}},openPropertyObserver:function(){this._propertyObserver&&this._propertyObserver.open(this.notifyPropertyChanges,this)},notifyPropertyChanges:function(a,b,c){var d,e,f={};for(var g in b)if(d=c[2*g+1],e=this.observe[d]){var h=b[g],i=a[g];this.observeArrayValue(d,i,h),f[e]||(void 0!==h&&null!==h||void 0!==i&&null!==i)&&(f[e]=!0,this.invokeMethod(e,[h,i,arguments]))}},invokeMethod:function(a,b){var c=this[a]||a;"function"==typeof c&&c.apply(this,b)},deliverChanges:function(){this._propertyObserver&&this._propertyObserver.deliver()},observeArrayValue:function(a,b,c){var e=this.observe[a];if(e&&(Array.isArray(c)&&(d.observe&&console.log("[%s] observeArrayValue: unregister observer [%s]",this.localName,a),this.closeNamedObserver(a+"__array")),Array.isArray(b))){d.observe&&console.log("[%s] observeArrayValue: register observer [%s]",this.localName,a,b);var f=new ArrayObserver(b);f.open(function(a){this.invokeMethod(e,[a])},this),this.registerNamedObserver(a+"__array",f)}},emitPropertyChangeRecord:function(a,c,d){if(!b(c,d)&&(this._propertyChanged(a,c,d),Observer.hasObjectObserve)){var f=this._objectNotifier;f||(f=this._objectNotifier=Object.getNotifier(this)),e.object=this,e.name=a,e.oldValue=d,f.notify(e)}},_propertyChanged:function(a){this.reflect[a]&&this.reflectPropertyToAttribute(a)},bindProperty:function(a,b,d){if(d)return void(this[a]=b);var e=this.element.prototype.computed;if(e&&e[a]){var f=a+"ComputedBoundObservable_";return void(this[f]=b)}return this.bindToAccessor(a,b,c)},bindToAccessor:function(a,c,d){function e(b,c){j[f]=b;var d=j[h];d&&"function"==typeof d.setValue&&d.setValue(b),j.emitPropertyChangeRecord(a,b,c)}var f=a+"_",g=a+"Observable_",h=a+"ComputedBoundObservable_";this[g]=c;var i=this[f],j=this,k=c.open(e);if(d&&!b(i,k)){var l=d(i,k);b(k,l)||(k=l,c.setValue&&c.setValue(k))}e(k,i);var m={close:function(){c.close(),j[g]=void 0,j[h]=void 0}};return this.registerObserver(m),m},createComputedProperties:function(){if(this._computedNames)for(var a=0;a<this._computedNames.length;a++){var b=this._computedNames[a],c=this.computed[b];try{var d=PolymerExpressions.getExpression(c),e=d.getBinding(this,this.element.syntax);this.bindToAccessor(b,e)}catch(f){console.error("Failed to create computed property",f)}}},registerObserver:function(a){return this._observers?void this._observers.push(a):void(this._observers=[a])},closeObservers:function(){if(this._observers){for(var a=this._observers,b=0;b<a.length;b++){var c=a[b];c&&"function"==typeof c.close&&c.close()}this._observers=[]}},registerNamedObserver:function(a,b){var c=this._namedObservers||(this._namedObservers={});c[a]=b},closeNamedObserver:function(a){var b=this._namedObservers;return b&&b[a]?(b[a].close(),b[a]=null,!0):void 0},closeNamedObservers:function(){if(this._namedObservers){for(var a in this._namedObservers)this.closeNamedObserver(a);this._namedObservers={}}}};a.api.instance.properties=g}(Polymer),function(a){var b=window.WebComponents?WebComponents.flags.log:{},c={instanceTemplate:function(a){HTMLTemplateElement.decorate(a);for(var b=this.syntax||!a.bindingDelegate&&this.element.syntax,c=a.createInstance(this,b),d=c.bindings_,e=0;e<d.length;e++)this.registerObserver(d[e]);return c},bind:function(a,b,c){var d=this.propertyForAttribute(a);if(d){var e=this.bindProperty(d,b,c);return Platform.enableBindingsReflection&&e&&(e.path=b.path_,this._recordBinding(d,e)),this.reflect[d]&&this.reflectPropertyToAttribute(d),e}return this.mixinSuper(arguments)},_recordBinding:function(a,b){this.bindings_=this.bindings_||{},this.bindings_[a]=b},bindFinished:function(){this.makeElementReady()},asyncUnbindAll:function(){this._unbound||(b.unbind&&console.log("[%s] asyncUnbindAll",this.localName),this._unbindAllJob=this.job(this._unbindAllJob,this.unbindAll,0))},unbindAll:function(){this._unbound||(this.closeObservers(),this.closeNamedObservers(),this._unbound=!0)},cancelUnbindAll:function(){return this._unbound?void(b.unbind&&console.warn("[%s] already unbound, cannot cancel unbindAll",this.localName)):(b.unbind&&console.log("[%s] cancelUnbindAll",this.localName),void(this._unbindAllJob&&(this._unbindAllJob=this._unbindAllJob.stop())))}},d=/\{\{([^{}]*)}}/;a.bindPattern=d,a.api.instance.mdv=c}(Polymer),function(a){function b(a){return a.hasOwnProperty("PolymerBase")}function c(){}var d={PolymerBase:!0,job:function(a,b,c){if("string"!=typeof a)return Polymer.job.call(this,a,b,c);var d="___"+a;this[d]=Polymer.job.call(this,this[d],b,c)},"super":Polymer["super"],created:function(){},ready:function(){},createdCallback:function(){this.templateInstance&&this.templateInstance.model&&console.warn("Attributes on "+this.localName+" were data bound prior to Polymer upgrading the element. This may result in incorrect binding types."),this.created(),this.prepareElement(),this.ownerDocument.isStagingDocument||this.makeElementReady()},prepareElement:function(){return this._elementPrepared?void console.warn("Element already prepared",this.localName):(this._elementPrepared=!0,this.shadowRoots={},this.createPropertyObserver(),this.openPropertyObserver(),this.copyInstanceAttributes(),this.takeAttributes(),void this.addHostListeners())},makeElementReady:function(){this._readied||(this._readied=!0,this.createComputedProperties(),this.parseDeclarations(this.__proto__),this.removeAttribute("unresolved"),this.ready())},attributeChangedCallback:function(a){"class"!==a&&"style"!==a&&this.attributeToProperty(a,this.getAttribute(a)),this.attributeChanged&&this.attributeChanged.apply(this,arguments)},attachedCallback:function(){this.cancelUnbindAll(),this.attached&&this.attached(),this.hasBeenAttached||(this.hasBeenAttached=!0,this.domReady&&this.async("domReady"))},detachedCallback:function(){this.preventDispose||this.asyncUnbindAll(),this.detached&&this.detached(),this.leftView&&this.leftView()},parseDeclarations:function(a){a&&a.element&&(this.parseDeclarations(a.__proto__),a.parseDeclaration.call(this,a.element))},parseDeclaration:function(a){var b=this.fetchTemplate(a);if(b){var c=this.shadowFromTemplate(b);this.shadowRoots[a.name]=c}},fetchTemplate:function(a){return a.querySelector("template")},shadowFromTemplate:function(a){if(a){var b=this.createShadowRoot(),c=this.instanceTemplate(a);return b.appendChild(c),this.shadowRootReady(b,a),b}},lightFromTemplate:function(a,b){if(a){this.eventController=this;var c=this.instanceTemplate(a);return b?this.insertBefore(c,b):this.appendChild(c),this.shadowRootReady(this),c}},shadowRootReady:function(a){this.marshalNodeReferences(a)},marshalNodeReferences:function(a){var b=this.$=this.$||{};if(a)for(var c,d=a.querySelectorAll("[id]"),e=0,f=d.length;f>e&&(c=d[e]);e++)b[c.id]=c},onMutation:function(a,b){var c=new MutationObserver(function(a){b.call(this,c,a),c.disconnect()}.bind(this));c.observe(a,{childList:!0,subtree:!0})}};c.prototype=d,d.constructor=c,a.Base=c,a.isBase=b,a.api.instance.base=d}(Polymer),function(a){function b(a){return a.__proto__}function c(a,b){var c="",d=!1;b&&(c=b.localName,d=b.hasAttribute("is"));var e=WebComponents.ShadowCSS.makeScopeSelector(c,d);return WebComponents.ShadowCSS.shimCssText(a,e)}var d=(window.WebComponents?WebComponents.flags.log:{},window.ShadowDOMPolyfill),e="element",f="controller",g={STYLE_SCOPE_ATTRIBUTE:e,installControllerStyles:function(){var a=this.findStyleScope();if(a&&!this.scopeHasNamedStyle(a,this.localName)){for(var c=b(this),d="";c&&c.element;)d+=c.element.cssTextForScope(f),c=b(c);d&&this.installScopeCssText(d,a)}},installScopeStyle:function(a,b,c){var c=c||this.findStyleScope(),b=b||"";if(c&&!this.scopeHasNamedStyle(c,this.localName+b)){var d="";if(a instanceof Array)for(var e,f=0,g=a.length;g>f&&(e=a[f]);f++)d+=e.textContent+"\n\n";else d=a.textContent;this.installScopeCssText(d,c,b)}},installScopeCssText:function(a,b,e){if(b=b||this.findStyleScope(),e=e||"",b){d&&(a=c(a,b.host));var g=this.element.cssTextToScopeStyle(a,f);Polymer.applyStyleToScope(g,b),this.styleCacheForScope(b)[this.localName+e]=!0}},findStyleScope:function(a){for(var b=a||this;b.parentNode;)b=b.parentNode;return b},scopeHasNamedStyle:function(a,b){var c=this.styleCacheForScope(a);return c[b]},styleCacheForScope:function(a){if(d){var b=a.host?a.host.localName:a.localName;return h[b]||(h[b]={})}return a._scopeStyles=a._scopeStyles||{}}},h={};a.api.instance.styles=g}(Polymer),function(a){function b(a,b){if("string"!=typeof a){var c=b||document._currentScript;if(b=a,a=c&&c.parentNode&&c.parentNode.getAttribute?c.parentNode.getAttribute("name"):"",!a)throw"Element name could not be inferred."}if(f(a))throw"Already registered (Polymer) prototype for element "+a;e(a,b),d(a)}function c(a,b){i[a]=b}function d(a){i[a]&&(i[a].registerWhenReady(),delete i[a])}function e(a,b){return j[a]=b||{}}function f(a){return j[a]}function g(a,b){if("string"!=typeof b)return!1;var c=HTMLElement.getPrototypeForTag(b),d=c&&c.constructor;return d?CustomElements["instanceof"]?CustomElements["instanceof"](a,d):a instanceof d:!1}var h=a.extend,i=(a.api,{}),j={};a.getRegisteredPrototype=f,a.waitingForPrototype=c,a.instanceOfType=g,window.Polymer=b,h(Polymer,a),WebComponents.consumeDeclarations&&WebComponents.consumeDeclarations(function(a){if(a)for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)b.apply(null,c)})}(Polymer),function(a){var b={resolveElementPaths:function(a){Polymer.urlResolver.resolveDom(a)},addResolvePathApi:function(){var a=this.getAttribute("assetpath")||"",b=new URL(a,this.ownerDocument.baseURI);this.prototype.resolvePath=function(a,c){var d=new URL(a,c||b);return d.href}}};a.api.declaration.path=b}(Polymer),function(a){function b(a,b){var c=new URL(a.getAttribute("href"),b).href;return"@import '"+c+"';"}function c(a,b){if(a){b===document&&(b=document.head),i&&(b=document.head);var c=d(a.textContent),e=a.getAttribute(h);e&&c.setAttribute(h,e);var f=b.firstElementChild;if(b===document.head){var g="style["+h+"]",j=document.head.querySelectorAll(g);j.length&&(f=j[j.length-1].nextElementSibling)}b.insertBefore(c,f)}}function d(a,b){b=b||document,b=b.createElement?b:b.ownerDocument;var c=b.createElement("style");return c.textContent=a,c}function e(a){return a&&a.__resource||""}function f(a,b){return q?q.call(a,b):void 0}var g=(window.WebComponents?WebComponents.flags.log:{},a.api.instance.styles),h=g.STYLE_SCOPE_ATTRIBUTE,i=window.ShadowDOMPolyfill,j="style",k="@import",l="link[rel=stylesheet]",m="global",n="polymer-scope",o={loadStyles:function(a){var b=this.fetchTemplate(),c=b&&this.templateContent();if(c){this.convertSheetsToStyles(c);var d=this.findLoadableStyles(c);if(d.length){var e=b.ownerDocument.baseURI;return Polymer.styleResolver.loadStyles(d,e,a)}}a&&a()},convertSheetsToStyles:function(a){for(var c,e,f=a.querySelectorAll(l),g=0,h=f.length;h>g&&(c=f[g]);g++)e=d(b(c,this.ownerDocument.baseURI),this.ownerDocument),this.copySheetAttributes(e,c),c.parentNode.replaceChild(e,c)},copySheetAttributes:function(a,b){for(var c,d=0,e=b.attributes,f=e.length;(c=e[d])&&f>d;d++)"rel"!==c.name&&"href"!==c.name&&a.setAttribute(c.name,c.value)},findLoadableStyles:function(a){var b=[];if(a)for(var c,d=a.querySelectorAll(j),e=0,f=d.length;f>e&&(c=d[e]);e++)c.textContent.match(k)&&b.push(c);return b},installSheets:function(){this.cacheSheets(),this.cacheStyles(),this.installLocalSheets(),this.installGlobalStyles()},cacheSheets:function(){this.sheets=this.findNodes(l),this.sheets.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},cacheStyles:function(){this.styles=this.findNodes(j+"["+n+"]"),this.styles.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},installLocalSheets:function(){var a=this.sheets.filter(function(a){return!a.hasAttribute(n)}),b=this.templateContent();if(b){var c="";if(a.forEach(function(a){c+=e(a)+"\n"}),c){var f=d(c,this.ownerDocument);b.insertBefore(f,b.firstChild)}}},findNodes:function(a,b){var c=this.querySelectorAll(a).array(),d=this.templateContent();if(d){var e=d.querySelectorAll(a).array();c=c.concat(e)}return b?c.filter(b):c},installGlobalStyles:function(){var a=this.styleForScope(m);c(a,document.head)},cssTextForScope:function(a){var b="",c="["+n+"="+a+"]",d=function(a){return f(a,c)},g=this.sheets.filter(d);g.forEach(function(a){b+=e(a)+"\n\n"});var h=this.styles.filter(d);return h.forEach(function(a){b+=a.textContent+"\n\n"}),b},styleForScope:function(a){var b=this.cssTextForScope(a);return this.cssTextToScopeStyle(b,a)},cssTextToScopeStyle:function(a,b){if(a){var c=d(a);return c.setAttribute(h,this.getAttribute("name")+"-"+b),c}}},p=HTMLElement.prototype,q=p.matches||p.matchesSelector||p.webkitMatchesSelector||p.mozMatchesSelector;a.api.declaration.styles=o,a.applyStyleToScope=c}(Polymer),function(a){var b=(window.WebComponents?WebComponents.flags.log:{},a.api.instance.events),c=b.EVENT_PREFIX,d={};["webkitAnimationStart","webkitAnimationEnd","webkitTransitionEnd","DOMFocusOut","DOMFocusIn","DOMMouseScroll"].forEach(function(a){d[a.toLowerCase()]=a});var e={parseHostEvents:function(){var a=this.prototype.eventDelegates;this.addAttributeDelegates(a)},addAttributeDelegates:function(a){for(var b,c=0;b=this.attributes[c];c++)this.hasEventPrefix(b.name)&&(a[this.removeEventPrefix(b.name)]=b.value.replace("{{","").replace("}}","").trim())},hasEventPrefix:function(a){return a&&"o"===a[0]&&"n"===a[1]&&"-"===a[2]},removeEventPrefix:function(a){return a.slice(f)},findController:function(a){for(;a.parentNode;){if(a.eventController)return a.eventController;a=a.parentNode}return a.host},getEventHandler:function(a,b,c){var d=this;return function(e){a&&a.PolymerBase||(a=d.findController(b));var f=[e,e.detail,e.currentTarget];a.dispatchMethod(a,c,f)}},prepareEventBinding:function(a,b){if(this.hasEventPrefix(b)){var c=this.removeEventPrefix(b);c=d[c]||c;var e=this;return function(b,d,f){function g(){return"{{ "+a+" }}"}var h=e.getEventHandler(void 0,d,a);return PolymerGestures.addEventListener(d,c,h),f?void 0:{open:g,discardChanges:g,close:function(){PolymerGestures.removeEventListener(d,c,h)}}}}}},f=c.length;a.api.declaration.events=e}(Polymer),function(a){var b=["attribute"],c={inferObservers:function(a){var b,c=a.observe;for(var d in a)"Changed"===d.slice(-7)&&(b=d.slice(0,-7),this.canObserveProperty(b)&&(c||(c=a.observe={}),c[b]=c[b]||d))},canObserveProperty:function(a){return b.indexOf(a)<0},explodeObservers:function(a){var b=a.observe;if(b){var c={};for(var d in b)for(var e,f=d.split(" "),g=0;e=f[g];g++)c[e]=b[d];a.observe=c}},optimizePropertyMaps:function(a){if(a.observe){var b=a._observeNames=[];for(var c in a.observe)for(var d,e=c.split(" "),f=0;d=e[f];f++)b.push(d)}if(a.publish){var b=a._publishNames=[];for(var c in a.publish)b.push(c)}if(a.computed){var b=a._computedNames=[];for(var c in a.computed)b.push(c)}},publishProperties:function(a,b){var c=a.publish;c&&(this.requireProperties(c,a,b),this.filterInvalidAccessorNames(c),a._publishLC=this.lowerCaseMap(c));var d=a.computed;d&&this.filterInvalidAccessorNames(d)},filterInvalidAccessorNames:function(a){for(var b in a)this.propertyNameBlacklist[b]&&(console.warn('Cannot define property "'+b+'" for element "'+this.name+'" because it has the same name as an HTMLElement property, and not all browsers support overriding that. Consider giving it a different name.'),delete a[b])},requireProperties:function(a,b){b.reflect=b.reflect||{};for(var c in a){var d=a[c];d&&void 0!==d.reflect&&(b.reflect[c]=Boolean(d.reflect),d=d.value),void 0!==d&&(b[c]=d)}},lowerCaseMap:function(a){var b={};for(var c in a)b[c.toLowerCase()]=c;return b},createPropertyAccessor:function(a,b){var c=this.prototype,d=a+"_",e=a+"Observable_";c[d]=c[a],Object.defineProperty(c,a,{get:function(){var a=this[e];return a&&a.deliver(),this[d]},set:function(c){if(b)return this[d];var f=this[e];if(f)return void f.setValue(c);var g=this[d];return this[d]=c,this.emitPropertyChangeRecord(a,c,g),c},configurable:!0})},createPropertyAccessors:function(a){var b=a._computedNames;if(b&&b.length)for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.createPropertyAccessor(c,!0);var b=a._publishNames;if(b&&b.length)for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)a.computed&&a.computed[c]||this.createPropertyAccessor(c)},propertyNameBlacklist:{children:1,"class":1,id:1,hidden:1,style:1,title:1}};a.api.declaration.properties=c}(Polymer),function(a){var b="attributes",c=/\s|,/,d={inheritAttributesObjects:function(a){this.inheritObject(a,"publishLC"),this.inheritObject(a,"_instanceAttributes")},publishAttributes:function(a){var d=this.getAttribute(b);if(d)for(var e,f=a.publish||(a.publish={}),g=d.split(c),h=0,i=g.length;i>h;h++)e=g[h].trim(),e&&void 0===f[e]&&(f[e]=void 0)},accumulateInstanceAttributes:function(){for(var a,b=this.prototype._instanceAttributes,c=this.attributes,d=0,e=c.length;e>d&&(a=c[d]);d++)this.isInstanceAttribute(a.name)&&(b[a.name]=a.value)},isInstanceAttribute:function(a){return!this.blackList[a]&&"on-"!==a.slice(0,3)},blackList:{name:1,"extends":1,constructor:1,noscript:1,assetpath:1,"cache-csstext":1}};d.blackList[b]=1,a.api.declaration.attributes=d}(Polymer),function(a){var b=a.api.declaration.events,c=new PolymerExpressions,d=c.prepareBinding;c.prepareBinding=function(a,e,f){return b.prepareEventBinding(a,e,f)||d.call(c,a,e,f)};var e={syntax:c,fetchTemplate:function(){return this.querySelector("template")},templateContent:function(){var a=this.fetchTemplate();return a&&a.content},installBindingDelegate:function(a){a&&(a.bindingDelegate=this.syntax)}};a.api.declaration.mdv=e}(Polymer),function(a){function b(a){if(!Object.__proto__){var b=Object.getPrototypeOf(a);a.__proto__=b,d(b)&&(b.__proto__=Object.getPrototypeOf(b))}}var c=a.api,d=a.isBase,e=a.extend,f=window.ShadowDOMPolyfill,g={register:function(a,b){this.buildPrototype(a,b),this.registerPrototype(a,b),this.publishConstructor()},buildPrototype:function(b,c){var d=a.getRegisteredPrototype(b),e=this.generateBasePrototype(c);this.desugarBeforeChaining(d,e),this.prototype=this.chainPrototypes(d,e),this.desugarAfterChaining(b,c)},desugarBeforeChaining:function(a,b){a.element=this,this.publishAttributes(a,b),this.publishProperties(a,b),this.inferObservers(a),this.explodeObservers(a)},chainPrototypes:function(a,c){this.inheritMetaData(a,c);var d=this.chainObject(a,c);return b(d),d},inheritMetaData:function(a,b){this.inheritObject("observe",a,b),this.inheritObject("publish",a,b),this.inheritObject("reflect",a,b),this.inheritObject("_publishLC",a,b),this.inheritObject("_instanceAttributes",a,b),this.inheritObject("eventDelegates",a,b)},desugarAfterChaining:function(a,b){this.optimizePropertyMaps(this.prototype),this.createPropertyAccessors(this.prototype),this.installBindingDelegate(this.fetchTemplate()),this.installSheets(),this.resolveElementPaths(this),this.accumulateInstanceAttributes(),this.parseHostEvents(),this.addResolvePathApi(),f&&WebComponents.ShadowCSS.shimStyling(this.templateContent(),a,b),this.prototype.registerCallback&&this.prototype.registerCallback(this)},publishConstructor:function(){var a=this.getAttribute("constructor");a&&(window[a]=this.ctor)},generateBasePrototype:function(a){var b=this.findBasePrototype(a);if(!b){var b=HTMLElement.getPrototypeForTag(a);b=this.ensureBaseApi(b),h[a]=b}return b},findBasePrototype:function(a){return h[a]},ensureBaseApi:function(a){if(a.PolymerBase)return a;var b=Object.create(a);return c.publish(c.instance,b),this.mixinMethod(b,a,c.instance.mdv,"bind"),b},mixinMethod:function(a,b,c,d){var e=function(a){return b[d].apply(this,a)};a[d]=function(){return this.mixinSuper=e,c[d].apply(this,arguments)}},inheritObject:function(a,b,c){var d=b[a]||{};b[a]=this.chainObject(d,c[a])},registerPrototype:function(a,b){var c={prototype:this.prototype},d=this.findTypeExtension(b);d&&(c["extends"]=d),HTMLElement.register(a,this.prototype),this.ctor=document.registerElement(a,c)},findTypeExtension:function(a){if(a&&a.indexOf("-")<0)return a;var b=this.findBasePrototype(a);return b.element?this.findTypeExtension(b.element["extends"]):void 0}},h={};g.chainObject=Object.__proto__?function(a,b){return a&&b&&a!==b&&(a.__proto__=b),a}:function(a,b){if(a&&b&&a!==b){var c=Object.create(b);a=e(c,a)}return a},c.declaration.prototype=g}(Polymer),function(a){function b(a){return document.contains(a)?j:i}function c(){return i.length?i[0]:j[0]}function d(a){f.waitToReady=!0,Polymer.endOfMicrotask(function(){HTMLImports.whenReady(function(){f.addReadyCallback(a),f.waitToReady=!1,f.check()})})}function e(a){if(void 0===a)return void f.ready();var b=setTimeout(function(){f.ready()},a);Polymer.whenReady(function(){clearTimeout(b)})}var f={wait:function(a){a.__queue||(a.__queue={},g.push(a))},enqueue:function(a,c,d){var e=a.__queue&&!a.__queue.check;return e&&(b(a).push(a),a.__queue.check=c,a.__queue.go=d),0!==this.indexOf(a)},indexOf:function(a){var c=b(a).indexOf(a);return c>=0&&document.contains(a)&&(c+=HTMLImports.useNative||HTMLImports.ready?i.length:1e9),c},go:function(a){var b=this.remove(a);b&&(a.__queue.flushable=!0,this.addToFlushQueue(b),this.check())},remove:function(a){var c=this.indexOf(a);if(0===c)return b(a).shift()},check:function(){var a=this.nextElement();return a&&a.__queue.check.call(a),this.canReady()?(this.ready(),!0):void 0},nextElement:function(){return c()},canReady:function(){return!this.waitToReady&&this.isEmpty()},isEmpty:function(){for(var a,b=0,c=g.length;c>b&&(a=g[b]);b++)if(a.__queue&&!a.__queue.flushable)return;return!0},addToFlushQueue:function(a){h.push(a)},flush:function(){if(!this.flushing){this.flushing=!0;for(var a;h.length;)a=h.shift(),a.__queue.go.call(a),a.__queue=null;this.flushing=!1}},ready:function(){var a=CustomElements.ready;CustomElements.ready=!1,this.flush(),CustomElements.useNative||CustomElements.upgradeDocumentTree(document),CustomElements.ready=a,Polymer.flush(),requestAnimationFrame(this.flushReadyCallbacks)},addReadyCallback:function(a){a&&k.push(a)},flushReadyCallbacks:function(){if(k)for(var a;k.length;)(a=k.shift())()},waitingFor:function(){for(var a,b=[],c=0,d=g.length;d>c&&(a=g[c]);c++)a.__queue&&!a.__queue.flushable&&b.push(a);return b},waitToReady:!0},g=[],h=[],i=[],j=[],k=[];a.elements=g,a.waitingFor=f.waitingFor.bind(f),a.forceReady=e,a.queue=f,a.whenReady=a.whenPolymerReady=d}(Polymer),function(a){function b(a){return Boolean(HTMLElement.getPrototypeForTag(a))}function c(a){return a&&a.indexOf("-")>=0}var d=a.extend,e=a.api,f=a.queue,g=a.whenReady,h=a.getRegisteredPrototype,i=a.waitingForPrototype,j=d(Object.create(HTMLElement.prototype),{createdCallback:function(){this.getAttribute("name")&&this.init()},init:function(){this.name=this.getAttribute("name"),this["extends"]=this.getAttribute("extends"),f.wait(this),this.loadResources(),this.registerWhenReady()},registerWhenReady:function(){this.registered||this.waitingForPrototype(this.name)||this.waitingForQueue()||this.waitingForResources()||f.go(this)},_register:function(){c(this["extends"])&&!b(this["extends"])&&console.warn("%s is attempting to extend %s, an unregistered element or one that was not registered with Polymer.",this.name,this["extends"]),this.register(this.name,this["extends"]),this.registered=!0},waitingForPrototype:function(a){return h(a)?void 0:(i(a,this),this.handleNoScript(a),!0)},handleNoScript:function(a){this.hasAttribute("noscript")&&!this.noscript&&(this.noscript=!0,Polymer(a))},waitingForResources:function(){return this._needsResources},waitingForQueue:function(){return f.enqueue(this,this.registerWhenReady,this._register)},loadResources:function(){this._needsResources=!0,this.loadStyles(function(){this._needsResources=!1,this.registerWhenReady()}.bind(this))}});e.publish(e.declaration,j),g(function(){document.body.removeAttribute("unresolved"),document.dispatchEvent(new CustomEvent("polymer-ready",{bubbles:!0}))}),document.registerElement("polymer-element",{prototype:j})}(Polymer),function(a){function b(a,b){a?(document.head.appendChild(a),d(b)):b&&b()}function c(a,c){if(a&&a.length){for(var d,e,f=document.createDocumentFragment(),g=0,h=a.length;h>g&&(d=a[g]);g++)e=document.createElement("link"),e.rel="import",e.href=d,f.appendChild(e);b(f,c)}else c&&c()}var d=a.whenReady;a["import"]=c,a.importElements=b}(Polymer),function(){var a=document.createElement("polymer-element");a.setAttribute("name","auto-binding"),a.setAttribute("extends","template"),a.init(),Polymer("auto-binding",{createdCallback:function(){this.syntax=this.bindingDelegate=this.makeSyntax(),Polymer.whenPolymerReady(function(){this.model=this,this.setAttribute("bind",""),this.async(function(){this.marshalNodeReferences(this.parentNode),this.fire("template-bound")})}.bind(this))},makeSyntax:function(){var a=Object.create(Polymer.api.declaration.events),b=this;a.findController=function(){return b.model};var c=new PolymerExpressions,d=c.prepareBinding;return c.prepareBinding=function(b,e,f){return a.prepareEventBinding(b,e,f)||d.call(c,b,e,f)},c}})}(); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.min.js b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.min.js
deleted file mode 100644
index c29c57e3f81..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/CustomElements.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,o=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};o.prototype={set:function(t,o){var n=t[this.name];return n&&n[0]===t?n[1]=o:e(t,this.name,{value:[t,o],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=o}(),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,o=[],n=function(e){o.push(e)},r=function(){o.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){o(e,function(e){return t(e)?!0:void n(e,t)}),n(e,t)}function o(e,t,n){var r=e.firstElementChild;if(!r)for(r=e.firstChild;r&&r.nodeType!==Node.ELEMENT_NODE;)r=r.nextSibling;for(;r;)t(r,n)!==!0&&o(r,t,n),r=r.nextElementSibling;return null}function n(e,o){for(var n=e.shadowRoot;n;)t(n,o),n=n.olderShadowRoot}function r(e,t){i=[],a(e,t),i=null}function a(e,t){if(e=wrap(e),!(i.indexOf(e)>=0)){i.push(e);for(var o,n=e.querySelectorAll("link[rel="+u+"]"),r=0,d=n.length;d>r&&(o=n[r]);r++)o["import"]&&a(o["import"],t);t(e)}}var i,u=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=r,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return o(e)||n(e)}function o(t){return e.upgrade(t)?!0:void u(t)}function n(e){y(e,function(e){return o(e)?!0:void 0})}function r(e){u(e),f(e)&&y(e,function(e){u(e)})}function a(e){M.push(e),C||(C=!0,setTimeout(i))}function i(){C=!1;for(var e,t=M,o=0,n=t.length;n>o&&(e=t[o]);o++)e();M=[]}function u(e){E?a(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&f(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function c(e){s(e),y(e,function(e){s(e)})}function s(e){E?a(function(){l(e)}):l(e)}function l(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!f(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function f(e){for(var t=e,o=wrap(document);t;){if(t==o)return!0;t=t.parentNode||t.host}}function p(e){if(e.shadowRoot&&!e.shadowRoot.__watched){_.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)h(t),t=t.olderShadowRoot}}function m(e){if(_.dom){var o=e[0];if(o&&"childList"===o.type&&o.addedNodes&&o.addedNodes){for(var n=o.addedNodes[0];n&&n!==document&&!n.host;)n=n.parentNode;var r=n&&(n.URL||n._URL||n.host&&n.host.localName)||"";r=r.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,r||"")}e.forEach(function(e){"childList"===e.type&&(N(e.addedNodes,function(e){e.localName&&t(e)}),N(e.removedNodes,function(e){e.localName&&c(e)}))}),_.dom&&console.groupEnd()}function w(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(m(t.takeRecords()),i())}function h(e){if(!e.__observer){var t=new MutationObserver(m);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function g(e){e=wrap(e),_.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),h(e),_.dom&&console.groupEnd()}function v(e){b(e,g)}var _=e.flags,y=e.forSubtree,b=e.forDocumentTree,E=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=E;var C=!1,M=[],N=Array.prototype.forEach.call.bind(Array.prototype.forEach),T=Element.prototype.createShadowRoot;T&&(Element.prototype.createShadowRoot=function(){var e=T.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=p,e.upgradeDocumentTree=v,e.upgradeSubtree=n,e.upgradeAll=t,e.attachedNode=r,e.takeRecords=w}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var n=t.getAttribute("is"),r=e.getRegisteredDefinition(n||t.localName);if(r){if(n&&r.tag==t.localName)return o(t,r);if(!n&&!r["extends"])return o(t,r)}}}function o(t,o){return i.upgrade&&console.group("upgrade:",t.localName),o.is&&t.setAttribute("is",o.is),n(t,o),t.__upgraded__=!0,a(t),e.attachedNode(t),e.upgradeSubtree(t),i.upgrade&&console.groupEnd(),t}function n(e,t){Object.__proto__?e.__proto__=t.prototype:(r(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function r(e,t,o){for(var n={},r=t;r!==o&&r!==HTMLElement.prototype;){for(var a,i=Object.getOwnPropertyNames(r),u=0;a=i[u];u++)n[a]||(Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(r,a)),n[a]=1);r=Object.getPrototypeOf(r)}}function a(e){e.createdCallback&&e.createdCallback()}var i=e.flags;e.upgrade=t,e.upgradeWithDefinition=o,e.implementPrototype=n}),CustomElements.addModule(function(e){function t(t,n){var d=n||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(r(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(c(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return d.prototype||(d.prototype=Object.create(HTMLElement.prototype)),d.__name=t.toLowerCase(),d.lifecycle=d.lifecycle||{},d.ancestry=a(d["extends"]),i(d),u(d),o(d.prototype),s(d.__name,d),d.ctor=l(d),d.ctor.prototype=d.prototype,d.prototype.constructor=d.ctor,e.ready&&h(document),d.ctor}function o(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,o){n.call(this,e,o,t)};var o=e.removeAttribute;e.removeAttribute=function(e){n.call(this,e,null,o)},e.setAttribute._polyfilled=!0}}function n(e,t,o){e=e.toLowerCase();var n=this.getAttribute(e);o.apply(this,arguments);var r=this.getAttribute(e);this.attributeChangedCallback&&r!==n&&this.attributeChangedCallback(e,n,r)}function r(e){for(var t=0;t<b.length;t++)if(e===b[t])return!0}function a(e){var t=c(e);return t?a(t["extends"]).concat([t]):[]}function i(e){for(var t,o=e["extends"],n=0;t=e.ancestry[n];n++)o=t.is&&t.tag;e.tag=o||e.__name,o&&(e.is=e.__name)}function u(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var o=document.createElement(e.tag),n=Object.getPrototypeOf(o);n===e.prototype&&(t=n)}for(var r,a=e.prototype;a&&a!==t;)r=Object.getPrototypeOf(a),a.__proto__=r,a=r;e["native"]=t}}function d(e){return v(M(e.tag),e)}function c(e){return e?E[e.toLowerCase()]:void 0}function s(e,t){E[e]=t}function l(e){return function(){return d(e)}}function f(e,t,o){return e===C?p(t,o):N(e,t)}function p(e,t){var o=c(t||e);if(o){if(e==o.tag&&t==o.is)return new o.ctor;if(!t&&!o.is)return new o.ctor}var n;return t?(n=p(e),n.setAttribute("is",t),n):(n=M(e),e.indexOf("-")>=0&&_(n,HTMLElement),n)}function m(e){var t=T.call(this,e);return g(t),t}var w,h=e.upgradeDocumentTree,g=e.upgrade,v=e.upgradeWithDefinition,_=e.implementPrototype,y=e.useNative,b=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],E={},C="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),N=document.createElementNS.bind(document),T=Node.prototype.cloneNode;w=Object.__proto__||y?function(e,t){return e instanceof t}:function(e,t){for(var o=e;o;){if(o===t.prototype)return!0;o=o.__proto__}return!1},document.registerElement=t,document.createElement=p,document.createElementNS=f,Node.prototype.cloneNode=m,e.registry=E,e["instanceof"]=w,e.reservedTagList=b,e.getRegisteredDefinition=c,document.register=document.registerElement}),function(e){function t(){i(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){i(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var o=e.useNative,n=e.initializeModules,r=/Trident/.test(navigator.userAgent);if(o){var a=function(){};e.watchShadow=a,e.upgrade=a,e.upgradeAll=a,e.upgradeDocumentTree=a,e.upgradeSubtree=a,e.takeRecords=a,e["instanceof"]=function(e,t){return e instanceof t}}else n();var i=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var o=document.createEvent("CustomEvent");return o.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),o},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var u=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(u,t)}else t()}(window.CustomElements); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.min.js b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.min.js
deleted file mode 100644
index a1a45ce177b..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/HTMLImports.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||h,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===g}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===g)&&(t.removeEventListener(_,o),r(e,t))};t.addEventListener(_,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){s==c&&e&&e()}function r(e){o(e),s++,n()}var i=t.querySelectorAll("link[rel=import]"),s=0,c=i.length;if(c)for(var d,l=0;c>l&&(d=i[l]);l++)a(d)?r.call(d,{target:d}):(d.addEventListener("load",r),d.addEventListener("error",r));else n()}function a(e){return u?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&d(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function d(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var l="import",u=Boolean(l in document.createElement("link")),m=Boolean(window.ShadowDOMPolyfill),p=function(e){return m?ShadowDOMPolyfill.wrapIfNeeded(e):e},h=p(document),f={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return p(e)},configurable:!0};Object.defineProperty(document,"_currentScript",f),Object.defineProperty(h,"_currentScript",f);var v=/Trident|Edge/.test(navigator.userAgent),g=v?"complete":"interactive",_="readystatechange";u&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)d(e)}()),t(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var e=h.createEvent("CustomEvent");e.initCustomEvent("HTMLImportsLoaded",!0,!0,{}),h.dispatchEvent(e)}),e.IMPORT_LINK_TYPE=l,e.useNative=u,e.rootDocument=h,e.whenReady=t,e.isIE=v}(HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e){var t=e.ownerDocument,n=t.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,n),e},resolveUrlsInCssText:function(e,r){var o=this.replaceUrls(e,r,t);return o=this.replaceUrls(o,r,n)},replaceUrls:function(e,t,n){return e.replace(n,function(e,n,r,o){var i=r.replace(/["']/g,"");return t.href=i,i=t.href,n+"'"+i+"'"+o})}};e.path=r}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(){if(4===i.readyState){var e=i.getResponseHeader("Location"),n=null;if(e)var n="/"===e.substr(0,1)?location.origin+e:e;r.call(o,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===l}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,d=e.isIE,l=e.IMPORT_LINK_TYPE,u="link[rel="+l+"]",m={documentSelectors:u,importsSelectors:[u,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(r){t&&t(r),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),d&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(){r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r["import"],r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=m,e.IMPORT_SELECTOR=u}),HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,d=e.Loader,l=e.Observer,u=e.parser,m={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){p.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);p.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n["import"]=c}u.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),u.parseNext()},loadedAll:function(){u.parseNext()}},p=new d(m.loaded.bind(m),m.loadedAll.bind(m));if(m.observer=new l,!document.baseURI){var h={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",h),Object.defineProperty(c,"baseURI",h)}e.importer=m,e.importLoader=p}),HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(o)}var n=e.initializeModules,r=e.isIE;if(!e.useNative){r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),n();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.min.js b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.min.js
deleted file mode 100644
index 72faf74cac2..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/ShadowDOM.min.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.ShadowDOMPolyfill={},function(e){"use strict";function t(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if(navigator.getDeviceStorage)return!1;try{var e=new Function("return true;");return e()}catch(t){return!1}}function n(e){if(!e)throw new Error("Assertion failed")}function r(e,t){for(var n=k(t),r=0;r<n.length;r++){var o=n[r];I(e,o,F(t,o))}return e}function o(e,t){for(var n=k(t),r=0;r<n.length;r++){var o=n[r];switch(o){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":continue}I(e,o,F(t,o))}return e}function i(e,t){for(var n=0;n<t.length;n++)if(t[n]in e)return t[n]}function a(e,t,n){B.value=n,I(e,t,B)}function s(e){var t=e.__proto__||Object.getPrototypeOf(e);if(U)try{k(t)}catch(n){t=t.__proto__}var r=R.get(t);if(r)return r;var o=s(t),i=E(o);return v(t,i,e),i}function c(e,t){m(e,t,!0)}function u(e,t){m(t,e,!1)}function l(e){return/^on[a-z]+$/.test(e)}function p(e){return/^\w[a-zA-Z_0-9]*$/.test(e)}function d(e){return A&&p(e)?new Function("return this.__impl4cf1e782hg__."+e):function(){return this.__impl4cf1e782hg__[e]}}function f(e){return A&&p(e)?new Function("v","this.__impl4cf1e782hg__."+e+" = v"):function(t){this.__impl4cf1e782hg__[e]=t}}function h(e){return A&&p(e)?new Function("return this.__impl4cf1e782hg__."+e+".apply(this.__impl4cf1e782hg__, arguments)"):function(){return this.__impl4cf1e782hg__[e].apply(this.__impl4cf1e782hg__,arguments)}}function w(e,t){try{return Object.getOwnPropertyDescriptor(e,t)}catch(n){return q}}function m(t,n,r){for(var o=k(t),i=0;i<o.length;i++){var a=o[i];if("polymerBlackList_"!==a&&!(a in n||t.polymerBlackList_&&t.polymerBlackList_[a])){U&&t.__lookupGetter__(a);var s,c,u=w(t,a);if(r&&"function"==typeof u.value)n[a]=h(a);else{var p=l(a);s=p?e.getEventHandlerGetter(a):d(a),(u.writable||u.set||V)&&(c=p?e.getEventHandlerSetter(a):f(a));var m=V||u.configurable;I(n,a,{get:s,set:c,configurable:m,enumerable:u.enumerable})}}}}function g(e,t,n){var r=e.prototype;v(r,t,n),o(t,e)}function v(e,t,r){var o=t.prototype;n(void 0===R.get(e)),R.set(e,t),P.set(o,e),c(e,o),r&&u(o,r),a(o,"constructor",t),t.prototype=o}function b(e,t){return R.get(t.prototype)===e}function y(e){var t=Object.getPrototypeOf(e),n=s(t),r=E(n);return v(t,r,e),r}function E(e){function t(t){e.call(this,t)}var n=Object.create(e.prototype);return n.constructor=t,t.prototype=n,t}function S(e){return e&&e.__impl4cf1e782hg__}function M(e){return!S(e)}function T(e){return null===e?null:(n(M(e)),e.__wrapper8e3dd93a60__||(e.__wrapper8e3dd93a60__=new(s(e))(e)))}function O(e){return null===e?null:(n(S(e)),e.__impl4cf1e782hg__)}function L(e){return e.__impl4cf1e782hg__}function j(e,t){t.__impl4cf1e782hg__=e,e.__wrapper8e3dd93a60__=t}function N(e){return e&&S(e)?O(e):e}function _(e){return e&&!S(e)?T(e):e}function C(e,t){null!==t&&(n(M(e)),n(void 0===t||S(t)),e.__wrapper8e3dd93a60__=t)}function D(e,t,n){G.get=n,I(e.prototype,t,G)}function H(e,t){D(e,t,function(){return T(this.__impl4cf1e782hg__[t])})}function x(e,t){e.forEach(function(e){t.forEach(function(t){e.prototype[t]=function(){var e=_(this);return e[t].apply(e,arguments)}})})}var R=new WeakMap,P=new WeakMap,W=Object.create(null),A=t(),I=Object.defineProperty,k=Object.getOwnPropertyNames,F=Object.getOwnPropertyDescriptor,B={value:void 0,configurable:!0,enumerable:!1,writable:!0};k(window);var U=/Firefox/.test(navigator.userAgent),q={get:function(){},set:function(){},configurable:!0,enumerable:!0},V=function(){var e=Object.getOwnPropertyDescriptor(Node.prototype,"nodeType");return e&&!e.get&&!e.set}(),G={get:void 0,configurable:!0,enumerable:!0};e.assert=n,e.constructorTable=R,e.defineGetter=D,e.defineWrapGetter=H,e.forwardMethodsToWrapper=x,e.isWrapper=S,e.isWrapperFor=b,e.mixin=r,e.nativePrototypeTable=P,e.oneOf=i,e.registerObject=y,e.registerWrapper=g,e.rewrap=C,e.setWrapper=j,e.unsafeUnwrap=L,e.unwrap=O,e.unwrapIfNeeded=N,e.wrap=T,e.wrapIfNeeded=_,e.wrappers=W}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t,n){return{index:e,removed:t,addedCount:n}}function n(){}var r=0,o=1,i=2,a=3;n.prototype={calcEditDistances:function(e,t,n,r,o,i){for(var a=i-o+1,s=n-t+1,c=new Array(a),u=0;a>u;u++)c[u]=new Array(s),c[u][0]=u;for(var l=0;s>l;l++)c[0][l]=l;for(var u=1;a>u;u++)for(var l=1;s>l;l++)if(this.equals(e[t+l-1],r[o+u-1]))c[u][l]=c[u-1][l-1];else{var p=c[u-1][l]+1,d=c[u][l-1]+1;c[u][l]=d>p?p:d}return c},spliceOperationsFromEditDistances:function(e){for(var t=e.length-1,n=e[0].length-1,s=e[t][n],c=[];t>0||n>0;)if(0!=t)if(0!=n){var u,l=e[t-1][n-1],p=e[t-1][n],d=e[t][n-1];u=d>p?l>p?p:l:l>d?d:l,u==l?(l==s?c.push(r):(c.push(o),s=l),t--,n--):u==p?(c.push(a),t--,s=p):(c.push(i),n--,s=d)}else c.push(a),t--;else c.push(i),n--;return c.reverse(),c},calcSplices:function(e,n,s,c,u,l){var p=0,d=0,f=Math.min(s-n,l-u);if(0==n&&0==u&&(p=this.sharedPrefix(e,c,f)),s==e.length&&l==c.length&&(d=this.sharedSuffix(e,c,f-p)),n+=p,u+=p,s-=d,l-=d,s-n==0&&l-u==0)return[];if(n==s){for(var h=t(n,[],0);l>u;)h.removed.push(c[u++]);return[h]}if(u==l)return[t(n,[],s-n)];for(var w=this.spliceOperationsFromEditDistances(this.calcEditDistances(e,n,s,c,u,l)),h=void 0,m=[],g=n,v=u,b=0;b<w.length;b++)switch(w[b]){case r:h&&(m.push(h),h=void 0),g++,v++;break;case o:h||(h=t(g,[],0)),h.addedCount++,g++,h.removed.push(c[v]),v++;break;case i:h||(h=t(g,[],0)),h.addedCount++,g++;break;case a:h||(h=t(g,[],0)),h.removed.push(c[v]),v++}return h&&m.push(h),m},sharedPrefix:function(e,t,n){for(var r=0;n>r;r++)if(!this.equals(e[r],t[r]))return r;return n},sharedSuffix:function(e,t,n){for(var r=e.length,o=t.length,i=0;n>i&&this.equals(e[--r],t[--o]);)i++;return i},calculateSplices:function(e,t){return this.calcSplices(e,0,e.length,t,0,t.length)},equals:function(e,t){return e===t}},e.ArraySplice=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(){a=!1;var e=i.slice(0);i=[];for(var t=0;t<e.length;t++)e[t]()}function n(e){i.push(e),a||(a=!0,r(t,0))}var r,o=window.MutationObserver,i=[],a=!1;if(o){var s=1,c=new o(t),u=document.createTextNode(s);c.observe(u,{characterData:!0}),r=function(){s=(s+1)%2,u.data=s}}else r=window.setTimeout;e.setEndOfMicrotask=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.scheduled_||(e.scheduled_=!0,h.push(e),w||(l(n),w=!0))}function n(){for(w=!1;h.length;){var e=h;h=[],e.sort(function(e,t){return e.uid_-t.uid_});for(var t=0;t<e.length;t++){var n=e[t];n.scheduled_=!1;var r=n.takeRecords();i(n),r.length&&n.callback_(r,n)}}}function r(e,t){this.type=e,this.target=t,this.addedNodes=new d.NodeList,this.removedNodes=new d.NodeList,this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function o(e,t){for(;e;e=e.parentNode){var n=f.get(e);if(n)for(var r=0;r<n.length;r++){var o=n[r];o.options.subtree&&o.addTransientObserver(t)}}}function i(e){for(var t=0;t<e.nodes_.length;t++){var n=e.nodes_[t],r=f.get(n);if(!r)return;for(var o=0;o<r.length;o++){var i=r[o];i.observer===e&&i.removeTransientObservers()}}}function a(e,n,o){for(var i=Object.create(null),a=Object.create(null),s=e;s;s=s.parentNode){var c=f.get(s);if(c)for(var u=0;u<c.length;u++){var l=c[u],p=l.options;if((s===e||p.subtree)&&!("attributes"===n&&!p.attributes||"attributes"===n&&p.attributeFilter&&(null!==o.namespace||-1===p.attributeFilter.indexOf(o.name))||"characterData"===n&&!p.characterData||"childList"===n&&!p.childList)){var d=l.observer;i[d.uid_]=d,("attributes"===n&&p.attributeOldValue||"characterData"===n&&p.characterDataOldValue)&&(a[d.uid_]=o.oldValue)}}}for(var h in i){var d=i[h],w=new r(n,e);"name"in o&&"namespace"in o&&(w.attributeName=o.name,w.attributeNamespace=o.namespace),o.addedNodes&&(w.addedNodes=o.addedNodes),o.removedNodes&&(w.removedNodes=o.removedNodes),o.previousSibling&&(w.previousSibling=o.previousSibling),o.nextSibling&&(w.nextSibling=o.nextSibling),void 0!==a[h]&&(w.oldValue=a[h]),t(d),d.records_.push(w)}}function s(e){if(this.childList=!!e.childList,this.subtree=!!e.subtree,this.attributes="attributes"in e||!("attributeOldValue"in e||"attributeFilter"in e)?!!e.attributes:!0,this.characterData="characterDataOldValue"in e&&!("characterData"in e)?!0:!!e.characterData,!this.attributes&&(e.attributeOldValue||"attributeFilter"in e)||!this.characterData&&e.characterDataOldValue)throw new TypeError;if(this.characterData=!!e.characterData,this.attributeOldValue=!!e.attributeOldValue,this.characterDataOldValue=!!e.characterDataOldValue,"attributeFilter"in e){if(null==e.attributeFilter||"object"!=typeof e.attributeFilter)throw new TypeError;this.attributeFilter=m.call(e.attributeFilter)}else this.attributeFilter=null}function c(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++g,this.scheduled_=!1}function u(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var l=e.setEndOfMicrotask,p=e.wrapIfNeeded,d=e.wrappers,f=new WeakMap,h=[],w=!1,m=Array.prototype.slice,g=0;c.prototype={constructor:c,observe:function(e,t){e=p(e);var n,r=new s(t),o=f.get(e);o||f.set(e,o=[]);for(var i=0;i<o.length;i++)o[i].observer===this&&(n=o[i],n.removeTransientObservers(),n.options=r);n||(n=new u(this,e,r),o.push(n),this.nodes_.push(e))},disconnect:function(){this.nodes_.forEach(function(e){for(var t=f.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}},u.prototype={addTransientObserver:function(e){if(e!==this.target){t(this.observer),this.transientObservedNodes.push(e);var n=f.get(e);n||f.set(e,n=[]),n.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[];for(var t=0;t<e.length;t++)for(var n=e[t],r=f.get(n),o=0;o<r.length;o++)if(r[o]===this){r.splice(o,1);break}}},e.enqueueMutation=a,e.registerTransientObservers=o,e.wrappers.MutationObserver=c,e.wrappers.MutationRecord=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){this.root=e,this.parent=t}function n(e,t){if(e.treeScope_!==t){e.treeScope_=t;for(var r=e.shadowRoot;r;r=r.olderShadowRoot)r.treeScope_.parent=t;for(var o=e.firstChild;o;o=o.nextSibling)n(o,t)}}function r(n){if(n instanceof e.wrappers.Window,n.treeScope_)return n.treeScope_;var o,i=n.parentNode;return o=i?r(i):new t(n,null),n.treeScope_=o}t.prototype={get renderer(){return this.root instanceof e.wrappers.ShadowRoot?e.getRendererForHost(this.root.host):null},contains:function(e){for(;e;e=e.parent)if(e===this)return!0;return!1}},e.TreeScope=t,e.getTreeScope=r,e.setTreeScope=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e instanceof G.ShadowRoot}function n(e){return I(e).root}function r(e,r){var s=[],c=e;for(s.push(c);c;){var u=a(c);if(u&&u.length>0){for(var l=0;l<u.length;l++){var d=u[l];if(i(d)){var f=n(d),h=f.olderShadowRoot;h&&s.push(h)}s.push(d)}c=u[u.length-1]}else if(t(c)){if(p(e,c)&&o(r))break;c=c.host,s.push(c)}else c=c.parentNode,c&&s.push(c)}return s}function o(e){if(!e)return!1;switch(e.type){case"abort":case"error":case"select":case"change":case"load":case"reset":case"resize":case"scroll":case"selectstart":return!0}return!1}function i(e){return e instanceof HTMLShadowElement}function a(t){return e.getDestinationInsertionPoints(t)}function s(e,t){if(0===e.length)return t;t instanceof G.Window&&(t=t.document);for(var n=I(t),r=e[0],o=I(r),i=u(n,o),a=0;a<e.length;a++){var s=e[a];if(I(s)===i)return s}return e[e.length-1]}function c(e){for(var t=[];e;e=e.parent)t.push(e);return t}function u(e,t){for(var n=c(e),r=c(t),o=null;n.length>0&&r.length>0;){var i=n.pop(),a=r.pop();if(i!==a)break;o=i}return o}function l(e,t,n){t instanceof G.Window&&(t=t.document);var o,i=I(t),a=I(n),s=r(n,e),o=u(i,a);o||(o=a.root);for(var c=o;c;c=c.parent)for(var l=0;l<s.length;l++){var p=s[l];if(I(p)===c)return p}return null}function p(e,t){return I(e)===I(t)}function d(e){if(!z.get(e)&&(z.set(e,!0),h(V(e),V(e.target)),W)){var t=W;throw W=null,t}}function f(e){switch(e.type){case"load":case"beforeunload":case"unload":return!0}return!1}function h(t,n){if(K.get(t))throw new Error("InvalidStateError");K.set(t,!0),e.renderAllPending();var o,i,a;if(f(t)&&!t.bubbles){var s=n;s instanceof G.Document&&(a=s.defaultView)&&(i=s,o=[])}if(!o)if(n instanceof G.Window)a=n,o=[];else if(o=r(n,t),!f(t)){var s=o[o.length-1];s instanceof G.Document&&(a=s.defaultView)}return nt.set(t,o),w(t,o,a,i)&&m(t,o,a,i)&&g(t,o,a,i),J.set(t,rt),$["delete"](t,null),K["delete"](t),t.defaultPrevented}function w(e,t,n,r){var o=ot;if(n&&!v(n,e,o,t,r))return!1;for(var i=t.length-1;i>0;i--)if(!v(t[i],e,o,t,r))return!1;return!0}function m(e,t,n,r){var o=it,i=t[0]||n;return v(i,e,o,t,r)}function g(e,t,n,r){for(var o=at,i=1;i<t.length;i++)if(!v(t[i],e,o,t,r))return;n&&t.length>0&&v(n,e,o,t,r)}function v(e,t,n,r,o){var i=X.get(e);if(!i)return!0;var a=o||s(r,e);if(a===e){if(n===ot)return!0;n===at&&(n=it)}else if(n===at&&!t.bubbles)return!0;if("relatedTarget"in t){var c=q(t),u=c.relatedTarget;if(u){if(u instanceof Object&&u.addEventListener){var p=V(u),d=l(t,e,p);if(d===a)return!0}else d=null;Z.set(t,d)}}J.set(t,n);var f=t.type,h=!1;Y.set(t,a),$.set(t,e),i.depth++;for(var w=0,m=i.length;m>w;w++){var g=i[w];if(g.removed)h=!0;else if(!(g.type!==f||!g.capture&&n===ot||g.capture&&n===at))try{if("function"==typeof g.handler?g.handler.call(e,t):g.handler.handleEvent(t),et.get(t))return!1}catch(v){W||(W=v)}}if(i.depth--,h&&0===i.depth){var b=i.slice();i.length=0;for(var w=0;w<b.length;w++)b[w].removed||i.push(b[w])}return!Q.get(t)}function b(e,t,n){this.type=e,this.handler=t,this.capture=Boolean(n)}function y(e,t){if(!(e instanceof st))return V(T(st,"Event",e,t));var n=e;return vt||"beforeunload"!==n.type||this instanceof O?void B(n,this):new O(n)}function E(e){return e&&e.relatedTarget?Object.create(e,{relatedTarget:{value:q(e.relatedTarget)}}):e}function S(e,t,n){var r=window[e],o=function(t,n){return t instanceof r?void B(t,this):V(T(r,e,t,n))};if(o.prototype=Object.create(t.prototype),n&&k(o.prototype,n),r)try{F(r,o,new r("temp"))}catch(i){F(r,o,document.createEvent(e))}return o}function M(e,t){return function(){arguments[t]=q(arguments[t]);var n=q(this);n[e].apply(n,arguments)}}function T(e,t,n,r){if(mt)return new e(n,E(r));var o=q(document.createEvent(t)),i=wt[t],a=[n];return Object.keys(i).forEach(function(e){var t=null!=r&&e in r?r[e]:i[e];"relatedTarget"===e&&(t=q(t)),a.push(t)}),o["init"+t].apply(o,a),o}function O(e){y.call(this,e)}function L(e){return"function"==typeof e?!0:e&&e.handleEvent}function j(e){switch(e){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function N(e){B(e,this)}function _(e){return e instanceof G.ShadowRoot&&(e=e.host),q(e)}function C(e,t){var n=X.get(e);if(n)for(var r=0;r<n.length;r++)if(!n[r].removed&&n[r].type===t)return!0;return!1}function D(e,t){for(var n=q(e);n;n=n.parentNode)if(C(V(n),t))return!0;return!1}function H(e){A(e,yt)}function x(t,n,o,i){e.renderAllPending();var a=V(Et.call(U(n),o,i));if(!a)return null;var c=r(a,null),u=c.lastIndexOf(t);return-1==u?null:(c=c.slice(0,u),s(c,t))}function R(e){return function(){var t=tt.get(this);return t&&t[e]&&t[e].value||null}}function P(e){var t=e.slice(2);return function(n){var r=tt.get(this);r||(r=Object.create(null),tt.set(this,r));var o=r[e];if(o&&this.removeEventListener(t,o.wrapped,!1),"function"==typeof n){var i=function(t){var r=n.call(this,t);r===!1?t.preventDefault():"onbeforeunload"===e&&"string"==typeof r&&(t.returnValue=r)};this.addEventListener(t,i,!1),r[e]={value:n,wrapped:i}}}}var W,A=e.forwardMethodsToWrapper,I=e.getTreeScope,k=e.mixin,F=e.registerWrapper,B=e.setWrapper,U=e.unsafeUnwrap,q=e.unwrap,V=e.wrap,G=e.wrappers,X=(new WeakMap,new WeakMap),z=new WeakMap,K=new WeakMap,Y=new WeakMap,$=new WeakMap,Z=new WeakMap,J=new WeakMap,Q=new WeakMap,et=new WeakMap,tt=new WeakMap,nt=new WeakMap,rt=0,ot=1,it=2,at=3;b.prototype={equals:function(e){return this.handler===e.handler&&this.type===e.type&&this.capture===e.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var st=window.Event;st.prototype.polymerBlackList_={returnValue:!0,keyLocation:!0},y.prototype={get target(){return Y.get(this)},get currentTarget(){return $.get(this)},get eventPhase(){return J.get(this)},get path(){var e=nt.get(this);return e?e.slice():[]},stopPropagation:function(){Q.set(this,!0)},stopImmediatePropagation:function(){Q.set(this,!0),et.set(this,!0)}},F(st,y,document.createEvent("Event"));var ct=S("UIEvent",y),ut=S("CustomEvent",y),lt={get relatedTarget(){var e=Z.get(this);return void 0!==e?e:V(q(this).relatedTarget)}},pt=k({initMouseEvent:M("initMouseEvent",14)},lt),dt=k({initFocusEvent:M("initFocusEvent",5)},lt),ft=S("MouseEvent",ct,pt),ht=S("FocusEvent",ct,dt),wt=Object.create(null),mt=function(){try{new window.FocusEvent("focus")}catch(e){return!1}return!0}();if(!mt){var gt=function(e,t,n){if(n){var r=wt[n];t=k(k({},r),t)}wt[e]=t};gt("Event",{bubbles:!1,cancelable:!1}),gt("CustomEvent",{detail:null},"Event"),gt("UIEvent",{view:null,detail:0},"Event"),gt("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),gt("FocusEvent",{relatedTarget:null},"UIEvent")}var vt=window.BeforeUnloadEvent;O.prototype=Object.create(y.prototype),k(O.prototype,{get returnValue(){return U(this).returnValue},set returnValue(e){U(this).returnValue=e}}),vt&&F(vt,O);var bt=window.EventTarget,yt=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(e){var t=e.prototype;yt.forEach(function(e){Object.defineProperty(t,e+"_",{value:t[e]})})}),N.prototype={addEventListener:function(e,t,n){if(L(t)&&!j(e)){var r=new b(e,t,n),o=X.get(this);if(o){for(var i=0;i<o.length;i++)if(r.equals(o[i]))return}else o=[],o.depth=0,X.set(this,o);o.push(r);var a=_(this);a.addEventListener_(e,d,!0)}},removeEventListener:function(e,t,n){n=Boolean(n);var r=X.get(this);if(r){for(var o=0,i=!1,a=0;a<r.length;a++)r[a].type===e&&r[a].capture===n&&(o++,r[a].handler===t&&(i=!0,r[a].remove()));if(i&&1===o){var s=_(this);s.removeEventListener_(e,d,!0)}}},dispatchEvent:function(t){var n=q(t),r=n.type;z.set(n,!1),e.renderAllPending();var o;D(this,r)||(o=function(){},this.addEventListener(r,o,!0));try{return q(this).dispatchEvent_(n)}finally{o&&this.removeEventListener(r,o,!0)}}},bt&&F(bt,N);var Et=document.elementFromPoint;e.elementFromPoint=x,e.getEventHandlerGetter=R,e.getEventHandlerSetter=P,e.wrapEventTargetMethods=H,e.wrappers.BeforeUnloadEvent=O,e.wrappers.CustomEvent=ut,e.wrappers.Event=y,e.wrappers.EventTarget=N,e.wrappers.FocusEvent=ht,e.wrappers.MouseEvent=ft,e.wrappers.UIEvent=ct}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,w)}function n(e){u(e,this)}function r(){this.length=0,t(this,"length")}function o(e){for(var t=new r,o=0;o<e.length;o++)t[o]=new n(e[o]);return t.length=o,t}function i(e){a.call(this,e)}var a=e.wrappers.UIEvent,s=e.mixin,c=e.registerWrapper,u=e.setWrapper,l=e.unsafeUnwrap,p=e.wrap,d=window.TouchEvent;if(d){var f;try{f=document.createEvent("TouchEvent")}catch(h){return}var w={enumerable:!1};n.prototype={get target(){return p(l(this).target)}};var m={configurable:!0,enumerable:!0,get:null};["clientX","clientY","screenX","screenY","pageX","pageY","identifier","webkitRadiusX","webkitRadiusY","webkitRotationAngle","webkitForce"].forEach(function(e){m.get=function(){return l(this)[e]},Object.defineProperty(n.prototype,e,m)}),r.prototype={item:function(e){return this[e]}},i.prototype=Object.create(a.prototype),s(i.prototype,{get touches(){return o(l(this).touches)},get targetTouches(){return o(l(this).targetTouches)},get changedTouches(){return o(l(this).changedTouches)},initTouchEvent:function(){throw new Error("Not implemented")}}),c(d,i,f),e.wrappers.Touch=n,e.wrappers.TouchEvent=i,e.wrappers.TouchList=r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,s)}function n(){this.length=0,t(this,"length")}function r(e){if(null==e)return e;for(var t=new n,r=0,o=e.length;o>r;r++)t[r]=a(e[r]);return t.length=o,t}function o(e,t){e.prototype[t]=function(){return r(i(this)[t].apply(i(this),arguments))}}var i=e.unsafeUnwrap,a=e.wrap,s={enumerable:!1};n.prototype={item:function(e){return this[e]}},t(n.prototype,"item"),e.wrappers.NodeList=n,e.addWrapNodeListMethod=o,e.wrapNodeList=r}(window.ShadowDOMPolyfill),function(e){"use strict";e.wrapHTMLCollection=e.wrapNodeList,e.wrappers.HTMLCollection=e.wrappers.NodeList}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){L(e instanceof S)}function n(e){var t=new T;return t[0]=e,t.length=1,t}function r(e,t,n){N(t,"childList",{removedNodes:n,previousSibling:e.previousSibling,nextSibling:e.nextSibling})}function o(e,t){N(e,"childList",{removedNodes:t})}function i(e,t,r,o){if(e instanceof DocumentFragment){var i=s(e);B=!0;for(var a=i.length-1;a>=0;a--)e.removeChild(i[a]),i[a].parentNode_=t;B=!1;for(var a=0;a<i.length;a++)i[a].previousSibling_=i[a-1]||r,i[a].nextSibling_=i[a+1]||o;return r&&(r.nextSibling_=i[0]),o&&(o.previousSibling_=i[i.length-1]),i}var i=n(e),c=e.parentNode;return c&&c.removeChild(e),e.parentNode_=t,e.previousSibling_=r,e.nextSibling_=o,r&&(r.nextSibling_=e),o&&(o.previousSibling_=e),i}function a(e){if(e instanceof DocumentFragment)return s(e);var t=n(e),o=e.parentNode;return o&&r(e,o,t),t}function s(e){for(var t=new T,n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t.length=n,o(e,t),t}function c(e){return e}function u(e,t){R(e,t),e.nodeIsInserted_()}function l(e,t){for(var n=_(t),r=0;r<e.length;r++)u(e[r],n)}function p(e){R(e,new O(e,null))}function d(e){for(var t=0;t<e.length;t++)p(e[t])}function f(e,t){var n=e.nodeType===S.DOCUMENT_NODE?e:e.ownerDocument;n!==t.ownerDocument&&n.adoptNode(t)}function h(t,n){if(n.length){var r=t.ownerDocument;if(r!==n[0].ownerDocument)for(var o=0;o<n.length;o++)e.adoptNodeNoRemove(n[o],r)}}function w(e,t){h(e,t);var n=t.length;if(1===n)return W(t[0]);for(var r=W(e.ownerDocument.createDocumentFragment()),o=0;n>o;o++)r.appendChild(W(t[o]));return r}function m(e){if(void 0!==e.firstChild_)for(var t=e.firstChild_;t;){var n=t;t=t.nextSibling_,n.parentNode_=n.previousSibling_=n.nextSibling_=void 0}e.firstChild_=e.lastChild_=void 0}function g(e){if(e.invalidateShadowRenderer()){for(var t=e.firstChild;t;){L(t.parentNode===e);var n=t.nextSibling,r=W(t),o=r.parentNode;o&&K.call(o,r),t.previousSibling_=t.nextSibling_=t.parentNode_=null,t=n}e.firstChild_=e.lastChild_=null}else for(var n,i=W(e),a=i.firstChild;a;)n=a.nextSibling,K.call(i,a),a=n}function v(e){var t=e.parentNode;return t&&t.invalidateShadowRenderer()}function b(e){for(var t,n=0;n<e.length;n++)t=e[n],t.parentNode.removeChild(t)}function y(e,t,n){var r;if(r=I(n?U.call(n,P(e),!1):q.call(P(e),!1)),t){for(var o=e.firstChild;o;o=o.nextSibling)r.appendChild(y(o,!0,n));if(e instanceof F.HTMLTemplateElement)for(var i=r.content,o=e.content.firstChild;o;o=o.nextSibling)i.appendChild(y(o,!0,n))}return r}function E(e,t){if(!t||_(e)!==_(t))return!1;for(var n=t;n;n=n.parentNode)if(n===e)return!0;return!1}function S(e){L(e instanceof V),M.call(this,e),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0,this.treeScope_=void 0}var M=e.wrappers.EventTarget,T=e.wrappers.NodeList,O=e.TreeScope,L=e.assert,j=e.defineWrapGetter,N=e.enqueueMutation,_=e.getTreeScope,C=e.isWrapper,D=e.mixin,H=e.registerTransientObservers,x=e.registerWrapper,R=e.setTreeScope,P=e.unsafeUnwrap,W=e.unwrap,A=e.unwrapIfNeeded,I=e.wrap,k=e.wrapIfNeeded,F=e.wrappers,B=!1,U=document.importNode,q=window.Node.prototype.cloneNode,V=window.Node,G=window.DocumentFragment,X=(V.prototype.appendChild,V.prototype.compareDocumentPosition),z=V.prototype.insertBefore,K=V.prototype.removeChild,Y=V.prototype.replaceChild,$=/Trident|Edge/.test(navigator.userAgent),Z=$?function(e,t){try{K.call(e,t)}catch(n){if(!(e instanceof G))throw n}}:function(e,t){K.call(e,t)};S.prototype=Object.create(M.prototype),D(S.prototype,{appendChild:function(e){return this.insertBefore(e,null)},insertBefore:function(e,n){t(e);var r;n?C(n)?r=W(n):(r=n,n=I(r)):(n=null,r=null),n&&L(n.parentNode===this);var o,s=n?n.previousSibling:this.lastChild,c=!this.invalidateShadowRenderer()&&!v(e);if(o=c?a(e):i(e,this,s,n),c)f(this,e),m(this),z.call(P(this),W(e),r);else{s||(this.firstChild_=o[0]),n||(this.lastChild_=o[o.length-1],void 0===this.firstChild_&&(this.firstChild_=this.firstChild));var u=r?r.parentNode:P(this);u?z.call(u,w(this,o),r):h(this,o)}return N(this,"childList",{addedNodes:o,nextSibling:n,previousSibling:s}),l(o,this),e},removeChild:function(e){if(t(e),e.parentNode!==this){for(var r=!1,o=(this.childNodes,this.firstChild);o;o=o.nextSibling)if(o===e){r=!0;break}if(!r)throw new Error("NotFoundError")}var i=W(e),a=e.nextSibling,s=e.previousSibling;if(this.invalidateShadowRenderer()){var c=this.firstChild,u=this.lastChild,l=i.parentNode;l&&Z(l,i),c===e&&(this.firstChild_=a),u===e&&(this.lastChild_=s),s&&(s.nextSibling_=a),a&&(a.previousSibling_=s),e.previousSibling_=e.nextSibling_=e.parentNode_=void 0}else m(this),Z(P(this),i);return B||N(this,"childList",{removedNodes:n(e),nextSibling:a,previousSibling:s}),H(this,e),e},replaceChild:function(e,r){t(e);var o;if(C(r)?o=W(r):(o=r,r=I(o)),r.parentNode!==this)throw new Error("NotFoundError");var s,c=r.nextSibling,u=r.previousSibling,d=!this.invalidateShadowRenderer()&&!v(e);return d?s=a(e):(c===e&&(c=e.nextSibling),s=i(e,this,u,c)),d?(f(this,e),m(this),Y.call(P(this),W(e),o)):(this.firstChild===r&&(this.firstChild_=s[0]),this.lastChild===r&&(this.lastChild_=s[s.length-1]),r.previousSibling_=r.nextSibling_=r.parentNode_=void 0,o.parentNode&&Y.call(o.parentNode,w(this,s),o)),N(this,"childList",{addedNodes:s,removedNodes:n(r),nextSibling:c,previousSibling:u}),p(r),l(s,this),r},nodeIsInserted_:function(){for(var e=this.firstChild;e;e=e.nextSibling)e.nodeIsInserted_()},hasChildNodes:function(){return null!==this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:I(P(this).parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:I(P(this).firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:I(P(this).lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:I(P(this).nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:I(P(this).previousSibling)},get parentElement(){for(var e=this.parentNode;e&&e.nodeType!==S.ELEMENT_NODE;)e=e.parentNode;return e},get textContent(){for(var e="",t=this.firstChild;t;t=t.nextSibling)t.nodeType!=S.COMMENT_NODE&&(e+=t.textContent);return e},set textContent(e){null==e&&(e="");var t=c(this.childNodes);if(this.invalidateShadowRenderer()){if(g(this),""!==e){var n=P(this).ownerDocument.createTextNode(e);this.appendChild(n)}}else m(this),P(this).textContent=e;var r=c(this.childNodes);N(this,"childList",{addedNodes:r,removedNodes:t}),d(t),l(r,this)},get childNodes(){for(var e=new T,t=0,n=this.firstChild;n;n=n.nextSibling)e[t++]=n;return e.length=t,e},cloneNode:function(e){return y(this,e)},contains:function(e){return E(this,k(e))},compareDocumentPosition:function(e){return X.call(P(this),A(e))},normalize:function(){for(var e,t,n=c(this.childNodes),r=[],o="",i=0;i<n.length;i++)t=n[i],t.nodeType===S.TEXT_NODE?e||t.data.length?e?(o+=t.data,r.push(t)):e=t:this.removeChild(t):(e&&r.length&&(e.data+=o,b(r)),r=[],o="",e=null,t.childNodes.length&&t.normalize());e&&r.length&&(e.data+=o,b(r))}}),j(S,"ownerDocument"),x(V,S,document.createDocumentFragment()),delete S.prototype.querySelector,delete S.prototype.querySelectorAll,S.prototype=D(Object.create(M.prototype),S.prototype),e.cloneNode=y,e.nodeWasAdded=u,e.nodeWasRemoved=p,e.nodesWereAdded=l,e.nodesWereRemoved=d,e.originalInsertBefore=z,e.originalRemoveChild=K,e.snapshotNodeList=c,e.wrappers.Node=S}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n,r,o){for(var i=null,a=null,s=0,c=t.length;c>s;s++)i=b(t[s]),!o&&(a=g(i).root)&&a instanceof e.wrappers.ShadowRoot||(r[n++]=i);return n}function n(e){return String(e).replace(/\/deep\/|::shadow/g," ")}function r(e){return String(e).replace(/:host\(([^\s]+)\)/g,"$1").replace(/([^\s]):host/g,"$1").replace(":host","*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content/g," ")}function o(e,t){for(var n,r=e.firstElementChild;r;){if(r.matches(t))return r;if(n=o(r,t))return n;r=r.nextElementSibling}return null}function i(e,t){return e.matches(t)}function a(e,t,n){var r=e.localName;return r===t||r===n&&e.namespaceURI===C}function s(){return!0}function c(e,t,n){return e.localName===n}function u(e,t){return e.namespaceURI===t}function l(e,t,n){return e.namespaceURI===t&&e.localName===n}function p(e,t,n,r,o,i){for(var a=e.firstElementChild;a;)r(a,o,i)&&(n[t++]=a),t=p(a,t,n,r,o,i),a=a.nextElementSibling;return t}function d(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,null);if(c instanceof N)s=M.call(c,i);else{if(!(c instanceof _))return p(this,r,o,n,i,null);s=S.call(c,i)}return t(s,r,o,a)}function f(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,a);if(c instanceof N)s=O.call(c,i,a);else{if(!(c instanceof _))return p(this,r,o,n,i,a);s=T.call(c,i,a)}return t(s,r,o,!1)}function h(n,r,o,i,a){var s,c=v(this),u=g(this).root;if(u instanceof e.wrappers.ShadowRoot)return p(this,r,o,n,i,a);if(c instanceof N)s=j.call(c,i,a);else{if(!(c instanceof _))return p(this,r,o,n,i,a);s=L.call(c,i,a)}return t(s,r,o,!1)}var w=e.wrappers.HTMLCollection,m=e.wrappers.NodeList,g=e.getTreeScope,v=e.unsafeUnwrap,b=e.wrap,y=document.querySelector,E=document.documentElement.querySelector,S=document.querySelectorAll,M=document.documentElement.querySelectorAll,T=document.getElementsByTagName,O=document.documentElement.getElementsByTagName,L=document.getElementsByTagNameNS,j=document.documentElement.getElementsByTagNameNS,N=window.Element,_=window.HTMLDocument||window.Document,C="http://www.w3.org/1999/xhtml",D={querySelector:function(t){var r=n(t),i=r!==t;t=r;var a,s=v(this),c=g(this).root;if(c instanceof e.wrappers.ShadowRoot)return o(this,t);if(s instanceof N)a=b(E.call(s,t));else{if(!(s instanceof _))return o(this,t);a=b(y.call(s,t))}return a&&!i&&(c=g(a).root)&&c instanceof e.wrappers.ShadowRoot?o(this,t):a},querySelectorAll:function(e){var t=n(e),r=t!==e;e=t;var o=new m;return o.length=d.call(this,i,0,o,e,r),o}},H={matches:function(t){return t=r(t),e.originalMatches.call(v(this),t)}},x={getElementsByTagName:function(e){var t=new w,n="*"===e?s:a;return t.length=f.call(this,n,0,t,e,e.toLowerCase()),t},getElementsByClassName:function(e){return this.querySelectorAll("."+e)},getElementsByTagNameNS:function(e,t){var n=new w,r=null;return r="*"===e?"*"===t?s:c:"*"===t?u:l,n.length=h.call(this,r,0,n,e||null,t),n}};e.GetElementsByInterface=x,e.SelectorsInterface=D,e.MatchesInterface=H}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;return e}function n(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.previousSibling;return e}var r=e.wrappers.NodeList,o={get firstElementChild(){return t(this.firstChild)
-},get lastElementChild(){return n(this.lastChild)},get childElementCount(){for(var e=0,t=this.firstElementChild;t;t=t.nextElementSibling)e++;return e},get children(){for(var e=new r,t=0,n=this.firstElementChild;n;n=n.nextElementSibling)e[t++]=n;return e.length=t,e},remove:function(){var e=this.parentNode;e&&e.removeChild(this)}},i={get nextElementSibling(){return t(this.nextSibling)},get previousElementSibling(){return n(this.previousSibling)}};e.ChildNodeInterface=i,e.ParentNodeInterface=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}var n=e.ChildNodeInterface,r=e.wrappers.Node,o=e.enqueueMutation,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=window.CharacterData;t.prototype=Object.create(r.prototype),i(t.prototype,{get textContent(){return this.data},set textContent(e){this.data=e},get data(){return s(this).data},set data(e){var t=s(this).data;o(this,"characterData",{oldValue:t}),s(this).data=e}}),i(t.prototype,n),a(c,t,document.createTextNode("")),e.wrappers.CharacterData=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e>>>0}function n(e){r.call(this,e)}var r=e.wrappers.CharacterData,o=(e.enqueueMutation,e.mixin),i=e.registerWrapper,a=window.Text;n.prototype=Object.create(r.prototype),o(n.prototype,{splitText:function(e){e=t(e);var n=this.data;if(e>n.length)throw new Error("IndexSizeError");var r=n.slice(0,e),o=n.slice(e);this.data=r;var i=this.ownerDocument.createTextNode(o);return this.parentNode&&this.parentNode.insertBefore(i,this.nextSibling),i}}),i(a,n,document.createTextNode("")),e.wrappers.Text=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return i(e).getAttribute("class")}function n(e,t){a(e,"attributes",{name:"class",namespace:null,oldValue:t})}function r(t){e.invalidateRendererBasedOnAttribute(t,"class")}function o(e,o,i){var a=e.ownerElement_;if(null==a)return o.apply(e,i);var s=t(a),c=o.apply(e,i);return t(a)!==s&&(n(a,s),r(a)),c}if(!window.DOMTokenList)return void console.warn("Missing DOMTokenList prototype, please include a compatible classList polyfill such as http://goo.gl/uTcepH.");var i=e.unsafeUnwrap,a=e.enqueueMutation,s=DOMTokenList.prototype.add;DOMTokenList.prototype.add=function(){o(this,s,arguments)};var c=DOMTokenList.prototype.remove;DOMTokenList.prototype.remove=function(){o(this,c,arguments)};var u=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(){return o(this,u,arguments)}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n){var r=t.parentNode;if(r&&r.shadowRoot){var o=e.getRendererForHost(r);o.dependsOnAttribute(n)&&o.invalidate()}}function n(e,t,n){l(e,"attributes",{name:t,namespace:null,oldValue:n})}function r(e){a.call(this,e)}var o=e.ChildNodeInterface,i=e.GetElementsByInterface,a=e.wrappers.Node,s=e.ParentNodeInterface,c=e.SelectorsInterface,u=e.MatchesInterface,l=(e.addWrapNodeListMethod,e.enqueueMutation),p=e.mixin,d=(e.oneOf,e.registerWrapper),f=e.unsafeUnwrap,h=e.wrappers,w=window.Element,m=["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"].filter(function(e){return w.prototype[e]}),g=m[0],v=w.prototype[g],b=new WeakMap;r.prototype=Object.create(a.prototype),p(r.prototype,{createShadowRoot:function(){var t=new h.ShadowRoot(this);f(this).polymerShadowRoot_=t;var n=e.getRendererForHost(this);return n.invalidate(),t},get shadowRoot(){return f(this).polymerShadowRoot_||null},setAttribute:function(e,r){var o=f(this).getAttribute(e);f(this).setAttribute(e,r),n(this,e,o),t(this,e)},removeAttribute:function(e){var r=f(this).getAttribute(e);f(this).removeAttribute(e),n(this,e,r),t(this,e)},get classList(){var e=b.get(this);if(!e){if(e=f(this).classList,!e)return;e.ownerElement_=this,b.set(this,e)}return e},get className(){return f(this).className},set className(e){this.setAttribute("class",e)},get id(){return f(this).id},set id(e){this.setAttribute("id",e)}}),m.forEach(function(e){"matches"!==e&&(r.prototype[e]=function(e){return this.matches(e)})}),w.prototype.webkitCreateShadowRoot&&(r.prototype.webkitCreateShadowRoot=r.prototype.createShadowRoot),p(r.prototype,o),p(r.prototype,i),p(r.prototype,s),p(r.prototype,c),p(r.prototype,u),d(w,r,document.createElementNS(null,"x")),e.invalidateRendererBasedOnAttribute=t,e.matchesNames=m,e.originalMatches=v,e.wrappers.Element=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e){case"&":return"&amp;";case"<":return"&lt;";case">":return"&gt;";case'"':return"&quot;";case" ":return"&nbsp;"}}function n(e){return e.replace(L,t)}function r(e){return e.replace(j,t)}function o(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=!0;return t}function i(e,t){switch(e.nodeType){case Node.ELEMENT_NODE:for(var o,i=e.tagName.toLowerCase(),s="<"+i,c=e.attributes,u=0;o=c[u];u++)s+=" "+o.name+'="'+n(o.value)+'"';return s+=">",N[i]?s:s+a(e)+"</"+i+">";case Node.TEXT_NODE:var l=e.data;return t&&_[t.localName]?l:r(l);case Node.COMMENT_NODE:return"<!--"+e.data+"-->";default:throw console.error(e),new Error("not implemented")}}function a(e){e instanceof O.HTMLTemplateElement&&(e=e.content);for(var t="",n=e.firstChild;n;n=n.nextSibling)t+=i(n,e);return t}function s(e,t,n){var r=n||"div";e.textContent="";var o=M(e.ownerDocument.createElement(r));o.innerHTML=t;for(var i;i=o.firstChild;)e.appendChild(T(i))}function c(e){h.call(this,e)}function u(e,t){var n=M(e.cloneNode(!1));n.innerHTML=t;for(var r,o=M(document.createDocumentFragment());r=n.firstChild;)o.appendChild(r);return T(o)}function l(t){return function(){return e.renderAllPending(),S(this)[t]}}function p(e){w(c,e,l(e))}function d(t){Object.defineProperty(c.prototype,t,{get:l(t),set:function(n){e.renderAllPending(),S(this)[t]=n},configurable:!0,enumerable:!0})}function f(t){Object.defineProperty(c.prototype,t,{value:function(){return e.renderAllPending(),S(this)[t].apply(S(this),arguments)},configurable:!0,enumerable:!0})}var h=e.wrappers.Element,w=e.defineGetter,m=e.enqueueMutation,g=e.mixin,v=e.nodesWereAdded,b=e.nodesWereRemoved,y=e.registerWrapper,E=e.snapshotNodeList,S=e.unsafeUnwrap,M=e.unwrap,T=e.wrap,O=e.wrappers,L=/[&\u00A0"]/g,j=/[&\u00A0<>]/g,N=o(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),_=o(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),C=/MSIE/.test(navigator.userAgent),D=window.HTMLElement,H=window.HTMLTemplateElement;c.prototype=Object.create(h.prototype),g(c.prototype,{get innerHTML(){return a(this)},set innerHTML(e){if(C&&_[this.localName])return void(this.textContent=e);var t=E(this.childNodes);this.invalidateShadowRenderer()?this instanceof O.HTMLTemplateElement?s(this.content,e):s(this,e,this.tagName):!H&&this instanceof O.HTMLTemplateElement?s(this.content,e):S(this).innerHTML=e;var n=E(this.childNodes);m(this,"childList",{addedNodes:n,removedNodes:t}),b(t),v(n,this)},get outerHTML(){return i(this,this.parentNode)},set outerHTML(e){var t=this.parentNode;if(t){t.invalidateShadowRenderer();var n=u(t,e);t.replaceChild(n,this)}},insertAdjacentHTML:function(e,t){var n,r;switch(String(e).toLowerCase()){case"beforebegin":n=this.parentNode,r=this;break;case"afterend":n=this.parentNode,r=this.nextSibling;break;case"afterbegin":n=this,r=this.firstChild;break;case"beforeend":n=this,r=null;break;default:return}var o=u(n,t);n.insertBefore(o,r)},get hidden(){return this.hasAttribute("hidden")},set hidden(e){e?this.setAttribute("hidden",""):this.removeAttribute("hidden")}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollWidth"].forEach(p),["scrollLeft","scrollTop"].forEach(d),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(f),y(D,c,document.createElement("b")),e.wrappers.HTMLElement=c,e.getInnerHTML=a,e.setInnerHTML=s}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.HTMLCanvasElement;t.prototype=Object.create(n.prototype),r(t.prototype,{getContext:function(){var e=i(this).getContext.apply(i(this),arguments);return e&&a(e)}}),o(s,t,document.createElement("canvas")),e.wrappers.HTMLCanvasElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=window.HTMLContentElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get select(){return this.getAttribute("select")},set select(e){this.setAttribute("select",e)},setAttribute:function(e,t){n.prototype.setAttribute.call(this,e,t),"select"===String(e).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),i&&o(i,t),e.wrappers.HTMLContentElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=window.HTMLFormElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get elements(){return i(a(this).elements)}}),o(s,t,document.createElement("form")),e.wrappers.HTMLFormElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e,t){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var o=i(document.createElement("img"));r.call(this,o),a(o,this),void 0!==e&&(o.width=e),void 0!==t&&(o.height=t)}var r=e.wrappers.HTMLElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLImageElement;t.prototype=Object.create(r.prototype),o(s,t,document.createElement("img")),n.prototype=t.prototype,e.wrappers.HTMLImageElement=t,e.wrappers.Image=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=(e.mixin,e.wrappers.NodeList,e.registerWrapper),o=window.HTMLShadowElement;t.prototype=Object.create(n.prototype),t.prototype.constructor=t,o&&r(o,t),e.wrappers.HTMLShadowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){if(!e.defaultView)return e;var t=p.get(e);if(!t){for(t=e.implementation.createHTMLDocument("");t.lastChild;)t.removeChild(t.lastChild);p.set(e,t)}return t}function n(e){for(var n,r=t(e.ownerDocument),o=c(r.createDocumentFragment());n=e.firstChild;)o.appendChild(n);return o}function r(e){if(o.call(this,e),!d){var t=n(e);l.set(this,u(t))}}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=e.unwrap,u=e.wrap,l=new WeakMap,p=new WeakMap,d=window.HTMLTemplateElement;r.prototype=Object.create(o.prototype),i(r.prototype,{constructor:r,get content(){return d?u(s(this).content):l.get(this)}}),d&&a(d,r),e.wrappers.HTMLTemplateElement=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.registerWrapper,o=window.HTMLMediaElement;o&&(t.prototype=Object.create(n.prototype),r(o,t,document.createElement("audio")),e.wrappers.HTMLMediaElement=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var t=i(document.createElement("audio"));r.call(this,t),a(t,this),t.setAttribute("preload","auto"),void 0!==e&&t.setAttribute("src",e)}var r=e.wrappers.HTMLMediaElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLAudioElement;s&&(t.prototype=Object.create(r.prototype),o(s,t,document.createElement("audio")),n.prototype=t.prototype,e.wrappers.HTMLAudioElement=t,e.wrappers.Audio=n)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e.replace(/\s+/g," ").trim()}function n(e){o.call(this,e)}function r(e,t,n,i){if(!(this instanceof r))throw new TypeError("DOM object constructor cannot be called as a function.");var a=c(document.createElement("option"));o.call(this,a),s(a,this),void 0!==e&&(a.text=e),void 0!==t&&a.setAttribute("value",t),n===!0&&a.setAttribute("selected",""),a.selected=i===!0}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.rewrap,c=e.unwrap,u=e.wrap,l=window.HTMLOptionElement;n.prototype=Object.create(o.prototype),i(n.prototype,{get text(){return t(this.textContent)},set text(e){this.textContent=t(String(e))},get form(){return u(c(this).form)}}),a(l,n,document.createElement("option")),r.prototype=n.prototype,e.wrappers.HTMLOptionElement=n,e.wrappers.Option=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=window.HTMLSelectElement;t.prototype=Object.create(n.prototype),r(t.prototype,{add:function(e,t){"object"==typeof t&&(t=i(t)),i(this).add(i(e),t)},remove:function(e){return void 0===e?void n.prototype.remove.call(this):("object"==typeof e&&(e=i(e)),void i(this).remove(e))},get form(){return a(i(this).form)}}),o(s,t,document.createElement("select")),e.wrappers.HTMLSelectElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=e.wrapHTMLCollection,c=window.HTMLTableElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get caption(){return a(i(this).caption)},createCaption:function(){return a(i(this).createCaption())},get tHead(){return a(i(this).tHead)},createTHead:function(){return a(i(this).createTHead())},createTFoot:function(){return a(i(this).createTFoot())},get tFoot(){return a(i(this).tFoot)},get tBodies(){return s(i(this).tBodies)},createTBody:function(){return a(i(this).createTBody())},get rows(){return s(i(this).rows)},insertRow:function(e){return a(i(this).insertRow(e))}}),o(c,t,document.createElement("table")),e.wrappers.HTMLTableElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableSectionElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get rows(){return i(a(this).rows)},insertRow:function(e){return s(a(this).insertRow(e))}}),o(c,t,document.createElement("thead")),e.wrappers.HTMLTableSectionElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableRowElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get cells(){return i(a(this).cells)},insertCell:function(e){return s(a(this).insertCell(e))}}),o(c,t,document.createElement("tr")),e.wrappers.HTMLTableRowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e.localName){case"content":return new n(e);case"shadow":return new o(e);case"template":return new i(e)}r.call(this,e)}var n=e.wrappers.HTMLContentElement,r=e.wrappers.HTMLElement,o=e.wrappers.HTMLShadowElement,i=e.wrappers.HTMLTemplateElement,a=(e.mixin,e.registerWrapper),s=window.HTMLUnknownElement;t.prototype=Object.create(r.prototype),a(s,t),e.wrappers.HTMLUnknownElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.wrappers.Element,n=e.wrappers.HTMLElement,r=e.registerObject,o=e.defineWrapGetter,i="http://www.w3.org/2000/svg",a=document.createElementNS(i,"title"),s=r(a),c=Object.getPrototypeOf(s.prototype).constructor;if(!("classList"in a)){var u=Object.getOwnPropertyDescriptor(t.prototype,"classList");Object.defineProperty(n.prototype,"classList",u),delete t.prototype.classList}o(c,"ownerSVGElement"),e.wrappers.SVGElement=c}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){d.call(this,e)}var n=e.mixin,r=e.registerWrapper,o=e.unwrap,i=e.wrap,a=window.SVGUseElement,s="http://www.w3.org/2000/svg",c=i(document.createElementNS(s,"g")),u=document.createElementNS(s,"use"),l=c.constructor,p=Object.getPrototypeOf(l.prototype),d=p.constructor;t.prototype=Object.create(p),"instanceRoot"in u&&n(t.prototype,{get instanceRoot(){return i(o(this).instanceRoot)},get animatedInstanceRoot(){return i(o(this).animatedInstanceRoot)}}),r(a,t,u),e.wrappers.SVGUseElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.SVGElementInstance;s&&(t.prototype=Object.create(n.prototype),r(t.prototype,{get correspondingElement(){return a(i(this).correspondingElement)},get correspondingUseElement(){return a(i(this).correspondingUseElement)},get parentNode(){return a(i(this).parentNode)},get childNodes(){throw new Error("Not implemented")},get firstChild(){return a(i(this).firstChild)},get lastChild(){return a(i(this).lastChild)},get previousSibling(){return a(i(this).previousSibling)},get nextSibling(){return a(i(this).nextSibling)}}),o(s,t),e.wrappers.SVGElementInstance=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrap,s=e.unwrapIfNeeded,c=e.wrap,u=window.CanvasRenderingContext2D;n(t.prototype,{get canvas(){return c(i(this).canvas)},drawImage:function(){arguments[0]=s(arguments[0]),i(this).drawImage.apply(i(this),arguments)},createPattern:function(){return arguments[0]=a(arguments[0]),i(this).createPattern.apply(i(this),arguments)}}),r(u,t,document.createElement("canvas").getContext("2d")),e.wrappers.CanvasRenderingContext2D=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.WebGLRenderingContext;if(c){n(t.prototype,{get canvas(){return s(i(this).canvas)},texImage2D:function(){arguments[5]=a(arguments[5]),i(this).texImage2D.apply(i(this),arguments)},texSubImage2D:function(){arguments[6]=a(arguments[6]),i(this).texSubImage2D.apply(i(this),arguments)}});var u=/WebKit/.test(navigator.userAgent)?{drawingBufferHeight:null,drawingBufferWidth:null}:{};r(c,t,u),e.wrappers.WebGLRenderingContext=t}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.Range;t.prototype={get startContainer(){return s(o(this).startContainer)},get endContainer(){return s(o(this).endContainer)},get commonAncestorContainer(){return s(o(this).commonAncestorContainer)},setStart:function(e,t){o(this).setStart(a(e),t)},setEnd:function(e,t){o(this).setEnd(a(e),t)},setStartBefore:function(e){o(this).setStartBefore(a(e))},setStartAfter:function(e){o(this).setStartAfter(a(e))},setEndBefore:function(e){o(this).setEndBefore(a(e))},setEndAfter:function(e){o(this).setEndAfter(a(e))},selectNode:function(e){o(this).selectNode(a(e))},selectNodeContents:function(e){o(this).selectNodeContents(a(e))},compareBoundaryPoints:function(e,t){return o(this).compareBoundaryPoints(e,i(t))},extractContents:function(){return s(o(this).extractContents())},cloneContents:function(){return s(o(this).cloneContents())},insertNode:function(e){o(this).insertNode(a(e))},surroundContents:function(e){o(this).surroundContents(a(e))},cloneRange:function(){return s(o(this).cloneRange())},isPointInRange:function(e,t){return o(this).isPointInRange(a(e),t)},comparePoint:function(e,t){return o(this).comparePoint(a(e),t)},intersectsNode:function(e){return o(this).intersectsNode(a(e))},toString:function(){return o(this).toString()}},c.prototype.createContextualFragment&&(t.prototype.createContextualFragment=function(e){return s(o(this).createContextualFragment(e))}),n(window.Range,t,document.createRange()),e.wrappers.Range=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.GetElementsByInterface,n=e.ParentNodeInterface,r=e.SelectorsInterface,o=e.mixin,i=e.registerObject,a=i(document.createDocumentFragment());o(a.prototype,n),o(a.prototype,r),o(a.prototype,t);var s=i(document.createComment(""));e.wrappers.Comment=s,e.wrappers.DocumentFragment=a}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=p(l(e).ownerDocument.createDocumentFragment());n.call(this,t),c(t,this);var o=e.shadowRoot;f.set(this,o),this.treeScope_=new r(this,a(o||e)),d.set(this,e)}var n=e.wrappers.DocumentFragment,r=e.TreeScope,o=e.elementFromPoint,i=e.getInnerHTML,a=e.getTreeScope,s=e.mixin,c=e.rewrap,u=e.setInnerHTML,l=e.unsafeUnwrap,p=e.unwrap,d=new WeakMap,f=new WeakMap,h=/[ \t\n\r\f]/;t.prototype=Object.create(n.prototype),s(t.prototype,{constructor:t,get innerHTML(){return i(this)},set innerHTML(e){u(this,e),this.invalidateShadowRenderer()},get olderShadowRoot(){return f.get(this)||null},get host(){return d.get(this)||null},invalidateShadowRenderer:function(){return d.get(this).invalidateShadowRenderer()},elementFromPoint:function(e,t){return o(this,this.ownerDocument,e,t)},getElementById:function(e){return h.test(e)?null:this.querySelector('[id="'+e+'"]')}}),e.wrappers.ShadowRoot=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.previousSibling_=e.previousSibling,e.nextSibling_=e.nextSibling,e.parentNode_=e.parentNode}function n(n,o,i){var a=x(n),s=x(o),c=i?x(i):null;if(r(o),t(o),i)n.firstChild===i&&(n.firstChild_=i),i.previousSibling_=i.previousSibling;else{n.lastChild_=n.lastChild,n.lastChild===n.firstChild&&(n.firstChild_=n.firstChild);var u=R(a.lastChild);u&&(u.nextSibling_=u.nextSibling)}e.originalInsertBefore.call(a,s,c)}function r(n){var r=x(n),o=r.parentNode;if(o){var i=R(o);t(n),n.previousSibling&&(n.previousSibling.nextSibling_=n),n.nextSibling&&(n.nextSibling.previousSibling_=n),i.lastChild===n&&(i.lastChild_=n),i.firstChild===n&&(i.firstChild_=n),e.originalRemoveChild.call(o,r)}}function o(e){W.set(e,[])}function i(e){var t=W.get(e);return t||W.set(e,t=[]),t}function a(e){for(var t=[],n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t}function s(){for(var e=0;e<F.length;e++){var t=F[e],n=t.parentRenderer;n&&n.dirty||t.render()}F=[]}function c(){T=null,s()}function u(e){var t=I.get(e);return t||(t=new f(e),I.set(e,t)),t}function l(e){var t=C(e).root;return t instanceof _?t:null}function p(e){return u(e.host)}function d(e){this.skip=!1,this.node=e,this.childNodes=[]}function f(e){this.host=e,this.dirty=!1,this.invalidateAttributes(),this.associateNode(e)}function h(e){for(var t=[],n=e.firstChild;n;n=n.nextSibling)E(n)?t.push.apply(t,i(n)):t.push(n);return t}function w(e){if(e instanceof j)return e;if(e instanceof L)return null;for(var t=e.firstChild;t;t=t.nextSibling){var n=w(t);if(n)return n}return null}function m(e,t){i(t).push(e);var n=A.get(e);n?n.push(t):A.set(e,[t])}function g(e){return A.get(e)}function v(e){A.set(e,void 0)}function b(e,t){var n=t.getAttribute("select");if(!n)return!0;if(n=n.trim(),!n)return!0;if(!(e instanceof O))return!1;if(!U.test(n))return!1;try{return e.matches(n)}catch(r){return!1}}function y(e,t){var n=g(t);return n&&n[n.length-1]===e}function E(e){return e instanceof L||e instanceof j}function S(e){return e.shadowRoot}function M(e){for(var t=[],n=e.shadowRoot;n;n=n.olderShadowRoot)t.push(n);return t}var T,O=e.wrappers.Element,L=e.wrappers.HTMLContentElement,j=e.wrappers.HTMLShadowElement,N=e.wrappers.Node,_=e.wrappers.ShadowRoot,C=(e.assert,e.getTreeScope),D=(e.mixin,e.oneOf),H=e.unsafeUnwrap,x=e.unwrap,R=e.wrap,P=e.ArraySplice,W=new WeakMap,A=new WeakMap,I=new WeakMap,k=D(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),F=[],B=new P;B.equals=function(e,t){return x(e.node)===t},d.prototype={append:function(e){var t=new d(e);return this.childNodes.push(t),t},sync:function(e){if(!this.skip){for(var t=this.node,o=this.childNodes,i=a(x(t)),s=e||new WeakMap,c=B.calculateSplices(o,i),u=0,l=0,p=0,d=0;d<c.length;d++){for(var f=c[d];p<f.index;p++)l++,o[u++].sync(s);for(var h=f.removed.length,w=0;h>w;w++){var m=R(i[l++]);s.get(m)||r(m)}for(var g=f.addedCount,v=i[l]&&R(i[l]),w=0;g>w;w++){var b=o[u++],y=b.node;n(t,y,v),s.set(y,!0),b.sync(s)}p+=g}for(var d=p;d<o.length;d++)o[d].sync(s)}}},f.prototype={render:function(e){if(this.dirty){this.invalidateAttributes();var t=this.host;this.distribution(t);var n=e||new d(t);this.buildRenderTree(n,t);var r=!e;r&&n.sync(),this.dirty=!1}},get parentRenderer(){return C(this.host).renderer},invalidate:function(){if(!this.dirty){this.dirty=!0;var e=this.parentRenderer;if(e&&e.invalidate(),F.push(this),T)return;T=window[k](c,0)}},distribution:function(e){this.resetAllSubtrees(e),this.distributionResolution(e)},resetAll:function(e){E(e)?o(e):v(e),this.resetAllSubtrees(e)},resetAllSubtrees:function(e){for(var t=e.firstChild;t;t=t.nextSibling)this.resetAll(t);e.shadowRoot&&this.resetAll(e.shadowRoot),e.olderShadowRoot&&this.resetAll(e.olderShadowRoot)},distributionResolution:function(e){if(S(e)){for(var t=e,n=h(t),r=M(t),o=0;o<r.length;o++)this.poolDistribution(r[o],n);for(var o=r.length-1;o>=0;o--){var i=r[o],a=w(i);if(a){var s=i.olderShadowRoot;s&&(n=h(s));for(var c=0;c<n.length;c++)m(n[c],a)}this.distributionResolution(i)}}for(var u=e.firstChild;u;u=u.nextSibling)this.distributionResolution(u)},poolDistribution:function(e,t){if(!(e instanceof j))if(e instanceof L){var n=e;this.updateDependentAttributes(n.getAttribute("select"));for(var r=!1,o=0;o<t.length;o++){var e=t[o];e&&b(e,n)&&(m(e,n),t[o]=void 0,r=!0)}if(!r)for(var i=n.firstChild;i;i=i.nextSibling)m(i,n)}else for(var i=e.firstChild;i;i=i.nextSibling)this.poolDistribution(i,t)},buildRenderTree:function(e,t){for(var n=this.compose(t),r=0;r<n.length;r++){var o=n[r],i=e.append(o);this.buildRenderTree(i,o)}if(S(t)){var a=u(t);a.dirty=!1}},compose:function(e){for(var t=[],n=e.shadowRoot||e,r=n.firstChild;r;r=r.nextSibling)if(E(r)){this.associateNode(n);for(var o=i(r),a=0;a<o.length;a++){var s=o[a];y(r,s)&&t.push(s)}}else t.push(r);return t},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(e){if(e){var t=this.attributes;/\.\w+/.test(e)&&(t["class"]=!0),/#\w+/.test(e)&&(t.id=!0),e.replace(/\[\s*([^\s=\|~\]]+)/g,function(e,n){t[n]=!0})}},dependsOnAttribute:function(e){return this.attributes[e]},associateNode:function(e){H(e).polymerShadowRenderer_=this}};var U=/^(:not\()?[*.#[a-zA-Z_|]/;N.prototype.invalidateShadowRenderer=function(){var e=H(this).polymerShadowRenderer_;return e?(e.invalidate(),!0):!1},L.prototype.getDistributedNodes=j.prototype.getDistributedNodes=function(){return s(),i(this)},O.prototype.getDestinationInsertionPoints=function(){return s(),g(this)||[]},L.prototype.nodeIsInserted_=j.prototype.nodeIsInserted_=function(){this.invalidateShadowRenderer();var e,t=l(this);t&&(e=p(t)),H(this).polymerShadowRenderer_=e,e&&e.invalidate()},e.getRendererForHost=u,e.getShadowTrees=M,e.renderAllPending=s,e.getDestinationInsertionPoints=g,e.visual={insertBefore:n,remove:r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t){if(window[t]){r(!e.wrappers[t]);var c=function(e){n.call(this,e)};c.prototype=Object.create(n.prototype),o(c.prototype,{get form(){return s(a(this).form)}}),i(window[t],c,document.createElement(t.slice(4,-7))),e.wrappers[t]=c}}var n=e.wrappers.HTMLElement,r=e.assert,o=e.mixin,i=e.registerWrapper,a=e.unwrap,s=e.wrap,c=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOutputElement","HTMLTextAreaElement"];c.forEach(t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}{var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap;window.Selection}t.prototype={get anchorNode(){return s(o(this).anchorNode)},get focusNode(){return s(o(this).focusNode)},addRange:function(e){o(this).addRange(i(e))},collapse:function(e,t){o(this).collapse(a(e),t)},containsNode:function(e,t){return o(this).containsNode(a(e),t)},extend:function(e,t){o(this).extend(a(e),t)},getRangeAt:function(e){return s(o(this).getRangeAt(e))},removeRange:function(e){o(this).removeRange(i(e))},selectAllChildren:function(e){o(this).selectAllChildren(a(e))},toString:function(){return o(this).toString()}},n(window.Selection,t,window.getSelection()),e.wrappers.Selection=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){l.call(this,e),this.treeScope_=new w(this,null)}function n(e){var n=document[e];t.prototype[e]=function(){return N(n.apply(L(this),arguments))}}function r(e,t){D.call(L(t),j(e)),o(e,t)}function o(e,t){e.shadowRoot&&t.adoptNode(e.shadowRoot),e instanceof h&&i(e,t);for(var n=e.firstChild;n;n=n.nextSibling)o(n,t)}function i(e,t){var n=e.olderShadowRoot;n&&t.adoptNode(n)}function a(e){O(e,this)}function s(e,t){var n=document.implementation[t];e.prototype[t]=function(){return N(n.apply(L(this),arguments))}}function c(e,t){var n=document.implementation[t];e.prototype[t]=function(){return n.apply(L(this),arguments)}}var u=e.GetElementsByInterface,l=e.wrappers.Node,p=e.ParentNodeInterface,d=e.wrappers.Selection,f=e.SelectorsInterface,h=e.wrappers.ShadowRoot,w=e.TreeScope,m=e.cloneNode,g=e.defineWrapGetter,v=e.elementFromPoint,b=e.forwardMethodsToWrapper,y=e.matchesNames,E=e.mixin,S=e.registerWrapper,M=e.renderAllPending,T=e.rewrap,O=e.setWrapper,L=e.unsafeUnwrap,j=e.unwrap,N=e.wrap,_=e.wrapEventTargetMethods,C=(e.wrapNodeList,new WeakMap);t.prototype=Object.create(l.prototype),g(t,"documentElement"),g(t,"body"),g(t,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(n);var D=document.adoptNode,H=document.getSelection;if(E(t.prototype,{adoptNode:function(e){return e.parentNode&&e.parentNode.removeChild(e),r(e,this),e},elementFromPoint:function(e,t){return v(this,this,e,t)},importNode:function(e,t){return m(e,t,L(this))},getSelection:function(){return M(),new d(H.call(j(this)))},getElementsByName:function(e){return f.querySelectorAll.call(this,"[name="+JSON.stringify(String(e))+"]")}}),document.registerElement){var x=document.registerElement;t.prototype.registerElement=function(t,n){function r(e){return e?void O(e,this):i?document.createElement(i,t):document.createElement(t)}var o,i;if(void 0!==n&&(o=n.prototype,i=n["extends"]),o||(o=Object.create(HTMLElement.prototype)),e.nativePrototypeTable.get(o))throw new Error("NotSupportedError");for(var a,s=Object.getPrototypeOf(o),c=[];s&&!(a=e.nativePrototypeTable.get(s));)c.push(s),s=Object.getPrototypeOf(s);if(!a)throw new Error("NotSupportedError");for(var u=Object.create(a),l=c.length-1;l>=0;l--)u=Object.create(u);["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"].forEach(function(e){var t=o[e];t&&(u[e]=function(){N(this)instanceof r||T(this),t.apply(N(this),arguments)})});var p={prototype:u};i&&(p["extends"]=i),r.prototype=o,r.prototype.constructor=r,e.constructorTable.set(u,r),e.nativePrototypeTable.set(o,u);x.call(j(this),t,p);return r},b([window.HTMLDocument||window.Document],["registerElement"])}b([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),b([window.HTMLBodyElement,window.HTMLHeadElement,window.HTMLHtmlElement],y),b([window.HTMLDocument||window.Document],["adoptNode","importNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById","getElementsByName","getSelection"]),E(t.prototype,u),E(t.prototype,p),E(t.prototype,f),E(t.prototype,{get implementation(){var e=C.get(this);return e?e:(e=new a(j(this).implementation),C.set(this,e),e)},get defaultView(){return N(j(this).defaultView)}}),S(window.Document,t,document.implementation.createHTMLDocument("")),window.HTMLDocument&&S(window.HTMLDocument,t),_([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),s(a,"createDocumentType"),s(a,"createDocument"),s(a,"createHTMLDocument"),c(a,"hasFeature"),S(window.DOMImplementation,a),b([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),e.adoptNodeNoRemove=r,e.wrappers.DOMImplementation=a,e.wrappers.Document=t
-}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.wrappers.Selection,o=e.mixin,i=e.registerWrapper,a=e.renderAllPending,s=e.unwrap,c=e.unwrapIfNeeded,u=e.wrap,l=window.Window,p=window.getComputedStyle,d=window.getDefaultComputedStyle,f=window.getSelection;t.prototype=Object.create(n.prototype),l.prototype.getComputedStyle=function(e,t){return u(this||window).getComputedStyle(c(e),t)},d&&(l.prototype.getDefaultComputedStyle=function(e,t){return u(this||window).getDefaultComputedStyle(c(e),t)}),l.prototype.getSelection=function(){return u(this||window).getSelection()},delete window.getComputedStyle,delete window.getDefaultComputedStyle,delete window.getSelection,["addEventListener","removeEventListener","dispatchEvent"].forEach(function(e){l.prototype[e]=function(){var t=u(this||window);return t[e].apply(t,arguments)},delete window[e]}),o(t.prototype,{getComputedStyle:function(e,t){return a(),p.call(s(this),c(e),t)},getSelection:function(){return a(),new r(f.call(s(this)))},get document(){return u(s(this).document)}}),d&&(t.prototype.getDefaultComputedStyle=function(e,t){return a(),d.call(s(this),c(e),t)}),i(l,t,window),e.wrappers.Window=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrap,n=window.DataTransfer||window.Clipboard,r=n.prototype.setDragImage;r&&(n.prototype.setDragImage=function(e,n,o){r.call(this,t(e),n,o)})}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t;t=e instanceof i?e:new i(e&&o(e)),r(t,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unwrap,i=window.FormData;i&&(n(i,t,new i),e.wrappers.FormData=t)}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrapIfNeeded,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(e){return n.call(this,t(e))}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=n[e],r=window[t];if(r){var o=document.createElement(e),i=o.constructor;window[t]=i}}var n=(e.isWrapperFor,{a:"HTMLAnchorElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",base:"HTMLBaseElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",content:"HTMLContentElement",data:"HTMLDataElement",datalist:"HTMLDataListElement",del:"HTMLModElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",head:"HTMLHeadElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",marquee:"HTMLMarqueeElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",shadow:"HTMLShadowElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",template:"HTMLTemplateElement",textarea:"HTMLTextAreaElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",ul:"HTMLUListElement",video:"HTMLVideoElement"});Object.keys(n).forEach(t),Object.getOwnPropertyNames(e.wrappers).forEach(function(t){window[t]=e.wrappers[t]})}(window.ShadowDOMPolyfill); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/build.log b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/build.log
deleted file mode 100644
index 44ece4a94d7..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/build.log
+++ /dev/null
@@ -1,31 +0,0 @@
-BUILD LOG
----------
-Build Time: 2015-02-17T17:24:48-0800
-
-NODEJS INFORMATION
-==================
-nodejs: v0.12.0
-gulp: 3.8.11
-gulp-audit: 1.0.0
-gulp-concat: 2.5.0
-gulp-header: 1.2.2
-gulp-uglify: 1.1.0
-run-sequence: 1.0.2
-web-component-tester: 2.2.3
-
-REPO REVISIONS
-==============
-webcomponentsjs: 74b6b18443dd13e1cee184f688e23ae3930ed30c
-
-BUILD HASHES
-============
-CustomElements.js: 939c4b32847bf8085532995428001c3402f96cff
-CustomElements.min.js: cb3fd472ea0a9c45f5f03f86a6c5083f5077e907
-HTMLImports.js: 018bc32bc02bc6dc7dcacbd409438b26c31c2e6d
-HTMLImports.min.js: a3cb3e4ded3d708ba8333a8d5927ec93587fc191
-ShadowDOM.js: e34e8e3707d015a0ac9ec718d17b93c54500d028
-ShadowDOM.min.js: b3c2f09259d03ec44bd08ebbe9ed67dae3a06aaf
-webcomponents-lite.js: 83f6c69c9f38d6c88b1717427e713e57a96e7d70
-webcomponents-lite.min.js: d369074b523ff3806e7f71770a4d360f33331d48
-webcomponents.js: b91a9a8ae8c79bfc0275a766f3153f390ef74d81
-webcomponents.min.js: 91901c97731fc010ba5bb43624aa37d5320071c4 \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.min.js b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.min.js
deleted file mode 100644
index db80a800edf..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents-lite.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-window.WebComponents=window.WebComponents||{},function(e){var t=e.flags||{},n="webcomponents.js",o=document.querySelector('script[src*="'+n+'"]');if(!t.noOpts){if(location.search.slice(1).split("&").forEach(function(e){e=e.split("="),e[0]&&(t[e[0]]=e[1]||!0)}),o)for(var r,i=0;r=o.attributes[i];i++)"src"!==r.name&&(t[r.name]=r.value||!0);if(t.log){var a=t.log.split(",");t.log={},a.forEach(function(e){t.log[e]=!0})}else t.log={}}t.shadow=t.shadow||t.shadowdom||t.polyfill,t.shadow="native"===t.shadow?!1:t.shadow||!HTMLElement.prototype.createShadowRoot,t.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=t.register),e.flags=t}(WebComponents),function(e){function t(e){_.push(e),w||(w=!0,h(o))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function o(){w=!1;var e=_;_=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();r(e),n.length&&(e.callback_(n,e),t=!0)}),t&&o()}function r(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var o=v.get(n);if(o)for(var r=0;r<o.length;r++){var i=o[r],a=i.options;if(n===e||a.subtree){var s=t(a);s&&i.enqueue(s)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++E}function s(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function d(e){var t=new s(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function c(e,t){return y=new s(e,t)}function u(e){return L?L:(L=d(y),L.oldValue=e,L)}function l(){y=L=void 0}function f(e){return e===L||e===y}function m(e,t){return e===t?e:L&&f(e)?L:null}function p(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var h,v=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))h=setTimeout;else if(window.setImmediate)h=window.setImmediate;else{var g=[],b=String(Math.random());window.addEventListener("message",function(e){if(e.data===b){var t=g;g=[],t.forEach(function(e){e()})}}),h=function(e){g.push(e),window.postMessage(b,"*")}}var w=!1,_=[],E=0;a.prototype={observe:function(e,t){if(e=n(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var o=v.get(e);o||v.set(e,o=[]);for(var r,i=0;i<o.length;i++)if(o[i].observer===this){r=o[i],r.removeListeners(),r.options=t;break}r||(r=new p(this,e,t),o.push(r),this.nodes_.push(e)),r.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=v.get(e),n=0;n<t.length;n++){var o=t[n];if(o.observer===this){o.removeListeners(),t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var y,L;p.prototype={enqueue:function(e){var n=this.observer.records_,o=n.length;if(n.length>0){var r=n[o-1],i=m(r,e);if(i)return void(n[o-1]=i)}else t(this.observer);n[o]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n<t.length;n++)if(t[n]===this){t.splice(n,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,n=e.relatedNode.namespaceURI,o=e.target,r=new c("attributes",o);r.attributeName=t,r.attributeNamespace=n;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(o,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(n)?void 0:e.attributeOldValue?u(a):r});break;case"DOMCharacterDataModified":var o=e.target,r=c("characterData",o),a=e.prevValue;i(o,function(e){return e.characterData?e.characterDataOldValue?u(a):r:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var s,d,f=e.target;"DOMNodeInserted"===e.type?(s=[f],d=[]):(s=[],d=[f]);var m=f.previousSibling,p=f.nextSibling,r=c("childList",e.target.parentNode);r.addedNodes=s,r.removedNodes=d,r.previousSibling=m,r.nextSibling=p,i(e.relatedNode,function(e){return e.childList?r:void 0})}l()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a)}(this),"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var o=t[this.name];return o&&o[0]===t?o[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,o(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===g}function o(e,t){if(n(t))e&&e();else{var r=function(){("complete"===t.readyState||t.readyState===g)&&(t.removeEventListener(b,r),o(e,t))};t.addEventListener(b,r)}}function r(e){e.target.__loaded=!0}function i(e,t){function n(){s==d&&e&&e()}function o(e){r(e),s++,n()}var i=t.querySelectorAll("link[rel=import]"),s=0,d=i.length;if(d)for(var c,u=0;d>u&&(c=i[u]);u++)a(c)?o.call(c,{target:c}):(c.addEventListener("load",o),c.addEventListener("error",o));else n()}function a(e){return l?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)d(t)&&c(t)}function d(e){return"link"===e.localName&&"import"===e.rel}function c(e){var t=e["import"];t?r({target:e}):(e.addEventListener("load",r),e.addEventListener("error",r))}var u="import",l=Boolean(u in document.createElement("link")),f=Boolean(window.ShadowDOMPolyfill),m=function(e){return f?ShadowDOMPolyfill.wrapIfNeeded(e):e},p=m(document),h={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return m(e)},configurable:!0};Object.defineProperty(document,"_currentScript",h),Object.defineProperty(p,"_currentScript",h);var v=/Trident|Edge/.test(navigator.userAgent),g=v?"complete":"interactive",b="readystatechange";l&&(new MutationObserver(function(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,o=t.length;o>n&&(e=t[n]);n++)c(e)}()),t(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var e=p.createEvent("CustomEvent");e.initCustomEvent("HTMLImportsLoaded",!0,!0,{}),p.dispatchEvent(e)}),e.IMPORT_LINK_TYPE=u,e.useNative=l,e.rootDocument=p,e.whenReady=t,e.isIE=v}(HTMLImports),function(e){var t=[],n=function(e){t.push(e)},o=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=o}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,o={resolveUrlsInStyle:function(e){var t=e.ownerDocument,n=t.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,n),e},resolveUrlsInCssText:function(e,o){var r=this.replaceUrls(e,o,t);return r=this.replaceUrls(r,o,n)},replaceUrls:function(e,t,n){return e.replace(n,function(e,n,o,r){var i=o.replace(/["']/g,"");return t.href=i,i=t.href,n+"'"+i+"'"+r})}};e.path=o}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,o,r){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(){if(4===i.readyState){var e=i.getResponseHeader("Location"),n=null;if(e)var n="/"===e.substr(0,1)?location.origin+e:e;o.call(r,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,o=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};o.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,o){if(n.load&&console.log("fetch",e,o),e)if(e.match(/^data:/)){var r=e.split(","),i=r[0],a=r[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,o,null,a)}.bind(this),0)}else{var s=function(t,n,r){this.receive(e,o,t,n,r)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,o,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,o,r){this.cache[e]=o;for(var i,a=this.pending[e],s=0,d=a.length;d>s&&(i=a[s]);s++)this.onload(e,i,o,n,r),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=o}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function n(e){var t=o(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function o(e){return e.textContent+r(e)}function r(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,o=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+o+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,d=e.flags,c=e.isIE,u=e.IMPORT_LINK_TYPE,l="link[rel="+u+"]",f={documentSelectors:l,importsSelectors:[l,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(d.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){d.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,d.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,o=function(o){t&&t(o),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",o),e.addEventListener("error",o),c&&"style"===e.localName){var r=!1;if(-1==e.textContent.indexOf("@import"))r=!0;else if(e.sheet){r=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,d=0;s>d&&(i=a[d]);d++)i.type===CSSRule.IMPORT_RULE&&(r=r&&Boolean(i.styleSheet))}r&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var o=document.createElement("script");o.__importElement=t,o.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(o,function(){o.parentNode.removeChild(o),e.currentScript=null}),this.addElementToDocument(o)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var o,r=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=r.length;a>i&&(o=r[i]);i++)if(!this.isParsed(o))return this.hasResource(o)?t(o)?this.nextToParseInDoc(o["import"],o):o:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=f,e.IMPORT_SELECTOR=l}),HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function o(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function r(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var r=n.createElement("base");r.setAttribute("href",t),n.baseURI||o(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(r),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,d=e.rootDocument,c=e.Loader,u=e.Observer,l=e.parser,f={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){m.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);m.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===d?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,o,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=o,n.__error=a,t(n)){var d=this.documents[e];void 0===d&&(d=a?null:r(o,s||e),d&&(d.__importLink=n,this.bootDocument(d)),this.documents[e]=d),n["import"]=d}l.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),l.parseNext()},loadedAll:function(){l.parseNext()}},m=new c(f.loaded.bind(f),f.loadedAll.bind(f));if(f.observer=new u,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(d,"baseURI",p)}e.importer=f,e.importLoader=m}),HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,o={added:function(e){for(var o,r,i,a,s=0,d=e.length;d>s&&(a=e[s]);s++)o||(o=a.ownerDocument,r=t.isParsed(o)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&r&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&r.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&r.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=o.added.bind(o);var r=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(r)}var n=e.initializeModules,o=e.isIE;if(!e.useNative){o&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),n();var r=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],o=function(e){n.push(e)},r=function(){n.forEach(function(t){t(e)})};e.addModule=o,e.initializeModules=r,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void o(e,t)}),o(e,t)}function n(e,t,o){var r=e.firstElementChild;if(!r)for(r=e.firstChild;r&&r.nodeType!==Node.ELEMENT_NODE;)r=r.nextSibling;for(;r;)t(r,o)!==!0&&n(r,t,o),r=r.nextElementSibling;return null}function o(e,n){for(var o=e.shadowRoot;o;)t(o,n),o=o.olderShadowRoot}function r(e,t){a=[],i(e,t),a=null}function i(e,t){if(e=wrap(e),!(a.indexOf(e)>=0)){a.push(e);for(var n,o=e.querySelectorAll("link[rel="+s+"]"),r=0,d=o.length;d>r&&(n=o[r]);r++)n["import"]&&i(n["import"],t);t(e)}}var a,s=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=r,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return n(e)||o(e)}function n(t){return e.upgrade(t)?!0:void s(t)}function o(e){_(e,function(e){return n(e)?!0:void 0})}function r(e){s(e),f(e)&&_(e,function(e){s(e)})}function i(e){M.push(e),L||(L=!0,setTimeout(a))}function a(){L=!1;for(var e,t=M,n=0,o=t.length;o>n&&(e=t[n]);n++)e();M=[]}function s(e){y?i(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&f(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function c(e){u(e),_(e,function(e){u(e)})}function u(e){y?i(function(){l(e)}):l(e)}function l(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!f(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function f(e){for(var t=e,n=wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.host}}function m(e){if(e.shadowRoot&&!e.shadowRoot.__watched){w.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)v(t),t=t.olderShadowRoot}}function p(e){if(w.dom){var n=e[0];if(n&&"childList"===n.type&&n.addedNodes&&n.addedNodes){for(var o=n.addedNodes[0];o&&o!==document&&!o.host;)o=o.parentNode;var r=o&&(o.URL||o._URL||o.host&&o.host.localName)||"";r=r.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,r||"")}e.forEach(function(e){"childList"===e.type&&(T(e.addedNodes,function(e){e.localName&&t(e)}),T(e.removedNodes,function(e){e.localName&&c(e)}))}),w.dom&&console.groupEnd()}function h(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(p(t.takeRecords()),a())}function v(e){if(!e.__observer){var t=new MutationObserver(p);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function g(e){e=wrap(e),w.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),v(e),w.dom&&console.groupEnd()}function b(e){E(e,g)}var w=e.flags,_=e.forSubtree,E=e.forDocumentTree,y=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=y;var L=!1,M=[],T=Array.prototype.forEach.call.bind(Array.prototype.forEach),N=Element.prototype.createShadowRoot;N&&(Element.prototype.createShadowRoot=function(){var e=N.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=m,e.upgradeDocumentTree=b,e.upgradeSubtree=o,e.upgradeAll=t,e.attachedNode=r,e.takeRecords=h}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var o=t.getAttribute("is"),r=e.getRegisteredDefinition(o||t.localName);if(r){if(o&&r.tag==t.localName)return n(t,r);if(!o&&!r["extends"])return n(t,r)}}}function n(t,n){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),o(t,n),t.__upgraded__=!0,i(t),e.attachedNode(t),e.upgradeSubtree(t),a.upgrade&&console.groupEnd(),t}function o(e,t){Object.__proto__?e.__proto__=t.prototype:(r(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function r(e,t,n){for(var o={},r=t;r!==n&&r!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(r),s=0;i=a[s];s++)o[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(r,i)),o[i]=1);r=Object.getPrototypeOf(r)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=o}),CustomElements.addModule(function(e){function t(t,o){var d=o||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(r(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(c(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return d.prototype||(d.prototype=Object.create(HTMLElement.prototype)),d.__name=t.toLowerCase(),d.lifecycle=d.lifecycle||{},d.ancestry=i(d["extends"]),a(d),s(d),n(d.prototype),u(d.__name,d),d.ctor=l(d),d.ctor.prototype=d.prototype,d.prototype.constructor=d.ctor,e.ready&&v(document),d.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){o.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){o.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function o(e,t,n){e=e.toLowerCase();var o=this.getAttribute(e);n.apply(this,arguments);var r=this.getAttribute(e);this.attributeChangedCallback&&r!==o&&this.attributeChangedCallback(e,o,r)}function r(e){for(var t=0;t<E.length;t++)if(e===E[t])return!0}function i(e){var t=c(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,n=e["extends"],o=0;t=e.ancestry[o];o++)n=t.is&&t.tag;e.tag=n||e.__name,n&&(e.is=e.__name)}function s(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var n=document.createElement(e.tag),o=Object.getPrototypeOf(n);o===e.prototype&&(t=o)}for(var r,i=e.prototype;i&&i!==t;)r=Object.getPrototypeOf(i),i.__proto__=r,i=r;e["native"]=t}}function d(e){return b(M(e.tag),e)}function c(e){return e?y[e.toLowerCase()]:void 0}function u(e,t){y[e]=t}function l(e){return function(){return d(e)}}function f(e,t,n){return e===L?m(t,n):T(e,t)}function m(e,t){var n=c(t||e);if(n){if(e==n.tag&&t==n.is)return new n.ctor;if(!t&&!n.is)return new n.ctor}var o;return t?(o=m(e),o.setAttribute("is",t),o):(o=M(e),e.indexOf("-")>=0&&w(o,HTMLElement),o)}function p(e){var t=N.call(this,e);return g(t),t}var h,v=e.upgradeDocumentTree,g=e.upgrade,b=e.upgradeWithDefinition,w=e.implementPrototype,_=e.useNative,E=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],y={},L="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),T=document.createElementNS.bind(document),N=Node.prototype.cloneNode;h=Object.__proto__||_?function(e,t){return e instanceof t}:function(e,t){for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},document.registerElement=t,document.createElement=m,document.createElementNS=f,Node.prototype.cloneNode=p,e.registry=y,e["instanceof"]=h,e.reservedTagList=E,e.getRegisteredDefinition=c,document.register=document.registerElement}),function(e){function t(){a(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){a(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var n=e.useNative,o=e.initializeModules,r=/Trident/.test(navigator.userAgent);if(n){var i=function(){};e.watchShadow=i,e.upgrade=i,e.upgradeAll=i,e.upgradeDocumentTree=i,e.upgradeSubtree=i,e.takeRecords=i,e["instanceof"]=function(e,t){return e instanceof t}}else o();var a=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t()}(window.CustomElements),"undefined"==typeof HTMLTemplateElement&&!function(){var e="template";HTMLTemplateElement=function(){},HTMLTemplateElement.prototype=Object.create(HTMLElement.prototype),HTMLTemplateElement.decorate=function(e){if(!e.content){e.content=e.ownerDocument.createDocumentFragment();for(var t;t=e.firstChild;)e.content.appendChild(t)}},HTMLTemplateElement.bootstrap=function(t){for(var n,o=t.querySelectorAll(e),r=0,i=o.length;i>r&&(n=o[r]);r++)HTMLTemplateElement.decorate(n)},addEventListener("DOMContentLoaded",function(){HTMLTemplateElement.bootstrap(document)})}(),function(){var e=document.createElement("style");e.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var t=document.querySelector("head");t.insertBefore(e,t.firstChild)}(window.WebComponents); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.min.js b/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.min.js
deleted file mode 100644
index 474305f73fc..00000000000
--- a/chromium/third_party/catapult/tracing/third_party/components/webcomponentsjs/webcomponents.min.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * @license
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-// @version 0.5.5
-window.WebComponents=window.WebComponents||{},function(e){var t=e.flags||{},n="webcomponents.js",r=document.querySelector('script[src*="'+n+'"]');if(!t.noOpts){if(location.search.slice(1).split("&").forEach(function(e){e=e.split("="),e[0]&&(t[e[0]]=e[1]||!0)}),r)for(var o,i=0;o=r.attributes[i];i++)"src"!==o.name&&(t[o.name]=o.value||!0);if(t.log){var a=t.log.split(",");t.log={},a.forEach(function(e){t.log[e]=!0})}else t.log={}}t.shadow=t.shadow||t.shadowdom||t.polyfill,t.shadow="native"===t.shadow?!1:t.shadow||!HTMLElement.prototype.createShadowRoot,t.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=t.register),e.flags=t}(WebComponents),WebComponents.flags.shadow&&("undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),window.ShadowDOMPolyfill={},function(e){"use strict";function t(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if(navigator.getDeviceStorage)return!1;try{var e=new Function("return true;");return e()}catch(t){return!1}}function n(e){if(!e)throw new Error("Assertion failed")}function r(e,t){for(var n=W(t),r=0;r<n.length;r++){var o=n[r];k(e,o,F(t,o))}return e}function o(e,t){for(var n=W(t),r=0;r<n.length;r++){var o=n[r];switch(o){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":continue}k(e,o,F(t,o))}return e}function i(e,t){for(var n=0;n<t.length;n++)if(t[n]in e)return t[n]}function a(e,t,n){B.value=n,k(e,t,B)}function s(e){var t=e.__proto__||Object.getPrototypeOf(e);if(U)try{W(t)}catch(n){t=t.__proto__}var r=R.get(t);if(r)return r;var o=s(t),i=E(o);return g(t,i,e),i}function c(e,t){w(e,t,!0)}function l(e,t){w(t,e,!1)}function u(e){return/^on[a-z]+$/.test(e)}function d(e){return/^\w[a-zA-Z_0-9]*$/.test(e)}function p(e){return A&&d(e)?new Function("return this.__impl4cf1e782hg__."+e):function(){return this.__impl4cf1e782hg__[e]}}function f(e){return A&&d(e)?new Function("v","this.__impl4cf1e782hg__."+e+" = v"):function(t){this.__impl4cf1e782hg__[e]=t}}function h(e){return A&&d(e)?new Function("return this.__impl4cf1e782hg__."+e+".apply(this.__impl4cf1e782hg__, arguments)"):function(){return this.__impl4cf1e782hg__[e].apply(this.__impl4cf1e782hg__,arguments)}}function m(e,t){try{return Object.getOwnPropertyDescriptor(e,t)}catch(n){return q}}function w(t,n,r){for(var o=W(t),i=0;i<o.length;i++){var a=o[i];if("polymerBlackList_"!==a&&!(a in n||t.polymerBlackList_&&t.polymerBlackList_[a])){U&&t.__lookupGetter__(a);var s,c,l=m(t,a);if(r&&"function"==typeof l.value)n[a]=h(a);else{var d=u(a);s=d?e.getEventHandlerGetter(a):p(a),(l.writable||l.set||V)&&(c=d?e.getEventHandlerSetter(a):f(a));var w=V||l.configurable;k(n,a,{get:s,set:c,configurable:w,enumerable:l.enumerable})}}}}function v(e,t,n){var r=e.prototype;g(r,t,n),o(t,e)}function g(e,t,r){var o=t.prototype;n(void 0===R.get(e)),R.set(e,t),P.set(o,e),c(e,o),r&&l(o,r),a(o,"constructor",t),t.prototype=o}function b(e,t){return R.get(t.prototype)===e}function y(e){var t=Object.getPrototypeOf(e),n=s(t),r=E(n);return g(t,r,e),r}function E(e){function t(t){e.call(this,t)}var n=Object.create(e.prototype);return n.constructor=t,t.prototype=n,t}function S(e){return e&&e.__impl4cf1e782hg__}function T(e){return!S(e)}function M(e){return null===e?null:(n(T(e)),e.__wrapper8e3dd93a60__||(e.__wrapper8e3dd93a60__=new(s(e))(e)))}function _(e){return null===e?null:(n(S(e)),e.__impl4cf1e782hg__)}function L(e){return e.__impl4cf1e782hg__}function O(e,t){t.__impl4cf1e782hg__=e,e.__wrapper8e3dd93a60__=t}function C(e){return e&&S(e)?_(e):e}function N(e){return e&&!S(e)?M(e):e}function D(e,t){null!==t&&(n(T(e)),n(void 0===t||S(t)),e.__wrapper8e3dd93a60__=t)}function j(e,t,n){G.get=n,k(e.prototype,t,G)}function H(e,t){j(e,t,function(){return M(this.__impl4cf1e782hg__[t])})}function x(e,t){e.forEach(function(e){t.forEach(function(t){e.prototype[t]=function(){var e=N(this);return e[t].apply(e,arguments)}})})}var R=new WeakMap,P=new WeakMap,I=Object.create(null),A=t(),k=Object.defineProperty,W=Object.getOwnPropertyNames,F=Object.getOwnPropertyDescriptor,B={value:void 0,configurable:!0,enumerable:!1,writable:!0};W(window);var U=/Firefox/.test(navigator.userAgent),q={get:function(){},set:function(){},configurable:!0,enumerable:!0},V=function(){var e=Object.getOwnPropertyDescriptor(Node.prototype,"nodeType");return e&&!e.get&&!e.set}(),G={get:void 0,configurable:!0,enumerable:!0};e.assert=n,e.constructorTable=R,e.defineGetter=j,e.defineWrapGetter=H,e.forwardMethodsToWrapper=x,e.isWrapper=S,e.isWrapperFor=b,e.mixin=r,e.nativePrototypeTable=P,e.oneOf=i,e.registerObject=y,e.registerWrapper=v,e.rewrap=D,e.setWrapper=O,e.unsafeUnwrap=L,e.unwrap=_,e.unwrapIfNeeded=C,e.wrap=M,e.wrapIfNeeded=N,e.wrappers=I}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t,n){return{index:e,removed:t,addedCount:n}}function n(){}var r=0,o=1,i=2,a=3;n.prototype={calcEditDistances:function(e,t,n,r,o,i){for(var a=i-o+1,s=n-t+1,c=new Array(a),l=0;a>l;l++)c[l]=new Array(s),c[l][0]=l;for(var u=0;s>u;u++)c[0][u]=u;for(var l=1;a>l;l++)for(var u=1;s>u;u++)if(this.equals(e[t+u-1],r[o+l-1]))c[l][u]=c[l-1][u-1];else{var d=c[l-1][u]+1,p=c[l][u-1]+1;c[l][u]=p>d?d:p}return c},spliceOperationsFromEditDistances:function(e){for(var t=e.length-1,n=e[0].length-1,s=e[t][n],c=[];t>0||n>0;)if(0!=t)if(0!=n){var l,u=e[t-1][n-1],d=e[t-1][n],p=e[t][n-1];l=p>d?u>d?d:u:u>p?p:u,l==u?(u==s?c.push(r):(c.push(o),s=u),t--,n--):l==d?(c.push(a),t--,s=d):(c.push(i),n--,s=p)}else c.push(a),t--;else c.push(i),n--;return c.reverse(),c},calcSplices:function(e,n,s,c,l,u){var d=0,p=0,f=Math.min(s-n,u-l);if(0==n&&0==l&&(d=this.sharedPrefix(e,c,f)),s==e.length&&u==c.length&&(p=this.sharedSuffix(e,c,f-d)),n+=d,l+=d,s-=p,u-=p,s-n==0&&u-l==0)return[];if(n==s){for(var h=t(n,[],0);u>l;)h.removed.push(c[l++]);return[h]}if(l==u)return[t(n,[],s-n)];for(var m=this.spliceOperationsFromEditDistances(this.calcEditDistances(e,n,s,c,l,u)),h=void 0,w=[],v=n,g=l,b=0;b<m.length;b++)switch(m[b]){case r:h&&(w.push(h),h=void 0),v++,g++;break;case o:h||(h=t(v,[],0)),h.addedCount++,v++,h.removed.push(c[g]),g++;break;case i:h||(h=t(v,[],0)),h.addedCount++,v++;break;case a:h||(h=t(v,[],0)),h.removed.push(c[g]),g++}return h&&w.push(h),w},sharedPrefix:function(e,t,n){for(var r=0;n>r;r++)if(!this.equals(e[r],t[r]))return r;return n},sharedSuffix:function(e,t,n){for(var r=e.length,o=t.length,i=0;n>i&&this.equals(e[--r],t[--o]);)i++;return i},calculateSplices:function(e,t){return this.calcSplices(e,0,e.length,t,0,t.length)},equals:function(e,t){return e===t}},e.ArraySplice=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(){a=!1;var e=i.slice(0);i=[];for(var t=0;t<e.length;t++)e[t]()}function n(e){i.push(e),a||(a=!0,r(t,0))}var r,o=window.MutationObserver,i=[],a=!1;if(o){var s=1,c=new o(t),l=document.createTextNode(s);c.observe(l,{characterData:!0}),r=function(){s=(s+1)%2,l.data=s}}else r=window.setTimeout;e.setEndOfMicrotask=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.scheduled_||(e.scheduled_=!0,h.push(e),m||(u(n),m=!0))}function n(){for(m=!1;h.length;){var e=h;h=[],e.sort(function(e,t){return e.uid_-t.uid_});for(var t=0;t<e.length;t++){var n=e[t];n.scheduled_=!1;var r=n.takeRecords();i(n),r.length&&n.callback_(r,n)}}}function r(e,t){this.type=e,this.target=t,this.addedNodes=new p.NodeList,this.removedNodes=new p.NodeList,this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function o(e,t){for(;e;e=e.parentNode){var n=f.get(e);if(n)for(var r=0;r<n.length;r++){var o=n[r];o.options.subtree&&o.addTransientObserver(t)}}}function i(e){for(var t=0;t<e.nodes_.length;t++){var n=e.nodes_[t],r=f.get(n);if(!r)return;for(var o=0;o<r.length;o++){var i=r[o];i.observer===e&&i.removeTransientObservers()}}}function a(e,n,o){for(var i=Object.create(null),a=Object.create(null),s=e;s;s=s.parentNode){var c=f.get(s);if(c)for(var l=0;l<c.length;l++){var u=c[l],d=u.options;if((s===e||d.subtree)&&!("attributes"===n&&!d.attributes||"attributes"===n&&d.attributeFilter&&(null!==o.namespace||-1===d.attributeFilter.indexOf(o.name))||"characterData"===n&&!d.characterData||"childList"===n&&!d.childList)){var p=u.observer;i[p.uid_]=p,("attributes"===n&&d.attributeOldValue||"characterData"===n&&d.characterDataOldValue)&&(a[p.uid_]=o.oldValue)}}}for(var h in i){var p=i[h],m=new r(n,e);"name"in o&&"namespace"in o&&(m.attributeName=o.name,m.attributeNamespace=o.namespace),o.addedNodes&&(m.addedNodes=o.addedNodes),o.removedNodes&&(m.removedNodes=o.removedNodes),o.previousSibling&&(m.previousSibling=o.previousSibling),o.nextSibling&&(m.nextSibling=o.nextSibling),void 0!==a[h]&&(m.oldValue=a[h]),t(p),p.records_.push(m)}}function s(e){if(this.childList=!!e.childList,this.subtree=!!e.subtree,this.attributes="attributes"in e||!("attributeOldValue"in e||"attributeFilter"in e)?!!e.attributes:!0,this.characterData="characterDataOldValue"in e&&!("characterData"in e)?!0:!!e.characterData,!this.attributes&&(e.attributeOldValue||"attributeFilter"in e)||!this.characterData&&e.characterDataOldValue)throw new TypeError;if(this.characterData=!!e.characterData,this.attributeOldValue=!!e.attributeOldValue,this.characterDataOldValue=!!e.characterDataOldValue,"attributeFilter"in e){if(null==e.attributeFilter||"object"!=typeof e.attributeFilter)throw new TypeError;this.attributeFilter=w.call(e.attributeFilter)}else this.attributeFilter=null}function c(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++v,this.scheduled_=!1}function l(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}var u=e.setEndOfMicrotask,d=e.wrapIfNeeded,p=e.wrappers,f=new WeakMap,h=[],m=!1,w=Array.prototype.slice,v=0;c.prototype={constructor:c,observe:function(e,t){e=d(e);var n,r=new s(t),o=f.get(e);o||f.set(e,o=[]);for(var i=0;i<o.length;i++)o[i].observer===this&&(n=o[i],n.removeTransientObservers(),n.options=r);n||(n=new l(this,e,r),o.push(n),this.nodes_.push(e))},disconnect:function(){this.nodes_.forEach(function(e){for(var t=f.get(e),n=0;n<t.length;n++){var r=t[n];if(r.observer===this){t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}},l.prototype={addTransientObserver:function(e){if(e!==this.target){t(this.observer),this.transientObservedNodes.push(e);var n=f.get(e);n||f.set(e,n=[]),n.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[];for(var t=0;t<e.length;t++)for(var n=e[t],r=f.get(n),o=0;o<r.length;o++)if(r[o]===this){r.splice(o,1);break}}},e.enqueueMutation=a,e.registerTransientObservers=o,e.wrappers.MutationObserver=c,e.wrappers.MutationRecord=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){this.root=e,this.parent=t}function n(e,t){if(e.treeScope_!==t){e.treeScope_=t;for(var r=e.shadowRoot;r;r=r.olderShadowRoot)r.treeScope_.parent=t;for(var o=e.firstChild;o;o=o.nextSibling)n(o,t)}}function r(n){if(n instanceof e.wrappers.Window,n.treeScope_)return n.treeScope_;var o,i=n.parentNode;return o=i?r(i):new t(n,null),n.treeScope_=o}t.prototype={get renderer(){return this.root instanceof e.wrappers.ShadowRoot?e.getRendererForHost(this.root.host):null},contains:function(e){for(;e;e=e.parent)if(e===this)return!0;return!1}},e.TreeScope=t,e.getTreeScope=r,e.setTreeScope=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e instanceof G.ShadowRoot}function n(e){return k(e).root}function r(e,r){var s=[],c=e;for(s.push(c);c;){var l=a(c);if(l&&l.length>0){for(var u=0;u<l.length;u++){var p=l[u];if(i(p)){var f=n(p),h=f.olderShadowRoot;h&&s.push(h)}s.push(p)}c=l[l.length-1]}else if(t(c)){if(d(e,c)&&o(r))break;c=c.host,s.push(c)}else c=c.parentNode,c&&s.push(c)}return s}function o(e){if(!e)return!1;switch(e.type){case"abort":case"error":case"select":case"change":case"load":case"reset":case"resize":case"scroll":case"selectstart":return!0}return!1}function i(e){return e instanceof HTMLShadowElement}function a(t){return e.getDestinationInsertionPoints(t)}function s(e,t){if(0===e.length)return t;t instanceof G.Window&&(t=t.document);for(var n=k(t),r=e[0],o=k(r),i=l(n,o),a=0;a<e.length;a++){var s=e[a];if(k(s)===i)return s}return e[e.length-1]}function c(e){for(var t=[];e;e=e.parent)t.push(e);return t}function l(e,t){for(var n=c(e),r=c(t),o=null;n.length>0&&r.length>0;){var i=n.pop(),a=r.pop();if(i!==a)break;o=i}return o}function u(e,t,n){t instanceof G.Window&&(t=t.document);var o,i=k(t),a=k(n),s=r(n,e),o=l(i,a);o||(o=a.root);for(var c=o;c;c=c.parent)for(var u=0;u<s.length;u++){var d=s[u];if(k(d)===c)return d}return null}function d(e,t){return k(e)===k(t)}function p(e){if(!K.get(e)&&(K.set(e,!0),h(V(e),V(e.target)),I)){var t=I;throw I=null,t}}function f(e){switch(e.type){case"load":case"beforeunload":case"unload":return!0}return!1}function h(t,n){if(Y.get(t))throw new Error("InvalidStateError");Y.set(t,!0),e.renderAllPending();var o,i,a;if(f(t)&&!t.bubbles){var s=n;s instanceof G.Document&&(a=s.defaultView)&&(i=s,o=[])}if(!o)if(n instanceof G.Window)a=n,o=[];else if(o=r(n,t),!f(t)){var s=o[o.length-1];s instanceof G.Document&&(a=s.defaultView)}return nt.set(t,o),m(t,o,a,i)&&w(t,o,a,i)&&v(t,o,a,i),Z.set(t,rt),$["delete"](t,null),Y["delete"](t),t.defaultPrevented}function m(e,t,n,r){var o=ot;if(n&&!g(n,e,o,t,r))return!1;for(var i=t.length-1;i>0;i--)if(!g(t[i],e,o,t,r))return!1;return!0}function w(e,t,n,r){var o=it,i=t[0]||n;return g(i,e,o,t,r)}function v(e,t,n,r){for(var o=at,i=1;i<t.length;i++)if(!g(t[i],e,o,t,r))return;n&&t.length>0&&g(n,e,o,t,r)}function g(e,t,n,r,o){var i=z.get(e);if(!i)return!0;var a=o||s(r,e);if(a===e){if(n===ot)return!0;n===at&&(n=it)}else if(n===at&&!t.bubbles)return!0;if("relatedTarget"in t){var c=q(t),l=c.relatedTarget;if(l){if(l instanceof Object&&l.addEventListener){var d=V(l),p=u(t,e,d);if(p===a)return!0}else p=null;J.set(t,p)}}Z.set(t,n);var f=t.type,h=!1;X.set(t,a),$.set(t,e),i.depth++;for(var m=0,w=i.length;w>m;m++){var v=i[m];if(v.removed)h=!0;else if(!(v.type!==f||!v.capture&&n===ot||v.capture&&n===at))try{if("function"==typeof v.handler?v.handler.call(e,t):v.handler.handleEvent(t),et.get(t))return!1}catch(g){I||(I=g)}}if(i.depth--,h&&0===i.depth){var b=i.slice();i.length=0;for(var m=0;m<b.length;m++)b[m].removed||i.push(b[m])}return!Q.get(t)}function b(e,t,n){this.type=e,this.handler=t,this.capture=Boolean(n)}function y(e,t){if(!(e instanceof st))return V(M(st,"Event",e,t));var n=e;return gt||"beforeunload"!==n.type||this instanceof _?void B(n,this):new _(n)}function E(e){return e&&e.relatedTarget?Object.create(e,{relatedTarget:{value:q(e.relatedTarget)}}):e}function S(e,t,n){var r=window[e],o=function(t,n){return t instanceof r?void B(t,this):V(M(r,e,t,n))};if(o.prototype=Object.create(t.prototype),n&&W(o.prototype,n),r)try{F(r,o,new r("temp"))}catch(i){F(r,o,document.createEvent(e))}return o}function T(e,t){return function(){arguments[t]=q(arguments[t]);var n=q(this);n[e].apply(n,arguments)}}function M(e,t,n,r){if(wt)return new e(n,E(r));var o=q(document.createEvent(t)),i=mt[t],a=[n];return Object.keys(i).forEach(function(e){var t=null!=r&&e in r?r[e]:i[e];"relatedTarget"===e&&(t=q(t)),a.push(t)}),o["init"+t].apply(o,a),o}function _(e){y.call(this,e)}function L(e){return"function"==typeof e?!0:e&&e.handleEvent}function O(e){switch(e){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function C(e){B(e,this)}function N(e){return e instanceof G.ShadowRoot&&(e=e.host),q(e)}function D(e,t){var n=z.get(e);if(n)for(var r=0;r<n.length;r++)if(!n[r].removed&&n[r].type===t)return!0;return!1}function j(e,t){for(var n=q(e);n;n=n.parentNode)if(D(V(n),t))return!0;return!1}function H(e){A(e,yt)}function x(t,n,o,i){e.renderAllPending();var a=V(Et.call(U(n),o,i));if(!a)return null;var c=r(a,null),l=c.lastIndexOf(t);return-1==l?null:(c=c.slice(0,l),s(c,t))}function R(e){return function(){var t=tt.get(this);return t&&t[e]&&t[e].value||null}}function P(e){var t=e.slice(2);return function(n){var r=tt.get(this);r||(r=Object.create(null),tt.set(this,r));var o=r[e];if(o&&this.removeEventListener(t,o.wrapped,!1),"function"==typeof n){var i=function(t){var r=n.call(this,t);r===!1?t.preventDefault():"onbeforeunload"===e&&"string"==typeof r&&(t.returnValue=r)};this.addEventListener(t,i,!1),r[e]={value:n,wrapped:i}}}}var I,A=e.forwardMethodsToWrapper,k=e.getTreeScope,W=e.mixin,F=e.registerWrapper,B=e.setWrapper,U=e.unsafeUnwrap,q=e.unwrap,V=e.wrap,G=e.wrappers,z=(new WeakMap,new WeakMap),K=new WeakMap,Y=new WeakMap,X=new WeakMap,$=new WeakMap,J=new WeakMap,Z=new WeakMap,Q=new WeakMap,et=new WeakMap,tt=new WeakMap,nt=new WeakMap,rt=0,ot=1,it=2,at=3;b.prototype={equals:function(e){return this.handler===e.handler&&this.type===e.type&&this.capture===e.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var st=window.Event;st.prototype.polymerBlackList_={returnValue:!0,keyLocation:!0},y.prototype={get target(){return X.get(this)},get currentTarget(){return $.get(this)},get eventPhase(){return Z.get(this)},get path(){var e=nt.get(this);return e?e.slice():[]},stopPropagation:function(){Q.set(this,!0)},stopImmediatePropagation:function(){Q.set(this,!0),et.set(this,!0)}},F(st,y,document.createEvent("Event"));var ct=S("UIEvent",y),lt=S("CustomEvent",y),ut={get relatedTarget(){var e=J.get(this);return void 0!==e?e:V(q(this).relatedTarget)}},dt=W({initMouseEvent:T("initMouseEvent",14)},ut),pt=W({initFocusEvent:T("initFocusEvent",5)},ut),ft=S("MouseEvent",ct,dt),ht=S("FocusEvent",ct,pt),mt=Object.create(null),wt=function(){try{new window.FocusEvent("focus")}catch(e){return!1}return!0}();if(!wt){var vt=function(e,t,n){if(n){var r=mt[n];t=W(W({},r),t)}mt[e]=t};vt("Event",{bubbles:!1,cancelable:!1}),vt("CustomEvent",{detail:null},"Event"),vt("UIEvent",{view:null,detail:0},"Event"),vt("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),vt("FocusEvent",{relatedTarget:null},"UIEvent")}var gt=window.BeforeUnloadEvent;_.prototype=Object.create(y.prototype),W(_.prototype,{get returnValue(){return U(this).returnValue},set returnValue(e){U(this).returnValue=e}}),gt&&F(gt,_);var bt=window.EventTarget,yt=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(e){var t=e.prototype;yt.forEach(function(e){Object.defineProperty(t,e+"_",{value:t[e]})})}),C.prototype={addEventListener:function(e,t,n){if(L(t)&&!O(e)){var r=new b(e,t,n),o=z.get(this);if(o){for(var i=0;i<o.length;i++)if(r.equals(o[i]))return}else o=[],o.depth=0,z.set(this,o);o.push(r);var a=N(this);a.addEventListener_(e,p,!0)}},removeEventListener:function(e,t,n){n=Boolean(n);var r=z.get(this);if(r){for(var o=0,i=!1,a=0;a<r.length;a++)r[a].type===e&&r[a].capture===n&&(o++,r[a].handler===t&&(i=!0,r[a].remove()));if(i&&1===o){var s=N(this);s.removeEventListener_(e,p,!0)}}},dispatchEvent:function(t){var n=q(t),r=n.type;K.set(n,!1),e.renderAllPending();var o;j(this,r)||(o=function(){},this.addEventListener(r,o,!0));try{return q(this).dispatchEvent_(n)}finally{o&&this.removeEventListener(r,o,!0)}}},bt&&F(bt,C);var Et=document.elementFromPoint;e.elementFromPoint=x,e.getEventHandlerGetter=R,e.getEventHandlerSetter=P,e.wrapEventTargetMethods=H,e.wrappers.BeforeUnloadEvent=_,e.wrappers.CustomEvent=lt,e.wrappers.Event=y,e.wrappers.EventTarget=C,e.wrappers.FocusEvent=ht,e.wrappers.MouseEvent=ft,e.wrappers.UIEvent=ct}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,m)}function n(e){l(e,this)}function r(){this.length=0,t(this,"length")}function o(e){for(var t=new r,o=0;o<e.length;o++)t[o]=new n(e[o]);return t.length=o,t}function i(e){a.call(this,e)}var a=e.wrappers.UIEvent,s=e.mixin,c=e.registerWrapper,l=e.setWrapper,u=e.unsafeUnwrap,d=e.wrap,p=window.TouchEvent;if(p){var f;try{f=document.createEvent("TouchEvent")}catch(h){return}var m={enumerable:!1};n.prototype={get target(){return d(u(this).target)}};var w={configurable:!0,enumerable:!0,get:null};["clientX","clientY","screenX","screenY","pageX","pageY","identifier","webkitRadiusX","webkitRadiusY","webkitRotationAngle","webkitForce"].forEach(function(e){w.get=function(){return u(this)[e]},Object.defineProperty(n.prototype,e,w)}),r.prototype={item:function(e){return this[e]}},i.prototype=Object.create(a.prototype),s(i.prototype,{get touches(){return o(u(this).touches)},get targetTouches(){return o(u(this).targetTouches)},get changedTouches(){return o(u(this).changedTouches)},initTouchEvent:function(){throw new Error("Not implemented")}}),c(p,i,f),e.wrappers.Touch=n,e.wrappers.TouchEvent=i,e.wrappers.TouchList=r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e,t){Object.defineProperty(e,t,s)}function n(){this.length=0,t(this,"length")}function r(e){if(null==e)return e;for(var t=new n,r=0,o=e.length;o>r;r++)t[r]=a(e[r]);return t.length=o,t}function o(e,t){e.prototype[t]=function(){return r(i(this)[t].apply(i(this),arguments))}}var i=e.unsafeUnwrap,a=e.wrap,s={enumerable:!1};n.prototype={item:function(e){return this[e]}},t(n.prototype,"item"),e.wrappers.NodeList=n,e.addWrapNodeListMethod=o,e.wrapNodeList=r}(window.ShadowDOMPolyfill),function(e){"use strict";e.wrapHTMLCollection=e.wrapNodeList,e.wrappers.HTMLCollection=e.wrappers.NodeList}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){L(e instanceof S)}function n(e){var t=new M;return t[0]=e,t.length=1,t}function r(e,t,n){C(t,"childList",{removedNodes:n,previousSibling:e.previousSibling,nextSibling:e.nextSibling})}function o(e,t){C(e,"childList",{removedNodes:t})}function i(e,t,r,o){if(e instanceof DocumentFragment){var i=s(e);B=!0;for(var a=i.length-1;a>=0;a--)e.removeChild(i[a]),i[a].parentNode_=t;B=!1;for(var a=0;a<i.length;a++)i[a].previousSibling_=i[a-1]||r,i[a].nextSibling_=i[a+1]||o;return r&&(r.nextSibling_=i[0]),o&&(o.previousSibling_=i[i.length-1]),i}var i=n(e),c=e.parentNode;return c&&c.removeChild(e),e.parentNode_=t,e.previousSibling_=r,e.nextSibling_=o,r&&(r.nextSibling_=e),o&&(o.previousSibling_=e),i}function a(e){if(e instanceof DocumentFragment)return s(e);var t=n(e),o=e.parentNode;return o&&r(e,o,t),t}function s(e){for(var t=new M,n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t.length=n,o(e,t),t}function c(e){return e}function l(e,t){R(e,t),e.nodeIsInserted_()}function u(e,t){for(var n=N(t),r=0;r<e.length;r++)l(e[r],n)}function d(e){R(e,new _(e,null))}function p(e){for(var t=0;t<e.length;t++)d(e[t])}function f(e,t){var n=e.nodeType===S.DOCUMENT_NODE?e:e.ownerDocument;n!==t.ownerDocument&&n.adoptNode(t)}function h(t,n){if(n.length){var r=t.ownerDocument;if(r!==n[0].ownerDocument)for(var o=0;o<n.length;o++)e.adoptNodeNoRemove(n[o],r)}}function m(e,t){h(e,t);var n=t.length;if(1===n)return I(t[0]);for(var r=I(e.ownerDocument.createDocumentFragment()),o=0;n>o;o++)r.appendChild(I(t[o]));return r}function w(e){if(void 0!==e.firstChild_)for(var t=e.firstChild_;t;){var n=t;t=t.nextSibling_,n.parentNode_=n.previousSibling_=n.nextSibling_=void 0}e.firstChild_=e.lastChild_=void 0}function v(e){if(e.invalidateShadowRenderer()){for(var t=e.firstChild;t;){L(t.parentNode===e);var n=t.nextSibling,r=I(t),o=r.parentNode;o&&Y.call(o,r),t.previousSibling_=t.nextSibling_=t.parentNode_=null,t=n}e.firstChild_=e.lastChild_=null}else for(var n,i=I(e),a=i.firstChild;a;)n=a.nextSibling,Y.call(i,a),a=n}function g(e){var t=e.parentNode;return t&&t.invalidateShadowRenderer()}function b(e){for(var t,n=0;n<e.length;n++)t=e[n],t.parentNode.removeChild(t)}function y(e,t,n){var r;if(r=k(n?U.call(n,P(e),!1):q.call(P(e),!1)),t){for(var o=e.firstChild;o;o=o.nextSibling)r.appendChild(y(o,!0,n));if(e instanceof F.HTMLTemplateElement)for(var i=r.content,o=e.content.firstChild;o;o=o.nextSibling)i.appendChild(y(o,!0,n))}return r}function E(e,t){if(!t||N(e)!==N(t))return!1;for(var n=t;n;n=n.parentNode)if(n===e)return!0;return!1}function S(e){L(e instanceof V),T.call(this,e),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0,this.treeScope_=void 0}var T=e.wrappers.EventTarget,M=e.wrappers.NodeList,_=e.TreeScope,L=e.assert,O=e.defineWrapGetter,C=e.enqueueMutation,N=e.getTreeScope,D=e.isWrapper,j=e.mixin,H=e.registerTransientObservers,x=e.registerWrapper,R=e.setTreeScope,P=e.unsafeUnwrap,I=e.unwrap,A=e.unwrapIfNeeded,k=e.wrap,W=e.wrapIfNeeded,F=e.wrappers,B=!1,U=document.importNode,q=window.Node.prototype.cloneNode,V=window.Node,G=window.DocumentFragment,z=(V.prototype.appendChild,V.prototype.compareDocumentPosition),K=V.prototype.insertBefore,Y=V.prototype.removeChild,X=V.prototype.replaceChild,$=/Trident|Edge/.test(navigator.userAgent),J=$?function(e,t){try{Y.call(e,t)}catch(n){if(!(e instanceof G))throw n}}:function(e,t){Y.call(e,t)};S.prototype=Object.create(T.prototype),j(S.prototype,{appendChild:function(e){return this.insertBefore(e,null)},insertBefore:function(e,n){t(e);var r;n?D(n)?r=I(n):(r=n,n=k(r)):(n=null,r=null),n&&L(n.parentNode===this);var o,s=n?n.previousSibling:this.lastChild,c=!this.invalidateShadowRenderer()&&!g(e);if(o=c?a(e):i(e,this,s,n),c)f(this,e),w(this),K.call(P(this),I(e),r);else{s||(this.firstChild_=o[0]),n||(this.lastChild_=o[o.length-1],void 0===this.firstChild_&&(this.firstChild_=this.firstChild));var l=r?r.parentNode:P(this);l?K.call(l,m(this,o),r):h(this,o)}return C(this,"childList",{addedNodes:o,nextSibling:n,previousSibling:s}),u(o,this),e},removeChild:function(e){if(t(e),e.parentNode!==this){for(var r=!1,o=(this.childNodes,this.firstChild);o;o=o.nextSibling)if(o===e){r=!0;break}if(!r)throw new Error("NotFoundError")}var i=I(e),a=e.nextSibling,s=e.previousSibling;if(this.invalidateShadowRenderer()){var c=this.firstChild,l=this.lastChild,u=i.parentNode;u&&J(u,i),c===e&&(this.firstChild_=a),l===e&&(this.lastChild_=s),s&&(s.nextSibling_=a),a&&(a.previousSibling_=s),e.previousSibling_=e.nextSibling_=e.parentNode_=void 0}else w(this),J(P(this),i);return B||C(this,"childList",{removedNodes:n(e),nextSibling:a,previousSibling:s}),H(this,e),e},replaceChild:function(e,r){t(e);var o;if(D(r)?o=I(r):(o=r,r=k(o)),r.parentNode!==this)throw new Error("NotFoundError");var s,c=r.nextSibling,l=r.previousSibling,p=!this.invalidateShadowRenderer()&&!g(e);return p?s=a(e):(c===e&&(c=e.nextSibling),s=i(e,this,l,c)),p?(f(this,e),w(this),X.call(P(this),I(e),o)):(this.firstChild===r&&(this.firstChild_=s[0]),this.lastChild===r&&(this.lastChild_=s[s.length-1]),r.previousSibling_=r.nextSibling_=r.parentNode_=void 0,o.parentNode&&X.call(o.parentNode,m(this,s),o)),C(this,"childList",{addedNodes:s,removedNodes:n(r),nextSibling:c,previousSibling:l}),d(r),u(s,this),r},nodeIsInserted_:function(){for(var e=this.firstChild;e;e=e.nextSibling)e.nodeIsInserted_()},hasChildNodes:function(){return null!==this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:k(P(this).parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:k(P(this).firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:k(P(this).lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:k(P(this).nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:k(P(this).previousSibling)},get parentElement(){for(var e=this.parentNode;e&&e.nodeType!==S.ELEMENT_NODE;)e=e.parentNode;return e},get textContent(){for(var e="",t=this.firstChild;t;t=t.nextSibling)t.nodeType!=S.COMMENT_NODE&&(e+=t.textContent);return e},set textContent(e){null==e&&(e="");var t=c(this.childNodes);if(this.invalidateShadowRenderer()){if(v(this),""!==e){var n=P(this).ownerDocument.createTextNode(e);this.appendChild(n)}}else w(this),P(this).textContent=e;var r=c(this.childNodes);C(this,"childList",{addedNodes:r,removedNodes:t}),p(t),u(r,this)},get childNodes(){for(var e=new M,t=0,n=this.firstChild;n;n=n.nextSibling)e[t++]=n;return e.length=t,e},cloneNode:function(e){return y(this,e)},contains:function(e){return E(this,W(e))},compareDocumentPosition:function(e){return z.call(P(this),A(e))},normalize:function(){for(var e,t,n=c(this.childNodes),r=[],o="",i=0;i<n.length;i++)t=n[i],t.nodeType===S.TEXT_NODE?e||t.data.length?e?(o+=t.data,r.push(t)):e=t:this.removeChild(t):(e&&r.length&&(e.data+=o,b(r)),r=[],o="",e=null,t.childNodes.length&&t.normalize());e&&r.length&&(e.data+=o,b(r))}}),O(S,"ownerDocument"),x(V,S,document.createDocumentFragment()),delete S.prototype.querySelector,delete S.prototype.querySelectorAll,S.prototype=j(Object.create(T.prototype),S.prototype),e.cloneNode=y,e.nodeWasAdded=l,e.nodeWasRemoved=d,e.nodesWereAdded=u,e.nodesWereRemoved=p,e.originalInsertBefore=K,e.originalRemoveChild=Y,e.snapshotNodeList=c,e.wrappers.Node=S}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n,r,o){for(var i=null,a=null,s=0,c=t.length;c>s;s++)i=b(t[s]),!o&&(a=v(i).root)&&a instanceof e.wrappers.ShadowRoot||(r[n++]=i);return n}function n(e){return String(e).replace(/\/deep\/|::shadow/g," ")}function r(e){return String(e).replace(/:host\(([^\s]+)\)/g,"$1").replace(/([^\s]):host/g,"$1").replace(":host","*").replace(/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content/g," ")}function o(e,t){for(var n,r=e.firstElementChild;r;){if(r.matches(t))return r;if(n=o(r,t))return n;r=r.nextElementSibling}return null}function i(e,t){return e.matches(t)}function a(e,t,n){var r=e.localName;return r===t||r===n&&e.namespaceURI===D}function s(){return!0}function c(e,t,n){return e.localName===n}function l(e,t){return e.namespaceURI===t}function u(e,t,n){return e.namespaceURI===t&&e.localName===n}function d(e,t,n,r,o,i){for(var a=e.firstElementChild;a;)r(a,o,i)&&(n[t++]=a),t=d(a,t,n,r,o,i),a=a.nextElementSibling;return t}function p(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,null);if(c instanceof C)s=T.call(c,i);else{if(!(c instanceof N))return d(this,r,o,n,i,null);s=S.call(c,i)}return t(s,r,o,a)}function f(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,a);if(c instanceof C)s=_.call(c,i,a);else{if(!(c instanceof N))return d(this,r,o,n,i,a);s=M.call(c,i,a)}return t(s,r,o,!1)}function h(n,r,o,i,a){var s,c=g(this),l=v(this).root;if(l instanceof e.wrappers.ShadowRoot)return d(this,r,o,n,i,a);if(c instanceof C)s=O.call(c,i,a);else{if(!(c instanceof N))return d(this,r,o,n,i,a);s=L.call(c,i,a)}return t(s,r,o,!1)}var m=e.wrappers.HTMLCollection,w=e.wrappers.NodeList,v=e.getTreeScope,g=e.unsafeUnwrap,b=e.wrap,y=document.querySelector,E=document.documentElement.querySelector,S=document.querySelectorAll,T=document.documentElement.querySelectorAll,M=document.getElementsByTagName,_=document.documentElement.getElementsByTagName,L=document.getElementsByTagNameNS,O=document.documentElement.getElementsByTagNameNS,C=window.Element,N=window.HTMLDocument||window.Document,D="http://www.w3.org/1999/xhtml",j={querySelector:function(t){var r=n(t),i=r!==t;t=r;var a,s=g(this),c=v(this).root;if(c instanceof e.wrappers.ShadowRoot)return o(this,t);if(s instanceof C)a=b(E.call(s,t));else{if(!(s instanceof N))return o(this,t);a=b(y.call(s,t))}return a&&!i&&(c=v(a).root)&&c instanceof e.wrappers.ShadowRoot?o(this,t):a},querySelectorAll:function(e){var t=n(e),r=t!==e;e=t;var o=new w;return o.length=p.call(this,i,0,o,e,r),o
-}},H={matches:function(t){return t=r(t),e.originalMatches.call(g(this),t)}},x={getElementsByTagName:function(e){var t=new m,n="*"===e?s:a;return t.length=f.call(this,n,0,t,e,e.toLowerCase()),t},getElementsByClassName:function(e){return this.querySelectorAll("."+e)},getElementsByTagNameNS:function(e,t){var n=new m,r=null;return r="*"===e?"*"===t?s:c:"*"===t?l:u,n.length=h.call(this,r,0,n,e||null,t),n}};e.GetElementsByInterface=x,e.SelectorsInterface=j,e.MatchesInterface=H}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;return e}function n(e){for(;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.previousSibling;return e}var r=e.wrappers.NodeList,o={get firstElementChild(){return t(this.firstChild)},get lastElementChild(){return n(this.lastChild)},get childElementCount(){for(var e=0,t=this.firstElementChild;t;t=t.nextElementSibling)e++;return e},get children(){for(var e=new r,t=0,n=this.firstElementChild;n;n=n.nextElementSibling)e[t++]=n;return e.length=t,e},remove:function(){var e=this.parentNode;e&&e.removeChild(this)}},i={get nextElementSibling(){return t(this.nextSibling)},get previousElementSibling(){return n(this.previousSibling)}};e.ChildNodeInterface=i,e.ParentNodeInterface=o}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}var n=e.ChildNodeInterface,r=e.wrappers.Node,o=e.enqueueMutation,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=window.CharacterData;t.prototype=Object.create(r.prototype),i(t.prototype,{get textContent(){return this.data},set textContent(e){this.data=e},get data(){return s(this).data},set data(e){var t=s(this).data;o(this,"characterData",{oldValue:t}),s(this).data=e}}),i(t.prototype,n),a(c,t,document.createTextNode("")),e.wrappers.CharacterData=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e>>>0}function n(e){r.call(this,e)}var r=e.wrappers.CharacterData,o=(e.enqueueMutation,e.mixin),i=e.registerWrapper,a=window.Text;n.prototype=Object.create(r.prototype),o(n.prototype,{splitText:function(e){e=t(e);var n=this.data;if(e>n.length)throw new Error("IndexSizeError");var r=n.slice(0,e),o=n.slice(e);this.data=r;var i=this.ownerDocument.createTextNode(o);return this.parentNode&&this.parentNode.insertBefore(i,this.nextSibling),i}}),i(a,n,document.createTextNode("")),e.wrappers.Text=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return i(e).getAttribute("class")}function n(e,t){a(e,"attributes",{name:"class",namespace:null,oldValue:t})}function r(t){e.invalidateRendererBasedOnAttribute(t,"class")}function o(e,o,i){var a=e.ownerElement_;if(null==a)return o.apply(e,i);var s=t(a),c=o.apply(e,i);return t(a)!==s&&(n(a,s),r(a)),c}if(!window.DOMTokenList)return void console.warn("Missing DOMTokenList prototype, please include a compatible classList polyfill such as http://goo.gl/uTcepH.");var i=e.unsafeUnwrap,a=e.enqueueMutation,s=DOMTokenList.prototype.add;DOMTokenList.prototype.add=function(){o(this,s,arguments)};var c=DOMTokenList.prototype.remove;DOMTokenList.prototype.remove=function(){o(this,c,arguments)};var l=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(){return o(this,l,arguments)}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t,n){var r=t.parentNode;if(r&&r.shadowRoot){var o=e.getRendererForHost(r);o.dependsOnAttribute(n)&&o.invalidate()}}function n(e,t,n){u(e,"attributes",{name:t,namespace:null,oldValue:n})}function r(e){a.call(this,e)}var o=e.ChildNodeInterface,i=e.GetElementsByInterface,a=e.wrappers.Node,s=e.ParentNodeInterface,c=e.SelectorsInterface,l=e.MatchesInterface,u=(e.addWrapNodeListMethod,e.enqueueMutation),d=e.mixin,p=(e.oneOf,e.registerWrapper),f=e.unsafeUnwrap,h=e.wrappers,m=window.Element,w=["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"].filter(function(e){return m.prototype[e]}),v=w[0],g=m.prototype[v],b=new WeakMap;r.prototype=Object.create(a.prototype),d(r.prototype,{createShadowRoot:function(){var t=new h.ShadowRoot(this);f(this).polymerShadowRoot_=t;var n=e.getRendererForHost(this);return n.invalidate(),t},get shadowRoot(){return f(this).polymerShadowRoot_||null},setAttribute:function(e,r){var o=f(this).getAttribute(e);f(this).setAttribute(e,r),n(this,e,o),t(this,e)},removeAttribute:function(e){var r=f(this).getAttribute(e);f(this).removeAttribute(e),n(this,e,r),t(this,e)},get classList(){var e=b.get(this);if(!e){if(e=f(this).classList,!e)return;e.ownerElement_=this,b.set(this,e)}return e},get className(){return f(this).className},set className(e){this.setAttribute("class",e)},get id(){return f(this).id},set id(e){this.setAttribute("id",e)}}),w.forEach(function(e){"matches"!==e&&(r.prototype[e]=function(e){return this.matches(e)})}),m.prototype.webkitCreateShadowRoot&&(r.prototype.webkitCreateShadowRoot=r.prototype.createShadowRoot),d(r.prototype,o),d(r.prototype,i),d(r.prototype,s),d(r.prototype,c),d(r.prototype,l),p(m,r,document.createElementNS(null,"x")),e.invalidateRendererBasedOnAttribute=t,e.matchesNames=w,e.originalMatches=g,e.wrappers.Element=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e){case"&":return"&amp;";case"<":return"&lt;";case">":return"&gt;";case'"':return"&quot;";case" ":return"&nbsp;"}}function n(e){return e.replace(L,t)}function r(e){return e.replace(O,t)}function o(e){for(var t={},n=0;n<e.length;n++)t[e[n]]=!0;return t}function i(e,t){switch(e.nodeType){case Node.ELEMENT_NODE:for(var o,i=e.tagName.toLowerCase(),s="<"+i,c=e.attributes,l=0;o=c[l];l++)s+=" "+o.name+'="'+n(o.value)+'"';return s+=">",C[i]?s:s+a(e)+"</"+i+">";case Node.TEXT_NODE:var u=e.data;return t&&N[t.localName]?u:r(u);case Node.COMMENT_NODE:return"<!--"+e.data+"-->";default:throw console.error(e),new Error("not implemented")}}function a(e){e instanceof _.HTMLTemplateElement&&(e=e.content);for(var t="",n=e.firstChild;n;n=n.nextSibling)t+=i(n,e);return t}function s(e,t,n){var r=n||"div";e.textContent="";var o=T(e.ownerDocument.createElement(r));o.innerHTML=t;for(var i;i=o.firstChild;)e.appendChild(M(i))}function c(e){h.call(this,e)}function l(e,t){var n=T(e.cloneNode(!1));n.innerHTML=t;for(var r,o=T(document.createDocumentFragment());r=n.firstChild;)o.appendChild(r);return M(o)}function u(t){return function(){return e.renderAllPending(),S(this)[t]}}function d(e){m(c,e,u(e))}function p(t){Object.defineProperty(c.prototype,t,{get:u(t),set:function(n){e.renderAllPending(),S(this)[t]=n},configurable:!0,enumerable:!0})}function f(t){Object.defineProperty(c.prototype,t,{value:function(){return e.renderAllPending(),S(this)[t].apply(S(this),arguments)},configurable:!0,enumerable:!0})}var h=e.wrappers.Element,m=e.defineGetter,w=e.enqueueMutation,v=e.mixin,g=e.nodesWereAdded,b=e.nodesWereRemoved,y=e.registerWrapper,E=e.snapshotNodeList,S=e.unsafeUnwrap,T=e.unwrap,M=e.wrap,_=e.wrappers,L=/[&\u00A0"]/g,O=/[&\u00A0<>]/g,C=o(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),N=o(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),D=/MSIE/.test(navigator.userAgent),j=window.HTMLElement,H=window.HTMLTemplateElement;c.prototype=Object.create(h.prototype),v(c.prototype,{get innerHTML(){return a(this)},set innerHTML(e){if(D&&N[this.localName])return void(this.textContent=e);var t=E(this.childNodes);this.invalidateShadowRenderer()?this instanceof _.HTMLTemplateElement?s(this.content,e):s(this,e,this.tagName):!H&&this instanceof _.HTMLTemplateElement?s(this.content,e):S(this).innerHTML=e;var n=E(this.childNodes);w(this,"childList",{addedNodes:n,removedNodes:t}),b(t),g(n,this)},get outerHTML(){return i(this,this.parentNode)},set outerHTML(e){var t=this.parentNode;if(t){t.invalidateShadowRenderer();var n=l(t,e);t.replaceChild(n,this)}},insertAdjacentHTML:function(e,t){var n,r;switch(String(e).toLowerCase()){case"beforebegin":n=this.parentNode,r=this;break;case"afterend":n=this.parentNode,r=this.nextSibling;break;case"afterbegin":n=this,r=this.firstChild;break;case"beforeend":n=this,r=null;break;default:return}var o=l(n,t);n.insertBefore(o,r)},get hidden(){return this.hasAttribute("hidden")},set hidden(e){e?this.setAttribute("hidden",""):this.removeAttribute("hidden")}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollWidth"].forEach(d),["scrollLeft","scrollTop"].forEach(p),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(f),y(j,c,document.createElement("b")),e.wrappers.HTMLElement=c,e.getInnerHTML=a,e.setInnerHTML=s}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.HTMLCanvasElement;t.prototype=Object.create(n.prototype),r(t.prototype,{getContext:function(){var e=i(this).getContext.apply(i(this),arguments);return e&&a(e)}}),o(s,t,document.createElement("canvas")),e.wrappers.HTMLCanvasElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=window.HTMLContentElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get select(){return this.getAttribute("select")},set select(e){this.setAttribute("select",e)},setAttribute:function(e,t){n.prototype.setAttribute.call(this,e,t),"select"===String(e).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),i&&o(i,t),e.wrappers.HTMLContentElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=window.HTMLFormElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get elements(){return i(a(this).elements)}}),o(s,t,document.createElement("form")),e.wrappers.HTMLFormElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e,t){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var o=i(document.createElement("img"));r.call(this,o),a(o,this),void 0!==e&&(o.width=e),void 0!==t&&(o.height=t)}var r=e.wrappers.HTMLElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLImageElement;t.prototype=Object.create(r.prototype),o(s,t,document.createElement("img")),n.prototype=t.prototype,e.wrappers.HTMLImageElement=t,e.wrappers.Image=n}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=(e.mixin,e.wrappers.NodeList,e.registerWrapper),o=window.HTMLShadowElement;t.prototype=Object.create(n.prototype),t.prototype.constructor=t,o&&r(o,t),e.wrappers.HTMLShadowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){if(!e.defaultView)return e;var t=d.get(e);if(!t){for(t=e.implementation.createHTMLDocument("");t.lastChild;)t.removeChild(t.lastChild);d.set(e,t)}return t}function n(e){for(var n,r=t(e.ownerDocument),o=c(r.createDocumentFragment());n=e.firstChild;)o.appendChild(n);return o}function r(e){if(o.call(this,e),!p){var t=n(e);u.set(this,l(t))}}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.unsafeUnwrap,c=e.unwrap,l=e.wrap,u=new WeakMap,d=new WeakMap,p=window.HTMLTemplateElement;r.prototype=Object.create(o.prototype),i(r.prototype,{constructor:r,get content(){return p?l(s(this).content):u.get(this)}}),p&&a(p,r),e.wrappers.HTMLTemplateElement=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.registerWrapper,o=window.HTMLMediaElement;o&&(t.prototype=Object.create(n.prototype),r(o,t,document.createElement("audio")),e.wrappers.HTMLMediaElement=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r.call(this,e)}function n(e){if(!(this instanceof n))throw new TypeError("DOM object constructor cannot be called as a function.");var t=i(document.createElement("audio"));r.call(this,t),a(t,this),t.setAttribute("preload","auto"),void 0!==e&&t.setAttribute("src",e)}var r=e.wrappers.HTMLMediaElement,o=e.registerWrapper,i=e.unwrap,a=e.rewrap,s=window.HTMLAudioElement;s&&(t.prototype=Object.create(r.prototype),o(s,t,document.createElement("audio")),n.prototype=t.prototype,e.wrappers.HTMLAudioElement=t,e.wrappers.Audio=n)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){return e.replace(/\s+/g," ").trim()}function n(e){o.call(this,e)}function r(e,t,n,i){if(!(this instanceof r))throw new TypeError("DOM object constructor cannot be called as a function.");var a=c(document.createElement("option"));o.call(this,a),s(a,this),void 0!==e&&(a.text=e),void 0!==t&&a.setAttribute("value",t),n===!0&&a.setAttribute("selected",""),a.selected=i===!0}var o=e.wrappers.HTMLElement,i=e.mixin,a=e.registerWrapper,s=e.rewrap,c=e.unwrap,l=e.wrap,u=window.HTMLOptionElement;n.prototype=Object.create(o.prototype),i(n.prototype,{get text(){return t(this.textContent)},set text(e){this.textContent=t(String(e))},get form(){return l(c(this).form)}}),a(u,n,document.createElement("option")),r.prototype=n.prototype,e.wrappers.HTMLOptionElement=n,e.wrappers.Option=r}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=window.HTMLSelectElement;t.prototype=Object.create(n.prototype),r(t.prototype,{add:function(e,t){"object"==typeof t&&(t=i(t)),i(this).add(i(e),t)},remove:function(e){return void 0===e?void n.prototype.remove.call(this):("object"==typeof e&&(e=i(e)),void i(this).remove(e))},get form(){return a(i(this).form)}}),o(s,t,document.createElement("select")),e.wrappers.HTMLSelectElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.unwrap,a=e.wrap,s=e.wrapHTMLCollection,c=window.HTMLTableElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get caption(){return a(i(this).caption)},createCaption:function(){return a(i(this).createCaption())},get tHead(){return a(i(this).tHead)},createTHead:function(){return a(i(this).createTHead())},createTFoot:function(){return a(i(this).createTFoot())},get tFoot(){return a(i(this).tFoot)},get tBodies(){return s(i(this).tBodies)},createTBody:function(){return a(i(this).createTBody())},get rows(){return s(i(this).rows)},insertRow:function(e){return a(i(this).insertRow(e))}}),o(c,t,document.createElement("table")),e.wrappers.HTMLTableElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableSectionElement;t.prototype=Object.create(n.prototype),r(t.prototype,{constructor:t,get rows(){return i(a(this).rows)},insertRow:function(e){return s(a(this).insertRow(e))}}),o(c,t,document.createElement("thead")),e.wrappers.HTMLTableSectionElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.HTMLElement,r=e.mixin,o=e.registerWrapper,i=e.wrapHTMLCollection,a=e.unwrap,s=e.wrap,c=window.HTMLTableRowElement;t.prototype=Object.create(n.prototype),r(t.prototype,{get cells(){return i(a(this).cells)},insertCell:function(e){return s(a(this).insertCell(e))}}),o(c,t,document.createElement("tr")),e.wrappers.HTMLTableRowElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){switch(e.localName){case"content":return new n(e);case"shadow":return new o(e);case"template":return new i(e)}r.call(this,e)}var n=e.wrappers.HTMLContentElement,r=e.wrappers.HTMLElement,o=e.wrappers.HTMLShadowElement,i=e.wrappers.HTMLTemplateElement,a=(e.mixin,e.registerWrapper),s=window.HTMLUnknownElement;t.prototype=Object.create(r.prototype),a(s,t),e.wrappers.HTMLUnknownElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.wrappers.Element,n=e.wrappers.HTMLElement,r=e.registerObject,o=e.defineWrapGetter,i="http://www.w3.org/2000/svg",a=document.createElementNS(i,"title"),s=r(a),c=Object.getPrototypeOf(s.prototype).constructor;if(!("classList"in a)){var l=Object.getOwnPropertyDescriptor(t.prototype,"classList");Object.defineProperty(n.prototype,"classList",l),delete t.prototype.classList}o(c,"ownerSVGElement"),e.wrappers.SVGElement=c}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){p.call(this,e)}var n=e.mixin,r=e.registerWrapper,o=e.unwrap,i=e.wrap,a=window.SVGUseElement,s="http://www.w3.org/2000/svg",c=i(document.createElementNS(s,"g")),l=document.createElementNS(s,"use"),u=c.constructor,d=Object.getPrototypeOf(u.prototype),p=d.constructor;t.prototype=Object.create(d),"instanceRoot"in l&&n(t.prototype,{get instanceRoot(){return i(o(this).instanceRoot)},get animatedInstanceRoot(){return i(o(this).animatedInstanceRoot)}}),r(a,t,l),e.wrappers.SVGUseElement=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.mixin,o=e.registerWrapper,i=e.unsafeUnwrap,a=e.wrap,s=window.SVGElementInstance;s&&(t.prototype=Object.create(n.prototype),r(t.prototype,{get correspondingElement(){return a(i(this).correspondingElement)},get correspondingUseElement(){return a(i(this).correspondingUseElement)},get parentNode(){return a(i(this).parentNode)},get childNodes(){throw new Error("Not implemented")},get firstChild(){return a(i(this).firstChild)},get lastChild(){return a(i(this).lastChild)},get previousSibling(){return a(i(this).previousSibling)},get nextSibling(){return a(i(this).nextSibling)}}),o(s,t),e.wrappers.SVGElementInstance=t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrap,s=e.unwrapIfNeeded,c=e.wrap,l=window.CanvasRenderingContext2D;n(t.prototype,{get canvas(){return c(i(this).canvas)},drawImage:function(){arguments[0]=s(arguments[0]),i(this).drawImage.apply(i(this),arguments)},createPattern:function(){return arguments[0]=a(arguments[0]),i(this).createPattern.apply(i(this),arguments)}}),r(l,t,document.createElement("canvas").getContext("2d")),e.wrappers.CanvasRenderingContext2D=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){o(e,this)}var n=e.mixin,r=e.registerWrapper,o=e.setWrapper,i=e.unsafeUnwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.WebGLRenderingContext;if(c){n(t.prototype,{get canvas(){return s(i(this).canvas)},texImage2D:function(){arguments[5]=a(arguments[5]),i(this).texImage2D.apply(i(this),arguments)},texSubImage2D:function(){arguments[6]=a(arguments[6]),i(this).texSubImage2D.apply(i(this),arguments)}});var l=/WebKit/.test(navigator.userAgent)?{drawingBufferHeight:null,drawingBufferWidth:null}:{};r(c,t,l),e.wrappers.WebGLRenderingContext=t}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap,c=window.Range;t.prototype={get startContainer(){return s(o(this).startContainer)},get endContainer(){return s(o(this).endContainer)},get commonAncestorContainer(){return s(o(this).commonAncestorContainer)},setStart:function(e,t){o(this).setStart(a(e),t)},setEnd:function(e,t){o(this).setEnd(a(e),t)},setStartBefore:function(e){o(this).setStartBefore(a(e))},setStartAfter:function(e){o(this).setStartAfter(a(e))},setEndBefore:function(e){o(this).setEndBefore(a(e))},setEndAfter:function(e){o(this).setEndAfter(a(e))},selectNode:function(e){o(this).selectNode(a(e))},selectNodeContents:function(e){o(this).selectNodeContents(a(e))},compareBoundaryPoints:function(e,t){return o(this).compareBoundaryPoints(e,i(t))},extractContents:function(){return s(o(this).extractContents())},cloneContents:function(){return s(o(this).cloneContents())},insertNode:function(e){o(this).insertNode(a(e))},surroundContents:function(e){o(this).surroundContents(a(e))},cloneRange:function(){return s(o(this).cloneRange())},isPointInRange:function(e,t){return o(this).isPointInRange(a(e),t)},comparePoint:function(e,t){return o(this).comparePoint(a(e),t)},intersectsNode:function(e){return o(this).intersectsNode(a(e))},toString:function(){return o(this).toString()}},c.prototype.createContextualFragment&&(t.prototype.createContextualFragment=function(e){return s(o(this).createContextualFragment(e))}),n(window.Range,t,document.createRange()),e.wrappers.Range=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.GetElementsByInterface,n=e.ParentNodeInterface,r=e.SelectorsInterface,o=e.mixin,i=e.registerObject,a=i(document.createDocumentFragment());o(a.prototype,n),o(a.prototype,r),o(a.prototype,t);var s=i(document.createComment(""));e.wrappers.Comment=s,e.wrappers.DocumentFragment=a}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=d(u(e).ownerDocument.createDocumentFragment());n.call(this,t),c(t,this);var o=e.shadowRoot;f.set(this,o),this.treeScope_=new r(this,a(o||e)),p.set(this,e)}var n=e.wrappers.DocumentFragment,r=e.TreeScope,o=e.elementFromPoint,i=e.getInnerHTML,a=e.getTreeScope,s=e.mixin,c=e.rewrap,l=e.setInnerHTML,u=e.unsafeUnwrap,d=e.unwrap,p=new WeakMap,f=new WeakMap,h=/[ \t\n\r\f]/;t.prototype=Object.create(n.prototype),s(t.prototype,{constructor:t,get innerHTML(){return i(this)},set innerHTML(e){l(this,e),this.invalidateShadowRenderer()},get olderShadowRoot(){return f.get(this)||null},get host(){return p.get(this)||null},invalidateShadowRenderer:function(){return p.get(this).invalidateShadowRenderer()},elementFromPoint:function(e,t){return o(this,this.ownerDocument,e,t)},getElementById:function(e){return h.test(e)?null:this.querySelector('[id="'+e+'"]')}}),e.wrappers.ShadowRoot=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){e.previousSibling_=e.previousSibling,e.nextSibling_=e.nextSibling,e.parentNode_=e.parentNode}function n(n,o,i){var a=x(n),s=x(o),c=i?x(i):null;if(r(o),t(o),i)n.firstChild===i&&(n.firstChild_=i),i.previousSibling_=i.previousSibling;else{n.lastChild_=n.lastChild,n.lastChild===n.firstChild&&(n.firstChild_=n.firstChild);var l=R(a.lastChild);l&&(l.nextSibling_=l.nextSibling)}e.originalInsertBefore.call(a,s,c)}function r(n){var r=x(n),o=r.parentNode;if(o){var i=R(o);t(n),n.previousSibling&&(n.previousSibling.nextSibling_=n),n.nextSibling&&(n.nextSibling.previousSibling_=n),i.lastChild===n&&(i.lastChild_=n),i.firstChild===n&&(i.firstChild_=n),e.originalRemoveChild.call(o,r)}}function o(e){I.set(e,[])}function i(e){var t=I.get(e);return t||I.set(e,t=[]),t}function a(e){for(var t=[],n=0,r=e.firstChild;r;r=r.nextSibling)t[n++]=r;return t}function s(){for(var e=0;e<F.length;e++){var t=F[e],n=t.parentRenderer;n&&n.dirty||t.render()}F=[]}function c(){M=null,s()}function l(e){var t=k.get(e);return t||(t=new f(e),k.set(e,t)),t}function u(e){var t=D(e).root;return t instanceof N?t:null}function d(e){return l(e.host)}function p(e){this.skip=!1,this.node=e,this.childNodes=[]}function f(e){this.host=e,this.dirty=!1,this.invalidateAttributes(),this.associateNode(e)}function h(e){for(var t=[],n=e.firstChild;n;n=n.nextSibling)E(n)?t.push.apply(t,i(n)):t.push(n);return t}function m(e){if(e instanceof O)return e;if(e instanceof L)return null;for(var t=e.firstChild;t;t=t.nextSibling){var n=m(t);if(n)return n}return null}function w(e,t){i(t).push(e);var n=A.get(e);n?n.push(t):A.set(e,[t])}function v(e){return A.get(e)}function g(e){A.set(e,void 0)}function b(e,t){var n=t.getAttribute("select");if(!n)return!0;if(n=n.trim(),!n)return!0;if(!(e instanceof _))return!1;if(!U.test(n))return!1;try{return e.matches(n)}catch(r){return!1}}function y(e,t){var n=v(t);return n&&n[n.length-1]===e}function E(e){return e instanceof L||e instanceof O}function S(e){return e.shadowRoot}function T(e){for(var t=[],n=e.shadowRoot;n;n=n.olderShadowRoot)t.push(n);return t}var M,_=e.wrappers.Element,L=e.wrappers.HTMLContentElement,O=e.wrappers.HTMLShadowElement,C=e.wrappers.Node,N=e.wrappers.ShadowRoot,D=(e.assert,e.getTreeScope),j=(e.mixin,e.oneOf),H=e.unsafeUnwrap,x=e.unwrap,R=e.wrap,P=e.ArraySplice,I=new WeakMap,A=new WeakMap,k=new WeakMap,W=j(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),F=[],B=new P;B.equals=function(e,t){return x(e.node)===t},p.prototype={append:function(e){var t=new p(e);return this.childNodes.push(t),t},sync:function(e){if(!this.skip){for(var t=this.node,o=this.childNodes,i=a(x(t)),s=e||new WeakMap,c=B.calculateSplices(o,i),l=0,u=0,d=0,p=0;p<c.length;p++){for(var f=c[p];d<f.index;d++)u++,o[l++].sync(s);for(var h=f.removed.length,m=0;h>m;m++){var w=R(i[u++]);s.get(w)||r(w)}for(var v=f.addedCount,g=i[u]&&R(i[u]),m=0;v>m;m++){var b=o[l++],y=b.node;n(t,y,g),s.set(y,!0),b.sync(s)}d+=v}for(var p=d;p<o.length;p++)o[p].sync(s)}}},f.prototype={render:function(e){if(this.dirty){this.invalidateAttributes();var t=this.host;this.distribution(t);var n=e||new p(t);this.buildRenderTree(n,t);var r=!e;r&&n.sync(),this.dirty=!1}},get parentRenderer(){return D(this.host).renderer},invalidate:function(){if(!this.dirty){this.dirty=!0;var e=this.parentRenderer;if(e&&e.invalidate(),F.push(this),M)return;M=window[W](c,0)}},distribution:function(e){this.resetAllSubtrees(e),this.distributionResolution(e)},resetAll:function(e){E(e)?o(e):g(e),this.resetAllSubtrees(e)},resetAllSubtrees:function(e){for(var t=e.firstChild;t;t=t.nextSibling)this.resetAll(t);e.shadowRoot&&this.resetAll(e.shadowRoot),e.olderShadowRoot&&this.resetAll(e.olderShadowRoot)},distributionResolution:function(e){if(S(e)){for(var t=e,n=h(t),r=T(t),o=0;o<r.length;o++)this.poolDistribution(r[o],n);for(var o=r.length-1;o>=0;o--){var i=r[o],a=m(i);if(a){var s=i.olderShadowRoot;s&&(n=h(s));for(var c=0;c<n.length;c++)w(n[c],a)}this.distributionResolution(i)}}for(var l=e.firstChild;l;l=l.nextSibling)this.distributionResolution(l)},poolDistribution:function(e,t){if(!(e instanceof O))if(e instanceof L){var n=e;this.updateDependentAttributes(n.getAttribute("select"));for(var r=!1,o=0;o<t.length;o++){var e=t[o];e&&b(e,n)&&(w(e,n),t[o]=void 0,r=!0)}if(!r)for(var i=n.firstChild;i;i=i.nextSibling)w(i,n)}else for(var i=e.firstChild;i;i=i.nextSibling)this.poolDistribution(i,t)},buildRenderTree:function(e,t){for(var n=this.compose(t),r=0;r<n.length;r++){var o=n[r],i=e.append(o);this.buildRenderTree(i,o)}if(S(t)){var a=l(t);a.dirty=!1}},compose:function(e){for(var t=[],n=e.shadowRoot||e,r=n.firstChild;r;r=r.nextSibling)if(E(r)){this.associateNode(n);for(var o=i(r),a=0;a<o.length;a++){var s=o[a];y(r,s)&&t.push(s)}}else t.push(r);return t},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(e){if(e){var t=this.attributes;/\.\w+/.test(e)&&(t["class"]=!0),/#\w+/.test(e)&&(t.id=!0),e.replace(/\[\s*([^\s=\|~\]]+)/g,function(e,n){t[n]=!0})}},dependsOnAttribute:function(e){return this.attributes[e]},associateNode:function(e){H(e).polymerShadowRenderer_=this}};var U=/^(:not\()?[*.#[a-zA-Z_|]/;C.prototype.invalidateShadowRenderer=function(){var e=H(this).polymerShadowRenderer_;return e?(e.invalidate(),!0):!1},L.prototype.getDistributedNodes=O.prototype.getDistributedNodes=function(){return s(),i(this)},_.prototype.getDestinationInsertionPoints=function(){return s(),v(this)||[]},L.prototype.nodeIsInserted_=O.prototype.nodeIsInserted_=function(){this.invalidateShadowRenderer();var e,t=u(this);t&&(e=d(t)),H(this).polymerShadowRenderer_=e,e&&e.invalidate()},e.getRendererForHost=l,e.getShadowTrees=T,e.renderAllPending=s,e.getDestinationInsertionPoints=v,e.visual={insertBefore:n,remove:r}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(t){if(window[t]){r(!e.wrappers[t]);var c=function(e){n.call(this,e)};c.prototype=Object.create(n.prototype),o(c.prototype,{get form(){return s(a(this).form)}}),i(window[t],c,document.createElement(t.slice(4,-7))),e.wrappers[t]=c}}var n=e.wrappers.HTMLElement,r=e.assert,o=e.mixin,i=e.registerWrapper,a=e.unwrap,s=e.wrap,c=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOutputElement","HTMLTextAreaElement"];c.forEach(t)}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){r(e,this)}{var n=e.registerWrapper,r=e.setWrapper,o=e.unsafeUnwrap,i=e.unwrap,a=e.unwrapIfNeeded,s=e.wrap;window.Selection}t.prototype={get anchorNode(){return s(o(this).anchorNode)},get focusNode(){return s(o(this).focusNode)},addRange:function(e){o(this).addRange(i(e))},collapse:function(e,t){o(this).collapse(a(e),t)},containsNode:function(e,t){return o(this).containsNode(a(e),t)},extend:function(e,t){o(this).extend(a(e),t)},getRangeAt:function(e){return s(o(this).getRangeAt(e))},removeRange:function(e){o(this).removeRange(i(e))},selectAllChildren:function(e){o(this).selectAllChildren(a(e))},toString:function(){return o(this).toString()}},n(window.Selection,t,window.getSelection()),e.wrappers.Selection=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){u.call(this,e),this.treeScope_=new m(this,null)}function n(e){var n=document[e];t.prototype[e]=function(){return C(n.apply(L(this),arguments))}}function r(e,t){j.call(L(t),O(e)),o(e,t)}function o(e,t){e.shadowRoot&&t.adoptNode(e.shadowRoot),e instanceof h&&i(e,t);for(var n=e.firstChild;n;n=n.nextSibling)o(n,t)}function i(e,t){var n=e.olderShadowRoot;n&&t.adoptNode(n)}function a(e){_(e,this)}function s(e,t){var n=document.implementation[t];e.prototype[t]=function(){return C(n.apply(L(this),arguments))}}function c(e,t){var n=document.implementation[t];e.prototype[t]=function(){return n.apply(L(this),arguments)}}var l=e.GetElementsByInterface,u=e.wrappers.Node,d=e.ParentNodeInterface,p=e.wrappers.Selection,f=e.SelectorsInterface,h=e.wrappers.ShadowRoot,m=e.TreeScope,w=e.cloneNode,v=e.defineWrapGetter,g=e.elementFromPoint,b=e.forwardMethodsToWrapper,y=e.matchesNames,E=e.mixin,S=e.registerWrapper,T=e.renderAllPending,M=e.rewrap,_=e.setWrapper,L=e.unsafeUnwrap,O=e.unwrap,C=e.wrap,N=e.wrapEventTargetMethods,D=(e.wrapNodeList,new WeakMap);t.prototype=Object.create(u.prototype),v(t,"documentElement"),v(t,"body"),v(t,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(n);var j=document.adoptNode,H=document.getSelection;if(E(t.prototype,{adoptNode:function(e){return e.parentNode&&e.parentNode.removeChild(e),r(e,this),e},elementFromPoint:function(e,t){return g(this,this,e,t)},importNode:function(e,t){return w(e,t,L(this))},getSelection:function(){return T(),new p(H.call(O(this)))},getElementsByName:function(e){return f.querySelectorAll.call(this,"[name="+JSON.stringify(String(e))+"]")}}),document.registerElement){var x=document.registerElement;t.prototype.registerElement=function(t,n){function r(e){return e?void _(e,this):i?document.createElement(i,t):document.createElement(t)}var o,i;if(void 0!==n&&(o=n.prototype,i=n["extends"]),o||(o=Object.create(HTMLElement.prototype)),e.nativePrototypeTable.get(o))throw new Error("NotSupportedError");for(var a,s=Object.getPrototypeOf(o),c=[];s&&!(a=e.nativePrototypeTable.get(s));)c.push(s),s=Object.getPrototypeOf(s);if(!a)throw new Error("NotSupportedError");for(var l=Object.create(a),u=c.length-1;u>=0;u--)l=Object.create(l);["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"].forEach(function(e){var t=o[e];t&&(l[e]=function(){C(this)instanceof r||M(this),t.apply(C(this),arguments)})});var d={prototype:l};i&&(d["extends"]=i),r.prototype=o,r.prototype.constructor=r,e.constructorTable.set(l,r),e.nativePrototypeTable.set(o,l);x.call(O(this),t,d);return r},b([window.HTMLDocument||window.Document],["registerElement"])}b([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),b([window.HTMLBodyElement,window.HTMLHeadElement,window.HTMLHtmlElement],y),b([window.HTMLDocument||window.Document],["adoptNode","importNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById","getElementsByName","getSelection"]),E(t.prototype,l),E(t.prototype,d),E(t.prototype,f),E(t.prototype,{get implementation(){var e=D.get(this);
-return e?e:(e=new a(O(this).implementation),D.set(this,e),e)},get defaultView(){return C(O(this).defaultView)}}),S(window.Document,t,document.implementation.createHTMLDocument("")),window.HTMLDocument&&S(window.HTMLDocument,t),N([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),s(a,"createDocumentType"),s(a,"createDocument"),s(a,"createHTMLDocument"),c(a,"hasFeature"),S(window.DOMImplementation,a),b([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),e.adoptNodeNoRemove=r,e.wrappers.DOMImplementation=a,e.wrappers.Document=t}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){n.call(this,e)}var n=e.wrappers.EventTarget,r=e.wrappers.Selection,o=e.mixin,i=e.registerWrapper,a=e.renderAllPending,s=e.unwrap,c=e.unwrapIfNeeded,l=e.wrap,u=window.Window,d=window.getComputedStyle,p=window.getDefaultComputedStyle,f=window.getSelection;t.prototype=Object.create(n.prototype),u.prototype.getComputedStyle=function(e,t){return l(this||window).getComputedStyle(c(e),t)},p&&(u.prototype.getDefaultComputedStyle=function(e,t){return l(this||window).getDefaultComputedStyle(c(e),t)}),u.prototype.getSelection=function(){return l(this||window).getSelection()},delete window.getComputedStyle,delete window.getDefaultComputedStyle,delete window.getSelection,["addEventListener","removeEventListener","dispatchEvent"].forEach(function(e){u.prototype[e]=function(){var t=l(this||window);return t[e].apply(t,arguments)},delete window[e]}),o(t.prototype,{getComputedStyle:function(e,t){return a(),d.call(s(this),c(e),t)},getSelection:function(){return a(),new r(f.call(s(this)))},get document(){return l(s(this).document)}}),p&&(t.prototype.getDefaultComputedStyle=function(e,t){return a(),p.call(s(this),c(e),t)}),i(u,t,window),e.wrappers.Window=t}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrap,n=window.DataTransfer||window.Clipboard,r=n.prototype.setDragImage;r&&(n.prototype.setDragImage=function(e,n,o){r.call(this,t(e),n,o)})}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t;t=e instanceof i?e:new i(e&&o(e)),r(t,this)}var n=e.registerWrapper,r=e.setWrapper,o=e.unwrap,i=window.FormData;i&&(n(i,t,new i),e.wrappers.FormData=t)}(window.ShadowDOMPolyfill),function(e){"use strict";var t=e.unwrapIfNeeded,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(e){return n.call(this,t(e))}}(window.ShadowDOMPolyfill),function(e){"use strict";function t(e){var t=n[e],r=window[t];if(r){var o=document.createElement(e),i=o.constructor;window[t]=i}}var n=(e.isWrapperFor,{a:"HTMLAnchorElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",base:"HTMLBaseElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",content:"HTMLContentElement",data:"HTMLDataElement",datalist:"HTMLDataListElement",del:"HTMLModElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",head:"HTMLHeadElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",marquee:"HTMLMarqueeElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",shadow:"HTMLShadowElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",template:"HTMLTemplateElement",textarea:"HTMLTextAreaElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",ul:"HTMLUListElement",video:"HTMLVideoElement"});Object.keys(n).forEach(t),Object.getOwnPropertyNames(e.wrappers).forEach(function(t){window[t]=e.wrappers[t]})}(window.ShadowDOMPolyfill),function(e){function t(e,t){var n="";return Array.prototype.forEach.call(e,function(e){n+=e.textContent+"\n\n"}),t||(n=n.replace(d,"")),n}function n(e){var t=document.createElement("style");return t.textContent=e,t}function r(e){var t=n(e);document.head.appendChild(t);var r=[];if(t.sheet)try{r=t.sheet.cssRules}catch(o){}else console.warn("sheet not found",t);return t.parentNode.removeChild(t),r}function o(){N.initialized=!0,document.body.appendChild(N);var e=N.contentDocument,t=e.createElement("base");t.href=document.baseURI,e.head.appendChild(t)}function i(e){N.initialized||o(),document.body.appendChild(N),e(N.contentDocument),document.body.removeChild(N)}function a(e,t){if(t){var o;if(e.match("@import")&&j){var a=n(e);i(function(e){e.head.appendChild(a.impl),o=Array.prototype.slice.call(a.sheet.cssRules,0),t(o)})}else o=r(e),t(o)}}function s(e){e&&l().appendChild(document.createTextNode(e))}function c(e,t){var r=n(e);r.setAttribute(t,""),r.setAttribute(x,""),document.head.appendChild(r)}function l(){return D||(D=document.createElement("style"),D.setAttribute(x,""),D[x]=!0),D}var u={strictStyling:!1,registry:{},shimStyling:function(e,n,r){var o=this.prepareRoot(e,n,r),i=this.isTypeExtension(r),a=this.makeScopeSelector(n,i),s=t(o,!0);s=this.scopeCssText(s,a),e&&(e.shimmedStyle=s),this.addCssToDocument(s,n)},shimStyle:function(e,t){return this.shimCssText(e.textContent,t)},shimCssText:function(e,t){return e=this.insertDirectives(e),this.scopeCssText(e,t)},makeScopeSelector:function(e,t){return e?t?"[is="+e+"]":e:""},isTypeExtension:function(e){return e&&e.indexOf("-")<0},prepareRoot:function(e,t,n){var r=this.registerRoot(e,t,n);return this.replaceTextInStyles(r.rootStyles,this.insertDirectives),this.removeStyles(e,r.rootStyles),this.strictStyling&&this.applyScopeToContent(e,t),r.scopeStyles},removeStyles:function(e,t){for(var n,r=0,o=t.length;o>r&&(n=t[r]);r++)n.parentNode.removeChild(n)},registerRoot:function(e,t,n){var r=this.registry[t]={root:e,name:t,extendsName:n},o=this.findStyles(e);r.rootStyles=o,r.scopeStyles=r.rootStyles;var i=this.registry[r.extendsName];return i&&(r.scopeStyles=i.scopeStyles.concat(r.scopeStyles)),r},findStyles:function(e){if(!e)return[];var t=e.querySelectorAll("style");return Array.prototype.filter.call(t,function(e){return!e.hasAttribute(R)})},applyScopeToContent:function(e,t){e&&(Array.prototype.forEach.call(e.querySelectorAll("*"),function(e){e.setAttribute(t,"")}),Array.prototype.forEach.call(e.querySelectorAll("template"),function(e){this.applyScopeToContent(e.content,t)},this))},insertDirectives:function(e){return e=this.insertPolyfillDirectivesInCssText(e),this.insertPolyfillRulesInCssText(e)},insertPolyfillDirectivesInCssText:function(e){return e=e.replace(p,function(e,t){return t.slice(0,-2)+"{"}),e.replace(f,function(e,t){return t+" {"})},insertPolyfillRulesInCssText:function(e){return e=e.replace(h,function(e,t){return t.slice(0,-1)}),e.replace(m,function(e,t,n,r){var o=e.replace(t,"").replace(n,"");return r+o})},scopeCssText:function(e,t){var n=this.extractUnscopedRulesFromCssText(e);if(e=this.insertPolyfillHostInCssText(e),e=this.convertColonHost(e),e=this.convertColonHostContext(e),e=this.convertShadowDOMSelectors(e),t){var e,r=this;a(e,function(n){e=r.scopeRules(n,t)})}return e=e+"\n"+n,e.trim()},extractUnscopedRulesFromCssText:function(e){for(var t,n="";t=w.exec(e);)n+=t[1].slice(0,-1)+"\n\n";for(;t=v.exec(e);)n+=t[0].replace(t[2],"").replace(t[1],t[3])+"\n\n";return n},convertColonHost:function(e){return this.convertColonRule(e,E,this.colonHostPartReplacer)},convertColonHostContext:function(e){return this.convertColonRule(e,S,this.colonHostContextPartReplacer)},convertColonRule:function(e,t,n){return e.replace(t,function(e,t,r,o){if(t=L,r){for(var i,a=r.split(","),s=[],c=0,l=a.length;l>c&&(i=a[c]);c++)i=i.trim(),s.push(n(t,i,o));return s.join(",")}return t+o})},colonHostContextPartReplacer:function(e,t,n){return t.match(g)?this.colonHostPartReplacer(e,t,n):e+t+n+", "+t+" "+e+n},colonHostPartReplacer:function(e,t,n){return e+t.replace(g,"")+n},convertShadowDOMSelectors:function(e){for(var t=0;t<C.length;t++)e=e.replace(C[t]," ");return e},scopeRules:function(e,t){var n="";return e&&Array.prototype.forEach.call(e,function(e){if(e.selectorText&&e.style&&void 0!==e.style.cssText)n+=this.scopeSelector(e.selectorText,t,this.strictStyling)+" {\n ",n+=this.propertiesFromRule(e)+"\n}\n\n";else if(e.type===CSSRule.MEDIA_RULE)n+="@media "+e.media.mediaText+" {\n",n+=this.scopeRules(e.cssRules,t),n+="\n}\n\n";else try{e.cssText&&(n+=e.cssText+"\n\n")}catch(r){e.type===CSSRule.KEYFRAMES_RULE&&e.cssRules&&(n+=this.ieSafeCssTextFromKeyFrameRule(e))}},this),n},ieSafeCssTextFromKeyFrameRule:function(e){var t="@keyframes "+e.name+" {";return Array.prototype.forEach.call(e.cssRules,function(e){t+=" "+e.keyText+" {"+e.style.cssText+"}"}),t+=" }"},scopeSelector:function(e,t,n){var r=[],o=e.split(",");return o.forEach(function(e){e=e.trim(),this.selectorNeedsScoping(e,t)&&(e=n&&!e.match(L)?this.applyStrictSelectorScope(e,t):this.applySelectorScope(e,t)),r.push(e)},this),r.join(", ")},selectorNeedsScoping:function(e,t){if(Array.isArray(t))return!0;var n=this.makeScopeMatcher(t);return!e.match(n)},makeScopeMatcher:function(e){return e=e.replace(/\[/g,"\\[").replace(/\]/g,"\\]"),new RegExp("^("+e+")"+T,"m")},applySelectorScope:function(e,t){return Array.isArray(t)?this.applySelectorScopeList(e,t):this.applySimpleSelectorScope(e,t)},applySelectorScopeList:function(e,t){for(var n,r=[],o=0;n=t[o];o++)r.push(this.applySimpleSelectorScope(e,n));return r.join(", ")},applySimpleSelectorScope:function(e,t){return e.match(O)?(e=e.replace(L,t),e.replace(O,t+" ")):t+" "+e},applyStrictSelectorScope:function(e,t){t=t.replace(/\[is=([^\]]*)\]/g,"$1");var n=[" ",">","+","~"],r=e,o="["+t+"]";return n.forEach(function(e){var t=r.split(e);r=t.map(function(e){var t=e.trim().replace(O,"");return t&&n.indexOf(t)<0&&t.indexOf(o)<0&&(e=t.replace(/([^:]*)(:*)(.*)/,"$1"+o+"$2$3")),e}).join(e)}),r},insertPolyfillHostInCssText:function(e){return e.replace(_,b).replace(M,g)},propertiesFromRule:function(e){var t=e.style.cssText;e.style.content&&!e.style.content.match(/['"]+|attr/)&&(t=t.replace(/content:[^;]*;/g,"content: '"+e.style.content+"';"));var n=e.style;for(var r in n)"initial"===n[r]&&(t+=r+": initial; ");return t},replaceTextInStyles:function(e,t){e&&t&&(e instanceof Array||(e=[e]),Array.prototype.forEach.call(e,function(e){e.textContent=t.call(this,e.textContent)},this))},addCssToDocument:function(e,t){e.match("@import")?c(e,t):s(e)}},d=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,p=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,f=/polyfill-next-selector[^}]*content\:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim,h=/\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,m=/(polyfill-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,w=/\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,v=/(polyfill-unscoped-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,g="-shadowcsshost",b="-shadowcsscontext",y=")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)",E=new RegExp("("+g+y,"gim"),S=new RegExp("("+b+y,"gim"),T="([>\\s~+[.,{:][\\s\\S]*)?$",M=/\:host/gim,_=/\:host-context/gim,L=g+"-no-combinator",O=new RegExp(g,"gim"),C=(new RegExp(b,"gim"),[/\^\^/g,/\^/g,/\/shadow\//g,/\/shadow-deep\//g,/::shadow/g,/\/deep\//g,/::content/g]),N=document.createElement("iframe");N.style.display="none";var D,j=navigator.userAgent.match("Chrome"),H="shim-shadowdom",x="shim-shadowdom-css",R="no-shim";if(window.ShadowDOMPolyfill){s("style { display: none !important; }\n");var P=ShadowDOMPolyfill.wrap(document),I=P.querySelector("head");I.insertBefore(l(),I.childNodes[0]),document.addEventListener("DOMContentLoaded",function(){e.urlResolver;if(window.HTMLImports&&!HTMLImports.useNative){var t="link[rel=stylesheet]["+H+"]",n="style["+H+"]";HTMLImports.importer.documentPreloadSelectors+=","+t,HTMLImports.importer.importsPreloadSelectors+=","+t,HTMLImports.parser.documentSelectors=[HTMLImports.parser.documentSelectors,t,n].join(",");var r=HTMLImports.parser.parseGeneric;HTMLImports.parser.parseGeneric=function(e){if(!e[x]){var t=e.__importElement||e;if(!t.hasAttribute(H))return void r.call(this,e);e.__resource&&(t=e.ownerDocument.createElement("style"),t.textContent=e.__resource),HTMLImports.path.resolveUrlsInStyle(t),t.textContent=u.shimStyle(t),t.removeAttribute(H,""),t.setAttribute(x,""),t[x]=!0,t.parentNode!==I&&(e.parentNode===I?I.replaceChild(t,e):this.addElementToDocument(t)),t.__importParsed=!0,this.markParsingComplete(e),this.parseNext()}};var o=HTMLImports.parser.hasResource;HTMLImports.parser.hasResource=function(e){return"link"===e.localName&&"stylesheet"===e.rel&&e.hasAttribute(H)?e.__resource:o.call(this,e)}}})}e.ShadowCSS=u}(window.WebComponents)),function(){window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}}(window.WebComponents),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||h,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===v}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===v)&&(t.removeEventListener(g,o),r(e,t))};t.addEventListener(g,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){s==c&&e&&e()}function r(e){o(e),s++,n()}var i=t.querySelectorAll("link[rel=import]"),s=0,c=i.length;if(c)for(var l,u=0;c>u&&(l=i[u]);u++)a(l)?r.call(l,{target:l}):(l.addEventListener("load",r),l.addEventListener("error",r));else n()}function a(e){return d?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&l(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function l(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var u="import",d=Boolean(u in document.createElement("link")),p=Boolean(window.ShadowDOMPolyfill),f=function(e){return p?ShadowDOMPolyfill.wrapIfNeeded(e):e},h=f(document),m={get:function(){var e=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return f(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(h,"_currentScript",m);var w=/Trident|Edge/.test(navigator.userAgent),v=w?"complete":"interactive",g="readystatechange";d&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)l(e)}()),t(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime();var e=h.createEvent("CustomEvent");e.initCustomEvent("HTMLImportsLoaded",!0,!0,{}),h.dispatchEvent(e)}),e.IMPORT_LINK_TYPE=u,e.useNative=d,e.rootDocument=h,e.whenReady=t,e.isIE=w}(HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(HTMLImports),HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e){var t=e.ownerDocument,n=t.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,n),e},resolveUrlsInCssText:function(e,r){var o=this.replaceUrls(e,r,t);return o=this.replaceUrls(o,r,n)},replaceUrls:function(e,t,n){return e.replace(n,function(e,n,r,o){var i=r.replace(/["']/g,"");return t.href=i,i=t.href,n+"'"+i+"'"+o})}};e.path=r}),HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(){if(4===i.readyState){var e=i.getResponseHeader("Location"),n=null;if(e)var n="/"===e.substr(0,1)?location.origin+e:e;r.call(o,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,l=e.isIE,u=e.IMPORT_LINK_TYPE,d="link[rel="+u+"]",p={documentSelectors:d,importsSelectors:[d,"link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.dispatchEvent(e.__resource&&!e.__error?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(r){t&&t(r),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),l&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(){r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r["import"],r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e["import"]?!1:!0}};e.parser=p,e.IMPORT_SELECTOR=d}),HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,l=e.Loader,u=e.Observer,d=e.parser,p={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){f.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);f.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n["import"]=c}d.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),d.parseNext()},loadedAll:function(){d.parseNext()}},f=new l(p.loaded.bind(p),p.loadedAll.bind(p));if(p.observer=new u,!document.baseURI){var h={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",h),Object.defineProperty(c,"baseURI",h)}e.importer=p,e.importLoader=f}),HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){HTMLImports.importer.bootDocument(o)}var n=e.initializeModules,r=e.isIE;if(!e.useNative){r&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),n();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],r=function(e){n.push(e)},o=function(){n.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||HTMLImports.useNative)}(CustomElements),CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void r(e,t)}),r(e,t)}function n(e,t,r){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,r)!==!0&&n(o,t,r),o=o.nextElementSibling;return null}function r(e,n){for(var r=e.shadowRoot;r;)t(r,n),r=r.olderShadowRoot}function o(e,t){a=[],i(e,t),a=null}function i(e,t){if(e=wrap(e),!(a.indexOf(e)>=0)){a.push(e);for(var n,r=e.querySelectorAll("link[rel="+s+"]"),o=0,c=r.length;c>o&&(n=r[o]);o++)n["import"]&&i(n["import"],t);t(e)}}var a,s=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),CustomElements.addModule(function(e){function t(e){return n(e)||r(e)}function n(t){return e.upgrade(t)?!0:void s(t)}function r(e){y(e,function(e){return n(e)?!0:void 0})}function o(e){s(e),p(e)&&y(e,function(e){s(e)})}function i(e){M.push(e),T||(T=!0,setTimeout(a))}function a(){T=!1;for(var e,t=M,n=0,r=t.length;r>n&&(e=t[n]);n++)e();M=[]}function s(e){S?i(function(){c(e)}):c(e)}function c(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&!e.__attached&&p(e)&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function l(e){u(e),y(e,function(e){u(e)})}function u(e){S?i(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&(e.attachedCallback||e.detachedCallback)&&e.__attached&&!p(e)&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function p(e){for(var t=e,n=wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.host}}function f(e){if(e.shadowRoot&&!e.shadowRoot.__watched){b.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)w(t),t=t.olderShadowRoot}}function h(e){if(b.dom){var n=e[0];if(n&&"childList"===n.type&&n.addedNodes&&n.addedNodes){for(var r=n.addedNodes[0];r&&r!==document&&!r.host;)r=r.parentNode;var o=r&&(r.URL||r._URL||r.host&&r.host.localName)||"";o=o.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",e.length,o||"")}e.forEach(function(e){"childList"===e.type&&(_(e.addedNodes,function(e){e.localName&&t(e)}),_(e.removedNodes,function(e){e.localName&&l(e)}))}),b.dom&&console.groupEnd()}function m(e){for(e=wrap(e),e||(e=wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(h(t.takeRecords()),a())}function w(e){if(!e.__observer){var t=new MutationObserver(h);t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=wrap(e),b.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()),t(e),w(e),b.dom&&console.groupEnd()}function g(e){E(e,v)}var b=e.flags,y=e.forSubtree,E=e.forDocumentTree,S=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;e.hasPolyfillMutations=S;var T=!1,M=[],_=Array.prototype.forEach.call.bind(Array.prototype.forEach),L=Element.prototype.createShadowRoot;L&&(Element.prototype.createShadowRoot=function(){var e=L.call(this);return CustomElements.watchShadow(this),e}),e.watchShadow=f,e.upgradeDocumentTree=g,e.upgradeSubtree=r,e.upgradeAll=t,e.attachedNode=o,e.takeRecords=m}),CustomElements.addModule(function(e){function t(t){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var r=t.getAttribute("is"),o=e.getRegisteredDefinition(r||t.localName);if(o){if(r&&o.tag==t.localName)return n(t,o);if(!r&&!o["extends"])return n(t,o)}}}function n(t,n){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),r(t,n),t.__upgraded__=!0,i(t),e.attachedNode(t),e.upgradeSubtree(t),a.upgrade&&console.groupEnd(),t}function r(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,n){for(var r={},o=t;o!==n&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)r[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),r[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=r}),CustomElements.addModule(function(e){function t(t,r){var c=r||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(l(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),u(c.__name,c),c.ctor=d(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&w(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){r.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){r.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function r(e,t,n){e=e.toLowerCase();var r=this.getAttribute(e);n.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==r&&this.attributeChangedCallback(e,r,o)}function o(e){for(var t=0;t<E.length;t++)if(e===E[t])return!0}function i(e){var t=l(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,n=e["extends"],r=0;t=e.ancestry[r];r++)n=t.is&&t.tag;e.tag=n||e.__name,n&&(e.is=e.__name)}function s(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var n=document.createElement(e.tag),r=Object.getPrototypeOf(n);r===e.prototype&&(t=r)}for(var o,i=e.prototype;i&&i!==t;)o=Object.getPrototypeOf(i),i.__proto__=o,i=o;e["native"]=t}}function c(e){return g(M(e.tag),e)}function l(e){return e?S[e.toLowerCase()]:void 0}function u(e,t){S[e]=t}function d(e){return function(){return c(e)}}function p(e,t,n){return e===T?f(t,n):_(e,t)}function f(e,t){var n=l(t||e);
-if(n){if(e==n.tag&&t==n.is)return new n.ctor;if(!t&&!n.is)return new n.ctor}var r;return t?(r=f(e),r.setAttribute("is",t),r):(r=M(e),e.indexOf("-")>=0&&b(r,HTMLElement),r)}function h(e){var t=L.call(this,e);return v(t),t}var m,w=e.upgradeDocumentTree,v=e.upgrade,g=e.upgradeWithDefinition,b=e.implementPrototype,y=e.useNative,E=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],S={},T="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),_=document.createElementNS.bind(document),L=Node.prototype.cloneNode;m=Object.__proto__||y?function(e,t){return e instanceof t}:function(e,t){for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},document.registerElement=t,document.createElement=f,document.createElementNS=p,Node.prototype.cloneNode=h,e.registry=S,e["instanceof"]=m,e.reservedTagList=E,e.getRegisteredDefinition=l,document.register=document.registerElement}),function(e){function t(){a(wrap(document)),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(e){a(wrap(e["import"]))}),CustomElements.ready=!0,setTimeout(function(){CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}var n=e.useNative,r=e.initializeModules,o=/Trident/.test(navigator.userAgent);if(n){var i=function(){};e.watchShadow=i,e.upgrade=i,e.upgradeAll=i,e.upgradeDocumentTree=i,e.upgradeSubtree=i,e.takeRecords=i,e["instanceof"]=function(e,t){return e instanceof t}}else r();var a=e.upgradeDocumentTree;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),o&&"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t()}(window.CustomElements),function(){Function.prototype.bind||(Function.prototype.bind=function(e){var t=this,n=Array.prototype.slice.call(arguments,1);return function(){var r=n.slice();return r.push.apply(r,arguments),t.apply(e,r)}})}(window.WebComponents),function(e){"use strict";function t(){window.Polymer===o&&(window.Polymer=function(){throw new Error('You tried to use polymer without loading it first. To load polymer, <link rel="import" href="components/polymer/polymer.html">')})}if(!window.performance){var n=Date.now();window.performance={now:function(){return Date.now()-n}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var r=[],o=function(e){"string"!=typeof e&&1===arguments.length&&Array.prototype.push.call(arguments,document._currentScript),r.push(arguments)};window.Polymer=o,e.consumeDeclarations=function(t){e.consumeDeclarations=function(){throw"Possible attempt to load Polymer twice"},t&&t(r),r=null},HTMLImports.useNative?t():addEventListener("DOMContentLoaded",t)}(window.WebComponents),function(){var e=document.createElement("style");e.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var t=document.querySelector("head");t.insertBefore(e,t.firstChild)}(window.WebComponents),function(e){window.Platform=e}(window.WebComponents); \ No newline at end of file
diff --git a/chromium/third_party/catapult/tracing/trace_viewer.gypi b/chromium/third_party/catapult/tracing/trace_viewer.gypi
index ae2a28367b6..284dd2b9661 100644
--- a/chromium/third_party/catapult/tracing/trace_viewer.gypi
+++ b/chromium/third_party/catapult/tracing/trace_viewer.gypi
@@ -30,6 +30,9 @@
'tracing/ui/tracks/track.css',
],
'tracing_js_html_files': [
+ '../third_party/polymer/components/polymer/polymer-micro.html',
+ '../third_party/polymer/components/polymer/polymer-mini.html',
+ '../third_party/polymer/components/polymer/polymer.html',
'tracing/base/base.html',
'tracing/base/base64.html',
'tracing/base/bbox2.html',
@@ -55,10 +58,14 @@
'tracing/base/rect.html',
'tracing/base/running_statistics.html',
'tracing/base/settings.html',
+ 'tracing/base/sinebow_color_generator.html',
'tracing/base/sorted_array_utils.html',
'tracing/base/statistics.html',
'tracing/base/task.html',
+ 'tracing/base/time_display_modes.html',
'tracing/base/timing.html',
+ 'tracing/base/unit.html',
+ 'tracing/base/unit_scale.html',
'tracing/base/utils.html',
'tracing/core/auditor.html',
'tracing/core/filter.html',
@@ -113,6 +120,7 @@
'tracing/extras/importer/linux_perf/exynos_parser.html',
'tracing/extras/importer/linux_perf/ftrace_importer.html',
'tracing/extras/importer/linux_perf/gesture_parser.html',
+ 'tracing/extras/importer/linux_perf/i2c_parser.html',
'tracing/extras/importer/linux_perf/i915_parser.html',
'tracing/extras/importer/linux_perf/irq_parser.html',
'tracing/extras/importer/linux_perf/kfunc_parser.html',
@@ -150,6 +158,9 @@
'tracing/extras/tquery/filter_is_top_level.html',
'tracing/extras/tquery/filter_not.html',
'tracing/extras/tquery/tquery.html',
+ 'tracing/extras/v8/v8_gc_stats_thread_slice.html',
+ 'tracing/extras/v8/v8_thread_slice.html',
+ 'tracing/extras/v8_config.html',
'tracing/extras/vsync/vsync_auditor.html',
'tracing/importer/context_processor.html',
'tracing/importer/empty_importer.html',
@@ -162,12 +173,15 @@
'tracing/importer/simple_line_reader.html',
'tracing/importer/user_model_builder.html',
'tracing/metrics/all_metrics.html',
+ 'tracing/metrics/blink/gc_metric.html',
+ 'tracing/metrics/cpu_process_metric.html',
+ 'tracing/metrics/metric_map_function.html',
'tracing/metrics/metric_registry.html',
'tracing/metrics/sample_metric.html',
'tracing/metrics/system_health/clock_sync_latency_metric.html',
- 'tracing/metrics/system_health/efficiency_metric.html',
- 'tracing/metrics/system_health/first_paint_metric.html',
+ 'tracing/metrics/system_health/cpu_time_metric.html',
'tracing/metrics/system_health/hazard_metric.html',
+ 'tracing/metrics/system_health/loading_metric.html',
'tracing/metrics/system_health/long_tasks_metric.html',
'tracing/metrics/system_health/memory_metric.html',
'tracing/metrics/system_health/power_metric.html',
@@ -255,6 +269,9 @@
'tracing/model/user_model/user_model.html',
'tracing/model/vm_region.html',
'tracing/model/x_marker_annotation.html',
+ 'tracing/mre/failure.html',
+ 'tracing/mre/function_handle.html',
+ 'tracing/mre/mre_result.html',
'tracing/ui/analysis/alert_sub_view.html',
'tracing/ui/analysis/analysis_link.html',
'tracing/ui/analysis/analysis_sub_view.html',
@@ -264,16 +281,17 @@
'tracing/ui/analysis/flow_classifier.html',
'tracing/ui/analysis/frame_power_usage_chart.html',
'tracing/ui/analysis/generic_object_view.html',
- 'tracing/ui/analysis/layout_tree_sub_view.html',
'tracing/ui/analysis/memory_dump_allocator_details_pane.html',
'tracing/ui/analysis/memory_dump_header_pane.html',
+ 'tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html',
'tracing/ui/analysis/memory_dump_heap_details_pane.html',
+ 'tracing/ui/analysis/memory_dump_heap_details_path_view.html',
+ 'tracing/ui/analysis/memory_dump_heap_details_util.html',
'tracing/ui/analysis/memory_dump_overview_pane.html',
'tracing/ui/analysis/memory_dump_sub_view_util.html',
'tracing/ui/analysis/memory_dump_vm_regions_details_pane.html',
'tracing/ui/analysis/multi_async_slice_sub_view.html',
'tracing/ui/analysis/multi_cpu_slice_sub_view.html',
- 'tracing/ui/analysis/multi_event_details_table.html',
'tracing/ui/analysis/multi_event_sub_view.html',
'tracing/ui/analysis/multi_event_summary.html',
'tracing/ui/analysis/multi_event_summary_table.html',
@@ -289,6 +307,7 @@
'tracing/ui/analysis/object_instance_view.html',
'tracing/ui/analysis/object_snapshot_view.html',
'tracing/ui/analysis/power_sample_summary_table.html',
+ 'tracing/ui/analysis/rebuildable_behavior.html',
'tracing/ui/analysis/related_events.html',
'tracing/ui/analysis/selection_summary_table.html',
'tracing/ui/analysis/single_async_slice_sub_view.html',
@@ -315,11 +334,13 @@
'tracing/ui/base/animation.html',
'tracing/ui/base/animation_controller.html',
'tracing/ui/base/bar_chart.html',
+ 'tracing/ui/base/base.html',
'tracing/ui/base/camera.html',
'tracing/ui/base/chart_base.html',
'tracing/ui/base/chart_base_2d.html',
'tracing/ui/base/chart_base_2d_brushable_x.html',
'tracing/ui/base/color_legend.html',
+ 'tracing/ui/base/column_chart.html',
'tracing/ui/base/constants.html',
'tracing/ui/base/container_that_decorates_its_children.html',
'tracing/ui/base/d3.html',
@@ -348,8 +369,10 @@
'tracing/ui/base/mouse_tracker.html',
'tracing/ui/base/overlay.html',
'tracing/ui/base/pie_chart.html',
- 'tracing/ui/base/polymer_utils.html',
+ 'tracing/ui/base/polymer_postload.html',
+ 'tracing/ui/base/polymer_preload.html',
'tracing/ui/base/quad_stack_view.html',
+ 'tracing/ui/base/radio_picker.html',
'tracing/ui/base/tab_view.html',
'tracing/ui/base/table.html',
'tracing/ui/base/timing_tool.html',
@@ -386,6 +409,7 @@
'tracing/ui/extras/chrome/cc/tile_view.html',
'tracing/ui/extras/chrome/gpu/gpu.html',
'tracing/ui/extras/chrome/gpu/state_view.html',
+ 'tracing/ui/extras/chrome/layout_tree_sub_view.html',
'tracing/ui/extras/chrome_config.html',
'tracing/ui/extras/full_config.html',
'tracing/ui/extras/highlighter/vsync_highlighter.html',
@@ -398,6 +422,13 @@
'tracing/ui/extras/system_stats/system_stats_instance_track.html',
'tracing/ui/extras/system_stats/system_stats_snapshot_view.html',
'tracing/ui/extras/systrace_config.html',
+ 'tracing/ui/extras/v8/gc_objects_stats_table.html',
+ 'tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html',
+ 'tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html',
+ 'tracing/ui/extras/v8/runtime_call_stats_table.html',
+ 'tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html',
+ 'tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html',
+ 'tracing/ui/extras/v8_config.html',
'tracing/ui/find_control.html',
'tracing/ui/find_controller.html',
'tracing/ui/scripting_control.html',
@@ -405,6 +436,7 @@
'tracing/ui/side_panel/metrics_side_panel.html',
'tracing/ui/side_panel/side_panel.html',
'tracing/ui/side_panel/side_panel_container.html',
+ 'tracing/ui/side_panel/side_panel_registry.html',
'tracing/ui/timeline_display_transform.html',
'tracing/ui/timeline_display_transform_animations.html',
'tracing/ui/timeline_interest_range.html',
@@ -454,18 +486,24 @@
'tracing/ui/tracks/thread_track.html',
'tracing/ui/tracks/track.html',
'tracing/ui/view_specific_brushing_state.html',
- 'tracing/value/diagnostics/composition.html',
+ 'tracing/value/diagnostics/breakdown.html',
'tracing/value/diagnostics/diagnostic.html',
'tracing/value/diagnostics/diagnostic_map.html',
+ 'tracing/value/diagnostics/event_ref.html',
'tracing/value/diagnostics/generic.html',
'tracing/value/diagnostics/iteration_info.html',
'tracing/value/diagnostics/related_event_set.html',
+ 'tracing/value/diagnostics/related_histogram_breakdown.html',
'tracing/value/diagnostics/related_value_map.html',
'tracing/value/diagnostics/related_value_set.html',
+ 'tracing/value/diagnostics/scalar.html',
+ 'tracing/value/diagnostics/value_ref.html',
'tracing/value/generic_table.html',
+ 'tracing/value/histogram.html',
'tracing/value/numeric.html',
- 'tracing/value/time_display_mode.html',
'tracing/value/ui/array_of_numbers_span.html',
+ 'tracing/value/ui/breakdown_span.html',
+ 'tracing/value/ui/diagnostic_map_table.html',
'tracing/value/ui/diagnostic_span.html',
'tracing/value/ui/generic_diagnostic_span.html',
'tracing/value/ui/generic_table_view.html',
@@ -475,12 +513,12 @@
'tracing/value/ui/related_event_set_span.html',
'tracing/value/ui/related_value_map_span.html',
'tracing/value/ui/related_value_set_span.html',
+ 'tracing/value/ui/scalar_context_controller.html',
+ 'tracing/value/ui/scalar_diagnostic_span.html',
+ 'tracing/value/ui/scalar_map_table.html',
'tracing/value/ui/scalar_span.html',
'tracing/value/ui/value_set_table.html',
'tracing/value/ui/value_set_view.html',
- 'tracing/value/unit.html',
- 'tracing/value/unit_scale.html',
- 'tracing/value/value.html',
'tracing/value/value_set.html',
],
'tracing_img_files': [
diff --git a/chromium/third_party/catapult/tracing/tracing/base/color.html b/chromium/third_party/catapult/tracing/tracing/base/color.html
index 586706b6977..d173fb45073 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/color.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/color.html
@@ -23,30 +23,30 @@ tr.exportTo('tr.b', function() {
Color.fromString = function(str) {
var tmp;
var values;
- if (str.substr(0, 4) == 'rgb(') {
+ if (str.substr(0, 4) === 'rgb(') {
tmp = str.substr(4, str.length - 5);
values = tmp.split(',').map(function(v) {
return v.replace(/^\s+/, '', 'g');
});
- if (values.length != 3)
+ if (values.length !== 3)
throw new Error('Malformatted rgb-expression');
return new Color(
parseInt(values[0]),
parseInt(values[1]),
parseInt(values[2]));
- } else if (str.substr(0, 5) == 'rgba(') {
+ } else if (str.substr(0, 5) === 'rgba(') {
tmp = str.substr(5, str.length - 6);
values = tmp.split(',').map(function(v) {
return v.replace(/^\s+/, '', 'g');
});
- if (values.length != 4)
+ if (values.length !== 4)
throw new Error('Malformatted rgb-expression');
return new Color(
parseInt(values[0]),
parseInt(values[1]),
parseInt(values[2]),
parseFloat(values[3]));
- } else if (str[0] == '#' && str.length == 7) {
+ } else if (str[0] === '#' && str.length === 7) {
return new Color(
parseInt(str.substr(1, 2), 16),
parseInt(str.substr(3, 2), 16),
@@ -150,8 +150,8 @@ tr.exportTo('tr.b', function() {
this.a);
},
- lighten: function(k, opt_max_l) {
- var max_l = opt_max_l !== undefined ? opt_max_l : 1.0;
+ lighten: function(k, opt_maxL) {
+ var maxL = opt_maxL !== undefined ? opt_maxL : 1.0;
var hsl = this.toHSL();
hsl.l = clamp01(hsl.l + k);
return Color.fromHSL(hsl);
diff --git a/chromium/third_party/catapult/tracing/tracing/base/color_scheme.html b/chromium/third_party/catapult/tracing/tracing/base/color_scheme.html
index 8ae4d745eb1..07fe220272a 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/color_scheme.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/color_scheme.html
@@ -55,6 +55,7 @@ tr.exportTo('tr.b', function() {
thread_state_sleeping: new tr.b.Color(240, 240, 240),
thread_state_unknown: new tr.b.Color(199, 155, 125),
+ background_memory_dump: new tr.b.Color(0, 180, 180),
light_memory_dump: new tr.b.Color(0, 0, 180),
detailed_memory_dump: new tr.b.Color(180, 0, 180),
@@ -78,6 +79,7 @@ tr.exportTo('tr.b', function() {
heap_dump_stack_frame: new tr.b.Color(128, 128, 128),
heap_dump_object_type: new tr.b.Color(0, 0, 255),
+ heap_dump_child_node_arrow: new tr.b.Color(204, 102, 0),
cq_build_running: new tr.b.Color(255, 255, 119),
cq_build_passed: new tr.b.Color(153, 238, 102),
@@ -180,10 +182,10 @@ tr.exportTo('tr.b', function() {
// Build reservedColorNameToIdMap.
var reservedColorNameToIdMap = (function() {
- var m = {};
+ var m = new Map();
var i = generalPurposeColors.length;
tr.b.iterItems(reservedColorsByName, function(key, value) {
- m[key] = i++;
+ m.set(key, i++);
});
return m;
})();
@@ -193,7 +195,7 @@ tr.exportTo('tr.b', function() {
* @return {Number} The color ID for the given color name.
*/
ColorScheme.getColorIdForReservedName = function(name) {
- var id = reservedColorNameToIdMap[name];
+ var id = reservedColorNameToIdMap.get(name);
if (id === undefined)
throw new Error('Unrecognized color ') + name;
return id;
@@ -218,7 +220,7 @@ tr.exportTo('tr.b', function() {
// Previously computed string color IDs. They are based on a stable hash, so
// it is safe to save them throughout the program time.
- var stringColorIdCache = {};
+ var stringColorIdCache = new Map();
/**
* @return {Number} A color ID that is stably associated to the provided via
@@ -226,11 +228,11 @@ tr.exportTo('tr.b', function() {
* purpose ID space only, e.g. no reserved ID will be used.
*/
ColorScheme.getColorIdForGeneralPurposeString = function(string) {
- if (stringColorIdCache[string] === undefined) {
+ if (stringColorIdCache.get(string) === undefined) {
var hash = ColorScheme.getStringHash(string);
- stringColorIdCache[string] = hash % numGeneralPurposeColorIds;
+ stringColorIdCache.set(string, hash % numGeneralPurposeColorIds);
}
- return stringColorIdCache[string];
+ return stringColorIdCache.get(string);
};
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/base/color_scheme_test.html b/chromium/third_party/catapult/tracing/tracing/base/color_scheme_test.html
index 602c91c2165..2accda5d95b 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/color_scheme_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/color_scheme_test.html
@@ -12,5 +12,38 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var ColorScheme = tr.b.ColorScheme;
+
+ function isValidColorId(colorId) {
+ return typeof(colorId) === 'number' &&
+ colorId >= 0 &&
+ colorId <= 200;
+ }
+
+ test('getColorIdForReservedName', function() {
+ assert.isTrue(isValidColorId(
+ ColorScheme.getColorIdForReservedName('black')));
+ assert.throws(ColorScheme.getColorIdForReservedName.bind(
+ undefined, 'NOT_A_RESERVED_NAME'));
+ assert.throws(ColorScheme.getColorIdForReservedName.bind(
+ undefined, 'constructor'));
+ });
+
+ test('getColorForReservedNameAsString', function() {
+ assert.equal('rgb(0,0,0)',
+ ColorScheme.getColorForReservedNameAsString('black'));
+ assert.throws(ColorScheme.getColorForReservedNameAsString.bind(
+ undefined, 'NOT_A_RESERVED_NAME'));
+ assert.throws(ColorScheme.getColorForReservedNameAsString.bind(
+ undefined, 'constructor'));
+ });
+
+ test('getColorIdForGeneralPurposeString', function() {
+ assert.isTrue(isValidColorId(
+ ColorScheme.getColorIdForGeneralPurposeString('black')));
+ assert.isTrue(isValidColorId(
+ ColorScheme.getColorIdForGeneralPurposeString('NOT_A_RESERVED_NAME')));
+ assert.isTrue(isValidColorId(
+ ColorScheme.getColorIdForGeneralPurposeString('constructor')));
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/event.html b/chromium/third_party/catapult/tracing/tracing/base/event.html
index 75ad3d5001a..4b10d3f31f9 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/event.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/event.html
@@ -77,11 +77,19 @@ tr.exportTo('tr.b', function() {
* @param {boolean=} opt_bubbles Whether the event bubbles or not.
* @param {boolean=} opt_cancelable Whether the default action of the event
* can be prevented.
+ * @param {!Object=} opt_fields
+ *
* @return {boolean} If any of the listeners called {@code preventDefault}
* during the dispatch this will return false.
*/
- function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
+ function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable,
+ opt_fields) {
var e = new tr.b.Event(type, opt_bubbles, opt_cancelable);
+ if (opt_fields) {
+ tr.b.iterItems(opt_fields, function(name, value) {
+ e[name] = value;
+ });
+ }
return target.dispatchEvent(e);
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/event_target.html b/chromium/third_party/catapult/tracing/tracing/base/event_target.html
index f1decc458e3..7c95eda5434 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/event_target.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/event_target.html
@@ -25,7 +25,7 @@ tr.exportTo('tr.b', function() {
}
EventTarget.decorate = function(target) {
for (var k in EventTarget.prototype) {
- if (k == 'decorate')
+ if (k === 'decorate')
continue;
var v = EventTarget.prototype[k];
if (typeof v !== 'function')
@@ -68,7 +68,7 @@ tr.exportTo('tr.b', function() {
var index = handlers.indexOf(handler);
if (index >= 0) {
// Clean up if this was the last listener.
- if (handlers.length == 1)
+ if (handlers.length === 1)
delete this.listeners_[type];
else
handlers.splice(index, 1);
@@ -123,7 +123,7 @@ tr.exportTo('tr.b', function() {
var EventTargetHelper = {
decorate: function(target) {
for (var k in EventTargetHelper) {
- if (k == 'decorate')
+ if (k === 'decorate')
continue;
var v = EventTargetHelper[k];
if (typeof v !== 'function')
diff --git a/chromium/third_party/catapult/tracing/tracing/base/extension_registry.html b/chromium/third_party/catapult/tracing/tracing/base/extension_registry.html
index e4615927f05..713a79045c2 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/extension_registry.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/extension_registry.html
@@ -4,10 +4,12 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/event_target.html">
+<link rel="import" href="/tracing/base/extension_registry_base.html">
<link rel="import" href="/tracing/base/extension_registry_basic.html">
<link rel="import" href="/tracing/base/extension_registry_type_based.html">
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+
<script>
'use strict';
@@ -23,9 +25,6 @@ found in the LICENSE file.
* of tracing categories or typeNames, then query
* for it based on a category, typeName or both.
*
- * Use these for pure-JS classes or ui.define'd classes. For polymer element
- * related registries, consult base/polymer_utils.html.
- *
* When you register subtypes, you pass the constructor for the
* subtype, and any metadata you want associated with the subtype. Use metadata
* instead of stuffing fields onto the constructor. E.g.:
@@ -46,9 +45,9 @@ tr.exportTo('tr.b', function() {
throw new Error('Already has registry');
registryOptions.freeze();
- if (registryOptions.mode == tr.b.BASIC_REGISTRY_MODE) {
+ if (registryOptions.mode === tr.b.BASIC_REGISTRY_MODE) {
tr.b._decorateBasicExtensionRegistry(registry, registryOptions);
- } else if (registryOptions.mode == tr.b.TYPE_BASED_REGISTRY_MODE) {
+ } else if (registryOptions.mode === tr.b.TYPE_BASED_REGISTRY_MODE) {
tr.b._decorateTypeBasedExtensionRegistry(registry, registryOptions);
} else {
throw new Error('Unrecognized mode');
diff --git a/chromium/third_party/catapult/tracing/tracing/base/extension_registry_basic.html b/chromium/third_party/catapult/tracing/tracing/base/extension_registry_basic.html
index d21d3941f5b..7547e13ea8a 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/extension_registry_basic.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/extension_registry_basic.html
@@ -65,7 +65,7 @@ tr.exportTo('tr.b', function() {
registry.findIndexOfRegisteredConstructor = function(constructor) {
for (var i = 0; i < registry.registeredTypeInfos_.length; i++)
- if (registry.registeredTypeInfos_[i].constructor == constructor)
+ if (registry.registeredTypeInfos_[i].constructor === constructor)
return i;
return undefined;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/base/extension_registry_type_based.html b/chromium/third_party/catapult/tracing/tracing/base/extension_registry_type_based.html
index 9d9bfcd9d67..e45639e96c2 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/extension_registry_type_based.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/extension_registry_type_based.html
@@ -4,9 +4,9 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/extension_registry_base.html">
-<link rel="import" href="/tracing/base/event.html">
<link rel="import" href="/tracing/base/category_util.html">
+<link rel="import" href="/tracing/base/event.html">
+<link rel="import" href="/tracing/base/extension_registry_base.html">
<script>
'use strict';
@@ -23,8 +23,8 @@ tr.exportTo('tr.b', function() {
registry.registeredTypeInfos_ = [];
- registry.categoryPartToTypeInfoMap_ = {};
- registry.typeNameToTypeInfoMap_ = {};
+ registry.categoryPartToTypeInfoMap_ = new Map();
+ registry.typeNameToTypeInfoMap_ = new Map();
registry.register = function(constructor,
metadata) {
@@ -54,11 +54,11 @@ tr.exportTo('tr.b', function() {
// Sanity checks...
typeInfo.typeNames.forEach(function(typeName) {
- if (registry.typeNameToTypeInfoMap_[typeName])
+ if (registry.typeNameToTypeInfoMap_.has(typeName))
throw new Error('typeName ' + typeName + ' already registered');
});
typeInfo.categoryParts.forEach(function(categoryPart) {
- if (registry.categoryPartToTypeInfoMap_[categoryPart]) {
+ if (registry.categoryPartToTypeInfoMap_.has(categoryPart)) {
throw new Error('categoryPart ' + categoryPart +
' already registered');
}
@@ -70,10 +70,10 @@ tr.exportTo('tr.b', function() {
// Actual registration.
typeInfo.typeNames.forEach(function(typeName) {
- registry.typeNameToTypeInfoMap_[typeName] = typeInfo;
+ registry.typeNameToTypeInfoMap_.set(typeName, typeInfo);
});
typeInfo.categoryParts.forEach(function(categoryPart) {
- registry.categoryPartToTypeInfoMap_[categoryPart] = typeInfo;
+ registry.categoryPartToTypeInfoMap_.set(categoryPart, typeInfo);
});
registry.registeredTypeInfos_.push(typeInfo);
@@ -88,8 +88,8 @@ tr.exportTo('tr.b', function() {
categoryPartToTypeInfoMap: registry.categoryPartToTypeInfoMap_
});
registry.registeredTypeInfos_ = [];
- registry.typeNameToTypeInfoMap_ = {};
- registry.categoryPartToTypeInfoMap_ = {};
+ registry.typeNameToTypeInfoMap_ = new Map();
+ registry.categoryPartToTypeInfoMap_ = new Map();
var e = new tr.b.Event('registry-changed');
registry.dispatchEvent(e);
};
@@ -108,7 +108,7 @@ tr.exportTo('tr.b', function() {
registry.unregister = function(constructor) {
var typeInfoIndex = -1;
for (var i = 0; i < registry.registeredTypeInfos_.length; i++) {
- if (registry.registeredTypeInfos_[i].constructor == constructor) {
+ if (registry.registeredTypeInfos_[i].constructor === constructor) {
typeInfoIndex = i;
break;
}
@@ -119,10 +119,10 @@ tr.exportTo('tr.b', function() {
var typeInfo = registry.registeredTypeInfos_[typeInfoIndex];
registry.registeredTypeInfos_.splice(typeInfoIndex, 1);
typeInfo.typeNames.forEach(function(typeName) {
- delete registry.typeNameToTypeInfoMap_[typeName];
+ registry.typeNameToTypeInfoMap_.delete(typeName);
});
typeInfo.categoryParts.forEach(function(categoryPart) {
- delete registry.categoryPartToTypeInfoMap_[categoryPart];
+ registry.categoryPartToTypeInfoMap_.delete(categoryPart);
});
var e = new tr.b.Event('registry-changed');
registry.dispatchEvent(e);
@@ -133,12 +133,14 @@ tr.exportTo('tr.b', function() {
var categoryParts = getCategoryParts(category);
for (var i = 0; i < categoryParts.length; i++) {
var categoryPart = categoryParts[i];
- if (registry.categoryPartToTypeInfoMap_[categoryPart])
- return registry.categoryPartToTypeInfoMap_[categoryPart];
+ var typeInfo = registry.categoryPartToTypeInfoMap_.get(categoryPart);
+ if (typeInfo !== undefined)
+ return typeInfo;
}
}
- if (registry.typeNameToTypeInfoMap_[typeName])
- return registry.typeNameToTypeInfoMap_[typeName];
+ var typeInfo = registry.typeNameToTypeInfoMap_.get(typeName);
+ if (typeInfo !== undefined)
+ return typeInfo;
return extensionRegistryOptions.defaultTypeInfo;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers.html b/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers.html
index ddd3a90d43e..d3e8bf7a4df 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers.html
@@ -11,9 +11,10 @@ found in the LICENSE file.
'use strict';
tr.exportTo('tr.b', function() {
+
/**
* Converts any object which is either (a) an iterable, or (b) an
- * "array-ish" obect (has length property and can be indexed into)
+ * "array-ish" object (has length property and can be indexed into)
* into an array.
*/
function asArray(x) {
@@ -66,7 +67,7 @@ tr.exportTo('tr.b', function() {
if (tmp)
return tmp;
}
- if (x.length == y.length)
+ if (x.length === y.length)
return 0;
if (x[i] === undefined)
@@ -173,21 +174,44 @@ tr.exportTo('tr.b', function() {
/**
* Returns a new dictionary with items grouped by the return value of the
* specified function being called on each item.
- * @param {!Array.<Object>} ary The array being iterated through
- * @param {!Function} fn The mapping function between the array value and the
- * map key.
+ * @param {!Array.<!*>} ary The array being iterated through
+ * @param {!function(!*):!*} callback The mapping function between the array
+ * value and the map key.
+ * @param {*=} opt_this
*/
- function group(ary, fn) {
- return ary.reduce(function(accumulator, curr) {
- var key = fn(curr);
-
- if (key in accumulator)
- accumulator[key].push(curr);
- else
- accumulator[key] = [curr];
+ function group(ary, callback, opt_this, opt_arrayConstructor) {
+ var arrayConstructor = opt_arrayConstructor || Array;
+ var results = {};
+ for (var element of ary) {
+ var key = callback.call(opt_this, element);
+ if (!(key in results))
+ results[key] = new arrayConstructor();
+ results[key].push(element);
+ }
+ return results;
+ }
- return accumulator;
- }, {});
+ /**
+ * Returns a new Map with items grouped by the return value of the
+ * specified function being called on each item.
+ * @param {!Array.<!*>} ary The array being iterated through
+ * @param {!function(!*):!*} callback The mapping function between the array
+ * value and the map key.
+ * @param {*=} opt_this
+ */
+ function groupIntoMap(ary, callback, opt_this, opt_arrayConstructor) {
+ var arrayConstructor = opt_arrayConstructor || Array;
+ var results = new Map();
+ for (var element of ary) {
+ var key = callback.call(opt_this, element);
+ var items = results.get(key);
+ if (items === undefined) {
+ items = new arrayConstructor();
+ results.set(key, items);
+ }
+ items.push(element);
+ }
+ return results;
}
function iterItems(dict, fn, opt_this) {
@@ -430,6 +454,7 @@ tr.exportTo('tr.b', function() {
getOnlyElement: getOnlyElement,
getFirstElement: getFirstElement,
group: group,
+ groupIntoMap: groupIntoMap,
iterItems: iterItems,
mapItems: mapItems,
filterItems: filterItems,
diff --git a/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers_test.html b/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers_test.html
index b162763602f..28d030b5db3 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/iteration_helpers_test.html
@@ -124,6 +124,24 @@ tr.b.unittest.testSuite(function() {
assert.deepEqual(tr.b.group(srcArray, fn), dstDict);
});
+ test('groupIntoMap', function() {
+ // Empty array
+ var srcArray = [];
+ var fn = function(curr) { return (curr % 2); };
+ var dstDict = {};
+
+ assert.deepEqual(tr.b.groupIntoMap(srcArray, fn), dstDict);
+
+ // Non-empty array
+ var srcArray = [0, 1, 2, 3, 4, 5, 6];
+ var dstMap = new Map([
+ [0, [0, 2, 4, 6]],
+ [1, [1, 3, 5]]
+ ]);
+
+ assert.deepEqual(tr.b.groupIntoMap(srcArray, fn), dstMap);
+ });
+
test('mapItems', function() {
// Empty dictionary.
var srcDict = {};
@@ -270,7 +288,7 @@ tr.b.unittest.testSuite(function() {
var that = this;
var k = tr.b.findFirstKeyInDictMatching(dict, function(key, value) {
assert.equal(this, that);
- return value == 2;
+ return value === 2;
}, this);
assert.equal(k, 'b');
diff --git a/chromium/third_party/catapult/tracing/tracing/base/math.html b/chromium/third_party/catapult/tracing/tracing/base/math.html
index 59b5d3117b9..8480bbb7120 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/math.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/math.html
@@ -31,6 +31,13 @@ found in the LICENSE file.
'use strict';
tr.exportTo('tr.b', function() {
+ /* Returns true when x and y are within delta of each other. */
+ function approximately(x, y, delta) {
+ if (delta === undefined)
+ delta = 1e-9;
+ return Math.abs(x - y) < delta;
+ }
+
function clamp(x, lo, hi) {
return Math.min(Math.max(x, lo), hi);
}
@@ -80,13 +87,13 @@ tr.exportTo('tr.b', function() {
return sign * y;
}
- var tmp_vec2 = vec2.create();
- var tmp_vec2b = vec2.create();
- var tmp_vec4 = vec4.create();
- var tmp_mat2d = mat2d.create();
+ var tmpVec2 = vec2.create();
+ var tmpVec2b = vec2.create();
+ var tmpVec4 = vec4.create();
+ var tmpMat2d = mat2d.create();
vec2.createFromArray = function(arr) {
- if (arr.length != 2)
+ if (arr.length !== 2)
throw new Error('Should be length 2');
var v = vec2.create();
vec2.set(v, arr[0], arr[1]);
@@ -105,9 +112,9 @@ tr.exportTo('tr.b', function() {
vec2.addTwoScaledUnitVectors = function(out, u1, scale1, u2, scale2) {
// out = u1 * scale1 + u2 * scale2
- vec2.scale(tmp_vec2, u1, scale1);
- vec2.scale(tmp_vec2b, u2, scale2);
- vec2.add(out, tmp_vec2, tmp_vec2b);
+ vec2.scale(tmpVec2, u1, scale1);
+ vec2.scale(tmpVec2b, u2, scale2);
+ vec2.add(out, tmpVec2, tmpVec2b);
};
vec2.interpolatePiecewiseFunction = function(points, x) {
@@ -133,13 +140,13 @@ tr.exportTo('tr.b', function() {
};
mat2d.translateXY = function(out, x, y) {
- vec2.set(tmp_vec2, x, y);
- mat2d.translate(out, out, tmp_vec2);
+ vec2.set(tmpVec2, x, y);
+ mat2d.translate(out, out, tmpVec2);
};
mat2d.scaleXY = function(out, x, y) {
- vec2.set(tmp_vec2, x, y);
- mat2d.scale(out, out, tmp_vec2);
+ vec2.set(tmpVec2, x, y);
+ mat2d.scale(out, out, tmpVec2);
};
vec4.unitize = function(out, a) {
@@ -151,11 +158,12 @@ tr.exportTo('tr.b', function() {
};
vec2.copyFromVec4 = function(out, a) {
- vec4.unitize(tmp_vec4, a);
- vec2.copy(out, tmp_vec4);
+ vec4.unitize(tmpVec4, a);
+ vec2.copy(out, tmpVec4);
};
return {
+ approximately: approximately,
clamp: clamp,
lerp: lerp,
normalize: normalize,
diff --git a/chromium/third_party/catapult/tracing/tracing/base/quad.html b/chromium/third_party/catapult/tracing/tracing/base/quad.html
index 0a1b4695886..9e66c5e21c5 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/quad.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/quad.html
@@ -70,7 +70,7 @@ tr.exportTo('tr.b', function() {
}
Quad.from8Array = function(arr) {
- if (arr.length != 8)
+ if (arr.length !== 8)
throw new Error('Array must be 8 long');
var q = new Quad();
q.p1[0] = arr[0];
@@ -126,14 +126,14 @@ tr.exportTo('tr.b', function() {
// Simple rectangle check. Note: will not handle out-of-order components.
var bounds = this.boundingRect();
return (
- bounds.x == this.p1[0] &&
- bounds.y == this.p1[1] &&
- bounds.width == this.p2[0] - this.p1[0] &&
- bounds.y == this.p2[1] &&
- bounds.width == this.p3[0] - this.p1[0] &&
- bounds.height == this.p3[1] - this.p2[1] &&
- bounds.x == this.p4[0] &&
- bounds.height == this.p4[1] - this.p2[1]
+ bounds.x === this.p1[0] &&
+ bounds.y === this.p1[1] &&
+ bounds.width === this.p2[0] - this.p1[0] &&
+ bounds.y === this.p2[1] &&
+ bounds.width === this.p3[0] - this.p1[0] &&
+ bounds.height === this.p3[1] - this.p2[1] &&
+ bounds.x === this.p4[0] &&
+ bounds.height === this.p4[1] - this.p2[1]
);
},
@@ -215,7 +215,7 @@ tr.exportTo('tr.b', function() {
var b1 = sign(pt, p1, p2) < 0.0;
var b2 = sign(pt, p2, p3) < 0.0;
var b3 = sign(pt, p3, p1) < 0.0;
- return ((b1 == b2) && (b2 == b3));
+ return ((b1 === b2) && (b2 === b3));
}
function pointInImplicitQuad(point, p1, p2, p3, p4) {
diff --git a/chromium/third_party/catapult/tracing/tracing/base/range.html b/chromium/third_party/catapult/tracing/tracing/base/range.html
index d24dc3327e4..593d85f13b5 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/range.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/range.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/math.html">
<script>
'use strict';
@@ -20,7 +21,7 @@ tr.exportTo('tr.b', function() {
this.isEmpty_ = true;
this.min_ = undefined;
this.max_ = undefined;
- };
+ }
Range.prototype = {
__proto__: Object.prototype,
@@ -102,10 +103,10 @@ tr.exportTo('tr.b', function() {
equals: function(that) {
if (this.isEmpty && that.isEmpty)
return true;
- if (this.isEmpty != that.isEmpty)
+ if (this.isEmpty !== that.isEmpty)
return false;
- return this.min === that.min &&
- this.max === that.max;
+ return (tr.b.approximately(this.min, that.min) &&
+ tr.b.approximately(this.max, that.max));
},
containsExplicitRangeInclusive: function(min, max) {
@@ -156,6 +157,14 @@ tr.exportTo('tr.b', function() {
return this.intersectsExplicitRangeExclusive(range.min_, range.max_);
},
+ findExplicitIntersectionDuration: function(min, max) {
+ var min = Math.max(this.min, min);
+ var max = Math.min(this.max, max);
+ if (max < min)
+ return 0;
+ return max - min;
+ },
+
findIntersection: function(range) {
if (this.isEmpty || range.isEmpty)
return new Range();
@@ -258,6 +267,9 @@ tr.exportTo('tr.b', function() {
return 0;
};
+ Range.PERCENT_RANGE = Range.fromExplicitRange(0, 1);
+ Object.freeze(Range.PERCENT_RANGE);
+
return {
Range: Range
};
diff --git a/chromium/third_party/catapult/tracing/tracing/base/range_test.html b/chromium/third_party/catapult/tracing/tracing/base/range_test.html
index 5d1f24cc296..e404f732c8c 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/range_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/range_test.html
@@ -347,6 +347,25 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(r2.findIntersection(r1).isEmpty);
});
+ test('findExplicitIntersectionDuration_overlapping', function() {
+ var r = Range.fromExplicitRange(2, 4);
+ assert.equal(1, r.findExplicitIntersectionDuration(1, 3));
+ assert.equal(1, r.findExplicitIntersectionDuration(3, 5));
+ assert.equal(2, r.findExplicitIntersectionDuration(0, 5));
+ });
+
+ test('findExplicitIntersectionDuration_invalidOtherRange', function() {
+ var r = Range.fromExplicitRange(2, 4);
+ assert.equal(0, r.findExplicitIntersectionDuration(3, 1));
+ assert.equal(0, r.findExplicitIntersectionDuration(5, 3));
+ });
+
+ test('findExplicitIntersectionDuration_disjoint', function() {
+ var r = Range.fromExplicitRange(2, 4);
+ assert.equal(0, r.findExplicitIntersectionDuration(0, 1));
+ assert.equal(0, r.findExplicitIntersectionDuration(4.5, 5));
+ });
+
test('filter_numericField', function() {
var r = Range.fromExplicitRange(2, 3);
var array = [{start: 1},
diff --git a/chromium/third_party/catapult/tracing/tracing/base/range_utils.html b/chromium/third_party/catapult/tracing/tracing/base/range_utils.html
index bc6810bc5d3..73dc67ae2d5 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/range_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/range_utils.html
@@ -29,7 +29,7 @@ tr.exportTo('tr.b', function() {
if (remainingEvents.length <= 1) {
var merged = [];
- if (remainingEvents.length == 1) {
+ if (remainingEvents.length === 1) {
merged.push(mergeFunction(remainingEvents));
}
return merged;
@@ -46,14 +46,14 @@ tr.exportTo('tr.b', function() {
}
function flushCurrentMergeBuffer() {
- if (currentMergeBuffer.length == 0)
+ if (currentMergeBuffer.length === 0)
return;
mergedEvents.push(mergeFunction(currentMergeBuffer));
currentMergeBuffer = [];
// Refill merge buffer if needed.
- if (remainingEvents.length != 0)
+ if (remainingEvents.length !== 0)
beginMerging();
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/rect.html b/chromium/third_party/catapult/tracing/tracing/base/rect.html
index 75fcadf5f65..3245a82f40c 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/rect.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/rect.html
@@ -20,7 +20,7 @@ tr.exportTo('tr.b', function() {
this.y = 0;
this.width = 0;
this.height = 0;
- };
+ }
Rect.fromXYWH = function(x, y, w, h) {
var rect = new Rect();
rect.x = x;
@@ -30,7 +30,7 @@ tr.exportTo('tr.b', function() {
return rect;
}
Rect.fromArray = function(ary) {
- if (ary.length != 4)
+ if (ary.length !== 4)
throw new Error('ary.length must be 4');
var rect = new Rect();
rect.x = ary[0];
diff --git a/chromium/third_party/catapult/tracing/tracing/base/running_statistics.html b/chromium/third_party/catapult/tracing/tracing/base/running_statistics.html
index 9110eb19eb0..292d595353a 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/running_statistics.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/running_statistics.html
@@ -4,12 +4,13 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/range.html">
+
+<link rel="import" href="/tracing/base/base.html">
+
<script>
'use strict';
tr.exportTo('tr.b', function() {
-
/***
* An object of this class computes basic statistics online in O(1).
* Usage:
@@ -17,60 +18,75 @@ tr.exportTo('tr.b', function() {
* 2. Add numbers using the |add| method.
* 3. Query statistics.
* 4. Repeat from step 2.
- *
- * @constructor
*/
- function RunningStatistics() {
- this.mean_ = 0;
- this.count_ = 0;
- this.max_ = -Infinity;
- this.min_ = Infinity;
- this.sum_ = 0;
- this.variance_ = 0;
- }
+ class RunningStatistics {
+ constructor() {
+ this.mean_ = 0;
+ this.count_ = 0;
+ this.max_ = -Infinity;
+ this.min_ = Infinity;
+ this.sum_ = 0;
+ this.variance_ = 0;
+
+ // Mean of logarithms of absolute values of samples, or undefined if any
+ // samples were <= 0.
+ this.meanlogs_ = 0;
+ }
- RunningStatistics.prototype = {
get count() {
return this.count_;
- },
+ }
+
+ get geometricMean() {
+ if (this.meanlogs_ === undefined)
+ return 0;
+ return Math.exp(this.meanlogs_);
+ }
get mean() {
- if (this.count_ == 0)
+ if (this.count_ === 0)
return undefined;
return this.mean_;
- },
+ }
get max() {
return this.max_;
- },
+ }
get min() {
return this.min_;
- },
+ }
get sum() {
return this.sum_;
- },
+ }
get variance() {
- if (this.count_ == 0)
+ if (this.count_ === 0)
return undefined;
- if (this.count_ == 1)
+ if (this.count_ === 1)
return 0;
return this.variance_ / (this.count_ - 1);
- },
+ }
get stddev() {
- if (this.count_ == 0)
+ if (this.count_ === 0)
return undefined;
return Math.sqrt(this.variance);
- },
+ }
- add: function(x) {
+ add(x) {
this.count_++;
this.max_ = Math.max(this.max_, x);
this.min_ = Math.min(this.min_, x);
this.sum_ += x;
+
+ // The geometric mean is computed using the arithmetic mean of logarithms.
+ if (x <= 0)
+ this.meanlogs_ = undefined;
+ else if (this.meanlogs_ !== undefined)
+ this.meanlogs_ += (Math.log(Math.abs(x)) - this.meanlogs_) / this.count;
+
// The following uses Welford's algorithm for computing running mean
// and variance. See http://www.johndcook.com/blog/standard_deviation.
if (this.count_ === 1) {
@@ -79,54 +95,83 @@ tr.exportTo('tr.b', function() {
} else {
var oldMean = this.mean_;
var oldVariance = this.variance_;
- this.mean_ = oldMean + (x - oldMean) / this.count_;
+ // Using the 2nd formula for updating the mean yields better precision
+ // but it doesn't work for the case oldMean is Infinity. Hence we handle
+ // that case separately.
+ if (oldMean === Infinity || oldMean === -Infinity) {
+ this.mean_ = this.sum_ / this.count_;
+ } else {
+ this.mean_ = oldMean + (x - oldMean) / this.count_;
+ }
this.variance_ = oldVariance + (x - oldMean) * (x - this.mean_);
}
- },
+ }
- merge: function(other) {
+ merge(other) {
var result = new RunningStatistics();
result.count_ = this.count_ + other.count_;
result.sum_ = this.sum_ + other.sum_;
result.min_ = Math.min(this.min_, other.min_);
result.max_ = Math.max(this.max_, other.max_);
- if (other.count_ === 0 && this.count_ === 0) {
+ if (result.count === 0) {
result.mean_ = 0;
result.variance_ = 0;
+ result.meanlogs_ = 0;
} else {
// Combine the mean and the variance using the formulas from
// https://goo.gl/ddcAep.
- var mx = this.mean_, my = other.mean_;
- var vx = this.variance_, vy = other.variance_;
- var n = this.count_, m = other.count_;
- result.mean_ = (n * mx + m * my) / (n + m);
- result.variance_ = vx + vy + n * m * (mx - my) * (mx - my) / (n + m);
+ result.mean_ = result.sum / result.count;
+ var deltaMean = (this.mean || 0) - (other.mean || 0);
+ result.variance_ = this.variance_ + other.variance_ +
+ (this.count * other.count * deltaMean * deltaMean / result.count);
+
+ // Merge the arithmetic means of logarithms of absolute values of
+ // samples, weighted by counts.
+ if (this.meanlogs_ === undefined || other.meanlogs_ === undefined) {
+ result.meanlogs_ = undefined;
+ } else {
+ result.meanlogs_ = (this.count * this.meanlogs_ +
+ other.count * other.meanlogs_) / result.count;
+ }
}
return result;
- },
-
- asDict: function() {
- return {
- mean: this.mean_,
- count: this.count_,
- max: this.max_,
- min: this.min_,
- sum: this.sum_,
- variance: this.variance_
- };
}
- };
- RunningStatistics.fromDict = function(d) {
- var result = new RunningStatistics();
- result.mean_ = d.mean;
- result.count_ = d.count;
- result.max_ = d.max;
- result.min_ = d.min;
- result.sum_ = d.sum;
- result.variance_ = d.variance;
- return result;
- };
+ asDict() {
+ if (!this.count) {
+ return [];
+ }
+ // It's more efficient to serialize these fields in an array. If you
+ // add any other fields, you should re-evaluate whether it would be more
+ // efficient to serialize as a dict.
+ return [
+ this.count_,
+ this.max_,
+ this.meanlogs_,
+ this.mean_,
+ this.min_,
+ this.sum_,
+ this.variance_,
+ ];
+ }
+
+ static fromDict(dict) {
+ var result = new RunningStatistics();
+ if (dict.length !== 7) {
+ return result;
+ }
+ [
+ result.count_,
+ result.max_,
+ result.meanlogs_,
+ result.mean_,
+ result.min_,
+ result.sum_,
+ result.variance_,
+ ] = dict;
+ return result;
+ }
+ }
return {
RunningStatistics: RunningStatistics
diff --git a/chromium/third_party/catapult/tracing/tracing/base/running_statistics_test.html b/chromium/third_party/catapult/tracing/tracing/base/running_statistics_test.html
index 5aba2cf644c..ab27bafc089 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/running_statistics_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/running_statistics_test.html
@@ -29,6 +29,10 @@ tr.b.unittest.testSuite(function() {
assert.closeTo(Statistics.sum(data), run(data).sum, 1e-6);
data = [2, 4, 4, 2];
assert.closeTo(Statistics.sum(data), run(data).sum, 1e-6);
+ data = [Infinity, Infinity, Infinity, 4, 4, Infinity, 1];
+ assert.equal(Statistics.sum(data), run(data).sum, Infinity);
+ data = [-Infinity, -Infinity, 2, -Infinity, 5, -Infinity];
+ assert.equal(Statistics.sum(data), run(data).sum, -Infinity);
});
test('min', function() {
@@ -65,6 +69,26 @@ tr.b.unittest.testSuite(function() {
assert.closeTo(Statistics.mean(data), run(data).mean, 1e-6);
data = [2, 4, 4, 2];
assert.closeTo(Statistics.mean(data), run(data).mean, 1e-6);
+ data = [Infinity, Infinity, Infinity, 4, 4, Infinity, 1];
+ assert.equal(Statistics.mean(data), run(data).mean, Infinity);
+ data = [-Infinity, -Infinity, 2, -Infinity, 5, -Infinity];
+ assert.equal(Statistics.mean(data), run(data).mean, -Infinity);
+ });
+
+ test('geometricMean', function() {
+ var data;
+ data = [];
+ assert.equal(Statistics.geometricMean(data), run(data).geometricMean);
+ data = [-1];
+ assert.equal(Statistics.geometricMean(data), run(data).geometricMean);
+ data = [1];
+ assert.equal(Statistics.geometricMean(data), run(data).geometricMean);
+ data = [1, 2, 3];
+ assert.closeTo(Statistics.geometricMean(data),
+ run(data).geometricMean, 1e-6);
+ data = [2, 4, 4, 2];
+ assert.closeTo(Statistics.geometricMean(data),
+ run(data).geometricMean, 1e-6);
});
test('variance', function() {
@@ -93,6 +117,7 @@ tr.b.unittest.testSuite(function() {
test('merge', function() {
var data1, data2, data, stats;
+
data1 = [];
data2 = [];
data = data1.concat(data2);
@@ -103,6 +128,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(Statistics.mean(data), stats.mean);
assert.equal(Statistics.variance(data), stats.variance);
assert.equal(Statistics.stddev(data), stats.stddev);
+ assert.equal(Statistics.geometricMean(data), stats.geometricMean);
+
data1 = [];
data2 = [1, 2, 3];
data = data1.concat(data2);
@@ -113,6 +140,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(Statistics.mean(data), stats.mean);
assert.closeTo(Statistics.variance(data), stats.variance, 1e-6);
assert.closeTo(Statistics.stddev(data), stats.stddev, 1e-6);
+ assert.closeTo(Statistics.geometricMean(data), stats.geometricMean, 1e-6);
+
data1 = [1, 2, 3];
data2 = [];
data = data1.concat(data2);
@@ -123,6 +152,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(Statistics.mean(data), stats.mean);
assert.closeTo(Statistics.variance(data), stats.variance, 1e-6);
assert.closeTo(Statistics.stddev(data), stats.stddev, 1e-6);
+ assert.closeTo(Statistics.geometricMean(data), stats.geometricMean, 1e-6);
+
data1 = [1, 2, 3];
data2 = [10, 20, 100];
data = data1.concat(data2);
@@ -133,6 +164,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(Statistics.mean(data), stats.mean);
assert.closeTo(Statistics.variance(data), stats.variance, 1e-6);
assert.closeTo(Statistics.stddev(data), stats.stddev, 1e-6);
+ assert.closeTo(Statistics.geometricMean(data), stats.geometricMean, 1e-6);
+
data1 = [1, 1, 1, 1, 1];
data2 = [10, 20, 10, 40];
data = data1.concat(data2);
@@ -143,13 +176,20 @@ tr.b.unittest.testSuite(function() {
assert.equal(Statistics.mean(data), stats.mean);
assert.closeTo(Statistics.variance(data), stats.variance, 1e-6);
assert.closeTo(Statistics.stddev(data), stats.stddev, 1e-6);
+ assert.closeTo(Statistics.geometricMean(data), stats.geometricMean, 1e-6);
});
test('serialization', function() {
- var data;
- data = [1, 2, 3];
- var stats = run(data);
- assert.deepEqual(stats, RunningStatistics.fromDict(stats.asDict()));
+ var data = [1, 2, 3];
+ var dict = run(data).asDict();
+ var cloneDict = RunningStatistics.fromDict(dict).asDict();
+ for (var field = 0; field < dict.length; ++field) {
+ assert.closeTo(dict[field], cloneDict[field], 1e-6);
+ }
+
+ // You can change this number, but when you do, please explain in your CL
+ // description why it changed.
+ assert.strictEqual(32, JSON.stringify(dict).length);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/settings.html b/chromium/third_party/catapult/tracing/tracing/base/settings.html
index 2c53956e4e4..9cef5eb9179 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/settings.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/settings.html
@@ -21,7 +21,7 @@ tr.exportTo('tr.b', function() {
*/
function Settings() {
return Settings;
- };
+ }
if (tr.b.unittest && tr.b.unittest.TestRunner) {
tr.b.unittest.TestRunner.addEventListener(
@@ -38,8 +38,8 @@ tr.exportTo('tr.b', function() {
return SessionSettings;
}
- function AddStaticStorageFunctionsToClass_(input_class, storage) {
- input_class.storage_ = storage;
+ function AddStaticStorageFunctionsToClass_(inputClass, storage) {
+ inputClass.storage_ = storage;
/**
* Get the setting with the given name.
@@ -50,9 +50,9 @@ tr.exportTo('tr.b', function() {
* with this namespace, e.g. "categories.settingName". This is useful for
* a set of related settings.
*/
- input_class.get = function(key, opt_default, opt_namespace) {
- key = input_class.namespace_(key, opt_namespace);
- var rawVal = input_class.storage_.getItem(key);
+ inputClass.get = function(key, opt_default, opt_namespace) {
+ key = inputClass.namespace_(key, opt_namespace);
+ var rawVal = inputClass.storage_.getItem(key);
if (rawVal === null || rawVal === undefined)
return opt_default;
@@ -62,10 +62,10 @@ tr.exportTo('tr.b', function() {
try {
return JSON.parse(rawVal).value;
} catch (e) {
- input_class.storage_.removeItem(key);
+ inputClass.storage_.removeItem(key);
return opt_default;
}
- };
+ }
/**
* Set the setting with the given name to the given value.
@@ -76,12 +76,12 @@ tr.exportTo('tr.b', function() {
* with this namespace, e.g. "categories.settingName". This is useful for
* a set of related settings.
*/
- input_class.set = function(key, value, opt_namespace) {
+ inputClass.set = function(key, value, opt_namespace) {
if (value === undefined)
throw new Error('Settings.set: value must not be undefined');
var v = JSON.stringify({value: value});
- input_class.storage_.setItem(
- input_class.namespace_(key, opt_namespace), v);
+ inputClass.storage_.setItem(
+ inputClass.namespace_(key, opt_namespace), v);
};
/**
@@ -91,51 +91,51 @@ tr.exportTo('tr.b', function() {
* @param {string=} opt_namespace If set, only return settings which
* begin with this prefix.
*/
- input_class.keys = function(opt_namespace) {
+ inputClass.keys = function(opt_namespace) {
var result = [];
opt_namespace = opt_namespace || '';
- for (var i = 0; i < input_class.storage_.length; i++) {
- var key = input_class.storage_.key(i);
- if (input_class.isnamespaced_(key, opt_namespace))
- result.push(input_class.unnamespace_(key, opt_namespace));
+ for (var i = 0; i < inputClass.storage_.length; i++) {
+ var key = inputClass.storage_.key(i);
+ if (inputClass.isnamespaced_(key, opt_namespace))
+ result.push(inputClass.unnamespace_(key, opt_namespace));
}
return result;
};
- input_class.isnamespaced_ = function(key, opt_namespace) {
- return key.indexOf(input_class.normalize_(opt_namespace)) == 0;
+ inputClass.isnamespaced_ = function(key, opt_namespace) {
+ return key.indexOf(inputClass.normalize_(opt_namespace)) === 0;
};
- input_class.namespace_ = function(key, opt_namespace) {
- return input_class.normalize_(opt_namespace) + key;
+ inputClass.namespace_ = function(key, opt_namespace) {
+ return inputClass.normalize_(opt_namespace) + key;
};
- input_class.unnamespace_ = function(key, opt_namespace) {
- return key.replace(input_class.normalize_(opt_namespace), '');
+ inputClass.unnamespace_ = function(key, opt_namespace) {
+ return key.replace(inputClass.normalize_(opt_namespace), '');
};
/**
* All settings are prefixed with a global namespace to avoid collisions.
- * input_class may also be namespaced with an additional prefix passed into
+ * inputClass may also be namespaced with an additional prefix passed into
* the get, set, and keys methods in order to group related settings.
* This method makes sure the two namespaces are always set properly.
*/
- input_class.normalize_ = function(opt_namespace) {
- return input_class.NAMESPACE + (opt_namespace ? opt_namespace + '.' : '');
+ inputClass.normalize_ = function(opt_namespace) {
+ return inputClass.NAMESPACE + (opt_namespace ? opt_namespace + '.' : '');
};
- input_class.setAlternativeStorageInstance = function(instance) {
- input_class.storage_ = instance;
+ inputClass.setAlternativeStorageInstance = function(instance) {
+ inputClass.storage_ = instance;
};
- input_class.getAlternativeStorageInstance = function() {
- if (!tr.isHeadless && input_class.storage_ === localStorage)
+ inputClass.getAlternativeStorageInstance = function() {
+ if (!tr.isHeadless && inputClass.storage_ === localStorage)
return undefined;
- return input_class.storage_;
+ return inputClass.storage_;
};
- input_class.NAMESPACE = 'trace-viewer';
- };
+ inputClass.NAMESPACE = 'trace-viewer';
+ }
function HeadlessStorage() {
this.length = 0;
diff --git a/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator.html b/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator.html
new file mode 100644
index 00000000000..45c4e5cc25c
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/color.html">
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/math.html">
+
+<script>
+'use strict';
+tr.exportTo('tr.b', function() {
+ /**
+ * Generate pretty colors!
+ * http://basecase.org/env/on-rainbows
+ * https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/
+ *
+ * Set brightness = 0 to always generate black.
+ * Set brightness = 2 to always generate white.
+ * Set brightness = 1 to generate saturated colors.
+ *
+ * @constructor
+ * @param {number=} opt_a alpha opacity in [0,1]
+ * @param {number=} opt_brightness in [0,2]
+ */
+ function SinebowColorGenerator(opt_a, opt_brightness) {
+ this.a_ = (opt_a === undefined) ? 1 : opt_a;
+ this.brightness_ = (opt_brightness === undefined) ? 1 : opt_brightness;
+ this.colorIndex_ = 0;
+ this.keyToColor = {};
+ }
+
+ SinebowColorGenerator.prototype = {
+ colorForKey: function(key) {
+ if (!this.keyToColor[key])
+ this.keyToColor[key] = this.nextColor();
+ return this.keyToColor[key];
+ },
+
+ nextColor: function() {
+ var components = SinebowColorGenerator.nthColor(this.colorIndex_++);
+ return tr.b.Color.fromString(SinebowColorGenerator.calculateColor(
+ components[0], components[1], components[2],
+ this.a_, this.brightness_));
+ }
+ };
+
+ SinebowColorGenerator.PHI = (1 + Math.sqrt(5)) / 2;
+
+ SinebowColorGenerator.sinebow_ = function(h) {
+ h += 0.5;
+ h = -h;
+ var r = Math.sin(Math.PI * h);
+ var g = Math.sin(Math.PI * (h + 1 / 3));
+ var b = Math.sin(Math.PI * (h + 2 / 3));
+ r *= r; g *= g; b *= b;
+ // Roughly correct for human perception.
+ // https://en.wikipedia.org/wiki/Luma_%28video%29
+ // Multiply by 2 to normalize all values to 0.5.
+ // (Halfway between black and white.)
+ var y = 2 * (0.2989 * r + 0.5870 * g + 0.1140 * b);
+ r /= y; g /= y; b /= y;
+ return [256 * r, 256 * g, 256 * b];
+ };
+
+ SinebowColorGenerator.nthColor = function(n) {
+ return SinebowColorGenerator.sinebow_(n * this.PHI);
+ };
+
+ SinebowColorGenerator.calculateColor = function(r, g, b, a, brightness) {
+ if (brightness <= 1) {
+ r *= brightness;
+ g *= brightness;
+ b *= brightness;
+ } else {
+ r = tr.b.lerp(tr.b.normalize(brightness, 1, 2), r, 255);
+ g = tr.b.lerp(tr.b.normalize(brightness, 1, 2), g, 255);
+ b = tr.b.lerp(tr.b.normalize(brightness, 1, 2), b, 255);
+ }
+ r = Math.round(r);
+ g = Math.round(g);
+ b = Math.round(b);
+ return 'rgba(' + r + ',' + g + ',' + b + ', ' + a + ')';
+ };
+
+ return {
+ SinebowColorGenerator: SinebowColorGenerator
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator_test.html b/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator_test.html
new file mode 100644
index 00000000000..0676847cb61
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/base/sinebow_color_generator_test.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/sinebow_color_generator.html">
+
+<script>
+'use strict';
+tr.b.unittest.testSuite(function() {
+ test('SinebowColorGenerator', function() {
+ var generator = new tr.b.SinebowColorGenerator();
+ assert.strictEqual('rgba(270,67,67,1)',
+ generator.colorForKey('z').toString());
+ assert.strictEqual('rgba(44,132,329,1)',
+ generator.colorForKey('y').toString());
+ assert.strictEqual('rgba(99,166,9,1)',
+ generator.colorForKey('x').toString());
+ assert.strictEqual('rgba(270,67,67,1)',
+ generator.colorForKey('z').toString());
+
+ generator = new tr.b.SinebowColorGenerator(0.5);
+ assert.strictEqual('rgba(270,67,67,0.5)',
+ generator.colorForKey('z').toString());
+ assert.strictEqual('rgba(44,132,329,0.5)',
+ generator.colorForKey('y').toString());
+ assert.strictEqual('rgba(99,166,9,0.5)',
+ generator.colorForKey('x').toString());
+ assert.strictEqual('rgba(270,67,67,0.5)',
+ generator.colorForKey('z').toString());
+
+ generator = new tr.b.SinebowColorGenerator(1, 0);
+ assert.strictEqual('rgba(0,0,0,1)',
+ generator.colorForKey('z').toString());
+ assert.strictEqual('rgba(0,0,0,1)',
+ generator.colorForKey('y').toString());
+ assert.strictEqual('rgba(0,0,0,1)',
+ generator.colorForKey('x').toString());
+ assert.strictEqual('rgba(0,0,0,1)',
+ generator.colorForKey('z').toString());
+
+ generator = new tr.b.SinebowColorGenerator(1, 2);
+ assert.strictEqual('rgba(255,255,255,1)',
+ generator.colorForKey('z').toString());
+ assert.strictEqual('rgba(255,255,255,1)',
+ generator.colorForKey('y').toString());
+ assert.strictEqual('rgba(255,255,255,1)',
+ generator.colorForKey('x').toString());
+ assert.strictEqual('rgba(255,255,255,1)',
+ generator.colorForKey('z').toString());
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/sorted_array_utils.html b/chromium/third_party/catapult/tracing/tracing/base/sorted_array_utils.html
index 44d4c80fff2..3352f9487ad 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/sorted_array_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/sorted_array_utils.html
@@ -30,7 +30,7 @@ tr.exportTo('tr.b', function() {
* the array.
*/
function findLowIndexInSortedArray(ary, mapFn, loVal) {
- if (ary.length == 0)
+ if (ary.length === 0)
return 1;
var low = 0;
@@ -50,7 +50,7 @@ tr.exportTo('tr.b', function() {
}
}
// return where we hit, or failing that the low pos
- return hitPos != -1 ? hitPos : low;
+ return hitPos !== -1 ? hitPos : low;
}
// From devtools/front_end/platform/utilities.js upperBound
@@ -91,7 +91,7 @@ tr.exportTo('tr.b', function() {
*/
function findIndexInSortedIntervals(ary, mapLoFn, mapWidthFn, loVal) {
var first = findLowIndexInSortedArray(ary, mapLoFn, loVal);
- if (first == 0) {
+ if (first === 0) {
if (loVal >= mapLoFn(ary[0]) &&
loVal < mapLoFn(ary[0]) + mapWidthFn(ary[0], 0)) {
return 0;
@@ -109,7 +109,7 @@ tr.exportTo('tr.b', function() {
} else {
return ary.length;
}
- } else if (first == ary.length) {
+ } else if (first === ary.length) {
if (loVal >= mapLoFn(ary[first - 1]) &&
loVal < mapLoFn(ary[first - 1]) +
mapWidthFn(ary[first - 1], first - 1)) {
@@ -165,7 +165,7 @@ tr.exportTo('tr.b', function() {
} else {
return ary.length;
}
- } else if (i == ary.length) {
+ } else if (i === ary.length) {
if (val >= mapLoFn(ary[i - 1], i - 1) &&
val <= mapHiFn(ary[i - 1], i - 1)) {
return i - 1;
@@ -198,13 +198,13 @@ tr.exportTo('tr.b', function() {
*/
function iterateOverIntersectingIntervals(ary, mapLoFn, mapWidthFn, loVal,
hiVal, cb) {
- if (ary.length == 0)
+ if (ary.length === 0)
return;
if (loVal > hiVal) return;
var i = findLowIndexInSortedArray(ary, mapLoFn, loVal);
- if (i == -1) {
+ if (i === -1) {
return;
}
if (i > 0) {
@@ -213,7 +213,7 @@ tr.exportTo('tr.b', function() {
cb(ary[i - 1], i - 1);
}
}
- if (i == ary.length) {
+ if (i === ary.length) {
return;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/statistics.html b/chromium/third_party/catapult/tracing/tracing/base/statistics.html
index 9620de944a4..b6decb2a54e 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/statistics.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/statistics.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2014 The Chromium Authors. All rights reserved.
+Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
@@ -11,6 +11,7 @@ found in the LICENSE file.
<script>
'use strict';
+
// In node, the script-src for mannwhitneyu above brings in mannwhitneyui
// into a module, instead of into the global scope. Whereas this file
// assumes that mannwhitneyu is in the global scope. So, in Node only, we
@@ -31,14 +32,13 @@ found in the LICENSE file.
<script>
'use strict';
-tr.exportTo('tr.b', function() {
+// TODO(charliea): Remove:
+/* eslint-disable catapult-camelcase */
- function identity(d) {
- return d;
- }
+tr.exportTo('tr.b', function() {
+ var identity = x => x;
- function Statistics() {
- }
+ var Statistics = {};
/* Returns the quotient, or zero if the denominator is zero.*/
Statistics.divideIfPossibleOrZero = function(numerator, denominator) {
@@ -57,9 +57,37 @@ tr.exportTo('tr.b', function() {
};
Statistics.mean = function(ary, opt_func, opt_this) {
- if (ary.length == 0)
+ var func = opt_func || identity;
+ var sum = 0;
+ var i = 0;
+
+ for (var elt of ary)
+ sum += func.call(opt_this, elt, i++);
+
+ if (i === 0)
return undefined;
- return Statistics.sum(ary, opt_func, opt_this) / ary.length;
+
+ return sum / i;
+ };
+
+ Statistics.geometricMean = function(ary, opt_func, opt_this) {
+ var func = opt_func || identity;
+ var i = 0;
+ var logsum = 0;
+
+ // The geometric mean is expressed as the arithmetic mean of logarithms
+ // in order to prevent overflow.
+ for (var elt of ary) {
+ var x = func.call(opt_this, elt, i++);
+ if (x <= 0)
+ return 0;
+ logsum += Math.log(Math.abs(x));
+ }
+
+ if (i === 0)
+ return 1;
+
+ return Math.exp(logsum / i);
};
// Returns undefined if the sum of the weights is zero.
@@ -104,7 +132,7 @@ tr.exportTo('tr.b', function() {
};
Statistics.stddev = function(ary, opt_func, opt_this) {
- if (ary.length == 0)
+ if (ary.length === 0)
return undefined;
return Math.sqrt(
Statistics.variance(ary, opt_func, opt_this));
@@ -151,13 +179,6 @@ tr.exportTo('tr.b', function() {
return tmp[idx];
};
- /* Clamp a value between some low and high value. */
- Statistics.clamp = function(value, opt_low, opt_high) {
- opt_low = opt_low || 0.0;
- opt_high = opt_high || 1.0;
- return Math.min(Math.max(value, opt_low), opt_high);
- };
-
/**
* Sorts the samples, and map them linearly to the range [0,1].
*
@@ -185,8 +206,8 @@ tr.exportTo('tr.b', function() {
);
var low = Math.min.apply(null, samples);
var high = Math.max.apply(null, samples);
- var new_low = 0.5 / samples.length;
- var new_high = (samples.length - 0.5) / samples.length;
+ var newLow = 0.5 / samples.length;
+ var newHigh = (samples.length - 0.5) / samples.length;
if (high - low === 0.0) {
// Samples is an array of 0.5 in this case.
samples = Array.apply(null, new Array(samples.length)).map(
@@ -196,9 +217,9 @@ tr.exportTo('tr.b', function() {
scale: 1.0
};
}
- var scale = (new_high - new_low) / (high - low);
+ var scale = (newHigh - newLow) / (high - low);
for (var i = 0; i < samples.length; i++) {
- samples[i] = (samples[i] - low) * scale + new_low;
+ samples[i] = (samples[i] - low) * scale + newLow;
}
return {
normalized_samples: samples,
@@ -215,95 +236,95 @@ tr.exportTo('tr.b', function() {
* http://en.wikipedia.org/wiki/Low-discrepancy_sequence
* http://mathworld.wolfram.com/Discrepancy.html
*/
- Statistics.discrepancy = function(samples, opt_location_count) {
+ Statistics.discrepancy = function(samples, opt_locationCount) {
if (samples.length === 0)
return 0.0;
- var max_local_discrepancy = 0;
- var inv_sample_count = 1.0 / samples.length;
+ var maxLocalDiscrepancy = 0;
+ var invSampleCount = 1.0 / samples.length;
var locations = [];
// For each location, stores the number of samples less than that location.
- var count_less = [];
+ var countLess = [];
// For each location, stores the number of samples less than or equal to
// that location.
- var count_less_equal = [];
+ var countLessEqual = [];
- if (opt_location_count !== undefined) {
+ if (opt_locationCount !== undefined) {
// Generate list of equally spaced locations.
- var sample_index = 0;
- for (var i = 0; i < opt_location_count; i++) {
- var location = i / (opt_location_count - 1);
+ var sampleIndex = 0;
+ for (var i = 0; i < opt_locationCount; i++) {
+ var location = i / (opt_locationCount - 1);
locations.push(location);
- while (sample_index < samples.length &&
- samples[sample_index] < location) {
- sample_index += 1;
+ while (sampleIndex < samples.length &&
+ samples[sampleIndex] < location) {
+ sampleIndex += 1;
}
- count_less.push(sample_index);
- while (sample_index < samples.length &&
- samples[sample_index] <= location) {
- sample_index += 1;
+ countLess.push(sampleIndex);
+ while (sampleIndex < samples.length &&
+ samples[sampleIndex] <= location) {
+ sampleIndex += 1;
}
- count_less_equal.push(sample_index);
+ countLessEqual.push(sampleIndex);
}
} else {
// Populate locations with sample positions. Append 0 and 1 if necessary.
if (samples[0] > 0.0) {
locations.push(0.0);
- count_less.push(0);
- count_less_equal.push(0);
+ countLess.push(0);
+ countLessEqual.push(0);
}
for (var i = 0; i < samples.length; i++) {
locations.push(samples[i]);
- count_less.push(i);
- count_less_equal.push(i + 1);
+ countLess.push(i);
+ countLessEqual.push(i + 1);
}
if (samples[-1] < 1.0) {
locations.push(1.0);
- count_less.push(samples.length);
- count_less_equal.push(samples.length);
+ countLess.push(samples.length);
+ countLessEqual.push(samples.length);
}
}
// Compute discrepancy as max(overshoot, -undershoot), where
- // overshoot = max(count_closed(i, j)/N - length(i, j)) for all i < j,
- // undershoot = min(count_open(i, j)/N - length(i, j)) for all i < j,
+ // overshoot = max(countClosed(i, j)/N - length(i, j)) for all i < j,
+ // undershoot = min(countOpen(i, j)/N - length(i, j)) for all i < j,
// N = len(samples),
- // count_closed(i, j) is the number of points between i and j
+ // countClosed(i, j) is the number of points between i and j
// including ends,
- // count_open(i, j) is the number of points between i and j excluding ends,
+ // countOpen(i, j) is the number of points between i and j excluding ends,
// length(i, j) is locations[i] - locations[j].
// The following algorithm is modification of Kadane's algorithm,
// see https://en.wikipedia.org/wiki/Maximum_subarray_problem.
- // The maximum of (count_closed(k, i-1)/N - length(k, i-1)) for any k < i-1.
- var max_diff = 0;
- // The minimum of (count_open(k, i-1)/N - length(k, i-1)) for any k < i-1.
- var min_diff = 0;
+ // The maximum of (countClosed(k, i-1)/N - length(k, i-1)) for any k < i-1.
+ var maxDiff = 0;
+ // The minimum of (countOpen(k, i-1)/N - length(k, i-1)) for any k < i-1.
+ var minDiff = 0;
for (var i = 1; i < locations.length; i++) {
var length = locations[i] - locations[i - 1];
- var count_closed = count_less_equal[i] - count_less[i - 1];
- var count_open = count_less[i] - count_less_equal[i - 1];
+ var countClosed = countLessEqual[i] - countLess[i - 1];
+ var countOpen = countLess[i] - countLessEqual[i - 1];
// Number of points that are added if we extend a closed range that
// ends at location (i-1).
- var count_closed_increment =
- count_less_equal[i] - count_less_equal[i - 1];
+ var countClosedIncrement =
+ countLessEqual[i] - countLessEqual[i - 1];
// Number of points that are added if we extend an open range that
// ends at location (i-1).
- var count_open_increment = count_less[i] - count_less[i - 1];
+ var countOpenIncrement = countLess[i] - countLess[i - 1];
// Either extend the previous optimal range or start a new one.
- max_diff = Math.max(
- count_closed_increment * inv_sample_count - length + max_diff,
- count_closed * inv_sample_count - length);
- min_diff = Math.min(
- count_open_increment * inv_sample_count - length + min_diff,
- count_open * inv_sample_count - length);
-
- max_local_discrepancy = Math.max(
- max_diff, -min_diff, max_local_discrepancy);
+ maxDiff = Math.max(
+ countClosedIncrement * invSampleCount - length + maxDiff,
+ countClosed * invSampleCount - length);
+ minDiff = Math.min(
+ countOpenIncrement * invSampleCount - length + minDiff,
+ countOpen * invSampleCount - length);
+
+ maxLocalDiscrepancy = Math.max(
+ maxDiff, -minDiff, maxLocalDiscrepancy);
}
- return max_local_discrepancy;
+ return maxLocalDiscrepancy;
};
/**
@@ -338,7 +359,7 @@ tr.exportTo('tr.b', function() {
* D(S) = max(D(S_1), D(S_2), ..., D(S_N))
**/
Statistics.timestampsDiscrepancy = function(timestamps, opt_absolute,
- opt_location_count) {
+ opt_locationCount) {
if (timestamps.length === 0)
return 0.0;
@@ -346,24 +367,24 @@ tr.exportTo('tr.b', function() {
opt_absolute = true;
if (Array.isArray(timestamps[0])) {
- var range_discrepancies = timestamps.map(function(r) {
+ var rangeDiscrepancies = timestamps.map(function(r) {
return Statistics.timestampsDiscrepancy(r);
});
- return Math.max.apply(null, range_discrepancies);
+ return Math.max.apply(null, rangeDiscrepancies);
}
var s = Statistics.normalizeSamples(timestamps);
var samples = s.normalized_samples;
- var sample_scale = s.scale;
- var discrepancy = Statistics.discrepancy(samples, opt_location_count);
- var inv_sample_count = 1.0 / samples.length;
+ var sampleScale = s.scale;
+ var discrepancy = Statistics.discrepancy(samples, opt_locationCount);
+ var invSampleCount = 1.0 / samples.length;
if (opt_absolute === true) {
// Compute absolute discrepancy
- discrepancy /= sample_scale;
+ discrepancy /= sampleScale;
} else {
// Compute relative discrepancy
- discrepancy = Statistics.clamp(
- (discrepancy - inv_sample_count) / (1.0 - inv_sample_count));
+ discrepancy = tr.b.clamp(
+ (discrepancy - invSampleCount) / (1.0 - invSampleCount), 0.0, 1.0);
}
return discrepancy;
};
@@ -383,10 +404,10 @@ tr.exportTo('tr.b', function() {
* Args:
* durations: List of interval lengths in milliseconds.
* absolute: See TimestampsDiscrepancy.
- * opt_location_count: See TimestampsDiscrepancy.
+ * opt_locationCount: See TimestampsDiscrepancy.
**/
Statistics.durationsDiscrepancy = function(
- durations, opt_absolute, opt_location_count) {
+ durations, opt_absolute, opt_locationCount) {
if (durations.length === 0)
return 0.0;
@@ -395,9 +416,26 @@ tr.exportTo('tr.b', function() {
return prev;
}, [0]);
return Statistics.timestampsDiscrepancy(
- timestamps, opt_absolute, opt_location_count);
+ timestamps, opt_absolute, opt_locationCount);
};
+ /**
+ * Modifies |samples| in-place to reduce its length down to |count|.
+ *
+ * @param {!Array} samples
+ * @param {number} count
+ * @return {!Array}
+ */
+ Statistics.uniformlySampleArray = function(samples, count) {
+ if (samples.length <= count) {
+ return samples;
+ }
+ while (samples.length > count) {
+ var i = parseInt(Math.random() * samples.length);
+ samples.splice(i, 1);
+ }
+ return samples;
+ };
/**
* A mechanism to uniformly sample elements from an arbitrary long stream.
@@ -513,10 +551,10 @@ tr.exportTo('tr.b', function() {
* letters like |x|.
* The probability that |X| ever exactly equals |x| is P(X==x) = 0.
*
- * For a discrete probability distribution, aka histogram, see tr.v.Numeric.
+ * For a discrete probability distribution, see tr.v.Histogram.
*/
function Distribution() {
- };
+ }
Distribution.prototype = {
/* The probability density of the random variable at value |x| is the
@@ -759,7 +797,49 @@ tr.exportTo('tr.b', function() {
return new Statistics.LogNormalDistribution(location, shape);
};
- Statistics.mwu = mannwhitneyu;
+ // p-values less than this indicate statistical significance.
+ Statistics.DEFAULT_ALPHA = 0.01;
+
+ // If a statistical significant difference has not been established with
+ // this many observations per sample, we'll assume none exists.
+ Statistics.MAX_SUGGESTED_SAMPLE_SIZE = 20;
+
+ /** @enum */
+ Statistics.Significance = {
+ SIGNIFICANT: 'REJECT',
+ INSIGNIFICANT: 'FAIL_TO_REJECT',
+ NEED_MORE_DATA: 'NEED_MORE_DATA',
+ DONT_CARE: 'DONT_CARE',
+ };
+
+
+ /**
+ * @typedef {Object} HypothesisTestResult
+ * @property {number} p
+ * @property {number} U
+ * @property {!tr.b.Statistics.Significance} significance
+ */
+
+ /**
+ * @param {!Array.<number>} a
+ * @param {!Array.<number>} b
+ * @param {number=} opt_alpha
+ * @param {number=} opt_reqSampleSize
+ * @return {!HypothesisTestResult}
+ */
+ Statistics.mwu = function(a, b, opt_alpha, opt_reqSampleSize) {
+ var result = mannwhitneyu.test(a, b);
+ var alpha = opt_alpha || Statistics.DEFAULT_ALPHA;
+ if (result.p < alpha) {
+ result.significance = Statistics.Significance.SIGNIFICANT;
+ } else if (opt_reqSampleSize && (a.length < opt_reqSampleSize ||
+ b.length < opt_reqSampleSize)) {
+ result.significance = Statistics.Significance.NEED_MORE_DATA;
+ } else {
+ result.significance = Statistics.Significance.INSIGNIFICANT;
+ }
+ return result;
+ };
return {
Statistics: Statistics
diff --git a/chromium/third_party/catapult/tracing/tracing/base/statistics_test.html b/chromium/third_party/catapult/tracing/tracing/base/statistics_test.html
index 83c756c0a1a..2b243c93dc8 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/statistics_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/statistics_test.html
@@ -8,6 +8,9 @@ found in the LICENSE file.
<script>
'use strict';
+// TODO(charliea): Remove:
+/* eslint-disable catapult-camelcase */
+
tr.b.unittest.testSuite(function() {
var Statistics = tr.b.Statistics;
@@ -19,27 +22,27 @@ tr.b.unittest.testSuite(function() {
function relax(samples, opt_iterations) {
opt_iterations = opt_iterations || 10;
for (var i = 0; i < opt_iterations; i++) {
- var voronoi_boundaries = [];
+ var voronoiBoundaries = [];
for (var j = 1; j < samples.length; j++)
- voronoi_boundaries.push((samples[j] + samples[j - 1]) * 0.5);
+ voronoiBoundaries.push((samples[j] + samples[j - 1]) * 0.5);
- var relaxed_samples = [];
- relaxed_samples.push(samples[0]);
+ var relaxedSamples = [];
+ relaxedSamples.push(samples[0]);
for (var j = 1; j < samples.length - 1; j++) {
- relaxed_samples.push(
- (voronoi_boundaries[j - 1] + voronoi_boundaries[j]) * 0.5);
+ relaxedSamples.push(
+ (voronoiBoundaries[j - 1] + voronoiBoundaries[j]) * 0.5);
}
- relaxed_samples.push(samples[samples.length - 1]);
- samples = relaxed_samples;
+ relaxedSamples.push(samples[samples.length - 1]);
+ samples = relaxedSamples;
}
return samples;
}
- function createRandomSamples(num_samples) {
+ function createRandomSamples(numSamples) {
var samples = [];
var position = 0.0;
samples.push(position);
- for (var i = 1; i < num_samples; i++) {
+ for (var i = 1; i < numSamples; i++) {
position += Math.random();
samples.push(position);
}
@@ -145,7 +148,33 @@ tr.b.unittest.testSuite(function() {
});
test('meanBasic', function() {
- assert.equal(Statistics.mean([1, 2, 3]), 2);
+ assert.closeTo(Statistics.mean([1, 2, 3]), 2, 1e-6);
+ assert.closeTo(Statistics.mean(new Set([1, 2, 3])), 2, 1e-6);
+ });
+
+ test('geometricMean', function() {
+ assert.strictEqual(1, Statistics.geometricMean([]));
+ assert.strictEqual(1, Statistics.geometricMean([1]));
+ assert.strictEqual(0, Statistics.geometricMean([-1]));
+ assert.strictEqual(0, Statistics.geometricMean([0]));
+ assert.strictEqual(0, Statistics.geometricMean([1, 2, 3, 0]));
+ assert.strictEqual(0, Statistics.geometricMean([1, 2, 3, -1]));
+ assert.strictEqual(1, Statistics.geometricMean([1, 1, 1]));
+ assert.strictEqual(2, Statistics.geometricMean([2]));
+ assert.closeTo(Math.sqrt(6), Statistics.geometricMean([2, 3]), 1e-6);
+ assert.closeTo(6, Statistics.geometricMean(new Set([4, 9])), 1e-6);
+
+ var samples = [];
+ for (var i = 0; i < 1e3; ++i)
+ samples.push(Number.MAX_SAFE_INTEGER);
+ assert.closeTo(Number.MAX_SAFE_INTEGER, Statistics.geometricMean(samples),
+ Number.MAX_SAFE_INTEGER * 1e-13);
+
+ samples = [];
+ for (var i = 0; i < 1e3; ++i)
+ samples.push(Number.MAX_VALUE / 1e3);
+ assert.closeTo(Number.MAX_VALUE / 1e3, Statistics.geometricMean(samples),
+ Number.MAX_VALUE * 1e-13);
});
test('weightedMean', function() {
@@ -319,9 +348,9 @@ tr.b.unittest.testSuite(function() {
var samples = createRandomSamples(10);
var samples = Statistics.normalizeSamples(samples).normalized_samples;
var d = Statistics.discrepancy(samples);
- var relaxed_samples = relax(samples);
- var d_relaxed = Statistics.discrepancy(relaxed_samples);
- assert.isBelow(d_relaxed, d);
+ var relaxedSamples = relax(samples);
+ var dRelaxed = Statistics.discrepancy(relaxedSamples);
+ assert.isBelow(dRelaxed, d);
}
});
@@ -366,43 +395,43 @@ tr.b.unittest.testSuite(function() {
});
test('timestampsDiscrepancy', function() {
- var time_stamps = [];
- var d_abs = Statistics.timestampsDiscrepancy(time_stamps, true);
- assert.equal(d_abs, 0.0);
-
- time_stamps = [4];
- d_abs = Statistics.timestampsDiscrepancy(time_stamps, true);
- assert.equal(d_abs, 0.5);
-
- var time_stamps_a = [0, 1, 2, 3, 5, 6];
- var time_stamps_b = [0, 1, 2, 3, 5, 7];
- var time_stamps_c = [0, 2, 3, 4];
- var time_stamps_d = [0, 2, 3, 4, 5];
-
-
- var d_abs_a = Statistics.timestampsDiscrepancy(time_stamps_a, true);
- var d_abs_b = Statistics.timestampsDiscrepancy(time_stamps_b, true);
- var d_abs_c = Statistics.timestampsDiscrepancy(time_stamps_c, true);
- var d_abs_d = Statistics.timestampsDiscrepancy(time_stamps_d, true);
- var d_rel_a = Statistics.timestampsDiscrepancy(time_stamps_a, false);
- var d_rel_b = Statistics.timestampsDiscrepancy(time_stamps_b, false);
- var d_rel_c = Statistics.timestampsDiscrepancy(time_stamps_c, false);
- var d_rel_d = Statistics.timestampsDiscrepancy(time_stamps_d, false);
-
-
- assert.isBelow(d_abs_a, d_abs_b);
- assert.isBelow(d_rel_a, d_rel_b);
- assert.isBelow(d_rel_d, d_rel_c);
- assert.closeTo(d_abs_d, d_abs_c, 0.0001);
+ var timestamps = [];
+ var dAbs = Statistics.timestampsDiscrepancy(timestamps, true);
+ assert.equal(dAbs, 0.0);
+
+ timestamps = [4];
+ dAbs = Statistics.timestampsDiscrepancy(timestamps, true);
+ assert.equal(dAbs, 0.5);
+
+ var timestampsA = [0, 1, 2, 3, 5, 6];
+ var timestampsB = [0, 1, 2, 3, 5, 7];
+ var timestampsC = [0, 2, 3, 4];
+ var timestampsD = [0, 2, 3, 4, 5];
+
+
+ var dAbsA = Statistics.timestampsDiscrepancy(timestampsA, true);
+ var dAbsB = Statistics.timestampsDiscrepancy(timestampsB, true);
+ var dAbsC = Statistics.timestampsDiscrepancy(timestampsC, true);
+ var dAbsD = Statistics.timestampsDiscrepancy(timestampsD, true);
+ var dRelA = Statistics.timestampsDiscrepancy(timestampsA, false);
+ var dRelB = Statistics.timestampsDiscrepancy(timestampsB, false);
+ var dRelC = Statistics.timestampsDiscrepancy(timestampsC, false);
+ var dRelD = Statistics.timestampsDiscrepancy(timestampsD, false);
+
+
+ assert.isBelow(dAbsA, dAbsB);
+ assert.isBelow(dRelA, dRelB);
+ assert.isBelow(dRelD, dRelC);
+ assert.closeTo(dAbsD, dAbsC, 0.0001);
});
test('discrepancyMultipleRanges', function() {
var samples = [[0.0, 1.2, 2.3, 3.3], [6.3, 7.5, 8.4], [4.2, 5.4, 5.9]];
- var d_0 = Statistics.timestampsDiscrepancy(samples[0]);
- var d_1 = Statistics.timestampsDiscrepancy(samples[1]);
- var d_2 = Statistics.timestampsDiscrepancy(samples[2]);
+ var d0 = Statistics.timestampsDiscrepancy(samples[0]);
+ var d1 = Statistics.timestampsDiscrepancy(samples[1]);
+ var d2 = Statistics.timestampsDiscrepancy(samples[2]);
var d = Statistics.timestampsDiscrepancy(samples);
- assert.equal(d, Math.max(d_0, d_1, d_2));
+ assert.equal(d, Math.max(d0, d1, d2));
});
/**
@@ -414,8 +443,8 @@ tr.b.unittest.testSuite(function() {
var samples = createRandomSamples(10);
samples = Statistics.normalizeSamples(samples).normalized_samples;
var d = Statistics.discrepancy(samples);
- var d_approx = Statistics.discrepancy(samples, 500);
- assert.closeTo(d, d_approx, 0.01);
+ var dApprox = Statistics.discrepancy(samples, 500);
+ assert.closeTo(d, dApprox, 0.01);
}
});
@@ -428,16 +457,24 @@ tr.b.unittest.testSuite(function() {
d = Statistics.durationsDiscrepancy(durations);
assert.equal(d, 4.0);
- var durations_a = [1, 1, 1, 1, 1];
- var durations_b = [1, 1, 2, 1, 1];
- var durations_c = [1, 2, 1, 2, 1];
+ var durationsA = [1, 1, 1, 1, 1];
+ var durationsB = [1, 1, 2, 1, 1];
+ var durationsC = [1, 2, 1, 2, 1];
- var d_a = Statistics.durationsDiscrepancy(durations_a);
- var d_b = Statistics.durationsDiscrepancy(durations_b);
- var d_c = Statistics.durationsDiscrepancy(durations_c);
+ var dA = Statistics.durationsDiscrepancy(durationsA);
+ var dB = Statistics.durationsDiscrepancy(durationsB);
+ var dC = Statistics.durationsDiscrepancy(durationsC);
- assert.isBelow(d_a, d_b);
- assert.isBelow(d_b, d_c);
+ assert.isBelow(dA, dB);
+ assert.isBelow(dB, dC);
+ });
+
+ test('uniformlySampleArray', function() {
+ var samples = ['A', 'B', 'C', 'D', 'E'];
+ for (var i = samples.length; i >= 0; --i) {
+ Statistics.uniformlySampleArray(samples, i);
+ assert.lengthOf(samples, i);
+ }
});
test('uniformlySampleStream', function() {
@@ -482,20 +519,20 @@ tr.b.unittest.testSuite(function() {
// x < 0.01
var sampleA = [1, 2, 2.1, 2.2, 2, 1];
var sampleB = [12, 13, 13.1, 13.2, 13, 12];
- var results = Statistics.mwu.test(sampleA, sampleB);
+ var results = Statistics.mwu(sampleA, sampleB);
assert.isBelow(results.p, 0.1);
// 0.01 < x < 0.1
sampleA = [1, 2, 2.1, 2.2, 2, 1];
sampleB = [2, 3, 3.1, 3.2, 3, 2];
- results = Statistics.mwu.test(sampleA, sampleB);
+ results = Statistics.mwu(sampleA, sampleB);
assert.isBelow(results.p, 0.1);
assert.isAbove(results.p, 0.01);
// 0.1 < x
sampleA = [1, 2, 2.1, 2.2, 2, 1];
sampleB = [1, 2, 2.1, 2.2, 2, 1];
- results = Statistics.mwu.test(sampleA, sampleB);
+ results = Statistics.mwu(sampleA, sampleB);
assert.isAbove(results.p, 0.1);
});
@@ -509,33 +546,32 @@ tr.b.unittest.testSuite(function() {
6.915150e+0, 7.881740e+0, 1.131160e+1, 9.959400e+0, 9.030880e+0
];
// Identical samples should not cause the null to be rejected.
- var results = Statistics.mwu.test(longRepeatingSample, longRepeatingSample);
+ var results = Statistics.mwu(longRepeatingSample, longRepeatingSample);
assert.isAbove(results.p, 0.05);
- results = Statistics.mwu.test(normallyDistributedSample,
+ results = Statistics.mwu(normallyDistributedSample,
normallyDistributedSample);
assert.isAbove(results.p, 0.05);
- results = Statistics.mwu.test(singleLargeValue, singleLargeValue);
+ results = Statistics.mwu(singleLargeValue, singleLargeValue);
// A single value is generally not sufficient to reject the null, no matter
// how far off it is.
- results = Statistics.mwu.test(normallyDistributedSample, singleLargeValue);
+ results = Statistics.mwu(normallyDistributedSample, singleLargeValue);
assert.isAbove(results.p, 0.05);
// A single value way outside the first sample may be enough to reject,
// if the first sample is large enough.
- results = Statistics.mwu.test(longRepeatingSample, singleLargeValue);
+ results = Statistics.mwu(longRepeatingSample, singleLargeValue);
assert.isBelow(results.p, 0.005);
// Empty samples should not be comparable.
- results = Statistics.mwu.test(emptySample, emptySample);
+ results = Statistics.mwu(emptySample, emptySample);
assert(isNaN(results.p));
// The result of comparing a sample against an empty sample should not be a
// valid p value. NOTE: The current implementation returns 0, it is up to
// the caller to interpret this.
- results = Statistics.mwu.test(normallyDistributedSample, emptySample);
+ results = Statistics.mwu(normallyDistributedSample, emptySample);
assert(!results.p);
});
-
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/time_display_mode.html b/chromium/third_party/catapult/tracing/tracing/base/time_display_modes.html
index ae6b4df8cfe..8c91df5d24a 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/time_display_mode.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/time_display_modes.html
@@ -5,7 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/unit_scale.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<script>
'use strict';
@@ -13,7 +13,7 @@ found in the LICENSE file.
/**
* @fileoverview Time currentDisplayUnit
*/
-tr.exportTo('tr.v', function() {
+tr.exportTo('tr.b', function() {
var msDisplayMode = {
scale: 1e-3,
suffix: 'ms',
@@ -23,7 +23,7 @@ tr.exportTo('tr.v', function() {
},
formatSpec: {
unit: 's',
- unitPrefix: tr.v.UnitScale.MetricTime.MILLI,
+ unitPrefix: tr.b.UnitScale.Metric.MILLI,
minimumFractionDigits: 3,
}
};
@@ -37,7 +37,7 @@ tr.exportTo('tr.v', function() {
},
formatSpec: {
unit: 's',
- unitPrefix: tr.v.UnitScale.MetricTime.NANO,
+ unitPrefix: tr.b.UnitScale.Metric.NANO,
maximumFractionDigits: 0
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/value/unit.html b/chromium/third_party/catapult/tracing/tracing/base/unit.html
index aa4fed27746..c260f55fe26 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/unit.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unit.html
@@ -8,14 +8,14 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/event.html">
<link rel="import" href="/tracing/base/event_target.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
-<link rel="import" href="/tracing/value/unit_scale.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<script>
'use strict';
-tr.exportTo('tr.v', function() {
- var TimeDisplayModes = tr.v.TimeDisplayModes;
+tr.exportTo('tr.b', function() {
+ var TimeDisplayModes = tr.b.TimeDisplayModes;
var PLUS_MINUS_SIGN = String.fromCharCode(177);
@@ -35,9 +35,11 @@ tr.exportTo('tr.v', function() {
};
/** @constructor */
- function Unit(unitName, jsonName, isDelta, improvementDirection, formatSpec) {
+ function Unit(unitName, jsonName, basePrefix, isDelta, improvementDirection,
+ formatSpec) {
this.unitName = unitName;
this.jsonName = jsonName;
+ this.basePrefix = basePrefix;
this.isDelta = isDelta;
this.improvementDirection = improvementDirection;
this.formatSpec_ = formatSpec;
@@ -55,6 +57,31 @@ tr.exportTo('tr.v', function() {
return this.jsonName;
},
+ get unitString() {
+ // TODO(benjhayden): Refactor with format() and test.
+ var formatSpec = this.formatSpec_;
+ if (typeof formatSpec === 'function')
+ formatSpec = formatSpec();
+ if (!formatSpec.unit) {
+ return '';
+ }
+
+ var unitString = '';
+ var unitPrefix = formatSpec.unitPrefix;
+ if (unitPrefix !== undefined) {
+ var selectedPrefix;
+ if (unitPrefix instanceof Array) {
+ selectedPrefix = unitPrefix[0];
+ } else {
+ selectedPrefix = unitPrefix;
+ }
+ unitString += selectedPrefix.symbol || '';
+ }
+ unitString += formatSpec.unit;
+
+ return unitString;
+ },
+
format: function(value, opt_context) {
var context = opt_context || {};
var formatSpec = this.formatSpec_;
@@ -96,7 +123,10 @@ tr.exportTo('tr.v', function() {
selectedPrefix = unitPrefix;
}
unitString += selectedPrefix.symbol || '';
- value /= selectedPrefix.value;
+ value = tr.b.convertUnit(value, this.basePrefix, selectedPrefix);
+ } else {
+ value = tr.b.convertUnit(value, this.basePrefix,
+ tr.b.UnitScale.Metric.NONE);
}
unitString += formatSpec.unit;
}
@@ -134,11 +164,8 @@ tr.exportTo('tr.v', function() {
};
Unit.timestampFromUs = function(us) {
- return us / 1000;
- };
-
- Unit.maybeTimestampFromUs = function(us) {
- return us === undefined ? undefined : us / 1000;
+ return tr.b.convertUnit(us, tr.b.UnitScale.Metric.MICRO,
+ tr.b.UnitScale.Metric.MILLI);
};
Object.defineProperty(Unit, 'currentTimeDisplayMode', {
@@ -222,21 +249,23 @@ tr.exportTo('tr.v', function() {
definedUnits.forEach(u => u.baseUnit = baseUnit);
};
- Unit.defineUnitVariant_ = function(params, isDelta, improvementDirection) {
- var nameSuffix = isDelta ? 'Delta' : '';
+ Unit.nameSuffixForImprovementDirection = function(improvementDirection) {
switch (improvementDirection) {
case ImprovementDirection.DONT_CARE:
- break;
+ return '';
case ImprovementDirection.BIGGER_IS_BETTER:
- nameSuffix += '_biggerIsBetter';
- break;
+ return '_biggerIsBetter';
case ImprovementDirection.SMALLER_IS_BETTER:
- nameSuffix += '_smallerIsBetter';
- break;
+ return '_smallerIsBetter';
default:
throw new Error(
'Unknown improvement direction: ' + improvementDirection);
}
+ };
+
+ Unit.defineUnitVariant_ = function(params, isDelta, improvementDirection) {
+ var nameSuffix = isDelta ? 'Delta' : '';
+ nameSuffix += Unit.nameSuffixForImprovementDirection(improvementDirection);
var unitName = params.baseUnitName + nameSuffix;
var jsonName = params.baseJsonName + nameSuffix;
@@ -245,8 +274,10 @@ tr.exportTo('tr.v', function() {
if (Unit.byJSONName[jsonName] !== undefined)
throw new Error('JSON unit \'' + jsonName + '\' alread exists');
- var unit = new Unit(
- unitName, jsonName, isDelta, improvementDirection, params.formatSpec);
+ var basePrefix = params.basePrefix ?
+ params.basePrefix : tr.b.UnitScale.Metric.NONE;
+ var unit = new Unit(unitName, jsonName, basePrefix,
+ isDelta, improvementDirection, params.formatSpec);
Unit.byName[unitName] = unit;
Unit.byJSONName[jsonName] = unit;
@@ -262,6 +293,7 @@ tr.exportTo('tr.v', function() {
Unit.define({
baseUnitName: 'timeDurationInMs',
baseJsonName: 'ms',
+ basePrefix: tr.b.UnitScale.Metric.MILLI,
formatSpec: function() {
return Unit.currentTimeDisplayMode_.formatSpec;
}
@@ -270,6 +302,7 @@ tr.exportTo('tr.v', function() {
Unit.define({
baseUnitName: 'timeStampInMs',
baseJsonName: 'tsMs',
+ basePrefix: tr.b.UnitScale.Metric.MILLI,
formatSpec: function() {
return Unit.currentTimeDisplayMode_.formatSpec;
}
@@ -292,7 +325,7 @@ tr.exportTo('tr.v', function() {
baseJsonName: 'sizeInBytes',
formatSpec: {
unit: 'B',
- unitPrefix: tr.v.UnitScale.Binary.AUTO,
+ unitPrefix: tr.b.UnitScale.Binary.AUTO,
minimumFractionDigits: 1,
maximumFractionDigits: 1
}
@@ -325,6 +358,25 @@ tr.exportTo('tr.v', function() {
}
});
+ Unit.define({
+ baseUnitName: 'count',
+ baseJsonName: 'count',
+ formatSpec: {
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 0
+ }
+ });
+
+ Unit.define({
+ baseUnitName: 'sigma',
+ baseJsonName: 'sigma',
+ formatSpec: {
+ unit: String.fromCharCode(963),
+ minimumFractionDigits: 1,
+ maximumFractionDigits: 1
+ }
+ });
+
return {
ImprovementDirection: ImprovementDirection,
Unit: Unit
diff --git a/chromium/third_party/catapult/tracing/tracing/value/unit_scale.html b/chromium/third_party/catapult/tracing/tracing/base/unit_scale.html
index 236caff9db1..d18022ed595 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/unit_scale.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unit_scale.html
@@ -10,7 +10,9 @@ found in the LICENSE file.
<script>
'use strict';
-tr.exportTo('tr.v', function() {
+var GREEK_SMALL_LETTER_MU = String.fromCharCode(956);
+
+tr.exportTo('tr.b', function() {
var UnitScale = {};
@@ -32,6 +34,23 @@ tr.exportTo('tr.v', function() {
UnitScale[name] = prefixes;
}
+ /**
+ * Converts |value| from |fromPrefix| (e.g. kilo) to |toPrefix| (e.g. mega).
+ *
+ * Returns undefined if |value| is undefined.
+ * |fromPrefix| and |toPrefix| need not come from the same UnitScale.
+ *
+ * @param {(undefined|number)} value
+ * @param {!object} fromPrefix
+ * @param {!object} toPrefix
+ * @return {(undefined|number)}
+ */
+ function convertUnit(value, fromPrefix, toPrefix) {
+ if (value === undefined)
+ return undefined;
+ return value * (fromPrefix.value / toPrefix.value);
+ }
+
// See https://en.wikipedia.org/wiki/Binary_prefix.
defineUnitScale('Binary', {
NONE: { value: Math.pow(1024, 0), symbol: '' },
@@ -42,15 +61,19 @@ tr.exportTo('tr.v', function() {
});
// See https://en.wikipedia.org/wiki/Metric_prefix.
- // The base time unit used in the whole repository is ms (milliseconds), so
- // all values are multiplied by 1000.
- defineUnitScale('MetricTime', {
- NANO: { value: 1e-6, symbol: 'n' },
- MILLI: { value: 1, symbol: 'm' }
+ defineUnitScale('Metric', {
+ NANO: { value: 1e-9, symbol: 'n' },
+ MICRO: { value: 1e-6, symbol: GREEK_SMALL_LETTER_MU },
+ MILLI: { value: 1e-3, symbol: 'm' },
+ NONE: { value: 1, symbol: ''},
+ KILO: { value: 1e3, symbol: 'k'},
+ MEGA: { value: 1e6, symbol: 'M'},
+ GIGA: { value: 1e9, symbol: 'G'}
});
return {
- UnitScale: UnitScale
+ UnitScale: UnitScale,
+ convertUnit: convertUnit
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/unit_test.html b/chromium/third_party/catapult/tracing/tracing/base/unit_test.html
index 2c355f9831a..79585ccd25d 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/unit_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unit_test.html
@@ -5,21 +5,20 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/time_display_mode.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/unit_scale.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var Unit = tr.v.Unit;
- var UnitScale = tr.v.UnitScale;
- var ImprovementDirection = tr.v.ImprovementDirection;
+ var ImprovementDirection = tr.b.ImprovementDirection;
+ var Unit = tr.b.Unit;
+ var UnitScale = tr.b.UnitScale;
test('Unit.display-mode-changed', function() {
- var Unit = tr.v.Unit;
- var TimeDisplayModes = tr.v.TimeDisplayModes;
+ var TimeDisplayModes = tr.b.TimeDisplayModes;
var listenerWasCalled = false;
function listener(e) {
@@ -43,7 +42,7 @@ tr.b.unittest.testSuite(function() {
function checkTimeUnit(unit) {
try {
// Use milliseconds to display time (default behavior).
- Unit.currentTimeDisplayMode = tr.v.TimeDisplayModes.ms;
+ Unit.currentTimeDisplayMode = tr.b.TimeDisplayModes.ms;
assert.strictEqual(unit.format(0), '0.000 ms');
assert.strictEqual(unit.format(0.02), '0.020 ms');
@@ -57,7 +56,7 @@ tr.b.unittest.testSuite(function() {
assert.strictEqual(unit.format(-123456789), '-123,456,789.000 ms');
// Change the unit to nanoseconds.
- Unit.currentTimeDisplayMode = tr.v.TimeDisplayModes.ns;
+ Unit.currentTimeDisplayMode = tr.b.TimeDisplayModes.ns;
assert.strictEqual(unit.format(0), '0 ns');
assert.strictEqual(unit.format(1), '1,000,000 ns');
@@ -220,5 +219,11 @@ tr.b.unittest.testSuite(function() {
assert.equal(Unit.byName.unitlessNumber.format(-1.23), '-1.230');
assert.equal(Unit.byName.unitlessNumber.format(0), '0.000');
});
+
+ test('count', function() {
+ assert.equal(Unit.byName.count.format(0), '0');
+ assert.equal(Unit.byName.count.format(1), '1');
+ assert.equal(Unit.byName.count.format(100), '100');
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/html_test_results.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/html_test_results.html
index fa65a9e88fb..d648fff082d 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/html_test_results.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/html_test_results.html
@@ -116,10 +116,10 @@ tr.exportTo('tr.b.unittest', function() {
var HTMLTestCaseResult = tr.ui.b.define('x-html-test-case-result');
HTMLTestCaseResult.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
- this.appendChild(tr.ui.b.instantiateTemplate(
+ Polymer.dom(this).appendChild(tr.ui.b.instantiateTemplate(
'#x-html-test-case-result-template', THIS_DOC));
this.testCase_ = undefined;
this.testCaseHRef_ = undefined;
@@ -157,61 +157,68 @@ tr.exportTo('tr.b.unittest', function() {
this.updateTitle_();
},
updateTitle_: function() {
- var titleEl = this.querySelector('#title');
+ var titleEl = Polymer.dom(this).querySelector('#title');
if (this.testCase_ === undefined) {
- titleEl.textContent = '';
+ Polymer.dom(titleEl).textContent = '';
return;
}
if (this.testCaseHRef_) {
- titleEl.innerHTML = '<a href="' + this.testCaseHRef_ + '">' +
+ Polymer.dom(titleEl).innerHTML =
+ '<a href="' + this.testCaseHRef_ + '">' +
this.testCase_.fullyQualifiedName + '</a>';
} else {
- titleEl.textContent = this.testCase_.fullyQualifiedName;
+ Polymer.dom(titleEl).textContent = this.testCase_.fullyQualifiedName;
}
},
addError: function(normalizedException) {
var errorEl = document.createElement('x-html-test-case-error');
- errorEl.appendChild(tr.ui.b.instantiateTemplate(
+ Polymer.dom(errorEl).appendChild(tr.ui.b.instantiateTemplate(
'#x-html-test-case-error-template', THIS_DOC));
- errorEl.querySelector('#stack').textContent = normalizedException.stack;
- this.querySelector('#details').appendChild(errorEl);
+ Polymer.dom(Polymer.dom(errorEl).querySelector('#stack')).
+ textContent = normalizedException.stack;
+ Polymer.dom(Polymer.dom(this).querySelector('#details')).appendChild(
+ errorEl);
this.updateColorAndStatus_();
},
addFlaky: function() {
var flakyEl = document.createElement('x-html-test-case-flaky');
- flakyEl.appendChild(tr.ui.b.instantiateTemplate(
+ Polymer.dom(flakyEl).appendChild(tr.ui.b.instantiateTemplate(
'#x-html-test-case-flaky-template', THIS_DOC));
- flakyEl.querySelector('#message').textContent = 'FLAKY';
- this.querySelector('#details').appendChild(flakyEl);
+ Polymer.dom(Polymer.dom(flakyEl).querySelector('#message'))
+ .textContent = 'FLAKY';
+ Polymer.dom(Polymer.dom(this).querySelector('#details')).appendChild(
+ flakyEl);
this.updateColorAndStatus_();
},
addHTMLOutput: function(element) {
var htmlResultEl = document.createElement('x-html-test-case-html-result');
- htmlResultEl.appendChild(element);
- this.querySelector('#details').appendChild(htmlResultEl);
+ Polymer.dom(htmlResultEl).appendChild(element);
+ Polymer.dom(Polymer.dom(this).querySelector('#details'))
+ .appendChild(htmlResultEl);
},
updateHTMLOutputDisplayState_: function() {
- var htmlResults = this.querySelectorAll('x-html-test-case-html-result');
+ var htmlResults =
+ Polymer.dom(this).querySelectorAll('x-html-test-case-html-result');
var display;
if (this.showHTMLOutput)
display = '';
else
- display = (this.testStatus_ == TestStatus.RUNNING) ? '' : 'none';
+ display = (this.testStatus_ === TestStatus.RUNNING) ? '' : 'none';
for (var i = 0; i < htmlResults.length; i++)
htmlResults[i].style.display = display;
},
get hadErrors() {
- return !!this.querySelector('x-html-test-case-error');
+ return !!Polymer.dom(this).querySelector('x-html-test-case-error');
},
get isFlaky() {
- return !!this.querySelector('x-html-test-case-flaky');
+ return !!Polymer.dom(this).querySelector('x-html-test-case-flaky');
},
get duration() {
@@ -242,10 +249,10 @@ tr.exportTo('tr.b.unittest', function() {
} else if (this.isFlaky) {
colorCls = 'unittest-flaky';
status = 'flaky';
- } else if (this.testStatus_ == TestStatus.PENDING) {
+ } else if (this.testStatus_ === TestStatus.PENDING) {
colorCls = 'unittest-pending';
status = 'pending';
- } else if (this.testStatus_ == TestStatus.RUNNING) {
+ } else if (this.testStatus_ === TestStatus.RUNNING) {
colorCls = 'unittest-running';
status = 'running';
} else { // DONE_RUNNING and no errors
@@ -253,12 +260,12 @@ tr.exportTo('tr.b.unittest', function() {
status = 'passed';
}
- var statusEl = this.querySelector('#status');
+ var statusEl = Polymer.dom(this).querySelector('#status');
if (this.duration_)
- statusEl.textContent = status + ' (' +
+ Polymer.dom(statusEl).textContent = status + ' (' +
this.duration_.toFixed(2) + 'ms)';
else
- statusEl.textContent = status;
+ Polymer.dom(statusEl).textContent = status;
statusEl.className = colorCls;
},
@@ -268,7 +275,8 @@ tr.exportTo('tr.b.unittest', function() {
set testReturnValue(testReturnValue) {
this.testReturnValue_ = testReturnValue;
- this.querySelector('#return-value').textContent = testReturnValue;
+ Polymer.dom(Polymer.dom(this).querySelector('#return-value'))
+ .textContent = testReturnValue;
}
};
@@ -315,7 +323,8 @@ tr.exportTo('tr.b.unittest', function() {
set showHTMLOutput(showHTMLOutput) {
this.showHTMLOutput_ = showHTMLOutput;
- var testCaseResults = this.querySelectorAll('x-html-test-case-result');
+ var testCaseResults =
+ Polymer.dom(this).querySelectorAll('x-html-test-case-result');
for (var i = 0; i < testCaseResults.length; i++)
testCaseResults[i].showHTMLOutput = showHTMLOutput;
},
@@ -327,7 +336,8 @@ tr.exportTo('tr.b.unittest', function() {
set showPendingAndPassedTests(showPendingAndPassedTests) {
this.showPendingAndPassedTests_ = showPendingAndPassedTests;
- var testCaseResults = this.querySelectorAll('x-html-test-case-result');
+ var testCaseResults =
+ Polymer.dom(this).querySelectorAll('x-html-test-case-result');
for (var i = testCaseResults.length - 1; i >= 0; i--)
this.updateDisplayStateForResult_(testCaseResults[i]);
},
@@ -335,7 +345,7 @@ tr.exportTo('tr.b.unittest', function() {
updateDisplayStateForResult_: function(res) {
var display;
if (this.showPendingAndPassedTests_) {
- if (res.testStatus == TestStatus.RUNNING ||
+ if (res.testStatus === TestStatus.RUNNING ||
res.hadErrors) {
display = '';
} else {
@@ -354,14 +364,14 @@ tr.exportTo('tr.b.unittest', function() {
testCaseResult.showHTMLOutput = this.showHTMLOutput_;
testCaseResult.testCase = testCase;
if ((i % 2) === 0)
- testCaseResult.classList.add('dark');
+ Polymer.dom(testCaseResult).classList.add('dark');
var href = this.getHRefForTestCase(testCase);
if (href)
testCaseResult.testCaseHRef = href;
testCaseResult.testStatus = TestStatus.PENDING;
this.testCaseResultsByCaseGUID_[testCase.guid] = testCaseResult;
- this.appendChild(testCaseResult);
+ Polymer.dom(this).appendChild(testCaseResult);
this.updateDisplayStateForResult_(testCaseResult);
}, this);
},
@@ -447,19 +457,19 @@ tr.exportTo('tr.b.unittest', function() {
};
},
- notifyTestResultToDevServer_: function(result, extra_msg) {
+ notifyTestResultToDevServer_: function(result, extraMsg) {
var req = new XMLHttpRequest();
var testName = this.currentTestCaseResult_.testCase.fullyQualifiedName;
- var data = result + ' ' + testName + ' ' + (extra_msg || '');
+ var data = result + ' ' + testName + ' ' + (extraMsg || '');
tr.b.postAsync('/tracing/notify_test_result', data);
},
notifyTestCompletionToDevServer_: function() {
if (this.numTestsThatPassed_ + this.numTestsThatFailed_ +
- this.numFlakyTests_ == 0) {
+ this.numFlakyTests_ === 0) {
return;
}
- var data = this.numTestsThatFailed_ == 0 ? 'ALL_PASSED' : 'HAD_FAILURES';
+ var data = this.numTestsThatFailed_ === 0 ? 'ALL_PASSED' : 'HAD_FAILURES';
data += '\nPassed tests: ' + this.numTestsThatPassed_ +
' Failed tests: ' + this.numTestsThatFailed_ +
' Flaky tests: ' + this.numFlakyTests_;
@@ -468,7 +478,6 @@ tr.exportTo('tr.b.unittest', function() {
},
log_: function(msg) {
- //this.textContent += msg;
tr.b.dispatchSimpleEvent(this, 'statschange');
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/interactive_test_runner.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/interactive_test_runner.html
index 79a5649275d..87c5127f57d 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/interactive_test_runner.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/interactive_test_runner.html
@@ -7,9 +7,9 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/unittest.html">
+<link rel="import" href="/tracing/base/unittest/html_test_results.html">
<link rel="import" href="/tracing/base/unittest/suite_loader.html">
<link rel="import" href="/tracing/base/unittest/test_runner.html">
-<link rel="import" href="/tracing/base/unittest/html_test_results.html">
<link rel="import" href="/tracing/ui/base/utils.html">
<style>
@@ -162,7 +162,7 @@ tr.exportTo('tr.b.unittest', function() {
var InteractiveTestRunner = tr.ui.b.define('x-base-interactive-test-runner');
InteractiveTestRunner.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.allTests_ = undefined;
@@ -184,12 +184,12 @@ tr.exportTo('tr.b.unittest', function() {
this.onTestFlaky_ = this.onTestFlaky_.bind(this);
this.onTestPassed_ = this.onTestPassed_.bind(this);
- this.appendChild(tr.ui.b.instantiateTemplate(
+ Polymer.dom(this).appendChild(tr.ui.b.instantiateTemplate(
'#x-base-interactive-test-runner-template', THIS_DOC));
- this.querySelector(
+ Polymer.dom(this).querySelector(
'input[name=test-type-to-run][value=unit]').checked = true;
- var testTypeToRunEls = tr.b.asArray(this.querySelectorAll(
+ var testTypeToRunEls = tr.b.asArray(Polymer.dom(this).querySelectorAll(
'input[name=test-type-to-run]'));
testTypeToRunEls.forEach(
@@ -198,7 +198,7 @@ tr.exportTo('tr.b.unittest', function() {
'click', this.onTestTypeToRunClick_.bind(this));
}, this);
- var shortFormatEl = this.querySelector('#short-format');
+ var shortFormatEl = Polymer.dom(this).querySelector('#short-format');
shortFormatEl.checked = this.shortFormat_;
shortFormatEl.addEventListener(
'click', this.onShortFormatClick_.bind(this));
@@ -209,7 +209,8 @@ tr.exportTo('tr.b.unittest', function() {
this.__defineSetter__(
'title',
function(title) {
- this.querySelector('#title').textContent = title;
+ Polymer.dom(Polymer.dom(this).querySelector('#title')).textContent =
+ title;
});
},
@@ -227,17 +228,17 @@ tr.exportTo('tr.b.unittest', function() {
},
set testLinks(testLinks) {
this.testLinks_ = testLinks;
- var linksEl = this.querySelector('#links');
- linksEl.textContent = '';
+ var linksEl = Polymer.dom(this).querySelector('#links');
+ Polymer.dom(linksEl).textContent = '';
this.testLinks_.forEach(function(l) {
var link = document.createElement('a');
link.href = l.linkPath;
- link.textContent = l.title;
+ Polymer.dom(link).textContent = l.title;
var li = document.createElement('li');
- li.appendChild(link);
+ Polymer.dom(li).appendChild(link);
- linksEl.appendChild(li);
+ Polymer.dom(linksEl).appendChild(li);
}, this);
},
@@ -258,7 +259,7 @@ tr.exportTo('tr.b.unittest', function() {
set shortFormat(shortFormat) {
this.shortFormat_ = shortFormat;
- this.querySelector('#short-format').checked = shortFormat;
+ Polymer.dom(this).querySelector('#short-format').checked = shortFormat;
if (this.results_)
this.results_.shortFormat = shortFormat;
if (!this.suppressStateChange_)
@@ -266,7 +267,8 @@ tr.exportTo('tr.b.unittest', function() {
},
onShortFormatClick_: function(e) {
- this.shortFormat_ = this.querySelector('#short-format').checked;
+ this.shortFormat_ =
+ Polymer.dom(this).querySelector('#short-format').checked;
this.updateShortFormResultsDisplay_();
this.updateResultsGivenShortFormat_();
if (!this.suppressStateChange_)
@@ -275,7 +277,8 @@ tr.exportTo('tr.b.unittest', function() {
updateShortFormResultsDisplay_: function() {
var display = this.shortFormat_ ? '' : 'none';
- this.querySelector('#shortform-results').style.display = display;
+ Polymer.dom(this).querySelector('#shortform-results').style.display =
+ display;
},
updateResultsGivenShortFormat_: function() {
@@ -309,7 +312,7 @@ tr.exportTo('tr.b.unittest', function() {
default:
throw new Error('Invalid test type to run: ' + testTypeToRun);
}
- this.querySelector(sel).checked = true;
+ Polymer.dom(this).querySelector(sel).checked = true;
this.scheduleRerun_();
if (!this.suppressStateChange_)
tr.b.dispatchSimpleEvent(this, 'statechange');
@@ -336,31 +339,33 @@ tr.exportTo('tr.b.unittest', function() {
},
onTestPassed_: function() {
- this.querySelector('#shortform-results').
+ Polymer.dom(Polymer.dom(this).querySelector('#shortform-results')).
appendChild(document.createTextNode('.'));
},
onTestFailed_: function() {
var span = document.createElement('span');
- span.classList.add('fail');
- span.appendChild(document.createTextNode('F'));
- this.querySelector('#shortform-results').appendChild(span);
+ Polymer.dom(span).classList.add('fail');
+ Polymer.dom(span).appendChild(document.createTextNode('F'));
+ Polymer.dom(Polymer.dom(this).querySelector('#shortform-results'))
+ .appendChild(span);
},
onTestFlaky_: function() {
var span = document.createElement('span');
- span.classList.add('flaky');
- span.appendChild(document.createTextNode('~'));
- this.querySelector('#shortform-results').appendChild(span);
+ Polymer.dom(span).classList.add('flaky');
+ Polymer.dom(span).appendChild(document.createTextNode('~'));
+ Polymer.dom(Polymer.dom(this).querySelector('#shortform-results'))
+ .appendChild(span);
},
onResultsStatsChanged_: function() {
- var statsEl = this.querySelector('#stats');
+ var statsEl = Polymer.dom(this).querySelector('#stats');
var stats = this.results_.getStats();
var numTestsOverall = this.runner_.testCases.length;
var numTestsThatRan = stats.numTestsThatPassed +
stats.numTestsThatFailed + stats.numFlakyTests;
- statsEl.innerHTML =
+ Polymer.dom(statsEl).innerHTML =
'<span>' + numTestsThatRan + '/' + numTestsOverall +
'</span> tests run, ' +
'<span class="unittest-failed">' + stats.numTestsThatFailed +
@@ -388,7 +393,8 @@ tr.exportTo('tr.b.unittest', function() {
},
beginRunning_: function() {
- var resultsContainer = this.querySelector('#results-container');
+ var resultsContainer =
+ Polymer.dom(this).querySelector('#results-container');
if (this.results_) {
this.results_.removeEventListener('testpassed', this.onTestPassed_);
this.results_.removeEventListener('testfailed', this.onTestFailed_);
@@ -396,7 +402,7 @@ tr.exportTo('tr.b.unittest', function() {
this.results_.removeEventListener('statschange',
this.onResultsStatsChanged_);
delete this.results_.getHRefForTestCase;
- resultsContainer.removeChild(this.results_);
+ Polymer.dom(resultsContainer).removeChild(this.results_);
}
this.results_ = new tr.b.unittest.HTMLTestResults();
@@ -410,11 +416,11 @@ tr.exportTo('tr.b.unittest', function() {
this.results_.addEventListener('testflaky', this.onTestFlaky_);
this.results_.addEventListener('statschange',
this.onResultsStatsChanged_);
- resultsContainer.appendChild(this.results_);
+ Polymer.dom(resultsContainer).appendChild(this.results_);
var tests = this.allTests_.filter(function(test) {
var i = test.fullyQualifiedName.indexOf(this.testFilterString_);
- if (i == -1)
+ if (i === -1)
return false;
if (this.testTypeToRun_ !== ALL_TEST_TYPES &&
test.testType !== this.testTypeToRun_)
@@ -515,16 +521,16 @@ tr.exportTo('tr.b.unittest', function() {
function stateFromSearchString(string) {
var state = {};
string.split('&').forEach(function(part) {
- if (part == '')
+ if (part === '')
return;
var kv = part.split('=');
var k, v;
- if (kv.length == 1) {
+ if (kv.length === 1) {
k = kv[0];
v = true;
} else {
k = kv[0];
- if (kv[1] == 'false')
+ if (kv[1] === 'false')
v = false;
else
v = kv[1];
@@ -570,9 +576,14 @@ tr.exportTo('tr.b.unittest', function() {
p = p.then(
function() {
hideLoadingOverlay();
- Polymer.whenReady(function() {
+ // FIXME
+ window.addEventListener('WebComponentsReady', function() {
runTests(loader, state);
});
+ runTests(loader, state);
+ // Polymer.whenReady(function() {
+ // runTests(loader, state);
+ // });
},
function(err) {
hideLoadingOverlay();
@@ -600,14 +611,15 @@ tr.exportTo('tr.b.unittest', function() {
var element = document.createElement('div');
element.style.flex = '1 1 auto';
element.style.overflow = 'auto';
- overlay.appendChild(element);
+ Polymer.dom(overlay).appendChild(element);
- element.textContent = 'Loading tests...';
- document.body.appendChild(overlay);
+ Polymer.dom(element).textContent = 'Loading tests...';
+ Polymer.dom(document.body).appendChild(overlay);
}
function hideLoadingOverlay() {
- var overlay = document.body.querySelector('#tests-loading-overlay');
- document.body.removeChild(overlay);
+ var overlay = Polymer.dom(document.body).querySelector(
+ '#tests-loading-overlay');
+ Polymer.dom(document.body).removeChild(overlay);
}
function updateTitle(state) {
@@ -628,7 +640,8 @@ tr.exportTo('tr.b.unittest', function() {
if (state.shortFormat)
title += '(s)';
document.title = title;
- var runner = document.querySelector('x-base-interactive-test-runner');
+ var runner = Polymer.dom(document).querySelector(
+ 'x-base-interactive-test-runner');
if (runner)
runner.title = title;
}
@@ -639,7 +652,7 @@ tr.exportTo('tr.b.unittest', function() {
runner.style.height = '100%';
runner.testLinks = runnerConfig.testLinks;
runner.allTests = loader.getAllTests();
- document.body.appendChild(runner);
+ Polymer.dom(document.body).appendChild(runner);
runner.setState(state);
updateTitle(state);
@@ -648,7 +661,7 @@ tr.exportTo('tr.b.unittest', function() {
var state = runner.getState();
var stateString = stateToSearchString(runner.getDefaultState(),
state);
- if (window.location.search.substring(1) == stateString)
+ if (window.location.search.substring(1) === stateString)
return;
updateTitle(state);
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/suite_loader.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/suite_loader.html
index 08fc7dc5ffa..c5be2b85a2a 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/suite_loader.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/suite_loader.html
@@ -22,8 +22,8 @@ tr.exportTo('tr.b.unittest', function() {
return new Promise(function(resolve, reject) {
var importEl = document.createElement('link');
importEl.moduleName = moduleName;
- importEl.setAttribute('rel', 'import');
- importEl.setAttribute('href', testRelpath);
+ Polymer.dom(importEl).setAttribute('rel', 'import');
+ Polymer.dom(importEl).setAttribute('href', testRelpath);
importEl.addEventListener('load', function() {
resolve({testRelpath: testRelpath,
@@ -34,7 +34,7 @@ tr.exportTo('tr.b.unittest', function() {
testRelpath + '"');
});
- tr.doc.head.appendChild(importEl);
+ Polymer.dom(tr.doc.head).appendChild(importEl);
});
},
@@ -52,9 +52,9 @@ tr.exportTo('tr.b.unittest', function() {
if (!m)
throw new Error('Guessing module name failed');
var path = m[1];
- if (path[0] != '/')
+ if (path[0] !== '/')
throw new Error('malformed path');
- if (path.substring(path.length - 5) != '.html')
+ if (path.substring(path.length - 5) !== '.html')
throw new Error('Cannot define testSuites outside html imports');
var parts = path.substring(1, path.length - 5).split('/');
return parts.join('.');
@@ -228,7 +228,7 @@ tr.exportTo('tr.b.unittest', function() {
var suite = this.testSuites[i];
for (var j = 0; j < suite.tests.length; j++) {
var test = suite.tests[j];
- if (test.fullyQualifiedName == fullyQualifiedName)
+ if (test.fullyQualifiedName === fullyQualifiedName)
return test;
}
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_case.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_case.html
index f092f2a9461..231ebfde0f7 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_case.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_case.html
@@ -29,7 +29,7 @@ tr.exportTo('tr.b.unittest', function() {
TestCase.parseFullyQualifiedName = function(fqn) {
var i = fqn.lastIndexOf('.');
- if (i == -1)
+ if (i === -1)
throw new Error('FullyQualifiedNames must have a period in them');
return {
suiteName: fqn.substr(0, i),
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_runner.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_runner.html
index 683372b2c0d..ac3b16f46e1 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_runner.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_runner.html
@@ -4,9 +4,9 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/event_target.html">
<link rel="import" href="/tracing/base/raf.html">
<link rel="import" href="/tracing/base/timing.html">
-<link rel="import" href="/tracing/base/event_target.html">
<script>
'use strict';
@@ -139,7 +139,7 @@ tr.exportTo('tr.b.unittest', function() {
runOneTestCase_: function() {
this.runOneTestCaseScheduled_ = false;
- if (this.pendingTestCases_.length == 0) {
+ if (this.pendingTestCases_.length === 0) {
this.didFinishRunningAllTests_();
return;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_suite.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_suite.html
index 9dbf2ce3358..34f5d0525a0 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/test_suite.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/test_suite.html
@@ -49,7 +49,7 @@ tr.exportTo('tr.b.unittest', function() {
var testName = testCaseOrName;
var testFn = opt_testFn;
var options = opt_options || {};
- if (testFn == undefined)
+ if (testFn === undefined)
throw new Error('Must provide opt_testFn');
// If the test cares about DPI settings then we first push a test
diff --git a/chromium/third_party/catapult/tracing/tracing/base/unittest/text_test_results.html b/chromium/third_party/catapult/tracing/tracing/base/unittest/text_test_results.html
index c1cae626aea..3c286d75fbe 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/unittest/text_test_results.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/unittest/text_test_results.html
@@ -4,8 +4,8 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/base/unittest/constants.html">
+<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<script>
'use strict';
@@ -91,12 +91,12 @@ tr.exportTo('tr.b.unittest', function() {
this.write_('Ran ' + this.numTestsThatRan + ' tests\n');
if (this.numTestsThatFailed > 0) {
- var flakyString = this.numFlakyTests == 0 ? '' :
+ var flakyString = this.numFlakyTests === 0 ? '' :
' flaky=' + this.numFlakyTests;
this.write_('\nFAILED (errors=' + this.numTestsThatFailed +
flakyString + ')');
} else {
- var flakyString = this.numFlakyTests == 0 ? '' :
+ var flakyString = this.numFlakyTests === 0 ? '' :
' (flaky=' + this.numFlakyTests + ')';
this.write_('\nOK' + flakyString);
}
diff --git a/chromium/third_party/catapult/tracing/tracing/base/utils.html b/chromium/third_party/catapult/tracing/tracing/base/utils.html
index 1a98cab4052..2f71be02483 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/utils.html
@@ -27,11 +27,11 @@ tr.exportTo('tr.b', function() {
if (!(value instanceof Object)) {
if (value === undefined || value === null)
return value;
- if (typeof value == 'string')
+ if (typeof value === 'string')
return value.substring();
- if (typeof value == 'boolean')
+ if (typeof value === 'boolean')
return value;
- if (typeof value == 'number')
+ if (typeof value === 'number')
return value;
throw new Error('Unrecognized: ' + typeof value);
}
@@ -44,7 +44,7 @@ tr.exportTo('tr.b', function() {
return res;
}
- if (object.__proto__ != Object.prototype)
+ if (object.__proto__ !== Object.prototype)
throw new Error('Can only clone simple types');
var res = {};
for (var key in object) {
@@ -62,7 +62,7 @@ tr.exportTo('tr.b', function() {
};
}
- if (typeof(e) == 'string') {
+ if (typeof(e) === 'string') {
return {
typeName: 'StringError',
message: e,
@@ -100,9 +100,9 @@ tr.exportTo('tr.b', function() {
return stack.slice(2);
}
- function getUsingPath(path, from_dict) {
+ function getUsingPath(path, fromDict) {
var parts = path.split('.');
- var cur = from_dict;
+ var cur = fromDict;
for (var part; parts.length && (part = parts.shift());) {
if (!parts.length) {
@@ -116,6 +116,18 @@ tr.exportTo('tr.b', function() {
return undefined;
}
+ /**
+ * Format date as a string "YYYY-MM-DD HH:mm:ss". The timezone is implicitly
+ * UTC. This format is based on the ISO format, but without milliseconds and
+ * the 'T' is replaced with a space for legibility.
+ *
+ * @param {!Date} date
+ * @return {string}
+ */
+ function formatDate(date) {
+ return date.toISOString().replace('T', ' ').slice(0, 19);
+ }
+
return {
addSingletonGetter: addSingletonGetter,
@@ -124,6 +136,7 @@ tr.exportTo('tr.b', function() {
normalizeException: normalizeException,
stackTrace: stackTrace,
stackTraceAsString: stackTraceAsString,
+ formatDate: formatDate,
getUsingPath: getUsingPath
};
diff --git a/chromium/third_party/catapult/tracing/tracing/base/utils_test.html b/chromium/third_party/catapult/tracing/tracing/base/utils_test.html
index a08ac33b24e..8e7c91a7fce 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/utils_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/utils_test.html
@@ -26,5 +26,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(ex.typeName, 'MyError');
});
+ test('formatDate', function() {
+ assert.strictEqual(tr.b.formatDate(new Date(0)), '1970-01-01 00:00:00');
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/base/xhr.html b/chromium/third_party/catapult/tracing/tracing/base/xhr.html
index 37ce4c2964f..cde65905a01 100644
--- a/chromium/third_party/catapult/tracing/tracing/base/xhr.html
+++ b/chromium/third_party/catapult/tracing/tracing/base/xhr.html
@@ -18,12 +18,12 @@ tr.exportTo('tr.b', function() {
function guessBinary(url) {
return /[.]gz$/.test(url) || /[.]zip$/.test(url);
}
- function xhr(method, url, async, opt_data, force_binary) {
+ function xhr(method, url, async, opt_data, forceBinary) {
var req = new XMLHttpRequest();
req.overrideMimeType('text/plain; charset=x-user-defined');
req.open(method, url, async);
- var isBinary = force_binary;
+ var isBinary = forceBinary;
if (isBinary === undefined) {
guessBinary(url);
@@ -35,7 +35,7 @@ tr.exportTo('tr.b', function() {
if (!async) {
req.send(data);
- if (req.status == 200) {
+ if (req.status === 200) {
return req.responseText;
} else {
throw new Error('XHR failed with status ' + req.status);
@@ -44,9 +44,9 @@ tr.exportTo('tr.b', function() {
var p = new Promise(function(resolve, reject) {
req.onreadystatechange = function(aEvt) {
- if (req.readyState == 4) {
+ if (req.readyState === 4) {
window.setTimeout(function() {
- if (req.status == 200) {
+ if (req.status === 200) {
if (req.responseType === 'arraybuffer')
return resolve(req.response);
return resolve(req.responseText);
diff --git a/chromium/third_party/catapult/tracing/tracing/core/test_utils.html b/chromium/third_party/catapult/tracing/tracing/core/test_utils.html
index a21fb014904..27654041438 100644
--- a/chromium/third_party/catapult/tracing/tracing/core/test_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/core/test_utils.html
@@ -10,9 +10,9 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/counter.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/model/scoped_id.html">
-<link rel="import" href="/tracing/model/slice.html">
<link rel="import" href="/tracing/model/slice_group.html">
<link rel="import" href="/tracing/model/stack_frame.html">
+<link rel="import" href="/tracing/model/thread_slice.html">
<link rel="import" href="/tracing/model/thread_time_slice.html">
<link rel="import" href="/tracing/model/user_model/stub_expectation.html">
@@ -80,7 +80,7 @@ tr.exportTo('tr.c', function() {
TestUtils.newAsyncSliceNamed = function(
name, start, duration, startThread, endThread) {
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor('', name);
+ tr.model.AsyncSlice.subTypes.getConstructor('', name);
var s = new asyncSliceConstructor('', name, 0, start);
s.duration = duration;
@@ -116,7 +116,7 @@ tr.exportTo('tr.c', function() {
isTopLevel = false;
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(cat, title);
+ tr.model.AsyncSlice.subTypes.getConstructor(cat, title);
var slice = new asyncSliceConstructor(
cat,
@@ -237,14 +237,16 @@ tr.exportTo('tr.c', function() {
var cpuSD = _maybeGetCpuStartAndCpuDurationFromDict(options);
+ var cat = options.cat ? options.cat : 'cat';
+
var type;
if (options.type)
type = options.type;
else
- type = tr.model.Slice;
+ type = tr.model.ThreadSlice.subTypes.getConstructor(cat, title);
var slice = new type(
- options.cat ? options.cat : 'cat',
+ cat,
title,
colorId,
sd.start,
@@ -284,7 +286,7 @@ tr.exportTo('tr.c', function() {
if (slices instanceof tr.model.SliceGroup)
slices = slices.slices;
for (var i = 0; i < slices.length; i++)
- if (slices[i].title == name)
+ if (slices[i].title === name)
return slices[i];
return undefined;
};
@@ -430,10 +432,10 @@ tr.exportTo('tr.c', function() {
TestUtils.addSourceListing = function(test, source) {
var testSourceEl = document.createElement('pre');
testSourceEl.style.fontFamily = 'monospace';
- testSourceEl.textContent = source;
+ Polymer.dom(testSourceEl).textContent = source;
var copyButtonEl = document.createElement('button');
- copyButtonEl.textContent = 'Copy into to clipboard';
+ Polymer.dom(copyButtonEl).textContent = 'Copy into to clipboard';
copyButtonEl.addEventListener('click', function() {
var selection = window.getSelection();
@@ -456,8 +458,8 @@ tr.exportTo('tr.c', function() {
});
var outputEl = document.createElement('div');
- outputEl.appendChild(copyButtonEl);
- outputEl.appendChild(testSourceEl);
+ Polymer.dom(outputEl).appendChild(copyButtonEl);
+ Polymer.dom(outputEl).appendChild(testSourceEl);
test.addHTMLOutput(outputEl);
};
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor.html b/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor.html
index 33a2a6757e3..c0cb2008395 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor.html
@@ -8,6 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/range_utils.html">
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/auditor.html">
<link rel="import" href="/tracing/model/alert.html">
<link rel="import" href="/tracing/model/frame.html">
@@ -15,7 +16,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/thread_time_slice.html">
<link rel="import" href="/tracing/model/user_model/response_expectation.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -33,7 +33,7 @@ tr.exportTo('tr.e.audits', function() {
var Alert = tr.model.Alert;
var EventInfo = tr.model.EventInfo;
var ScalarNumeric = tr.v.ScalarNumeric;
- var timeDurationInMs = tr.v.Unit.byName.timeDurationInMs;
+ var timeDurationInMs = tr.b.Unit.byName.timeDurationInMs;
// TODO: extract from VSYNC, since not all devices have vsync near 60fps
var EXPECTED_FRAME_TIME_MS = 16.67;
@@ -89,7 +89,7 @@ tr.exportTo('tr.e.audits', function() {
var helper = model.getOrCreateHelper(AndroidModelHelper);
if (helper.apps.length || helper.surfaceFlinger)
this.helper = helper;
- };
+ }
//////////////////////////////////////////////////////////////////////////////
// Rendering / RenderThread alerts - only available on SDK 22+
@@ -163,7 +163,7 @@ tr.exportTo('tr.e.audits', function() {
var uploadRegEx = /^Generate Path Texture$/;
var events = frame.associatedEvents.filter(function(event) {
- return event.title == 'Generate Path Texture';
+ return event.title === 'Generate Path Texture';
});
var start = Statistics.min(events, getStart);
var duration = Statistics.sum(events, getDuration);
@@ -196,7 +196,7 @@ tr.exportTo('tr.e.audits', function() {
pixelsUploaded += parseInt(match[1]) * parseInt(match[2]);
}
});
- if (events.length == 0 || duration < 3)
+ if (events.length === 0 || duration < 3)
return undefined;
var mPixels = (pixelsUploaded / 1000000).toFixed(2) + ' million';
@@ -222,19 +222,15 @@ tr.exportTo('tr.e.audits', function() {
});
var duration = Statistics.sum(events, getCpuDuration);
- if (events.length == 0 || duration < 3)
+ if (events.length === 0 || duration < 3)
return undefined;
// simplifying assumption - check for *any* inflation.
// TODO(ccraik): make 'inflate' slices associated events.
var hasInflation = false;
- for (var i = 0; i < events.length; i++) {
- if (events[i] instanceof tr.model.Slice &&
- events[i].findDescendentSlice('inflate')) {
+ for (var event of events)
+ if (event.findDescendentSlice('inflate'))
hasInflation = true;
- break;
- }
- }
var start = Statistics.min(events, getStart);
var args = { 'Time spent': new ScalarNumeric(timeDurationInMs, duration) };
@@ -259,7 +255,7 @@ tr.exportTo('tr.e.audits', function() {
});
var duration = Statistics.sum(events, getCpuDuration);
- if (events.length == 0 || duration < 3)
+ if (events.length === 0 || duration < 3)
return undefined;
var start = Statistics.min(events, getStart);
@@ -308,8 +304,8 @@ tr.exportTo('tr.e.audits', function() {
.build());
AndroidAuditor.getBlockingGcAlert_ = function(frame) {
var events = frame.associatedEvents.filter(function(event) {
- return event.title == 'DVM Suspend' ||
- event.title == 'GC: Wait For Concurrent';
+ return event.title === 'DVM Suspend' ||
+ event.title === 'GC: Wait For Concurrent';
});
var blockedDuration = Statistics.sum(events, getDuration);
if (blockedDuration < 3)
@@ -361,7 +357,7 @@ tr.exportTo('tr.e.audits', function() {
// only alert if frame not running for > 3ms. Note that we expect a frame
// to never describe intentionally idle time.
if (!(SCHEDULING_STATE.RUNNING in totalStats) ||
- totalDuration == 0 ||
+ totalDuration === 0 ||
totalDuration - totalStats[SCHEDULING_STATE.RUNNING] < 3)
return;
@@ -386,7 +382,7 @@ tr.exportTo('tr.e.audits', function() {
// SurfaceFlinger first, other processes sorted by slice count
this.model.getAllProcesses().forEach(function(process) {
if (this.helper.surfaceFlinger &&
- process == this.helper.surfaceFlinger.process) {
+ process === this.helper.surfaceFlinger.process) {
if (!process.name)
process.name = 'SurfaceFlinger';
process.sortIndex = Number.NEGATIVE_INFINITY;
@@ -411,9 +407,9 @@ tr.exportTo('tr.e.audits', function() {
// ensure sequential, relative order for UI/Render/Worker threads
this.model.getAllThreads().forEach(function(thread) {
- if (thread.tid == thread.parent.pid)
+ if (thread.tid === thread.parent.pid)
thread.sortIndex = -3;
- if (thread.name == 'RenderThread')
+ if (thread.name === 'RenderThread')
thread.sortIndex = -2;
if (/^hwuiTask/.test(thread.name))
thread.sortIndex = -1;
@@ -488,8 +484,8 @@ tr.exportTo('tr.e.audits', function() {
alerts.push.apply(alerts, AndroidAuditor.getSaveLayerAlerts_(frame));
// skip most alerts for neutral or good frames
- if (frame.perfClass == FRAME_PERF_CLASS.NEUTRAL ||
- frame.perfClass == FRAME_PERF_CLASS.GOOD)
+ if (frame.perfClass === FRAME_PERF_CLASS.NEUTRAL ||
+ frame.perfClass === FRAME_PERF_CLASS.GOOD)
return;
var alert = AndroidAuditor.getPathAlert_(frame);
@@ -563,18 +559,18 @@ tr.exportTo('tr.e.audits', function() {
Auditor.register(AndroidAuditor);
function AppAnnotator() {
- this.titleInfoLookup = {};
- this.titleParentLookup = {};
+ this.titleInfoLookup = new Map();
+ this.titleParentLookup = new Map();
this.build_();
}
AppAnnotator.prototype = {
build_: function() {
var registerEventInfo = function(dict) {
- this.titleInfoLookup[dict.title] = new EventInfo(
- dict.title, dict.description, dict.docLinks);
+ this.titleInfoLookup.set(dict.title, new EventInfo(
+ dict.title, dict.description, dict.docLinks));
if (dict.parents)
- this.titleParentLookup[dict.title] = dict.parents;
+ this.titleParentLookup.set(dict.title, dict.parents);
}.bind(this);
registerEventInfo({
@@ -716,23 +712,22 @@ tr.exportTo('tr.e.audits', function() {
if (!expectedParentNames)
return true;
return expectedParentNames.some(function(name) {
- return name in parentNames;
+ return parentNames.has(name);
});
};
-
// Set EventInfo on the slice if it matches title, and parent.
- if (slice.title in this.titleInfoLookup) {
- if (checkExpectedParentNames(this.titleParentLookup[slice.title]))
- slice.info = this.titleInfoLookup[slice.title];
+ if (this.titleInfoLookup.has(slice.title)) {
+ if (checkExpectedParentNames(this.titleParentLookup.get(slice.title)))
+ slice.info = this.titleInfoLookup.get(slice.title);
}
// Push slice into parentNames, and recurse over subSlices.
if (slice.subSlices.length > 0) {
// Increment title in parentName dict.
- if (!(slice.title in parentNames))
- parentNames[slice.title] = 0;
- parentNames[slice.title]++;
+ if (!parentNames.has(slice.title))
+ parentNames.set(slice.title, 0);
+ parentNames.set(slice.title, parentNames.get(slice.title) + 1);
// Recurse over subSlices.
slice.subSlices.forEach(function(subSlice) {
@@ -740,15 +735,15 @@ tr.exportTo('tr.e.audits', function() {
}, this);
// Decrement title in parentName dict.
- parentNames[slice.title]--;
- if (parentNames[slice.title] == 0)
+ parentNames.set(slice.title, parentNames.get(slice.title) - 1);
+ if (parentNames.get(slice.title) === 0)
delete parentNames[slice.title];
}
},
applyEventInfos: function(sliceGroup) {
sliceGroup.topLevelSlices.forEach(function(slice) {
- this.applyEventInfosRecursive_({}, slice);
+ this.applyEventInfosRecursive_(new Map(), slice);
}, this);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor_test.html b/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor_test.html
index 9cecad7aa0b..6ceb0bd67d0 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/android/android_auditor_test.html
@@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/android/android_auditor.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
<link rel="import" href="/tracing/model/frame.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -21,7 +21,19 @@ tr.b.unittest.testSuite(function() {
var FRAME_PERF_CLASS = tr.model.FRAME_PERF_CLASS;
var newThreadSlice = tr.c.TestUtils.newThreadSlice;
var ScalarNumeric = tr.v.ScalarNumeric;
- var timeDurationInMs = tr.v.Unit.byName.timeDurationInMs;
+ var timeDurationInMs = tr.b.Unit.byName.timeDurationInMs;
+
+ test('constructorSliceName', function() {
+ // verify 'constructor' slice name doesn't break the auditor
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
+ var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
+ renderThread.name = 'RenderThread';
+ renderThread.sliceGroup.pushSlice(newSliceEx(
+ {title: 'constructor', start: 200, duration: 5}));
+ }, tr.e.audits.AndroidAuditor);
+
+ assert.equal(model.alerts.length, 0);
+ });
test('saveLayerAlert_badAlpha', function() {
var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/blame_context_test.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/blame_context_test.html
index 5b0b9730a84..f8009f0bd10 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/blame_context_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/blame_context_test.html
@@ -27,7 +27,7 @@ tr.b.unittest.testSuite(function() {
}
};
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
TestBlameContextSnapshot,
{typeName: 'Test'});
@@ -43,7 +43,7 @@ tr.b.unittest.testSuite(function() {
}
};
- tr.model.ObjectInstance.register(
+ tr.model.ObjectInstance.subTypes.register(
TestBlameContextInstance,
{typeName: 'Test'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/frame_tree_node.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/frame_tree_node.html
index 7916e3dfe4e..4a1fc5e61d7 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/frame_tree_node.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/frame_tree_node.html
@@ -41,7 +41,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
FrameTreeNodeSnapshot,
{typeName: 'FrameTreeNode'});
@@ -57,7 +57,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectInstance.register(
+ tr.model.ObjectInstance.subTypes.register(
FrameTreeNodeInstance,
{typeName: 'FrameTreeNode'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/render_frame.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/render_frame.html
index 3bd29e907fe..081ef81c2e6 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/render_frame.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/render_frame.html
@@ -51,7 +51,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
RenderFrameSnapshot,
{typeName: 'RenderFrame'});
@@ -67,7 +67,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectInstance.register(
+ tr.model.ObjectInstance.subTypes.register(
RenderFrameInstance,
{typeName: 'RenderFrame'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/top_level.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/top_level.html
index cf9e07c05f7..b8b70692ab1 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/top_level.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/blame_context/top_level.html
@@ -31,7 +31,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
TopLevelSnapshot,
{typeName: 'TopLevel'});
@@ -47,7 +47,7 @@ tr.exportTo('tr.e.chrome', function() {
}
};
- tr.model.ObjectInstance.register(
+ tr.model.ObjectInstance.subTypes.register(
TopLevelInstance,
{typeName: 'TopLevel'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/display_item_list.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/display_item_list.html
index f679b56c590..36a0d33728b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/display_item_list.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/display_item_list.html
@@ -42,7 +42,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
DisplayItemListSnapshot,
{typeNames: ['cc::DisplayItemList']});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice.html
index 44871935d2a..d641963e59f 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice.html
@@ -4,9 +4,10 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
+
<link rel="import" href="/tracing/model/async_slice.html">
<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
<script>
'use strict';
@@ -93,8 +94,8 @@ tr.exportTo('tr.e.cc', function() {
if (!this.typeName_)
throw 'Unable to determine typeName';
var found = false;
- for (var type_name in INPUT_EVENT_TYPE_NAMES) {
- if (this.typeName === INPUT_EVENT_TYPE_NAMES[type_name]) {
+ for (var typeName in INPUT_EVENT_TYPE_NAMES) {
+ if (this.typeName === INPUT_EVENT_TYPE_NAMES[typeName]) {
found = true;
break;
}
@@ -122,17 +123,17 @@ tr.exportTo('tr.e.cc', function() {
determineLegacyTypeName_: function() {
// Iterate over all descendent subSlices.
- this.iterateAllDescendents(function(subSlice) {
+ for (var subSlice of this.enumerateAllDescendents()) {
// If |subSlice| is not an InputLatencyAsyncSlice, then ignore it.
var subSliceIsAInputLatencyAsyncSlice = (
subSlice instanceof InputLatencyAsyncSlice);
if (!subSliceIsAInputLatencyAsyncSlice)
- return;
+ continue;
// If |subSlice| does not have a typeName, then ignore it.
if (!subSlice.typeName)
- return;
+ continue;
// If |this| already has a typeName and |subSlice| has a different
// typeName, then explode!
@@ -148,7 +149,7 @@ tr.exportTo('tr.e.cc', function() {
// The typeName of |this| top-level event is whatever the typeName of
// |subSlice| is. Set |this.typeName_| to the subSlice's typeName.
this.typeName_ = subSlice.typeName_;
- }, this);
+ }
// If typeName could not be determined, then explode!
if (!this.typeName_)
@@ -423,14 +424,14 @@ tr.exportTo('tr.e.cc', function() {
return;
var rasterWorkerThreads = rendererHelper.rasterWorkerThreads;
- var prepare_tile_id = prepareTiles.args.prepare_tiles_id;
+ var prepareTileId = prepareTiles.args.prepare_tiles_id;
var pendingEventQueue = [];
// Collect all the rasterizer tasks. Return the cached copy if possible.
if (sortedRasterizerSlices.length === 0)
this.sortRasterizerSlices(rasterWorkerThreads, sortedRasterizerSlices);
- // TODO(yuhao): Once TaskSetFinishedTaskImpl also get the prepare_tile_id
+ // TODO(yuhao): Once TaskSetFinishedTaskImpl also get the prepareTileId
// we can simply track by checking id rather than counting.
var numFinishedTasks = 0;
var RASTER_TASK_TITLE = 'RasterizerTaskImpl::RunOnWorkerThread';
@@ -442,7 +443,7 @@ tr.exportTo('tr.e.cc', function() {
if (task.title === RASTER_TASK_TITLE ||
task.title === IMAGEDECODE_TASK_TITLE) {
- if (task.args.source_prepare_tiles_id === prepare_tile_id)
+ if (task.args.source_prepare_tiles_id === prepareTileId)
this.addEntireSliceHierarchy(task.mostTopLevelSlice);
} else if (task.title === FINISHED_TASK_TITLE) {
if (task.start > prepareTiles.start) {
@@ -454,7 +455,7 @@ tr.exportTo('tr.e.cc', function() {
}
// Trace PostTask from rasterizer tasks.
- while (pendingEventQueue.length != 0) {
+ while (pendingEventQueue.length !== 0) {
var event = pendingEventQueue.pop();
this.addEntireSliceHierarchy(event);
@@ -479,7 +480,7 @@ tr.exportTo('tr.e.cc', function() {
}
}, this);
- while (pendingEventQueue.length != 0) {
+ while (pendingEventQueue.length !== 0) {
var event = pendingEventQueue.pop();
// Push the current event chunk into associatedEvents.
@@ -613,7 +614,7 @@ tr.exportTo('tr.e.cc', function() {
allTypeNames.push('InputLatency::' + eventTypeName);
});
- AsyncSlice.register(
+ AsyncSlice.subTypes.register(
InputLatencyAsyncSlice,
{
typeNames: allTypeNames,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html
index 500a4edbbf8..9f711166a7c 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html
@@ -102,14 +102,14 @@ tr.exportTo('tr.e.cc', function() {
},
get activeLayer() {
- if (this.layerTreeImpl.whichTree == constants.ACTIVE_TREE)
+ if (this.layerTreeImpl.whichTree === constants.ACTIVE_TREE)
return this;
var activeTree = this.layerTreeImpl.layerTreeHostImpl.activeTree;
return activeTree.findLayerWithId(this.layerId);
},
get pendingLayer() {
- if (this.layerTreeImpl.whichTree == constants.PENDING_TREE)
+ if (this.layerTreeImpl.whichTree === constants.PENDING_TREE)
return this;
var pendingTree = this.layerTreeImpl.layerTreeHostImpl.pendingTree;
return pendingTree.findLayerWithId(this.layerId);
@@ -170,13 +170,13 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
PictureLayerImplSnapshot,
{
typeName: 'cc::PictureLayerImpl'
});
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
LayerImplSnapshot,
{
typeNames: [
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl.html
index 8d81a4fd99e..3df73b5d39b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/bbox2.html">
<link rel="import" href="/tracing/extras/chrome/cc/constants.html">
<link rel="import" href="/tracing/extras/chrome/cc/layer_tree_impl.html">
<link rel="import" href="/tracing/extras/chrome/cc/util.html">
-<link rel="import" href="/tracing/base/bbox2.html">
<link rel="import" href="/tracing/model/object_instance.html">
<script>
@@ -83,9 +83,9 @@ tr.exportTo('tr.e.cc', function() {
},
getTree: function(whichTree) {
- if (whichTree == constants.ACTIVE_TREE)
+ if (whichTree === constants.ACTIVE_TREE)
return this.activeTree;
- if (whichTree == constants.PENDING_TREE)
+ if (whichTree === constants.PENDING_TREE)
return this.pendingTree;
throw new Exception('Unknown tree type + ' + whichTree);
},
@@ -131,7 +131,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
LayerTreeHostImplSnapshot,
{typeName: 'cc::LayerTreeHostImpl'});
@@ -179,7 +179,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectInstance.register(
+ ObjectInstance.subTypes.register(
LayerTreeHostImplInstance,
{typeName: 'cc::LayerTreeHostImpl'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_impl.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_impl.html
index 752c8ad509f..639e98e3451 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_impl.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/layer_tree_impl.html
@@ -86,7 +86,7 @@ tr.exportTo('tr.e.cc', function() {
},
get hasSourceFrameBeenDrawnBefore() {
- if (this.whichTree == tr.e.cc.constants.PENDING_TREE)
+ if (this.whichTree === tr.e.cc.constants.PENDING_TREE)
return false;
// Old chrome's don't produce sourceFrameNumber.
@@ -107,11 +107,11 @@ tr.exportTo('tr.e.cc', function() {
// Old chrome's don't produce sourceFrameNumber.
if (prevLTHI.activeTree.sourceFrameNumber === undefined)
return;
- return prevLTHI.activeTree.sourceFrameNumber == this.sourceFrameNumber;
+ return prevLTHI.activeTree.sourceFrameNumber === this.sourceFrameNumber;
},
get otherTree() {
- var other = this.whichTree == constants.ACTIVE_TREE ?
+ var other = this.whichTree === constants.ACTIVE_TREE ?
constants.PENDING_TREE : constants.ACTIVE_TREE;
return this.layerTreeHostImpl.getTree(other);
},
@@ -151,7 +151,7 @@ tr.exportTo('tr.e.cc', function() {
findLayerWithId: function(id) {
var foundLayer = undefined;
function visitLayer(layer) {
- if (layer.layerId == id)
+ if (layer.layerId === id)
foundLayer = layer;
}
this.iterLayers(visitLayer);
@@ -159,7 +159,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
LayerTreeImplSnapshot,
{typeName: 'cc::LayerTreeImpl'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/picture.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/picture.html
index 6cfca65b4b0..ca25a118528 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/picture.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/picture.html
@@ -100,7 +100,7 @@ tr.exportTo('tr.e.cc', function() {
opTimings[iteration] = this.getOpTimings();
if (!opTimings[iteration] || !opTimings[iteration].cmd_times)
return ops;
- if (opTimings[iteration].cmd_times.length != ops.length)
+ if (opTimings[iteration].cmd_times.length !== ops.length)
return ops;
}
@@ -400,7 +400,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
PictureSnapshot,
{typeNames: ['cc::Picture']});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/region.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/region.html
index b023e80f5cc..e6934a93c71 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/region.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/region.html
@@ -18,7 +18,7 @@ tr.exportTo('tr.e.cc', function() {
}
Region.fromArray = function(array) {
- if (array.length % 4 != 0)
+ if (array.length % 4 !== 0)
throw new Error('Array must consist be a multiple of 4 in length');
var r = new Region();
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/render_pass.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/render_pass.html
index 48f1186525d..8b302435858 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/render_pass.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/render_pass.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/extras/chrome/cc/util.html">
<link rel="import" href="/tracing/base/rect.html">
+<link rel="import" href="/tracing/extras/chrome/cc/util.html">
<link rel="import" href="/tracing/model/object_instance.html">
<script>
@@ -35,7 +35,9 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(RenderPassSnapshot, {typeName: 'cc::RenderPass'});
+ ObjectSnapshot.subTypes.register(
+ RenderPassSnapshot,
+ {typeName: 'cc::RenderPass'});
return {
RenderPassSnapshot: RenderPassSnapshot
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/tile.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/tile.html
index 605c3ef968d..a24e58483e2 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/tile.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/tile.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/extras/chrome/cc/util.html">
-<link rel="import" href="/tracing/extras/chrome/cc/debug_colors.html">
<link rel="import" href="/tracing/base/rect.html">
+<link rel="import" href="/tracing/extras/chrome/cc/debug_colors.html">
+<link rel="import" href="/tracing/extras/chrome/cc/util.html">
<link rel="import" href="/tracing/model/object_instance.html">
<script>
@@ -69,7 +69,7 @@ tr.exportTo('tr.e.cc', function() {
getTypeForLayer: function(layer) {
var type = this.type_;
- if (type == tr.e.cc.tileTypes.unknown) {
+ if (type === tr.e.cc.tileTypes.unknown) {
if (this.contentsScale < layer.idealContentsScale)
type = tr.e.cc.tileTypes.extraLowRes;
else if (this.contentsScale > layer.idealContentsScale)
@@ -79,7 +79,7 @@ tr.exportTo('tr.e.cc', function() {
}
};
- ObjectSnapshot.register(TileSnapshot, {typeName: 'cc::Tile'});
+ ObjectSnapshot.subTypes.register(TileSnapshot, {typeName: 'cc::Tile'});
return {
TileSnapshot: TileSnapshot
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/util.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/util.html
index f12c4b8f3fd..a8689fe0d6d 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/util.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/cc/util.html
@@ -18,14 +18,14 @@ tr.exportTo('tr.e.cc', function() {
if (name in convertedNameCache)
return convertedNameCache[name];
- if (name[0] == '_' ||
- name[name.length - 1] == '_') {
+ if (name[0] === '_' ||
+ name[name.length - 1] === '_') {
convertedNameCache[name] = name;
return name;
}
var words = name.split('_');
- if (words.length == 1) {
+ if (words.length === 1) {
convertedNameCache[name] = words[0];
return words[0];
}
@@ -104,7 +104,7 @@ tr.exportTo('tr.e.cc', function() {
for (var key in object) {
var newKey = convertNameToJSConvention(key);
- if (newKey != key) {
+ if (newKey !== key) {
var value = object[key];
delete object[key];
object[newKey] = value;
@@ -138,16 +138,11 @@ tr.exportTo('tr.e.cc', function() {
}
}
- function bytesToRoundedMegabytes(bytes) {
- return Math.round(bytes / 100000.0) / 10.0;
- }
-
return {
preInitializeObject: preInitializeObject,
convertNameToJSConvention: convertNameToJSConvention,
moveRequiredFieldsFromArgsToToplevel: moveRequiredFieldsFromArgsToToplevel,
moveOptionalFieldsFromArgsToToplevel: moveOptionalFieldsFromArgsToToplevel,
- bytesToRoundedMegabytes: bytesToRoundedMegabytes
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
index 5ff273daa34..df91f506ece 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
@@ -86,7 +86,7 @@ tr.exportTo('tr.e.chrome', function() {
dict.title = tr.model.helpers.IMPL_RENDERING_STATS;
dict.type = tr.model.ThreadSlice;
var slice = tr.c.TestUtils.newSliceEx(dict);
- model.rendererMain.asyncSliceGroup.push(slice);
+ model.rendererMain.sliceGroup.pushSlice(slice);
return slice;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver.html
index 800f92c7158..ee542f12e0c 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/event.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/sinebow_color_generator.html">
<script>
'use strict';
@@ -92,18 +93,6 @@ tr.exportTo('tr.e.chrome', function() {
'RenderLayer::updateLayerPositionsAfterLayout'
],
- script: [
- 'EvaluateScript',
- 'FunctionCall',
- 'ScheduledAction::execute',
- 'Script',
- 'V8.Execute',
- 'v8.run',
- 'v8.callModuleMethod',
- 'v8.callFunction',
- 'WindowProxy::initialize'
- ],
-
style: [
'CSSParserImpl::parseStyleSheet.parse',
'CSSParserImpl::parseStyleSheet.tokenize',
@@ -118,27 +107,13 @@ tr.exportTo('tr.e.chrome', function() {
],
script_parse_and_compile: [
- 'V8.RecompileSynchronous',
- 'V8.RecompileConcurrent',
- 'V8.PreParseMicroSeconds',
'v8.parseOnBackground',
- 'V8.ParseMicroSeconds',
- 'V8.ParseLazyMicroSeconds',
- 'V8.CompileScriptMicroSeconds',
- 'V8.CompileMicroSeconds',
- 'V8.CompileFullCode',
- 'V8.CompileEvalMicroSeconds',
- 'v8.compile'
+ 'V8.ScriptCompiler'
],
- script_parse: [
- 'V8Test.ParseScript',
- 'V8Test.ParseFunction',
- ],
-
- script_compile: [
- 'V8Test.Compile',
- 'V8Test.CompileFullCode',
+ script_execute: [
+ 'V8.Execute',
+ 'WindowProxy::initialize'
],
resource_loading: [
@@ -155,19 +130,27 @@ tr.exportTo('tr.e.chrome', function() {
'ThreadState::completeSweep' // blink_gc
],
+ // TODO(fmeawad): https://github.com/catapult-project/catapult/issues/2572
+ v8_runtime: [
+ // Dynamically populated.
+ ],
+
[SAME_AS_PARENT]: [
'SyncChannel::Send'
]
};
- var USER_FRIENDLY_CATEGORY_FOR_TITLE = {};
+ var COLOR_FOR_USER_FRIENDLY_CATEGORY = new tr.b.SinebowColorGenerator();
+ var USER_FRIENDLY_CATEGORY_FOR_TITLE = new Map();
for (var category in TITLES_FOR_USER_FRIENDLY_CATEGORY) {
TITLES_FOR_USER_FRIENDLY_CATEGORY[category].forEach(function(title) {
- USER_FRIENDLY_CATEGORY_FOR_TITLE[title] = category;
+ USER_FRIENDLY_CATEGORY_FOR_TITLE.set(title, category);
});
}
+ // keys: event.category part
+ // values: user friendly category
var USER_FRIENDLY_CATEGORY_FOR_EVENT_CATEGORY = {
netlog: 'net',
overhead: 'overhead',
@@ -179,9 +162,10 @@ tr.exportTo('tr.e.chrome', function() {
}
ChromeUserFriendlyCategoryDriver.fromEvent = function(event) {
- var userFriendlyCategory = USER_FRIENDLY_CATEGORY_FOR_TITLE[event.title];
+ var userFriendlyCategory =
+ USER_FRIENDLY_CATEGORY_FOR_TITLE.get(event.title);
if (userFriendlyCategory) {
- if (userFriendlyCategory == SAME_AS_PARENT) {
+ if (userFriendlyCategory === SAME_AS_PARENT) {
if (event.parentSlice)
return ChromeUserFriendlyCategoryDriver.fromEvent(event.parentSlice);
} else {
@@ -198,9 +182,30 @@ tr.exportTo('tr.e.chrome', function() {
return userFriendlyCategory;
}
- return undefined;
+ return 'other';
+ };
+
+ ChromeUserFriendlyCategoryDriver.getColor = function(ufc) {
+ return COLOR_FOR_USER_FRIENDLY_CATEGORY.colorForKey(ufc);
};
+ ChromeUserFriendlyCategoryDriver.ALL_TITLES = ['other'];
+ for (var category in TITLES_FOR_USER_FRIENDLY_CATEGORY) {
+ if (category === SAME_AS_PARENT)
+ continue;
+ ChromeUserFriendlyCategoryDriver.ALL_TITLES.push(category);
+ }
+ for (var category of tr.b.dictionaryValues(
+ USER_FRIENDLY_CATEGORY_FOR_EVENT_CATEGORY)) {
+ ChromeUserFriendlyCategoryDriver.ALL_TITLES.push(category);
+ }
+ ChromeUserFriendlyCategoryDriver.ALL_TITLES.sort();
+
+ // Prime the color generator by iterating through all UFCs in alphabetical
+ // order.
+ for (var category of ChromeUserFriendlyCategoryDriver.ALL_TITLES)
+ ChromeUserFriendlyCategoryDriver.getColor(category);
+
return {
ChromeUserFriendlyCategoryDriver: ChromeUserFriendlyCategoryDriver
};
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver_test.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver_test.html
index fadf09a6bca..26fa4d599c9 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_user_friendly_category_driver_test.html
@@ -26,9 +26,9 @@ tr.b.unittest.testSuite(function() {
assert.equal(ufcFromEvent({
guid: tr.b.GUID.allocateSimple(),
- title: 'Script',
+ title: 'V8.Execute',
category: 'cat'
- }), 'script');
+ }), 'script_execute');
assert.equal(ufcFromEvent({
guid: tr.b.GUID.allocateSimple(),
@@ -45,6 +45,12 @@ tr.b.unittest.testSuite(function() {
title: 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser',
category: 'cat'
}), 'parseHTML');
+
+ assert.equal(ufcFromEvent({
+ guid: tr.b.GUID.allocateSimple(),
+ title: 'constructor',
+ category: 'cat'
+ }), 'other');
});
test('ufcFromTraceCategory', function() {
@@ -67,12 +73,12 @@ tr.b.unittest.testSuite(function() {
}), 'startup');
});
- test('ufcUndefined', function() {
- assert.isUndefined(ufcFromEvent({
+ test('ufcOther', function() {
+ assert.equal(ufcFromEvent({
guid: tr.b.GUID.allocateSimple(),
title: 'a',
category: 'other'
- }));
+ }), 'other');
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice.html
index 13c4fbece2a..e95d6787b48 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice.html
@@ -21,7 +21,7 @@ tr.exportTo('tr.e.gpu', function() {
get viewSubGroupTitle() {
if (this.args.channel) {
- if (this.category == 'disabled-by-default-gpu.device')
+ if (this.category === 'disabled-by-default-gpu.device')
return 'Device.' + this.args.channel;
else
return 'Service.' + this.args.channel;
@@ -30,7 +30,7 @@ tr.exportTo('tr.e.gpu', function() {
}
};
- AsyncSlice.register(
+ AsyncSlice.subTypes.register(
GpuAsyncSlice,
{
categoryParts: ['disabled-by-default-gpu.device',
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
index 24bd98cc8c6..3b23bb5a80e 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
@@ -18,23 +18,23 @@ tr.b.unittest.testSuite(function() {
var GpuAsyncSlice = tr.e.gpu.GpuAsyncSlice;
test('construct', function() {
- assert.equal(AsyncSlice.getConstructor('disabled-by-default-gpu.device',
- 'gpu1'),
+ assert.equal(AsyncSlice.subTypes.getConstructor(
+ 'disabled-by-default-gpu.device', 'gpu1'),
GpuAsyncSlice);
- assert.equal(AsyncSlice.getConstructor('disabled-by-default-gpu.service',
- 'gpu2'),
+ assert.equal(AsyncSlice.subTypes.getConstructor(
+ 'disabled-by-default-gpu.service', 'gpu2'),
GpuAsyncSlice);
});
test('subgroup', function() {
- var s_device = new GpuAsyncSlice('disabled-by-default-gpu.device', 'gpu1',
+ var sDevice = new GpuAsyncSlice('disabled-by-default-gpu.device', 'gpu1',
7, 0, {'channel': 'test_channel1'});
- var s_service = new GpuAsyncSlice('disabled-by-default-gpu.service', 'gpu2',
+ var sService = new GpuAsyncSlice('disabled-by-default-gpu.service', 'gpu2',
7, 0, {'channel': 'test_channel2'});
- assert.equal(s_device.viewSubGroupTitle, 'Device.test_channel1');
- assert.equal(s_service.viewSubGroupTitle, 'Service.test_channel2');
+ assert.equal(sDevice.viewSubGroupTitle, 'Device.test_channel1');
+ assert.equal(sService.viewSubGroupTitle, 'Service.test_channel2');
});
test('import', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state.html
index b3185f7ef4e..68ac8e1594d 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state.html
@@ -41,7 +41,7 @@ tr.exportTo('tr.e.gpu', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
StateSnapshot,
{typeName: 'gpu::State'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test.html
index 4ddfe1e46ca..97747dbd44b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test.html
@@ -17,7 +17,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.TestUtils.newModelWithEvents([g_gpu_state_trace]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_gpuStateTrace]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('gpu::State')[0];
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test_data.js b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test_data.js
index 39af04d95b5..a781837f140 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test_data.js
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/gpu/state_test_data.js
@@ -4,7 +4,7 @@
'use strict';
-var g_gpu_state_trace = [
+var g_gpuStateTrace = [
{
'cat': 'disabled-by-default-gpu.debug',
'pid': 23969,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/layout_tree.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/layout_tree.html
index 98e8f14e099..288016cb796 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/layout_tree.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/layout_tree.html
@@ -23,7 +23,8 @@ tr.exportTo('tr.e.chrome', function() {
__proto__: ObjectInstance.prototype,
};
- ObjectInstance.register(LayoutTreeInstance, {typeName: 'LayoutTree'});
+ ObjectInstance.subTypes.register(
+ LayoutTreeInstance, {typeName: 'LayoutTree'});
function LayoutTreeSnapshot() {
ObjectSnapshot.apply(this, arguments);
@@ -34,16 +35,8 @@ tr.exportTo('tr.e.chrome', function() {
__proto__: ObjectSnapshot.prototype,
};
- ObjectSnapshot.register(LayoutTreeSnapshot, {typeName: 'LayoutTree'});
-
- tr.model.EventRegistry.register(
- LayoutTreeSnapshot,
- {
- name: 'layoutTree',
- pluralName: 'layoutTrees',
- singleViewElementName: 'tr-ui-a-layout-tree-sub-view',
- multiViewElementName: 'tr-ui-a-layout-tree-sub-view'
- });
+ ObjectSnapshot.subTypes.register(
+ LayoutTreeSnapshot, {typeName: 'LayoutTree'});
return {
LayoutTreeInstance: LayoutTreeInstance,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome_config.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome_config.html
index b90a2cd8ddd..8e0ef237d64 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/chrome_config.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome_config.html
@@ -30,4 +30,5 @@ The chrome config is heavily used:
<link rel="import" href="/tracing/extras/measure/measure.html">
<link rel="import" href="/tracing/extras/net/net.html">
<link rel="import" href="/tracing/extras/systrace_config.html">
+<link rel="import" href="/tracing/extras/v8_config.html">
<link rel="import" href="/tracing/extras/vsync/vsync_auditor.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/android/event_log_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/android/event_log_importer.html
index ff2e22e16a2..af24ea1cbbc 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/android/event_log_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/android/event_log_importer.html
@@ -230,13 +230,13 @@ tr.exportTo('tr.e.importer.android', function() {
// The Android event log will eventually contain the year once this
// CL is in a release:
// https://android-review.googlesource.com/#/c/168900
- var first_realtime_ts = this.model_.bounds.min -
+ var firstRealtimeTs = this.model_.bounds.min -
this.model_.realtime_to_monotonic_offset_ms;
- var year = new Date(first_realtime_ts).getFullYear();
+ var year = new Date(firstRealtimeTs).getFullYear();
var ts = match[1].substring(0, 5) + '-' + year + ' ' +
match[1].substring(5, match[1].length);
- var monotonic_ts = Date.parse(ts) +
+ var monotonicTs = Date.parse(ts) +
this.model_.realtime_to_monotonic_offset_ms;
var pid = match[2];
@@ -246,37 +246,37 @@ tr.exportTo('tr.e.importer.android', function() {
if (action === 'am_create_activity') {
match = amCreateRE.exec(data);
if (match && match.length >= 2) {
- this.handleCreateActivity(monotonic_ts,
+ this.handleCreateActivity(monotonicTs,
this.getFullActivityName(match[1]));
}
} else if (action === 'am_focused_activity') {
match = amFocusedRE.exec(data);
if (match && match.length >= 2) {
- this.handleFocusActivity(monotonic_ts,
+ this.handleFocusActivity(monotonicTs,
this.getProcName(match[1]), this.getFullActivityName(match[1]));
}
} else if (action === 'am_proc_start') {
match = amProcStartRE.exec(data);
if (match && match.length >= 2) {
- this.handleProcStartForActivity(monotonic_ts,
+ this.handleProcStartForActivity(monotonicTs,
this.getFullActivityName(match[1]));
}
} else if (action === 'am_on_resume_called') {
match = amOnResumeRE.exec(data);
if (match && match.length >= 2)
- this.handleOnResumeCalled(monotonic_ts, pid, match[1]);
+ this.handleOnResumeCalled(monotonicTs, pid, match[1]);
} else if (action === 'am_on_paused_called') {
match = amOnPauseRE.exec(data);
if (match && match.length >= 2)
- this.handleOnPauseCalled(monotonic_ts, match[1]);
+ this.handleOnPauseCalled(monotonicTs, match[1]);
} else if (action === 'am_activity_launch_time') {
match = amLaunchTimeRE.exec(data);
- this.handleLaunchTime(monotonic_ts,
+ this.handleLaunchTime(monotonicTs,
this.getFullActivityName(match[1]), match[2]);
} else if (action === 'am_destroy_activity') {
match = amDestroyRE.exec(data);
- if (match && match.length == 2) {
- this.handleDestroyActivity(monotonic_ts,
+ if (match && match.length === 2) {
+ this.handleDestroyActivity(monotonicTs,
this.getFullActivityName(match[1]));
}
}
@@ -303,7 +303,7 @@ tr.exportTo('tr.e.importer.android', function() {
for (var activityName in activityMap) {
var activity = activityMap[activityName];
// If we're still in the foreground, store the activity anyway
- if (activity.state == ACTIVITY_STATE.RESUMED) {
+ if (activity.state === ACTIVITY_STATE.RESUMED) {
// Set the pause timestamp to the end of the model bounds
activity.lastPauseTs = this.model_.bounds.max;
this.addActivityToProcess(activity);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer.html
index 381bf0f8687..03db04866d9 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/importer/importer.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/model/power_series.html">
@@ -27,7 +28,13 @@ tr.exportTo('tr.e.importer.battor', function() {
function BattorImporter(model, events) {
this.importPriority = 3; // runs after the linux_perf importer
this.model_ = model;
- this.samples_ = this.linesToSamples_(events.split('\n'));
+
+ // The list of power samples contained within the trace.
+ this.samples_ = [];
+ // The clock sync markers contained within the trace.
+ this.syncTimestampsById_ = new Map();
+
+ this.parseTrace_(events);
}
var battorDataLineRE = new RegExp(
@@ -61,20 +68,17 @@ tr.exportTo('tr.e.importer.battor', function() {
},
/**
- * Imports clock sync markers in this.events_ into model_.
+ * Imports clock sync markers from the trace into into this.model_.
*/
importClockSyncMarkers: function() {
- for (var i = 0; i < this.samples_.length; i++) {
- var sample = this.samples_[i];
- if (sample.syncId) {
- this.model_.clockSyncManager.addClockSyncMarker(
- tr.model.ClockDomainId.BATTOR, sample.syncId, sample.ts);
- }
+ for (var [syncId, ts] of this.syncTimestampsById_) {
+ this.model_.clockSyncManager.addClockSyncMarker(
+ tr.model.ClockDomainId.BATTOR, syncId, ts);
}
},
/**
- * Imports the data in this.events_ into model_.
+ * Imports the events from the trace into this.model_.
*/
importEvents: function() {
if (this.model_.device.powerSeries) {
@@ -94,19 +98,18 @@ tr.exportTo('tr.e.importer.battor', function() {
for (var i = 0; i < this.samples_.length; i++) {
var sample = this.samples_[i];
powerSeries.addPowerSample(
- modelTimeTransformer(sample.ts), sample.power);
+ modelTimeTransformer(sample.ts), sample.powerInW);
}
},
/**
- * Given an array of strings that make up the lines of a BattOr trace,
- * returns an array of samples contained within those lines.
+ * Given the BattOr trace as a string, parse it and store the results in
+ * this.samples_ and this.syncTimestampsById_.
*/
- linesToSamples_: function(lines) {
- var samples = [];
+ parseTrace_: function(trace) {
+ var lines = trace.split('\n');
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i];
+ for (var line of lines) {
line = line.trim();
if (line.length === 0)
@@ -126,11 +129,16 @@ tr.exportTo('tr.e.importer.battor', function() {
}
var ts = parseFloat(groups[1]);
- var voltage = parseFloat(groups[2]) / 1000;
- var current = parseFloat(groups[3]) / 1000;
+ var voltageInV = tr.b.convertUnit(parseFloat(groups[2]),
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
+ var currentInA = tr.b.convertUnit(parseFloat(groups[3]),
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
var syncId = groups[4];
- if (voltage < 0 || current < 0) {
+ if (syncId)
+ this.syncTimestampsById_.set(syncId, ts);
+
+ if (voltageInV < 0 || currentInA < 0) {
this.model_.importWarning({
type: 'parse_error',
message: 'The following line in the BattOr trace has a negative ' +
@@ -141,10 +149,8 @@ tr.exportTo('tr.e.importer.battor', function() {
continue;
}
- samples.push(new Sample(ts, voltage, current, syncId));
+ this.samples_.push(new Sample(ts, voltageInV, currentInA));
}
-
- return samples;
}
};
@@ -154,27 +160,24 @@ tr.exportTo('tr.e.importer.battor', function() {
* @param {number} ts The timestamp (in milliseconds) of the sample.
* @param {number} voltage The voltage (in volts) at the specified time.
* @param {number} current The current (in amps) at the specified time.
- * @param {string=} opt_syncId The sync ID of the sync that happened at this
- * sample.
*
* @constructor
*/
- function Sample(ts, voltage, current, opt_syncId) {
+ function Sample(ts, voltageInV, currentInA) {
this.ts = ts;
- this.voltage = voltage;
- this.current = current;
- this.syncId = opt_syncId;
+ this.voltageInV = voltageInV;
+ this.currentInA = currentInA;
}
Sample.prototype = {
/** Returns the instantaneous power consumption (in Watts). */
- get power() { return this.voltage * this.current; }
+ get powerInW() { return this.voltageInV * this.currentInA; }
};
tr.importer.Importer.register(BattorImporter);
return {
- BattorImporter: BattorImporter,
+ BattorImporter: BattorImporter
};
});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer_test.html
index ac8c125dbc6..a5e347caede 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/battor_importer_test.html
@@ -63,6 +63,24 @@ tr.b.unittest.testSuite(function() {
assert.strictEqual(m.device.powerSeries.samples[5].start, 10.0);
});
+ test('importExplicitClockSync_syncOnNegativeVoltageLine', function() {
+ // Add a BattOr sample with an explicit clock sync that occurs on a line
+ // with a negative voltage measurement. The sample should be ignored, but
+ // the clock sync should be counted.
+ var battorLinesWithExplicitSync = BATTOR_LINES.slice();
+ battorLinesWithExplicitSync.push(
+ '2.500000 -1.000000 4000.000000 <ABCDEF-01234-5678-0A1B2C3D>');
+
+ var m = tr.c.TestUtils.newModelWithEvents(
+ [CHROMIUM_EVENTS, battorLinesWithExplicitSync.join('\n')]);
+
+ // Check to see if power samples were imported successfully.
+ assert.isDefined(m.device.powerSeries);
+
+ assert.lengthOf(m.device.powerSeries.samples, 5);
+ assert.strictEqual(m.device.powerSeries.samples[0].start, 7.5);
+ });
+
test('explicitClockSyncWithoutSyncMarkers', function() {
// Create an empty model.
var m = new tr.Model();
@@ -78,6 +96,7 @@ tr.b.unittest.testSuite(function() {
var m = tr.c.TestUtils.newModelWithEvents(
[battorLinesWithExplicitSync.join('\n')]);
+ assert.lengthOf(m.device.powerSeries.samples, 6);
assert.strictEqual(m.device.powerSeries.samples[0].start, 0);
assert.strictEqual(m.device.powerSeries.samples[5].start, 2.5);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/ddms_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/ddms_importer.html
index fd760c7c7f4..a4019cefcd1 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/ddms_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/ddms_importer.html
@@ -35,9 +35,9 @@ tr.exportTo('tr.e.importer.ddms', function() {
var kTraceRecordSizeSingleClock = 10; // using v2
var kTraceRecordSizeDualClock = 14; // using v3 with two timestamps
- function Reader(string_payload) {
+ function Reader(stringPayload) {
this.position_ = 0;
- this.data_ = JSZip.utils.transformTo('uint8array', string_payload);
+ this.data_ = JSZip.utils.transformTo('uint8array', stringPayload);
}
Reader.prototype = {
@@ -69,9 +69,9 @@ tr.exportTo('tr.e.importer.ddms', function() {
// Javascript isn't able to manage 64-bit numeric values.
var low = this.uint32();
var high = this.uint32();
- var low_str = ('0000000' + low.toString(16)).substr(-8);
- var high_str = ('0000000' + high.toString(16)).substr(-8);
- var result = high_str + low_str;
+ var lowStr = ('0000000' + low.toString(16)).substr(-8);
+ var highStr = ('0000000' + high.toString(16)).substr(-8);
+ var result = highStr + lowStr;
return result;
},
@@ -133,11 +133,11 @@ tr.exportTo('tr.e.importer.ddms', function() {
var traceReader = new Reader(this.data_.slice(divider));
var magic = traceReader.uint32();
- if (magic != kTraceMagicValue) {
+ if (magic !== kTraceMagicValue) {
throw Error('Failed to match magic value');
}
this.version_ = traceReader.uint16();
- if (this.version_ != kTraceVersionDualClock) {
+ if (this.version_ !== kTraceVersionDualClock) {
throw Error('Unknown version');
}
var dataOffest = traceReader.uint16();
@@ -160,7 +160,7 @@ tr.exportTo('tr.e.importer.ddms', function() {
var action = methodPacked & kTraceMethodActionMask;
var thread = this.getTid(tid);
method = this.getMethodName(method);
- if (action == kTraceMethodEnter) {
+ if (action === kTraceMethodEnter) {
thread.sliceGroup.beginSlice(kCategory, method, wallClockSinceStart,
undefined, cpuSinceStart);
} else if (thread.sliceGroup.openSliceCount) {
@@ -176,10 +176,10 @@ tr.exportTo('tr.e.importer.ddms', function() {
threads.forEach(this.parseThread.bind(this));
},
- parseThread: function(thread_line) {
- var tid = thread_line.slice(0, thread_line.indexOf('\t'));
+ parseThread: function(threadLine) {
+ var tid = threadLine.slice(0, threadLine.indexOf('\t'));
var thread = this.getTid(parseInt(tid));
- thread.name = thread_line.slice(thread_line.indexOf('\t') + 1);
+ thread.name = threadLine.slice(threadLine.indexOf('\t') + 1);
},
getTid: function(tid) {
@@ -195,8 +195,8 @@ tr.exportTo('tr.e.importer.ddms', function() {
methods.forEach(this.parseMethod.bind(this));
},
- parseMethod: function(method_line) {
- var data = method_line.split('\t');
+ parseMethod: function(methodLine) {
+ var data = methodLine.split('\t');
var methodId = parseInt(data[0]);
var methodName = data[1] + '.' + data[2] + data[3];
this.addMethod(methodId, methodName);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer.html
index 799e2a13b95..215978b75f2 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer.html
@@ -62,17 +62,17 @@ tr.exportTo('tr.e.importer.etw', function() {
*/
function Decoder() {
this.payload_ = new DataView(new ArrayBuffer(256));
- };
+ }
Decoder.prototype = {
__proto__: Object.prototype,
- reset: function(base64_payload) {
- var decoded_size = tr.b.Base64.getDecodedBufferLength(base64_payload);
- if (decoded_size > this.payload_.byteLength)
- this.payload_ = new DataView(new ArrayBuffer(decoded_size));
+ reset: function(base64Payload) {
+ var decodedSize = tr.b.Base64.getDecodedBufferLength(base64Payload);
+ if (decodedSize > this.payload_.byteLength)
+ this.payload_ = new DataView(new ArrayBuffer(decodedSize));
- tr.b.Base64.DecodeToTypedArray(base64_payload, this.payload_);
+ tr.b.Base64.DecodeToTypedArray(base64Payload, this.payload_);
this.position_ = 0;
},
@@ -102,9 +102,9 @@ tr.exportTo('tr.e.importer.etw', function() {
// Javascript isn't able to manage 64-bit numeric values.
var low = this.decodeUInt32();
var high = this.decodeUInt32();
- var low_str = ('0000000' + low.toString(16)).substr(-8);
- var high_str = ('0000000' + high.toString(16)).substr(-8);
- var result = high_str + low_str;
+ var lowStr = ('0000000' + low.toString(16)).substr(-8);
+ var highStr = ('0000000' + high.toString(16)).substr(-8);
+ var result = highStr + lowStr;
return result;
},
@@ -159,7 +159,7 @@ tr.exportTo('tr.e.importer.etw', function() {
},
decodeFixedW16String: function(length) {
- var old_position = this.position_;
+ var oldPosition = this.position_;
var str = '';
for (var i = 0; i < length; i++) {
var c = this.decodeUInt16();
@@ -169,7 +169,7 @@ tr.exportTo('tr.e.importer.etw', function() {
}
// Move the position after the fixed buffer (i.e. wchar[length]).
- this.position_ = old_position + 2 * length;
+ this.position_ = oldPosition + 2 * length;
return str;
},
@@ -197,7 +197,7 @@ tr.exportTo('tr.e.importer.etw', function() {
this.decodeUInt16();
this.decodeUInt32();
- if (revision != 1)
+ if (revision !== 1)
throw 'Invalid SID revision: could not decode the SID structure.';
var sid = this.decodeBytes(4 * subAuthorityCount);
@@ -317,10 +317,10 @@ tr.exportTo('tr.e.importer.etw', function() {
},
getPidFromWindowsTid: function(tid) {
- if (tid == 0)
+ if (tid === 0)
return 0;
var pid = this.tidsToPid_[tid];
- if (pid == undefined) {
+ if (pid === undefined) {
// Kernel threads are not defined.
return 0;
}
@@ -350,10 +350,10 @@ tr.exportTo('tr.e.importer.etw', function() {
importEvents: function() {
this.events_.content.forEach(this.parseInfo.bind(this));
- if (this.walltime_ == undefined || this.ticks_ == undefined)
+ if (this.walltime_ === undefined || this.ticks_ === undefined)
throw Error('Cannot find clock sync information in the system trace.');
- if (this.is64bit_ == undefined)
+ if (this.is64bit_ === undefined)
throw Error('Cannot determine pointer size of the system trace.');
this.events_.content.forEach(this.parseEvent.bind(this));
@@ -375,27 +375,27 @@ tr.exportTo('tr.e.importer.etw', function() {
}
// Retrieve pointer size information from a Thread.DCStart event.
- if (this.is64bit_ == undefined &&
+ if (this.is64bit_ === undefined &&
event.hasOwnProperty('guid') &&
event.hasOwnProperty('op') &&
event.hasOwnProperty('ver') &&
event.hasOwnProperty('payload') &&
event.guid === kThreadGuid &&
- event.op == kThreadDCStartOpcode) {
- var decoded_size = tr.b.Base64.getDecodedBufferLength(event.payload);
+ event.op === kThreadDCStartOpcode) {
+ var decodedSize = tr.b.Base64.getDecodedBufferLength(event.payload);
- if (event.ver == 1) {
- if (decoded_size >= 52)
+ if (event.ver === 1) {
+ if (decodedSize >= 52)
this.is64bit_ = true;
else
this.is64bit_ = false;
- } else if (event.ver == 2) {
- if (decoded_size >= 64)
+ } else if (event.ver === 2) {
+ if (decodedSize >= 64)
this.is64bit_ = true;
else
this.is64bit_ = false;
- } else if (event.ver == 3) {
- if (decoded_size >= 60)
+ } else if (event.ver === 3) {
+ if (decodedSize >= 60)
this.is64bit_ = true;
else
this.is64bit_ = false;
@@ -451,7 +451,7 @@ tr.exportTo('tr.e.importer.etw', function() {
* Registers a windows ETW event handler used by parseEvent().
*/
registerEventHandler: function(guid, opcode, handler) {
- if (this.handlers_[guid] == undefined)
+ if (this.handlers_[guid] === undefined)
this.handlers_[guid] = [];
this.handlers_[guid][opcode] = handler;
},
@@ -460,7 +460,7 @@ tr.exportTo('tr.e.importer.etw', function() {
* Retrieves a registered event handler.
*/
getEventHandler: function(guid, opcode) {
- if (this.handlers_[guid] == undefined)
+ if (this.handlers_[guid] === undefined)
return undefined;
return this.handlers_[guid][opcode];
}
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer_test.html
index 91a94d6c015..584233fccd2 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/etw_importer_test.html
@@ -40,13 +40,13 @@ tr.b.unittest.testSuite(function() {
var model = 'dummy';
var events = ['events'];
var importer = new tr.e.importer.etw.EtwImporter(model, events);
- var dummy_handler = function() {};
+ var dummyHandler = function() {};
// The handler must not exists.
assert.isUndefined(importer.getEventHandler('ABCDEF', 2));
// Register an event handler for guid: ABCDEF and opcode: 2.
- importer.registerEventHandler('ABCDEF', 2, dummy_handler);
+ importer.registerEventHandler('ABCDEF', 2, dummyHandler);
// The handler exists now, must find it.
assert.isDefined(importer.getEventHandler('ABCDEF', 2));
@@ -59,24 +59,24 @@ tr.b.unittest.testSuite(function() {
var model = 'dummy';
var events = [];
var importer = new tr.e.importer.etw.EtwImporter(model, events);
- var handler_called = false;
- var dummy_handler = function() { handler_called = true; return true; };
+ var handlerCalled = false;
+ var dummyHandler = function() { handlerCalled = true; return true; };
// Register a valid handler.
- importer.registerEventHandler('aaaa', 42, dummy_handler);
+ importer.registerEventHandler('aaaa', 42, dummyHandler);
// Try to parse an invalid event with missing fields.
- var incomplet_event = { guid: 'aaaa', 'op': 42, 'ver': 0 };
- assert.isFalse(importer.parseEvent(incomplet_event));
- assert.isFalse(handler_called);
+ var incompleteEvent = { guid: 'aaaa', 'op': 42, 'ver': 0 };
+ assert.isFalse(importer.parseEvent(incompleteEvent));
+ assert.isFalse(handlerCalled);
// Try to parse a valid event.
- var valid_event = {
+ var validEvent = {
guid: 'aaaa', 'op': 42, 'ver': 0, 'cpu': 0, 'ts': 0,
'payload': Base64.btoa('0')
};
- assert.isTrue(importer.parseEvent(valid_event));
- assert.isTrue(handler_called);
+ assert.isTrue(importer.parseEvent(validEvent));
+ assert.isTrue(handlerCalled);
});
test('resetTooSmall', function() {
@@ -288,4 +288,3 @@ tr.b.unittest.testSuite(function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/eventtrace_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/eventtrace_parser.html
index 14c1dcf5c1b..8496ec958b7 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/eventtrace_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/eventtrace_parser.html
@@ -37,7 +37,7 @@ tr.exportTo('tr.e.importer.etw', function() {
__proto__: Parser.prototype,
decodeFields: function(header, decoder) {
- if (header.version != 2)
+ if (header.version !== 2)
throw new Error('Incompatible EventTrace event version.');
var bufferSize = decoder.decodeUInt32();
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/process_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/process_parser.html
index 51f1e9b51aa..040d24d3bf7 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/process_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/process_parser.html
@@ -63,7 +63,7 @@ tr.exportTo('tr.e.importer.etw', function() {
throw new Error('Incompatible Process event version.');
var pageDirectoryBase;
- if (header.version == 1)
+ if (header.version === 1)
pageDirectoryBase = decoder.decodeUInteger(header.is64);
var uniqueProcessKey;
@@ -106,7 +106,7 @@ tr.exportTo('tr.e.importer.etw', function() {
}
var exitTime;
- if (header.version == 5 && header.opcode == kProcessDefunctOpcode)
+ if (header.version === 5 && header.opcode === kProcessDefunctOpcode)
exitTime = decoder.decodeUInt64ToString();
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/thread_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/thread_parser.html
index d4f75d1e4e5..530cb69e5a9 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/thread_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/etw/thread_parser.html
@@ -82,10 +82,10 @@ tr.exportTo('tr.e.importer.etw', function() {
var threadFlags;
var waitMode;
- if (header.version == 1) {
+ if (header.version === 1) {
// On version 1, only start events have extended information.
- if (header.opcode == kThreadStartOpcode ||
- header.opcode == kThreadDCStartOpcode) {
+ if (header.opcode === kThreadStartOpcode ||
+ header.opcode === kThreadDCStartOpcode) {
stackBase = decoder.decodeUInteger(header.is64);
stackLimit = decoder.decodeUInteger(header.is64);
userStackBase = decoder.decodeUInteger(header.is64);
@@ -102,7 +102,7 @@ tr.exportTo('tr.e.importer.etw', function() {
userStackLimit = decoder.decodeUInteger(header.is64);
// Version 2 produces a field named 'startAddr'.
- if (header.version == 2)
+ if (header.version === 2)
startAddr = decoder.decodeUInteger(header.is64);
else
affinity = decoder.decodeUInteger(header.is64);
@@ -111,7 +111,7 @@ tr.exportTo('tr.e.importer.etw', function() {
tebBase = decoder.decodeUInteger(header.is64);
subProcessTag = decoder.decodeUInt32();
- if (header.version == 3) {
+ if (header.version === 3) {
basePriority = decoder.decodeUInt8();
pagePriority = decoder.decodeUInt8();
ioPriority = decoder.decodeUInt8();
@@ -140,7 +140,7 @@ tr.exportTo('tr.e.importer.etw', function() {
},
decodeCSwitchFields: function(header, decoder) {
- if (header.version != 2)
+ if (header.version !== 2)
throw new Error('Incompatible Thread event version.');
// Decode CSwitch payload.
@@ -200,33 +200,33 @@ tr.exportTo('tr.e.importer.etw', function() {
decodeCSwitch: function(header, decoder) {
var fields = this.decodeCSwitchFields(header, decoder);
var cpu = this.importer.getOrCreateCpu(header.cpu);
- var new_thread =
+ var newThread =
this.importer.getThreadFromWindowsTid(fields.newThreadId);
// Generate the new thread name. If some events were lost, it's possible
// that information about the new thread or process is not available.
- var new_thread_name;
- if (new_thread && new_thread.userFriendlyName) {
- new_thread_name = new_thread.userFriendlyName;
+ var newThreadName;
+ if (newThread && newThread.userFriendlyName) {
+ newThreadName = newThread.userFriendlyName;
} else {
- var new_process_id = this.importer.getPidFromWindowsTid(
+ var newProcessId = this.importer.getPidFromWindowsTid(
fields.newThreadId);
- var new_process = this.model.getProcess(new_process_id);
- var new_process_name;
- if (new_process)
- new_process_name = new_process.name;
+ var newProcess = this.model.getProcess(newProcessId);
+ var newProcessName;
+ if (newProcess)
+ newProcessName = newProcess.name;
else
- new_process_name = 'Unknown process';
+ newProcessName = 'Unknown process';
- new_thread_name =
- new_process_name + ' (tid ' + fields.newThreadId + ')';
+ newThreadName =
+ newProcessName + ' (tid ' + fields.newThreadId + ')';
}
cpu.switchActiveThread(
header.timestamp,
{},
fields.newThreadId,
- new_thread_name,
+ newThreadName,
fields);
return true;
}
@@ -240,4 +240,3 @@ tr.exportTo('tr.e.importer.etw', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html
index b110a7e6c82..08bc702914e 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html
@@ -32,7 +32,7 @@ tr.exportTo('tr.e.importer.gcloud_trace', function() {
if (normalizedEventData.length < 14)
return false;
- return normalizedEventData.slice(0, 14) == '{"projectId":"';
+ return normalizedEventData.slice(0, 14) === '{"projectId":"';
};
GcloudTraceImporter.prototype = {
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer.html
index 8dfd2f199d2..0af7cbee80e 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer.html
@@ -50,9 +50,9 @@ tr.exportTo('tr.e.importer', function() {
header = JSZip.utils.transformTo('uint8array', header);
} else
return false;
- return header[0] == GZIP_HEADER_ID1 &&
- header[1] == GZIP_HEADER_ID2 &&
- header[2] == GZIP_DEFLATE_COMPRESSION;
+ return header[0] === GZIP_HEADER_ID1 &&
+ header[1] === GZIP_HEADER_ID2 &&
+ header[2] === GZIP_DEFLATE_COMPRESSION;
};
/**
@@ -79,45 +79,45 @@ tr.exportTo('tr.e.importer', function() {
}
function skipZeroTerminatedString() {
- while (getByte() != 0) {}
+ while (getByte() !== 0) {}
}
var id1 = getByte();
var id2 = getByte();
if (id1 !== GZIP_HEADER_ID1 || id2 !== GZIP_HEADER_ID2)
throw new Error('Not gzip data');
- var compression_method = getByte();
- if (compression_method !== GZIP_DEFLATE_COMPRESSION)
- throw new Error('Unsupported compression method: ' + compression_method);
+ var compressionMethod = getByte();
+ if (compressionMethod !== GZIP_DEFLATE_COMPRESSION)
+ throw new Error('Unsupported compression method: ' + compressionMethod);
var flags = getByte();
- var have_header_crc = flags & (1 << 1);
- var have_extra_fields = flags & (1 << 2);
- var have_file_name = flags & (1 << 3);
- var have_comment = flags & (1 << 4);
+ var haveHeaderCrc = flags & (1 << 1);
+ var haveExtraFields = flags & (1 << 2);
+ var haveFileName = flags & (1 << 3);
+ var haveComment = flags & (1 << 4);
// Skip modification time, extra flags and OS.
skipBytes(4 + 1 + 1);
// Skip remaining fields before compressed data.
- if (have_extra_fields) {
- var bytes_to_skip = getWord();
- skipBytes(bytes_to_skip);
+ if (haveExtraFields) {
+ var bytesToSkip = getWord();
+ skipBytes(bytesToSkip);
}
- if (have_file_name)
+ if (haveFileName)
skipZeroTerminatedString();
- if (have_comment)
+ if (haveComment)
skipZeroTerminatedString();
- if (have_header_crc)
+ if (haveHeaderCrc)
getWord();
// Inflate the data using jszip.
- var inflated_data =
+ var inflatedData =
JSZip.compressions['DEFLATE'].uncompress(data.subarray(position));
- var string = GzipImporter.transformToString(inflated_data);
+ var string = GzipImporter.transformToString(inflatedData);
- if (inflated_data.length > 0 && string.length === 0) {
+ if (inflatedData.length > 0 && string.length === 0) {
throw new RangeError('Inflated gzip data too long to fit into a string' +
- ' (' + inflated_data.length + ').');
+ ' (' + inflatedData.length + ').');
}
return string;
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
index f226aae6813..ea64eb0188b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
@@ -16,11 +16,11 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Base64 = tr.b.Base64;
var findSliceNamed = tr.c.TestUtils.findSliceNamed;
- var original_data =
+ var ORIGINAL_DATA =
'[{"name":"a","args":{},"pid":52,"ts":520,"cat":"foo","tid":53,' +
'"ph":"B"},{"name":"a","args":{},"pid":52,"ts":520,"cat":"foo",' +
'"tid":53,"ph":"E"}]\n';
- var gzip_data_base64 =
+ var GZIP_DATA_BASE_64 =
'H4sICHr4HVIAA3RyYWNlAIuuVspLzE1VslJKVNJRSixKL1ayqq7VUSrITFGy' +
'MjXSUSopBtEGOkrJiSVAVWn5+UB1JWBZY6CyDKCYk1KtDhWMcVWqjeUCALak' +
'EH+QAAAA';
@@ -32,29 +32,29 @@ tr.b.unittest.testSuite(function() {
test('inflateString', function() {
// Test inflating the data from a string.
- var gzip_data = Base64.atob(gzip_data_base64);
- var importer = new tr.e.importer.GzipImporter(null, gzip_data);
- assert.isTrue(tr.e.importer.GzipImporter.canImport(gzip_data));
- assert.equal(importer.extractSubtraces()[0], original_data);
+ var gzipData = Base64.atob(GZIP_DATA_BASE_64);
+ var importer = new tr.e.importer.GzipImporter(null, gzipData);
+ assert.isTrue(tr.e.importer.GzipImporter.canImport(gzipData));
+ assert.equal(importer.extractSubtraces()[0], ORIGINAL_DATA);
});
test('inflateArrayBuffer', function() {
// Test inflating the data from an ArrayBuffer.
- var gzip_data = Base64.atob(gzip_data_base64);
- var buffer = new ArrayBuffer(gzip_data.length);
+ var gzipData = Base64.atob(GZIP_DATA_BASE_64);
+ var buffer = new ArrayBuffer(gzipData.length);
var view = new Uint8Array(buffer);
- for (var i = 0; i < gzip_data.length; i++)
- view[i] = gzip_data.charCodeAt(i);
+ for (var i = 0; i < gzipData.length; i++)
+ view[i] = gzipData.charCodeAt(i);
var importer = new tr.e.importer.GzipImporter(null, buffer);
assert.isTrue(tr.e.importer.GzipImporter.canImport(buffer));
- assert.equal(importer.extractSubtraces()[0], original_data);
+ assert.equal(importer.extractSubtraces()[0], ORIGINAL_DATA);
});
test('import', function() {
- var gzip_data = Base64.atob(gzip_data_base64);
- assert.isTrue(tr.e.importer.GzipImporter.canImport(gzip_data));
+ var gzipData = Base64.atob(GZIP_DATA_BASE_64);
+ assert.isTrue(tr.e.importer.GzipImporter.canImport(gzipData));
- var model = tr.c.TestUtils.newModelWithEvents(gzip_data);
+ var model = tr.c.TestUtils.newModelWithEvents(gzipData);
var threads = model.getAllThreads();
assert.equal(threads.length, 1);
@@ -102,4 +102,3 @@ tr.b.unittest.testSuite(function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/android_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/android_parser.html
index 5e9dda90f42..33dc13a76e4 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/android_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/android_parser.html
@@ -53,7 +53,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
openAsyncSlice: function(thread, category, name, cookie, ts, args) {
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(
+ tr.model.AsyncSlice.subTypes.getConstructor(
category, name);
var slice = new asyncSliceConstructor(
category, name,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser.html
index 4cebf557bdf..3cabe135cf6 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser.html
@@ -74,25 +74,25 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
return slice.subSlices[0];
}
var kthread = trans.calling_kthread.thread;
- var internal_slice = kthread.sliceGroup.pushCompleteSlice('binder',
+ var internalSlice = kthread.sliceGroup.pushCompleteSlice('binder',
slice.title,
ts, .001, 0, 0,
slice.args);
- internal_slice.title = slice.title;
- internal_slice.id = slice.id;
- internal_slice.colorId = slice.colorId;
- slice.subSlices.push(internal_slice);
- return internal_slice;
+ internalSlice.title = slice.title;
+ internalSlice.id = slice.id;
+ internalSlice.colorId = slice.colorId;
+ slice.subSlices.push(internalSlice);
+ return internalSlice;
}
- function generateBinderArgsForSlice(trans, c_threadName) {
+ function generateBinderArgsForSlice(trans, cThreadName) {
return {
'Transaction Id': trans.transaction_key,
'Destination Node': trans.dest_node,
'Destination Process': trans.dest_proc,
'Destination Thread': trans.dest_thread,
- 'Destination Name': c_threadName,
+ 'Destination Name': cThreadName,
'Reply transaction?': trans.is_reply_transaction,
'Flags': trans.flags + ' ' +
binderFlagsToHuman(trans.flags),
@@ -106,7 +106,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
}
/** @constructor */
- function BinderTransaction(events, calling_pid, calling_ts, calling_kthread) {
+ function BinderTransaction(events, callingPid, callingTs, callingKthread) {
this.transaction_key = parseInt(events[1]);
this.dest_node = parseInt(events[2]);
this.dest_proc = parseInt(events[3]);
@@ -117,9 +117,9 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
this.flags = events[6];
this.code = events[7];
- this.calling_pid = calling_pid;
- this.calling_ts = calling_ts;
- this.calling_kthread = calling_kthread;
+ this.calling_pid = callingPid;
+ this.calling_ts = callingTs;
+ this.calling_kthread = callingKthread;
}
@@ -166,10 +166,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
},
binderLocked: function(eventName, cpuNumber, pid, ts, eventBase) {
- var binder_thread = isBinderThread(eventBase.threadName);
+ var binderThread = isBinderThread(eventBase.threadName);
var tgid, name;
- var as_slice;
- var need_push = false;
var kthread, rthread;
tgid = parseInt(eventBase.tgid);
@@ -255,7 +253,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* binder object from B. This function adds outstanding non-complete
* transactions to a stack on thread B.
*
- * Case Four: 'recursive_trans'
+ * Case Four: 'recursiveTrans'
* This case follows Like above:
* A sent binder_transaction
* B got binder_transaction_received
@@ -339,20 +337,20 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* it and are now sending a transaction.
* The transaction could be a response, or it could be recursive.
*/
- var prior_receive = this.getPriorReceiveOnPID(pid);
+ var priorReceive = this.getPriorReceiveOnPID(pid);
- if (prior_receive !== false) {
- return this.modelPriorReceive(prior_receive, ts, pid, tgid, kthread,
+ if (priorReceive !== false) {
+ return this.modelPriorReceive(priorReceive, ts, pid, tgid, kthread,
trans, args, event);
}
/**
* This Thread has an already established recursive slice. We will now
* either complete the entire transaction, OR do more recursive calls.
*/
- var recursive_trans = this.getRecursiveTransactionNeedingCompletion(pid);
+ var recursiveTrans = this.getRecursiveTransactionNeedingCompletion(pid);
- if (recursive_trans !== false)
- return this.modelRecursiveTransactions(recursive_trans, ts, pid,
+ if (recursiveTrans !== false)
+ return this.modelRecursiveTransactions(recursiveTrans, ts, pid,
kthread, trans, args);
/**
@@ -397,45 +395,45 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* We need to scale the slice up to the current ts and finish
* creating some flows.
*/
- var sync_trans = syncComplete[0];
- var sync_slice = sync_trans.slice;
- var response_trans = syncComplete[1];
- var response_slice = response_trans.slice;
+ var syncTrans = syncComplete[0];
+ var syncSlice = syncTrans.slice;
+ var responseTrans = syncComplete[1];
+ var responseSlice = responseTrans.slice;
- sync_slice.duration = ts - sync_slice.start;
+ syncSlice.duration = ts - syncSlice.start;
/** These calls are a little hack that places a very small slice at
* the end of the sync slice and the response slice. This allows us
* to hook flow events (arrows) from the start to the end of the
* slices.
*/
- var sync_internal = doInternalSlice(sync_trans, sync_slice, ts);
- var response_ts = response_slice.start + response_slice.duration;
- var response_internal = doInternalSlice(response_trans,
- response_slice, response_ts);
-
- if (response_slice.outFlowEvents.length === 0 ||
- sync_slice.inFlowEvents.length === 0) {
- var flow = this.generateFlow(response_internal, sync_internal,
- response_trans, sync_trans);
-
- sync_slice.inFlowEvents.push(flow);
- response_slice.outFlowEvents.push(flow);
+ var syncInternal = doInternalSlice(syncTrans, syncSlice, ts);
+ var responseTs = responseSlice.start + responseSlice.duration;
+ var responseInternal = doInternalSlice(responseTrans,
+ responseSlice, responseTs);
+
+ if (responseSlice.outFlowEvents.length === 0 ||
+ syncSlice.inFlowEvents.length === 0) {
+ var flow = this.generateFlow(responseInternal, syncInternal,
+ responseTrans, syncTrans);
+
+ syncSlice.inFlowEvents.push(flow);
+ responseSlice.outFlowEvents.push(flow);
this.model_.flowEvents.push(flow);
}
// Move flow arrows -- but not the first one.
- for (var i = 1; i < sync_slice.inFlowEvents.length; i++) {
- sync_slice.inFlowEvents[i].duration =
- ts - sync_slice.inFlowEvents[i].start;
+ for (var i = 1; i < syncSlice.inFlowEvents.length; i++) {
+ syncSlice.inFlowEvents[i].duration =
+ ts - syncSlice.inFlowEvents[i].start;
}
return true;
}
- var tr_for_recv = this.getTransactionWaitingForRecv(transactionkey);
+ var trForRecv = this.getTransactionWaitingForRecv(transactionkey);
- if (tr_for_recv !== false) {
- if (!tr_for_recv.expect_reply) {
+ if (trForRecv !== false) {
+ if (!trForRecv.expect_reply) {
// This is an async call place an Async slice.
- var args = generateBinderArgsForSlice(tr_for_recv,
+ var args = generateBinderArgsForSlice(trForRecv,
eventBase.threadName);
var slice = kthread.thread.sliceGroup.
pushCompleteSlice('binder',
@@ -443,19 +441,19 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
ts, .03, 0, 0,
args);
- var fake_event = [0, 0, 0, 0, 0, 0, 0];
- var fake_trans = new BinderTransaction(fake_event, pid, ts, kthread);
- var flow = this.generateFlow(tr_for_recv.slice, slice,
- tr_for_recv, fake_trans);
+ var fakeEvent = [0, 0, 0, 0, 0, 0, 0];
+ var fakeTrans = new BinderTransaction(fakeEvent, pid, ts, kthread);
+ var flow = this.generateFlow(trForRecv.slice, slice,
+ trForRecv, fakeTrans);
this.model_.flowEvents.push(flow);
- tr_for_recv.slice.title = 'binder transaction async';
- tr_for_recv.slice.duration = .03;
+ trForRecv.slice.title = 'binder transaction async';
+ trForRecv.slice.duration = .03;
return true;
}
// Setup prior receive.
- tr_for_recv.slice.title = 'binder transaction';
- this.setCurrentReceiveOnPID(pid, [ts, tr_for_recv]);
+ trForRecv.slice.title = 'binder transaction';
+ this.setCurrentReceiveOnPID(pid, [ts, trForRecv]);
return true;
}
/** This case is when we received an ack for a transaction we have
@@ -467,23 +465,23 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
},
// helper functions
- modelRecursiveTransactions: function(recursive_trans, ts, pid, kthread,
+ modelRecursiveTransactions: function(recursiveTrans, ts, pid, kthread,
trans, args) {
- var recursive_slice = recursive_trans[1].slice;
- var orig_slice = recursive_trans[0].slice;
- recursive_slice.duration = ts - recursive_slice.start;
- trans.slice = recursive_slice;
+ var recursiveSlice = recursiveTrans[1].slice;
+ var origSlice = recursiveTrans[0].slice;
+ recursiveSlice.duration = ts - recursiveSlice.start;
+ trans.slice = recursiveSlice;
if (trans.is_reply_transaction) {
/* Case one:
* This transaction is finally the reply of the recursion.
*/
- orig_slice.duration = ts - orig_slice.start;
+ origSlice.duration = ts - origSlice.start;
this.addSyncTransNeedingCompletion(trans.transaction_key,
- recursive_trans);
+ recursiveTrans);
- if (isReplyToOrigin(recursive_trans[0], trans))
+ if (isReplyToOrigin(recursiveTrans[0], trans))
this.removeRecursiveTransaction(pid);
} else {
/**
@@ -502,15 +500,15 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
return true;
},
- modelPriorReceive: function(prior_receive, ts, pid, tgid, kthread, trans,
+ modelPriorReceive: function(priorReceive, ts, pid, tgid, kthread, trans,
args, event) {
- var callee_slice = prior_receive[1].slice;
- var callee_trans = prior_receive[1];
- var recv_ts = prior_receive[0];
+ var calleeSlice = priorReceive[1].slice;
+ var calleeTrans = priorReceive[1];
+ var recvTs = priorReceive[0];
var slice = kthread.thread.sliceGroup.pushCompleteSlice('binder',
- '', recv_ts, ts - recv_ts, 0, 0, args);
+ '', recvTs, ts - recvTs, 0, 0, args);
- var flow = this.generateFlow(callee_slice, slice, callee_trans, trans);
+ var flow = this.generateFlow(calleeSlice, slice, calleeTrans, trans);
this.model_.flowEvents.push(flow);
trans.slice = slice;
@@ -523,7 +521,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* a sync transaction.
*/
this.addSyncTransNeedingCompletion(trans.transaction_key,
- [callee_trans, trans]);
+ [calleeTrans, trans]);
} else {
/**
* Recursive calls and or calls around, either way it's not
@@ -542,8 +540,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
slice = kthread.thread.sliceGroup.
pushCompleteSlice('binder',
'binder transaction',
- recv_ts,
- (ts - recv_ts), 0,
+ recvTs,
+ (ts - recvTs), 0,
0, args);
/* could be a async trans if so set the length to be a small one */
@@ -563,7 +561,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
}
trans1.slice = slice;
this.addRecursiveSyncTransNeedingCompletion(pid,
- [callee_trans, trans]);
+ [calleeTrans, trans]);
this.addTransactionWaitingForRecv(trans.transaction_key, trans1);
}
return true;
@@ -642,12 +640,12 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
this.transWaitingRecv[transactionkey] = transaction;
},
- generateFlow: function(from, to, from_trans, to_trans) {
+ generateFlow: function(from, to, fromTrans, toTrans) {
var title = 'Transaction from : ' +
- this.pid2name(from_trans.calling_pid) +
- ' From PID: ' + from_trans.calling_pid + ' to pid: ' +
- to_trans.calling_pid +
- ' Thread Name: ' + this.pid2name(to_trans.calling_pid);
+ this.pid2name(fromTrans.calling_pid) +
+ ' From PID: ' + fromTrans.calling_pid + ' to pid: ' +
+ toTrans.calling_pid +
+ ' Thread Name: ' + this.pid2name(toTrans.calling_pid);
var ts = from.start;
var flow = new tr.model.FlowEvent('binder', 'binder',
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
index 513279adbea..9365df1ea5b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
@@ -107,14 +107,14 @@ tr.b.unittest.testSuite(function() {
assert.equal(thread.sliceGroup.length, 2);
/* check flow events for service manager */
- var main_slice = thread.sliceGroup.slices[0];
- assert.equal(main_slice.inFlowEvents.length, 1);
- assert.equal(main_slice.outFlowEvents.length, 1);
- var internal_slice = thread.sliceGroup.slices[1];
- assert.equal(internal_slice.outFlowEvents.length, 1);
+ var mainSlice = thread.sliceGroup.slices[0];
+ assert.equal(mainSlice.inFlowEvents.length, 1);
+ assert.equal(mainSlice.outFlowEvents.length, 1);
+ var internalSlice = thread.sliceGroup.slices[1];
+ assert.equal(internalSlice.outFlowEvents.length, 1);
/* check name of slice */
- assert.equal(main_slice.title, 'binder reply');
+ assert.equal(mainSlice.title, 'binder reply');
/* check binderLibTest */
thread = threads[1];
@@ -124,13 +124,13 @@ tr.b.unittest.testSuite(function() {
assert.equal(2, thread.sliceGroup.length);
- main_slice = thread.sliceGroup.slices[0];
- assert.equal(main_slice.inFlowEvents.length, 1);
- assert.equal(main_slice.outFlowEvents.length, 1);
- internal_slice = thread.sliceGroup.slices[1];
- assert.equal(internal_slice.inFlowEvents.length, 1);
+ mainSlice = thread.sliceGroup.slices[0];
+ assert.equal(mainSlice.inFlowEvents.length, 1);
+ assert.equal(mainSlice.outFlowEvents.length, 1);
+ internalSlice = thread.sliceGroup.slices[1];
+ assert.equal(internalSlice.inFlowEvents.length, 1);
- assert.equal(main_slice.title, 'binder transaction');
+ assert.equal(mainSlice.title, 'binder transaction');
/* check Binder_4 */
thread = threads[2];
@@ -139,13 +139,13 @@ tr.b.unittest.testSuite(function() {
assert.equal(thread.name, 'Binder_4');
assert.equal(2, thread.sliceGroup.length);
- main_slice = thread.sliceGroup.slices[0];
- assert.equal(main_slice.inFlowEvents.length, 1);
- assert.equal(main_slice.outFlowEvents.length, 1);
- internal_slice = thread.sliceGroup.slices[1];
- assert.equal(internal_slice.outFlowEvents.length, 1);
+ mainSlice = thread.sliceGroup.slices[0];
+ assert.equal(mainSlice.inFlowEvents.length, 1);
+ assert.equal(mainSlice.outFlowEvents.length, 1);
+ internalSlice = thread.sliceGroup.slices[1];
+ assert.equal(internalSlice.outFlowEvents.length, 1);
- assert.equal(main_slice.title, 'binder reply');
+ assert.equal(mainSlice.title, 'binder reply');
/* check last binderLibTest with recursive slices */
thread = threads[3];
@@ -154,29 +154,29 @@ tr.b.unittest.testSuite(function() {
assert.equal(thread.name, 'binderLibTest');
assert.equal(6, thread.sliceGroup.length);
- main_slice = thread.sliceGroup.slices[0];
- assert.equal(main_slice.inFlowEvents.length, 1);
- assert.equal(main_slice.outFlowEvents.length, 1);
- internal_slice = thread.sliceGroup.slices[5];
- assert.equal(internal_slice.outFlowEvents.length, 1);
+ mainSlice = thread.sliceGroup.slices[0];
+ assert.equal(mainSlice.inFlowEvents.length, 1);
+ assert.equal(mainSlice.outFlowEvents.length, 1);
+ internalSlice = thread.sliceGroup.slices[5];
+ assert.equal(internalSlice.outFlowEvents.length, 1);
- assert.equal(main_slice.title, 'binder reply');
+ assert.equal(mainSlice.title, 'binder reply');
var recursive = thread.sliceGroup.slices[1];
- var recursive_internal = thread.sliceGroup.slices[2];
+ var recursiveInternal = thread.sliceGroup.slices[2];
assert.equal(recursive.inFlowEvents.length, 1);
assert.equal(recursive.outFlowEvents.length, 1);
- assert.equal(recursive_internal.inFlowEvents.length, 1);
+ assert.equal(recursiveInternal.inFlowEvents.length, 1);
assert.equal(recursive.title, 'binder transaction');
/* check second recursive slice and internal */
var recursive = thread.sliceGroup.slices[3];
- var recursive_internal = thread.sliceGroup.slices[4];
+ var recursiveInternal = thread.sliceGroup.slices[4];
assert.equal(recursive.inFlowEvents.length, 1);
assert.equal(recursive.outFlowEvents.length, 1);
- assert.equal(recursive_internal.inFlowEvents.length, 1);
+ assert.equal(recursiveInternal.inFlowEvents.length, 1);
assert.equal(recursive.title, 'binder transaction');
});
@@ -222,4 +222,3 @@ tr.b.unittest.testSuite(function() {
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser.html
index 55d80730405..d3ac9837afb 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/parser.html">
<link rel="import" href="/tracing/model/counter_series.html">
@@ -43,17 +44,23 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var event = re.exec(eventBase.details);
var name = event[1];
- var rw_bytes = parseInt(event[2]);
- var r_bytes = parseInt(event[3]);
- var w_bytes = parseInt(event[4]);
+ var rwBytes = parseInt(event[2]);
+ var rBytes = parseInt(event[3]);
+ var wBytes = parseInt(event[4]);
var cycles = parseInt(event[5]);
var ns = parseInt(event[6]);
- // BW in MB/s
- var r_bw = r_bytes * 1000000000 / ns;
- r_bw /= 1024 * 1024;
- var w_bw = w_bytes * 1000000000 / ns;
- w_bw /= 1024 * 1024;
+ // BW in MiB/s.
+ var sec = tr.b.convertUnit(ns, tr.b.UnitScale.Metric.NANO,
+ tr.b.UnitScale.Metric.NONE);
+ var readBandwidthInBps = rBytes / sec;
+ var readBandwidthInMiBps = tr.b.convertUnit(readBandwidthInBps,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI);
+ var writeBandwidthInBps = wBytes / sec;
+ var writeBandwidthInMiBps = tr.b.convertUnit(writeBandwidthInBps,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI);
var ctr = this.model_.kernel
.getOrCreateCounter(null, 'bus ' + name + ' read');
@@ -63,7 +70,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
ctr.name + '.' + 'value')));
}
ctr.series.forEach(function(series) {
- series.addCounterSample(ts, r_bw);
+ series.addCounterSample(ts, readBandwidthInMiBps);
});
ctr = this.model_.kernel
@@ -74,7 +81,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
ctr.name + '.' + 'value')));
}
ctr.series.forEach(function(series) {
- series.addCounterSample(ts, r_bw);
+ series.addCounterSample(ts, writeBandwidthInMiBps);
});
return true;
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser.html
index cd7f357c8e5..8845abc0f0f 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser.html
@@ -62,7 +62,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
// TODO(sleffler) should be per-cpu
var kthread = this.importer.getOrCreatePseudoThread('cpufreq');
kthread.openSlice = eventName;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
@@ -72,7 +72,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
cpufreqBoostSlice: function(ts, eventName, args) {
var kthread = this.importer.getOrCreatePseudoThread('cpufreq_boost');
kthread.openSlice = eventName;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser.html
index bbbeae733f3..7e223467fc3 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser.html
@@ -55,7 +55,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var kthread = this.importer.getOrCreateKernelThread(
category + ':' + threadName, pid);
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(
+ tr.model.AsyncSlice.subTypes.getConstructor(
category, name);
var slice = new asyncSliceConstructor(
category, name,
@@ -207,7 +207,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var device = event[1];
var inode = parseInt(event[2]);
- var datasync = event[4] == 1;
+ var datasync = (event[4] === '1') || (event[4] === 1);
var key = device + '-' + inode;
var action = datasync ? 'fdatasync' : 'fsync';
this.openAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
@@ -261,16 +261,16 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (event[2]) {
action += ' flush';
}
- if (event[4] == 'F') {
+ if (event[4] === 'F') {
action += ' fua';
}
- if (event[5] == 'A') {
+ if (event[5] === 'A') {
action += ' ahead';
}
- if (event[6] == 'S') {
+ if (event[6] === 'S') {
action += ' sync';
}
- if (event[7] == 'M') {
+ if (event[7] === 'M') {
action += ' meta';
}
var device = event[1];
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser.html
index 78dd9515f25..163ba066944 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser.html
@@ -35,7 +35,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
drmVblankSlice: function(ts, eventName, args) {
var kthread = this.importer.getOrCreatePseudoThread('drm_vblank');
kthread.openSlice = eventName;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser.html
index e573b8d25a1..e0e8975f67b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser.html
@@ -85,7 +85,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var kthread = this.importer.getOrCreatePseudoThread(
'exynos_flip_state (pipe:' + pipe + ', fb:' + fb + ')');
if (kthread.openSlice) {
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
kthread.openSliceTS,
args,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
index c27e7c65a93..1e5d16cd1db 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
@@ -67,8 +67,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(threads.length, 2);
// in the test data, event of fb=26 occurs first, so it's thread[0]
- var gfxFbId26Thread = threads[0]; // thread where fb == 26
- var gfxFbId25Thread = threads[1]; // thread where fb == 25
+ var gfxFbId26Thread = threads[0]; // thread where fb === 26
+ var gfxFbId25Thread = threads[1]; // thread where fb === 25
assert.equal(gfxFbId25Thread.name, 'exynos_flip_state (pipe:0, fb:25)');
assert.equal(gfxFbId26Thread.name, 'exynos_flip_state (pipe:0, fb:26)');
// Every state (except for 'flipped') will start a new slice.
@@ -114,8 +114,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(threads.length, 2);
// in the test data, event of fb=26 occurs first, so it's thread[0]
- var gfxFbId26Thread = threads[0]; // thread where fb == 26
- var gfxFbId25Thread = threads[1]; // thread where fb == 25
+ var gfxFbId26Thread = threads[0]; // thread where fb === 26
+ var gfxFbId25Thread = threads[1]; // thread where fb === 25
assert.equal(gfxFbId25Thread.name, 'exynos_flip_state (pipe:0, fb:25)');
assert.equal(gfxFbId26Thread.name, 'exynos_flip_state (pipe:0, fb:26)');
// Every state (except for 'flipped') will start a new slice.
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer.html
index 477223b1640..2e83145cf98 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer.html
@@ -16,6 +16,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/extras/importer/linux_perf/drm_parser.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/exynos_parser.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/gesture_parser.html">
+<link rel="import" href="/tracing/extras/importer/linux_perf/i2c_parser.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/i915_parser.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/irq_parser.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/kfunc_parser.html">
@@ -60,7 +61,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
this.model_ = model;
this.events_ = events;
this.wakeups_ = [];
- this.blocked_reasons_ = [];
+ this.blockedReasons_ = [];
this.kernelThreadStates_ = {};
this.buildMapFromLinuxPidsToThreads_();
this.lines_ = [];
@@ -152,7 +153,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
TestExports.traceEventClockSyncRE = traceEventClockSyncRE;
var realTimeClockSyncRE = /trace_event_clock_sync: realtime_ts=(\d+)/;
- var genericClockSyncRE = /trace_event_clock_sync: name=(\w+)/;
+ var genericClockSyncRE = /trace_event_clock_sync: name=([\w\-]+)/;
// Some kernel trace events are manually classified in slices and
// hand-assigned a pseudo PID.
@@ -167,7 +168,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* recognized; otherwise undefined.
*/
function autoDetectLineParser(line) {
- if (line[0] == '{')
+ if (line[0] === '{')
return false;
if (lineREWithTGID.test(line))
return lineParserWithTGID;
@@ -176,7 +177,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (lineREWithLegacyFmt.test(line))
return lineParserWithLegacyFmt;
return undefined;
- };
+ }
TestExports.autoDetectLineParser = autoDetectLineParser;
/**
@@ -211,14 +212,14 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
};
FTraceImporter._extractEventsFromSystraceHTML = function(
- incoming_events, produce_result) {
+ incomingEvents, produceResult) {
var failure = {ok: false};
- if (produce_result === undefined)
- produce_result = true;
+ if (produceResult === undefined)
+ produceResult = true;
- if (/^<!DOCTYPE html>/.test(incoming_events) == false)
+ if (!/^<!DOCTYPE html>/.test(incomingEvents))
return failure;
- var r = new tr.importer.SimpleLineReader(incoming_events);
+ var r = new tr.importer.SimpleLineReader(incomingEvents);
// Try to find the data...
if (!r.advanceToLineMatching(/^ <script>$/))
@@ -226,15 +227,15 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (!r.advanceToLineMatching(/^ var linuxPerfData = "\\$/))
return failure;
- var events_begin_at_line = r.curLineNumber + 1;
+ var eventsBeginAtLine = r.curLineNumber + 1;
r.beginSavingLines();
if (!r.advanceToLineMatching(/^ <\/script>$/))
return failure;
- var raw_events = r.endSavingLinesAndGetResult();
+ var rawEvents = r.endSavingLinesAndGetResult();
// Drop off first and last event as it contains the tag.
- raw_events = raw_events.slice(1, raw_events.length - 1);
+ rawEvents = rawEvents.slice(1, rawEvents.length - 1);
if (!r.advanceToLineMatching(/^<\/body>$/))
return failure;
@@ -252,39 +253,39 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
// Strip off escaping in the file needed to preserve linebreaks.
var events = [];
- if (produce_result) {
- for (var i = 0; i < raw_events.length; i++) {
- var event = raw_events[i];
+ if (produceResult) {
+ for (var i = 0; i < rawEvents.length; i++) {
+ var event = rawEvents[i];
event = stripSuffix(event, '\\n\\');
events.push(event);
}
} else {
- events = [raw_events[raw_events.length - 1]];
+ events = [rawEvents[rawEvents.length - 1]];
}
// Last event ends differently. Strip that off too,
// treating absence of that trailing string as a failure.
var oldLastEvent = events[events.length - 1];
var newLastEvent = stripSuffix(oldLastEvent, '\\n";');
- if (newLastEvent == oldLastEvent)
+ if (newLastEvent === oldLastEvent)
return failure;
events[events.length - 1] = newLastEvent;
return {ok: true,
- lines: produce_result ? events : undefined,
- events_begin_at_line: events_begin_at_line};
+ lines: produceResult ? events : undefined,
+ eventsBeginAtLine: eventsBeginAtLine};
};
FTraceImporter._extractEventsFromSystraceMultiHTML = function(
- incoming_events, produce_result) {
+ incomingEvents, produceResult) {
var failure = {ok: false};
- if (produce_result === undefined)
- produce_result = true;
+ if (produceResult === undefined)
+ produceResult = true;
- if (new RegExp('^<!DOCTYPE HTML>', 'i').test(incoming_events) == false)
+ if (!(new RegExp('^<!DOCTYPE HTML>', 'i').test(incomingEvents)))
return failure;
- var r = new tr.importer.SimpleLineReader(incoming_events);
+ var r = new tr.importer.SimpleLineReader(incomingEvents);
// Try to find the Linux perf trace in any of the trace-data tags
var events = [];
@@ -293,7 +294,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
/^ <script class="trace-data" type="application\/text">$/))
return failure;
- var events_begin_at_line = r.curLineNumber + 1;
+ var eventsBeginAtLine = r.curLineNumber + 1;
r.beginSavingLines();
if (!r.advanceToLineMatching(/^ <\/script>$/))
@@ -311,8 +312,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
return failure;
return {ok: true,
- lines: produce_result ? events : undefined,
- events_begin_at_line: events_begin_at_line};
+ lines: produceResult ? events : undefined,
+ eventsBeginAtLine: eventsBeginAtLine};
};
FTraceImporter.prototype = {
@@ -455,7 +456,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
// pids, which identify threads. The rest of trace-viewer refers to
// these as tids, so the change of nomenclature happens in the following
// construction of the wakeup object.
- this.blocked_reasons_.push({ts: ts, tid: pid, iowait: iowait,
+ this.blockedReasons_.push({ts: ts, tid: pid, iowait: iowait,
caller: caller});
},
@@ -509,8 +510,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
thread.tempWakeups = thread.tempWakeups || [];
thread.tempWakeups.push(wakeup);
}
- for (var i in this.blocked_reasons_) {
- var reason = this.blocked_reasons_[i];
+ for (var i in this.blockedReasons_) {
+ var reason = this.blockedReasons_[i];
var thread = this.threadsByLinuxPid[reason.tid];
if (!thread)
continue;
@@ -575,14 +576,14 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
wakeup = w;
}
}
- var blocked_reason = undefined;
+ var blockedReason = undefined;
while (reasons.length && reasons[0].ts < prevSlice.end) {
var r = reasons.shift();
}
if (wakeup !== undefined &&
reasons.length &&
reasons[0].ts < wakeup.ts) {
- blocked_reason = reasons.shift();
+ blockedReason = reasons.shift();
}
// Push a sleep slice onto the slices list, interrupting it with a
@@ -592,11 +593,11 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
midDuration = wakeup.ts - prevSlice.end;
}
- if (blocked_reason !== undefined) {
+ if (blockedReason !== undefined) {
var args = {
- 'kernel callsite when blocked:' : blocked_reason.caller
+ 'kernel callsite when blocked:' : blockedReason.caller
};
- if (blocked_reason.iowait) {
+ if (blockedReason.iowait) {
switch (state) {
case SCHEDULING_STATE.UNINTR_SLEEP:
state = SCHEDULING_STATE.UNINTR_SLEEP_IO;
@@ -628,46 +629,46 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
}
};
- if (prevSlice.args.stateWhenDescheduled == 'S') {
+ if (prevSlice.args.stateWhenDescheduled === 'S') {
pushSleep(SCHEDULING_STATE.SLEEPING);
- } else if (prevSlice.args.stateWhenDescheduled == 'R' ||
- prevSlice.args.stateWhenDescheduled == 'R+') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'R' ||
+ prevSlice.args.stateWhenDescheduled === 'R+') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.RUNNABLE, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'D') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'D') {
pushSleep(SCHEDULING_STATE.UNINTR_SLEEP);
- } else if (prevSlice.args.stateWhenDescheduled == 'T') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'T') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.STOPPED, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 't') {
+ } else if (prevSlice.args.stateWhenDescheduled === 't') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.DEBUG, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'Z') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'Z') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.ZOMBIE, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'X') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'X') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.EXIT_DEAD, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'x') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'x') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.TASK_DEAD, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'K') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'K') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.WAKE_KILL, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'W') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'W') {
slices.push(new tr.model.ThreadTimeSlice(
thread, SCHEDULING_STATE.WAKING, '',
prevSlice.end, {}, midDuration));
- } else if (prevSlice.args.stateWhenDescheduled == 'D|K') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'D|K') {
pushSleep(SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL);
- } else if (prevSlice.args.stateWhenDescheduled == 'D|W') {
+ } else if (prevSlice.args.stateWhenDescheduled === 'D|W') {
pushSleep(SCHEDULING_STATE.UNINTR_SLEEP_WAKING);
} else {
slices.push(new tr.model.ThreadTimeSlice(
@@ -729,6 +730,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
// sync ID and the current time according to the "ftrace global" clock.
var event = /name=(\w+?)\s(.+)/.exec(eventBase.details);
if (event) {
+ // TODO(alexandermont): This section of code seems to be broken. It
+ // creates an "args" variable, but doesn't seem to do anything with it.
var name = event[1];
var pieces = event[2].split(' ');
var args = {
@@ -736,7 +739,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
};
for (var i = 0; i < pieces.length; i++) {
var parts = pieces[i].split('=');
- if (parts.length != 2)
+ if (parts.length !== 2)
throw new Error('omgbbq');
args[parts[0]] = parts[1];
}
@@ -746,6 +749,15 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
return true;
}
+ // Check to see if we have a "new style" clock sync marker that contains
+ // only a sync ID.
+ var event = /name=([\w\-]+)/.exec(eventBase.details);
+ if (event) {
+ this.model_.clockSyncManager.addClockSyncMarker(
+ tr.model.ClockDomainId.LINUX_FTRACE_GLOBAL, event[1], ts);
+ return true;
+ }
+
// Check to see if we have a special clock sync marker that contains both
// the current "ftrace global" time and the current CLOCK_MONOTONIC time.
event = /parent_ts=(\d+\.?\d*)/.exec(eventBase.details);
@@ -792,8 +804,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (!event) {
// Check if the event matches events traced by the Android framework
var tag = eventBase.details.substring(0, 2);
- if (tag == 'B|' || tag == 'E' || tag == 'E|' || tag == 'X|' ||
- tag == 'C|' || tag == 'S|' || tag == 'F|') {
+ if (tag === 'B|' || tag === 'E' || tag === 'E|' || tag === 'X|' ||
+ tag === 'C|' || tag === 'S|' || tag === 'F|') {
eventBase.subEventName = 'android';
} else {
return false;
@@ -855,7 +867,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var lineParser = undefined;
for (var lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
var line = lines[lineNumber].trim();
- if (line.length == 0 || /^#/.test(line))
+ if (line.length === 0 || /^#/.test(line))
continue;
if (!lineParser) {
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser.html
index f2c3924867b..42d2d7ebecf 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser.html
@@ -50,7 +50,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var thread = this.importer.getOrCreatePseudoThread('gesture').thread;
if (thread.sliceGroup.openSliceCount) {
var slice = thread.sliceGroup.mostRecentlyOpenedPartialSlice;
- if (slice.title != title) {
+ if (slice.title !== title) {
this.importer.model.importWarning({
type: 'title_match_error',
message: 'Titles do not match. Title is ' +
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser.html
new file mode 100644
index 00000000000..d6e3cac93db
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/importer/linux_perf/parser.html">
+
+<script>
+'use strict';
+
+/**
+ * @fileoverview Parses i2c driver events in the Linux event trace format.
+ */
+tr.exportTo('tr.e.importer.linux_perf', function() {
+
+ var ColorScheme = tr.b.ColorScheme;
+ var Parser = tr.e.importer.linux_perf.Parser;
+
+ /**
+ * Parses linux i2c trace events.
+ * @constructor
+ */
+ function I2cParser(importer) {
+ Parser.call(this, importer);
+
+ importer.registerEventHandler('i2c_write',
+ I2cParser.prototype.i2cWriteEvent.bind(this));
+ importer.registerEventHandler('i2c_read',
+ I2cParser.prototype.i2cReadEvent.bind(this));
+ importer.registerEventHandler('i2c_reply',
+ I2cParser.prototype.i2cReplyEvent.bind(this));
+ importer.registerEventHandler('i2c_result',
+ I2cParser.prototype.i2cResultEvent.bind(this));
+ }
+
+ // Matches the i2c_write and i2c_reply records
+ var i2cWriteReplyRE = new RegExp(
+ 'i2c-(\\d+) #(\\d+) a=([\\da-fA-F]+) f=([\\da-fA-F]+) l=(\\d+) ' +
+ '(\\[[\\da-fA-F\\-]+\\])');
+ // Matches the i2c_read record
+ var i2cReadRE = /i2c-(\d+) #(\d+) a=([\da-fA-F]+) f=([\da-fA-F]+) l=(\d+)/;
+ // Matches the i2c_result record
+ var i2cResultRE = /i2c-(\d+) n=(\d+) ret=(\d+)/;
+
+ I2cParser.prototype = {
+ __proto__: Parser.prototype,
+
+ /**
+ * Parses i2c events and sets up state in the importer.
+ */
+ i2cWriteEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
+ var event = i2cWriteReplyRE.exec(eventBase.details);
+ if (!event)
+ return false;
+
+ var adapterNumber = parseInt(event[1]);
+ var messageNumber = event[2];
+ var address = event[3];
+ var flags = event[4];
+ var dataLength = event[5];
+ var data = event[6];
+ var thread = this.importer.getOrCreatePseudoThread(
+ 'i2c adapter ' + adapterNumber);
+
+ pushLastSliceIfNeeded(thread, event[1], ts);
+
+ thread.lastEntryTitle = 'i2c write';
+ thread.lastEntryTs = ts;
+ thread.lastEntryArgs = {
+ 'Message number': messageNumber,
+ 'Address': address,
+ 'Flags': flags,
+ 'Data Length': dataLength,
+ 'Data': data
+ };
+
+ return true;
+ },
+
+ i2cReadEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
+ var event = i2cReadRE.exec(eventBase.details);
+ if (!event)
+ return false;
+
+ var adapterNumber = parseInt(event[1]);
+ var messageNumber = event[2];
+ var address = event[3];
+ var flags = event[4];
+ var dataLength = event[5];
+ var thread = this.importer.getOrCreatePseudoThread(
+ 'i2c adapter ' + adapterNumber);
+
+ pushLastSliceIfNeeded(thread, event[1], ts);
+
+ thread.lastEntryTitle = 'i2c read';
+ thread.lastEntryTs = ts;
+ thread.lastEntryArgs = {
+ 'Message number': messageNumber,
+ 'Address': address,
+ 'Flags': flags,
+ 'Data Length': dataLength
+ };
+
+ return true;
+ },
+
+ i2cReplyEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
+ var event = i2cWriteReplyRE.exec(eventBase.details);
+ if (!event)
+ return false;
+
+ var adapterNumber = parseInt(event[1]);
+ var messageNumber = event[2];
+ var address = event[3];
+ var flags = event[4];
+ var dataLength = event[5];
+ var data = event[6];
+ var thread = this.importer.getOrCreatePseudoThread(
+ 'i2c adapter ' + adapterNumber);
+
+ pushLastSliceIfNeeded(thread, event[1], ts);
+
+ thread.lastEntryTitle = 'i2c reply';
+ thread.lastEntryTs = ts;
+ thread.lastEntryArgs = {
+ 'Message number': messageNumber,
+ 'Address': address,
+ 'Flags': flags,
+ 'Data Length': dataLength,
+ 'Data': data
+ };
+
+ return true;
+ },
+
+ i2cResultEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
+ var event = i2cResultRE.exec(eventBase.details);
+ if (!event)
+ return false;
+
+ var adapterNumber = parseInt(event[1]);
+ var numMessages = event[2];
+ var ret = event[3];
+ var thread = this.importer.getOrCreatePseudoThread(
+ 'i2c adapter ' + adapterNumber);
+
+ var args = thread.lastEntryArgs;
+ if (args !== undefined) {
+ args['Number of messages'] = numMessages;
+ args['Return'] = ret;
+ }
+
+ pushLastSliceIfNeeded(thread, event[1], ts);
+
+ thread.lastEntryTitle = undefined;
+ thread.lastEntryTs = undefined;
+ thread.lastEntryArgs = undefined;
+
+ return true;
+ },
+ };
+
+ function pushLastSliceIfNeeded(thread, id, currentTs) {
+ if (thread.lastEntryTs !== undefined) {
+ var duration = currentTs - thread.lastEntryTs;
+ var slice = new tr.model.ThreadSlice(
+ '', thread.lastEntryTitle,
+ ColorScheme.getColorIdForGeneralPurposeString(id),
+ thread.lastEntryTs, thread.lastEntryArgs, duration);
+ thread.thread.sliceGroup.pushSlice(slice);
+ }
+ }
+
+ Parser.register(I2cParser);
+
+ return {
+ I2cParser: I2cParser
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser_test.html
new file mode 100644
index 00000000000..156a50ba767
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i2c_parser_test.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('i2cImport', function() {
+ var lines = [
+
+ ' /system/bin/surfaceflinger-516 ( 516) [002] ...1 6481.291425: ' +
+ 'i2c_write: i2c-3 #0 a=020 f=0000 l=2 [15-00]',
+ ' /system/bin/surfaceflinger-516 ( 516) [002] ...1 6481.291602: ' +
+ 'i2c_result: i2c-3 n=1 ret=1',
+ ' kworker/u8:5-9309 ( 9309) [001] ...1 6481.365821: ' +
+ 'i2c_write: i2c-7 #0 a=01d f=0000 l=1 [00]',
+ ' kworker/u8:5-9309 ( 9309) [001] ...1 6481.365823: ' +
+ 'i2c_read: i2c-7 #1 a=01d f=0001 l=1',
+ ' kworker/u8:5-9309 ( 9309) [001] ...1 6481.366730: ' +
+ 'i2c_reply: i2c-7 #1 a=01d f=0001 l=1 [01]',
+ ' kworker/u8:5-9309 ( 9309) [001] ...1 6481.366732: ' +
+ 'i2c_result: i2c-7 n=2 ret=2'
+ ];
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
+ shiftWorldToZero: false
+ });
+ var warnings = m.importWarnings;
+ for (var i = 0; i < warnings.length; i++) {
+ console.log(warnings[i]);
+ }
+ assert.isFalse(m.hasImportWarnings);
+
+ var threads = m.getAllThreads();
+ assert.equal(threads.length, 2);
+
+ var threads = m.findAllThreadsNamed('i2c adapter 3');
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].sliceGroup.length, 1);
+ var slice = threads[0].sliceGroup.slices[0];
+ assert.equal(slice.title, 'i2c write');
+ assert.isDefined(slice.args);
+ assert.equal(slice.args['Message number'], '0');
+ assert.equal(slice.args['Address'], '020');
+ assert.equal(slice.args['Flags'], '0000');
+ assert.equal(slice.args['Data Length'], '2');
+ assert.equal(slice.args['Data'], '[15-00]');
+
+ var threads = m.findAllThreadsNamed('i2c adapter 7');
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].sliceGroup.length, 3);
+
+ var slice = threads[0].sliceGroup.slices[0];
+ assert.equal(slice.title, 'i2c write');
+ assert.equal(slice.args['Message number'], '0');
+ assert.equal(slice.args['Address'], '01d');
+ assert.equal(slice.args['Flags'], '0000');
+ assert.equal(slice.args['Data Length'], '1');
+ assert.equal(slice.args['Data'], '[00]');
+
+ slice = threads[0].sliceGroup.slices[1];
+ assert.equal(slice.title, 'i2c read');
+ assert.equal(slice.args['Message number'], '1');
+ assert.equal(slice.args['Address'], '01d');
+ assert.equal(slice.args['Flags'], '0001');
+ assert.equal(slice.args['Data Length'], '1');
+
+ slice = threads[0].sliceGroup.slices[2];
+ assert.equal(slice.title, 'i2c reply');
+ assert.equal(slice.args['Message number'], '1');
+ assert.equal(slice.args['Address'], '01d');
+ assert.equal(slice.args['Flags'], '0001');
+ assert.equal(slice.args['Data Length'], '1');
+ assert.equal(slice.args['Data'], '[01]');
+ assert.equal(slice.args['Number of messages'], '2');
+ assert.equal(slice.args['Return'], '2');
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser.html
index 91c733a0e11..e1c6334a28a 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser.html
@@ -86,7 +86,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
i915FlipCloseSlice: function(ts, args) {
var kthread = this.importer.getOrCreatePseudoThread('i915_flip');
if (kthread.openSlice) {
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
kthread.openSliceTS,
args,
@@ -100,7 +100,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
i915GemObjectSlice: function(ts, eventName, obj, args) {
var kthread = this.importer.getOrCreatePseudoThread('i915_gem');
kthread.openSlice = eventName + ':' + obj;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
@@ -110,7 +110,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
i915GemRingSlice: function(ts, eventName, dev, ring, args) {
var kthread = this.importer.getOrCreatePseudoThread('i915_gem_ring');
kthread.openSlice = eventName + ':' + dev + '.' + ring;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
@@ -120,7 +120,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
i915RegSlice: function(ts, eventName, reg, args) {
var kthread = this.importer.getOrCreatePseudoThread('i915_reg');
kthread.openSlice = eventName + ':' + reg;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
@@ -130,7 +130,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
i915FreqChangeSlice: function(ts, eventName, args) {
var kthread = this.importer.getOrCreatePseudoThread('i915_gpu_freq');
kthread.openSlice = eventName;
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
ts, args, 0);
@@ -337,7 +337,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var plane = parseInt(event[1]);
var obj = event[2];
- if (eventName == 'i915_flip_request')
+ if (eventName === 'i915_flip_request')
this.i915FlipOpenSlice(ts, obj, plane);
else
this.i915FlipCloseSlice(ts,
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser.html
index 24903ae3133..eeae99d836b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser.html
@@ -87,7 +87,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (thread.lastEntryTs !== undefined) {
var duration = ts - thread.lastEntryTs;
- var slice = new tr.model.Slice(
+ var slice = new tr.model.ThreadSlice(
'',
'IRQ (' + thread.irqName + ')',
ColorScheme.getColorIdForGeneralPurposeString(event[1]),
@@ -129,7 +129,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (thread.lastEntryTs !== undefined) {
var duration = ts - thread.lastEntryTs;
- var slice = new tr.model.Slice(
+ var slice = new tr.model.ThreadSlice(
'', action,
ColorScheme.getColorIdForGeneralPurposeString(event[1]),
thread.lastEntryTs, { vec: vec },
@@ -161,7 +161,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (thread.lastEntryTs !== undefined) {
var duration = ts - thread.lastEntryTs;
- var slice = new tr.model.Slice(
+ var slice = new tr.model.ThreadSlice(
'',
'IPI (' + ipiName + ')',
ColorScheme.getColorIdForGeneralPurposeString(ipiName),
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser.html
index 0516805f740..7cba16fcf6d 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser.html
@@ -278,9 +278,9 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
* gles/src/texture/mali_gles_texture_slave.c@1505:
*/
maliDDKEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
- if (this.lineRE == null) {
+ if (this.lineRE === null) {
this.lineRE = this.autoDetectLineRE(eventBase.details);
- if (this.lineRE == null)
+ if (this.lineRE === null)
return false;
}
var maliEvent = this.lineRE.exec(eventBase.details);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html
index c4b7f57f844..3c4c7bbbacd 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html
@@ -122,7 +122,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (!event)
return false;
- var nr_reclaimed = parseInt(event[1]);
+ var nrReclaimed = parseInt(event[1]);
var tgid = parseInt(eventBase.tgid);
var kthread = this.importer.getOrCreateKernelThread(
@@ -135,7 +135,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
{
order: kthread.order,
gfp: kthread.gfp,
- nr_reclaimed: nr_reclaimed
+ nr_reclaimed: nrReclaimed
});
}
kthread.openSliceTS = undefined;
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
index f6a10ecf47e..dcfb9992247 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
@@ -47,10 +47,10 @@ tr.b.unittest.testSuite(function() {
'Binder_8-1735 ( 1022) [001] ...1 1735.472849: mm_vmscan_direct_reclaim_end: nr_reclaimed=47', // @suppress longLineCheck
'Binder_8-1735 ( 1022) [001] ...1 1735.473002: mm_vmscan_direct_reclaim_begin: order=3 may_writepage=1 gfp_flags=GFP_KERNEL|GFP_NOWARN|0x2', // @suppress longLineCheck
'Binder_8-1735 ( 1022) [001] ...1 1735.474859: mm_vmscan_direct_reclaim_end: nr_reclaimed=48', // @suppress longLineCheck
- 'touch_fusion-88 ( 88) [000] ...1 1736.510656: mm_vmscan_direct_reclaim_begin: order=2 may_writepage=1 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_COMP|GFP_NOMEMALLOC|GFP_KMEMCG', // @suppress longLineCheck
- 'touch_fusion-88 ( 88) [000] ...1 1736.517616: mm_vmscan_direct_reclaim_end: nr_reclaimed=34', // @suppress longLineCheck
- 'touch_fusion-88 ( 88) [000] ...1 1736.527061: mm_vmscan_direct_reclaim_begin: order=2 may_writepage=1 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_COMP|GFP_NOMEMALLOC|GFP_KMEMCG', // @suppress longLineCheck
- 'touch_fusion-88 ( 88) [000] ...1 1736.530857: mm_vmscan_direct_reclaim_end: nr_reclaimed=39'// @suppress longLineCheck
+ 'touchFusion-88 ( 88) [000] ...1 1736.510656: mm_vmscan_direct_reclaim_begin: order=2 may_writepage=1 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_COMP|GFP_NOMEMALLOC|GFP_KMEMCG', // @suppress longLineCheck
+ 'touchFusion-88 ( 88) [000] ...1 1736.517616: mm_vmscan_direct_reclaim_end: nr_reclaimed=34', // @suppress longLineCheck
+ 'touchFusion-88 ( 88) [000] ...1 1736.527061: mm_vmscan_direct_reclaim_begin: order=2 may_writepage=1 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_COMP|GFP_NOMEMALLOC|GFP_KMEMCG', // @suppress longLineCheck
+ 'touchFusion-88 ( 88) [000] ...1 1736.530857: mm_vmscan_direct_reclaim_end: nr_reclaimed=39'// @suppress longLineCheck
];
var m = newModel(lines.join('\n'));
@@ -60,21 +60,21 @@ tr.b.unittest.testSuite(function() {
assert.equal(threads.length, 3);
- var Binder_8 = threads[0];
- var touch_fusion = threads[1];
+ var Binder8 = threads[0];
+ var touchFusion = threads[1];
var RenderThread = threads[2];
/* make sure there are the expected amount of slices per thread */
- assert.equal(Binder_8.sliceGroup.length, 2);
- assert.equal(touch_fusion.sliceGroup.length, 2);
+ assert.equal(Binder8.sliceGroup.length, 2);
+ assert.equal(touchFusion.sliceGroup.length, 2);
assert.equal(RenderThread.sliceGroup.length, 4);
/* make sure the slices have information to display to the
* user when selected
*/
- var iterate_me = [Binder_8, touch_fusion, RenderThread];
- iterate_me.forEach(function(thread) {
+ var iterateMe = [Binder8, touchFusion, RenderThread];
+ iterateMe.forEach(function(thread) {
for (var i = 0; i < thread.sliceGroup.length; i++) {
assert.equal(thread.sliceGroup.slices[i].args !== undefined, true);
}
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/power_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/power_parser.html
index c6d01a26d05..228132173c3 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/power_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/power_parser.html
@@ -46,7 +46,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
cpuStateSlice: function(ts, targetCpuNumber, eventType, cpuState) {
var targetCpu = this.importer.getOrCreateCpu(targetCpuNumber);
var powerCounter;
- if (eventType != '1') {
+ if (eventType !== '1') {
this.importer.model.importWarning({
type: 'parse_error',
message: 'Don\'t understand power_start events of ' +
@@ -73,7 +73,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name)));
}
// NB: 4294967295/-1 means an exit from the current state
- var val = (cpuState != 4294967295 ? cpuState + 1 : 0);
+ var val = (cpuState !== 4294967295 ? cpuState + 1 : 0);
powerCounter.series.forEach(function(series) {
series.addCounterSample(ts, val);
});
@@ -106,9 +106,9 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
powerCounter.name + '.' + 'Max Frequency')));
}
powerCounter.series.forEach(function(series) {
- if (series.name == 'Min Frequency')
+ if (series.name === 'Min Frequency')
series.addCounterSample(ts, minFreq);
- if (series.name == 'Max Frequency')
+ if (series.name === 'Max Frequency')
series.addCounterSample(ts, maxFreq);
});
},
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser.html
index 08ad46aed4b..b3fa3788160 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser.html
@@ -119,7 +119,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
powerCounter.name + '.' + 'State')));
}
powerCounter.series.forEach(function(series) {
- if (series.name == 'State')
+ if (series.name === 'State')
series.addCounterSample(ts, state.localeCompare('offline') ? 0 : 1);
});
return true;
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser.html
index ce6afe7179a..e5e3228aa59 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser.html
@@ -58,9 +58,9 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
if (thread.lastActiveTs !== undefined) {
var duration = ts - thread.lastActiveTs;
var value = thread.lastActiveValue;
- if (value == undefined)
+ if (value === undefined)
value = ' ';
- var slice = new tr.model.Slice(
+ var slice = new tr.model.ThreadSlice(
'', value,
ColorScheme.getColorIdForGeneralPurposeString(value),
thread.lastActiveTs, {},
@@ -96,11 +96,11 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
}
var name = 'fence_wait("' + event[2] + '")';
- if (event[1] == 'begin') {
+ if (event[1] === 'begin') {
var slice = slices.beginSlice(null, name, ts, {
'Start state': event[3]
});
- } else if (event[1] == 'end') {
+ } else if (event[1] === 'end') {
if (slices.openSliceCount > 0) {
slices.endSlice(ts);
}
@@ -112,16 +112,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
},
syncPtEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
- var event = syncPtRE.exec(eventBase.details);
- if (!event)
- return false;
-
- return true;
-
- var thread = this.importer.getOrCreateKernelThread(
- eventBase[1]).thread;
- thread.syncWaitSyncPts[event[1]] = event[2];
- return true;
+ return !!syncPtRE.exec(eventBase.details);
}
};
@@ -132,4 +123,3 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser.html
index ab71565b6b4..b9579422ed0 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser.html
@@ -69,7 +69,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() {
var kthread = this.importer.getOrCreateKernelThread(eventBase.threadName,
pid, pid);
if (kthread.openSlice) {
- var slice = new tr.model.Slice('', kthread.openSlice,
+ var slice = new tr.model.ThreadSlice('', kthread.openSlice,
ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),
kthread.openSliceTS,
{},
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer.html
index 14854745eb4..dd0cf112a47 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer.html
@@ -38,11 +38,11 @@ tr.exportTo('tr.e.importer', function() {
if (!r.advanceToLineMatching(/^<\/\s*script>$/))
return;
- var raw_events = r.endSavingLinesAndGetResult();
+ var rawEvents = r.endSavingLinesAndGetResult();
// Drop off first and last event as it contains the end script tag.
- raw_events = raw_events.slice(1, raw_events.length - 1);
- var data64 = raw_events.join('\n');
+ rawEvents = rawEvents.slice(1, rawEvents.length - 1);
+ var data64 = rawEvents.join('\n');
var buffer = new ArrayBuffer(
tr.b.Base64.getDecodedBufferLength(data64));
var len = tr.b.Base64.DecodeToTypedArray(data64, new DataView(buffer));
@@ -51,7 +51,7 @@ tr.exportTo('tr.e.importer', function() {
}
function _canImportFromHTML(text) {
- if (/^<!DOCTYPE html>/.test(text) === false)
+ if (!/^<!DOCTYPE html>/.test(text))
return false;
// Try to find viewer-data...
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer_test.html
index 8d91c1494a7..26eb0e4c87b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace2html_importer_test.html
@@ -15,7 +15,7 @@ tr.b.unittest.testSuite(function() {
var Base64 = tr.b.Base64;
test('simple', function() {
- var html_lines = [
+ var htmlLines = [
'<!DOCTYPE html>',
'<script id="viewer-data" type="application/json">',
Base64.btoa('hello'),
@@ -25,11 +25,11 @@ tr.b.unittest.testSuite(function() {
'<\/script>',
'</html>'
];
- var html_text = html_lines.join('\n');
- assert.isTrue(tr.e.importer.Trace2HTMLImporter.canImport(html_text));
+ var htmlText = htmlLines.join('\n');
+ assert.isTrue(tr.e.importer.Trace2HTMLImporter.canImport(htmlText));
var m = new tr.Model();
- var imp = new tr.e.importer.Trace2HTMLImporter(m, html_text);
+ var imp = new tr.e.importer.Trace2HTMLImporter(m, htmlText);
var subTracesAsBuffers = imp.extractSubtraces();
var subTracesAsStrings = subTracesAsBuffers.map(function(buffer) {
var str = '';
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_code_map.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_code_map.html
index dbdfecbd3e4..c677d2f5c86 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_code_map.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_code_map.html
@@ -47,7 +47,7 @@ tr.exportTo('tr.e.importer', function() {
},
getAddress_: function(addressHex) {
- // 13 hex digits == 52 bits, double mantissa fits 53 bits.
+ // 13 hex digits === 52 bits, double mantissa fits 53 bits.
var bankSizeHexDigits = 13;
addressHex = addressHex.slice(2); // cut 0x prefix.
return parseInt(addressHex.slice(-bankSizeHexDigits), 16);
@@ -56,7 +56,7 @@ tr.exportTo('tr.e.importer', function() {
getBank_: function(addressHex) {
addressHex = addressHex.slice(2); // cut 0x prefix.
- // 13 hex digits == 52 bits, double mantissa fits 53 bits.
+ // 13 hex digits === 52 bits, double mantissa fits 53 bits.
var bankSizeHexDigits = 13;
var maxHexDigits = 16;
var bankName = addressHex.slice(-maxHexDigits, -bankSizeHexDigits);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer.html
index b7cf2badef2..d3db68ef7fe 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer.html
@@ -8,6 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base64.html">
<link rel="import" href="/tracing/base/color_scheme.html">
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/extras/importer/trace_code_entry.html">
<link rel="import" href="/tracing/extras/importer/trace_code_map.html">
@@ -31,7 +32,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/vm_region.html">
<link rel="import" href="/tracing/model/x_marker_annotation.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -54,19 +54,20 @@ tr.exportTo('tr.e.importer', function() {
}
}
- var timestampFromUs = tr.v.Unit.timestampFromUs;
- var maybeTimestampFromUs = tr.v.Unit.maybeTimestampFromUs;
-
var PRODUCER = 'producer';
var CONSUMER = 'consumer';
var STEP = 'step';
+ var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
- var MEMORY_DUMP_LEVEL_OF_DETAIL_ORDER = [undefined, LIGHT, DETAILED];
+ var MEMORY_DUMP_LEVEL_OF_DETAIL_ORDER = [undefined, BACKGROUND, LIGHT,
+ DETAILED];
var GLOBAL_MEMORY_ALLOCATOR_DUMP_PREFIX = 'global/';
+ var ASYNC_CLOCK_SYNC_EVENT_TITLE_PREFIX = 'ClockSyncEvent.';
+
// Map from raw memory dump byte stat names to model byte stat names. See
// //base/trace_event/process_memory_maps.cc in Chromium.
var BYTE_STAT_NAME_MAP = {
@@ -131,6 +132,7 @@ tr.exportTo('tr.e.importer', function() {
this.eventsWereFromString_ = false;
this.softwareMeasuredCpuCount_ = undefined;
+
this.allAsyncEvents_ = [];
this.allFlowEvents_ = [];
this.allObjectEvents_ = [];
@@ -143,6 +145,11 @@ tr.exportTo('tr.e.importer', function() {
this.v8ProcessRootStackFrame_ = {};
this.v8SamplingData_ = [];
+ // For tracking async events that is used to create back-compat clock sync
+ // event.
+ this.asyncClockSyncStart_ = undefined;
+ this.asyncClockSyncFinish_ = undefined;
+
// Dump ID -> PID -> [process memory dump events].
this.allMemoryDumpEvents_ = {};
@@ -152,6 +159,9 @@ tr.exportTo('tr.e.importer', function() {
// For old Chrome traces with no clock domain metadata, just use a
// placeholder clock domain.
this.clockDomainId_ = tr.model.ClockDomainId.UNKNOWN_CHROME_LEGACY;
+ // A function able to transform timestamps in |clockDomainId| to timestamps
+ // in the model clock domain.
+ this.toModelTime_ = undefined;
if (typeof(eventData) === 'string' || eventData instanceof String) {
eventData = eventData.trim();
@@ -193,7 +203,7 @@ tr.exportTo('tr.e.importer', function() {
// Some implementations specify displayTimeUnit
if (container.displayTimeUnit) {
var unitName = container.displayTimeUnit;
- var unit = tr.v.TimeDisplayModes[unitName];
+ var unit = tr.b.TimeDisplayModes[unitName];
if (unit === undefined) {
throw new Error('Unit ' + unitName + ' is not supported.');
}
@@ -318,14 +328,14 @@ tr.exportTo('tr.e.importer', function() {
* 'C' phase events.
*/
processCounterEvent: function(event) {
- var ctr_name;
+ var ctrName;
if (event.id !== undefined)
- ctr_name = event.name + '[' + event.id + ']';
+ ctrName = event.name + '[' + event.id + ']';
else
- ctr_name = event.name;
+ ctrName = event.name;
var ctr = this.model_.getOrCreateProcess(event.pid)
- .getOrCreateCounter(event.cat, ctr_name);
+ .getOrCreateCounter(event.cat, ctrName);
var reservedColorId = event.cname ? getEventColor(event) : undefined;
// Initialize the counter's series fields if needed.
@@ -349,7 +359,7 @@ tr.exportTo('tr.e.importer', function() {
}
}
- var ts = timestampFromUs(event.ts);
+ var ts = this.toModelTimeFromUs_(event.ts);
ctr.series.forEach(function(series) {
var val = event.args[series.name] ? event.args[series.name] : 0;
series.addCounterSample(ts, val);
@@ -414,7 +424,7 @@ tr.exportTo('tr.e.importer', function() {
processDurationEvent: function(event) {
var thread = this.model_.getOrCreateProcess(event.pid)
.getOrCreateThread(event.tid);
- var ts = timestampFromUs(event.ts);
+ var ts = this.toModelTimeFromUs_(event.ts);
if (!thread.sliceGroup.isTimestampValidForBeginOrEnd(ts)) {
this.model_.importWarning({
type: 'duration_parse_error',
@@ -425,9 +435,9 @@ tr.exportTo('tr.e.importer', function() {
if (event.ph === 'B') {
var slice = thread.sliceGroup.beginSlice(
- event.cat, event.name, timestampFromUs(event.ts),
+ event.cat, event.name, this.toModelTimeFromUs_(event.ts),
this.deepCopyIfNeeded_(event.args),
- timestampFromUs(event.tts), event.argsStripped,
+ this.toModelTimeFromUs_(event.tts), event.argsStripped,
getEventColor(event));
slice.startStackFrame = this.getStackFrameForEvent_(event);
this.setContextsFromThread_(thread, slice);
@@ -436,13 +446,14 @@ tr.exportTo('tr.e.importer', function() {
throw new Error('This should never happen');
thread.sliceGroup.beginSlice(event.cat, event.name,
- timestampFromUs(event.ts),
+ this.toModelTimeFromUs_(event.ts),
this.deepCopyIfNeeded_(event.args),
- timestampFromUs(event.tts),
+ this.toModelTimeFromUs_(event.tts),
event.argsStripped,
getEventColor(event));
- var slice = thread.sliceGroup.endSlice(timestampFromUs(event.ts),
- timestampFromUs(event.tts));
+ var slice = thread.sliceGroup.endSlice(
+ this.toModelTimeFromUs_(event.ts),
+ this.toModelTimeFromUs_(event.tts));
slice.startStackFrame = this.getStackFrameForEvent_(event);
slice.endStackFrame = undefined;
} else {
@@ -454,10 +465,11 @@ tr.exportTo('tr.e.importer', function() {
return;
}
- var slice = thread.sliceGroup.endSlice(timestampFromUs(event.ts),
- timestampFromUs(event.tts),
- getEventColor(event));
- if (event.name && slice.title != event.name) {
+ var slice = thread.sliceGroup.endSlice(
+ this.toModelTimeFromUs_(event.ts),
+ this.toModelTimeFromUs_(event.tts),
+ getEventColor(event));
+ if (event.name && slice.title !== event.name) {
this.model_.importWarning({
type: 'title_match_error',
message: 'Titles do not match. Title is ' +
@@ -506,10 +518,11 @@ tr.exportTo('tr.e.importer', function() {
}
var slice = thread.sliceGroup.pushCompleteSlice(event.cat, event.name,
- timestampFromUs(event.ts),
- maybeTimestampFromUs(event.dur),
- maybeTimestampFromUs(event.tts),
- maybeTimestampFromUs(event.tdur),
+
+ this.toModelTimeFromUs_(event.ts),
+ this.maybeToModelTimeFromUs_(event.dur),
+ this.maybeToModelTimeFromUs_(event.tts),
+ this.maybeToModelTimeFromUs_(event.tdur),
this.deepCopyIfNeeded_(event.args),
event.argsStripped,
getEventColor(event),
@@ -639,7 +652,7 @@ tr.exportTo('tr.e.importer', function() {
}
var instantEvent = new constructor(event.cat, event.name,
- getEventColor(event), timestampFromUs(event.ts),
+ getEventColor(event), this.toModelTimeFromUs_(event.ts),
this.deepCopyIfNeeded_(event.args));
switch (instantEvent.type) {
@@ -735,7 +748,7 @@ tr.exportTo('tr.e.importer', function() {
var sample = new tr.model.Sample(
undefined /* cpu */, thread, 'V8 Sample',
- timestampFromUs(event.ts), lastStackFrame, 1 /* weight */,
+ this.toModelTimeFromUs_(event.ts), lastStackFrame, 1 /* weight */,
this.deepCopyIfNeeded_(event.args));
this.model_.samples.push(sample);
},
@@ -765,7 +778,7 @@ tr.exportTo('tr.e.importer', function() {
var sample = new tr.model.Sample(
undefined, thread, 'Trace Event Sample',
- timestampFromUs(event.ts), stackFrame, 1,
+ this.toModelTimeFromUs_(event.ts), stackFrame, 1,
this.deepCopyIfNeeded_(event.args));
this.setContextsFromThread_(thread, sample);
this.model_.samples.push(sample);
@@ -838,8 +851,9 @@ tr.exportTo('tr.e.importer', function() {
// ...
// }
this.model_.clockSyncManager.addClockSyncMarker(
- this.clockDomainId_, syncId, timestampFromUs(event.args.issue_ts),
- timestampFromUs(event.ts));
+ this.clockDomainId_, syncId,
+ tr.b.Unit.timestampFromUs(event.args.issue_ts),
+ tr.b.Unit.timestampFromUs(event.ts));
} else {
// When Chrome is a tracing agent and is the recipient of the clock
// sync request, the clock sync event looks like:
@@ -851,7 +865,7 @@ tr.exportTo('tr.e.importer', function() {
// ...
// }
this.model_.clockSyncManager.addClockSyncMarker(
- this.clockDomainId_, syncId, timestampFromUs(event.ts));
+ this.clockDomainId_, syncId, tr.b.Unit.timestampFromUs(event.ts));
}
},
@@ -878,10 +892,57 @@ tr.exportTo('tr.e.importer', function() {
}
},
+ initBackcompatClockSyncEventTracker_: function(event) {
+ if (event.name !== undefined &&
+ event.name.startsWith(ASYNC_CLOCK_SYNC_EVENT_TITLE_PREFIX) &&
+ event.ph === 'S')
+ this.asyncClockSyncStart_ = event;
+
+ if (event.name !== undefined &&
+ event.name.startsWith(ASYNC_CLOCK_SYNC_EVENT_TITLE_PREFIX) &&
+ event.ph === 'F')
+ this.asyncClockSyncFinish_ = event;
+ if (this.asyncClockSyncStart_ === undefined ||
+ this.asyncClockSyncFinish_ === undefined)
+ return;
+
+ // Older version of Chrome doesn't support clock sync API, hence
+ // telemetry get around it by marking the clock sync events with
+ // console.time & console.timeEnd. When we encounter async events
+ // with named started with 'ClockSyncEvent.' prefix, create a
+ // synthetic clock sync events based on their timestamps.
+ var syncId =
+ this.asyncClockSyncStart_.name.substring(
+ ASYNC_CLOCK_SYNC_EVENT_TITLE_PREFIX.length);
+ if (syncId !==
+ this.asyncClockSyncFinish_.name.substring(
+ ASYNC_CLOCK_SYNC_EVENT_TITLE_PREFIX.length)) {
+ throw new Error('Inconsistent clock sync id of async clock sync ' +
+ 'events.');
+ }
+ var clockSyncEvent = {
+ ph: 'c',
+ args: {
+ sync_id: syncId,
+ issue_ts: this.asyncClockSyncStart_.ts
+ },
+ ts: this.asyncClockSyncFinish_.ts,
+ };
+ this.asyncClockSyncStart_ = undefined;
+ this.asyncClockSyncFinish_ = undefined;
+ return clockSyncEvent;
+ },
+
importClockSyncMarkers: function() {
+ var asyncClockSyncStart, asyncClockSyncFinish;
for (var i = 0; i < this.events_.length; i++) {
var event = this.events_[i];
+ var possibleBackCompatClockSyncEvent =
+ this.initBackcompatClockSyncEventTracker_(event);
+ if (possibleBackCompatClockSyncEvent)
+ this.processClockSyncEvent(possibleBackCompatClockSyncEvent);
+
if (event.ph !== 'c')
continue;
@@ -1215,7 +1276,7 @@ tr.exportTo('tr.e.importer', function() {
var sample = new tr.model.Sample(
cpu, thread,
event.name,
- timestampFromUs(event.ts),
+ this.toModelTimeFromUs_(event.ts),
stackFrame,
event.weight);
m.samples.push(sample);
@@ -1306,7 +1367,7 @@ tr.exportTo('tr.e.importer', function() {
legacyEvents.sort(function(x, y) {
var d = x.event.ts - y.event.ts;
- if (d != 0)
+ if (d !== 0)
return d;
return x.sequenceNumber - y.sequenceNumber;
});
@@ -1374,17 +1435,17 @@ tr.exportTo('tr.e.importer', function() {
if (event.ph === 'F') {
// Create a slice from start to end.
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(
+ tr.model.AsyncSlice.subTypes.getConstructor(
events[0].event.cat,
name);
var slice = new asyncSliceConstructor(
events[0].event.cat,
name,
getEventColor(events[0].event),
- timestampFromUs(events[0].event.ts),
+ this.toModelTimeFromUs_(events[0].event.ts),
tr.b.concatenateObjects(events[0].event.args,
events[events.length - 1].event.args),
- timestampFromUs(event.ts - events[0].event.ts),
+ this.toModelTimeFromUs_(event.ts - events[0].event.ts),
true, undefined, undefined, events[0].event.argsStripped);
slice.startThread = events[0].thread;
slice.endThread = asyncEventState.thread;
@@ -1431,16 +1492,16 @@ tr.exportTo('tr.e.importer', function() {
subName = subName + ':' + events[j].event.args.step;
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(
+ tr.model.AsyncSlice.subTypes.getConstructor(
events[0].event.cat,
subName);
var subSlice = new asyncSliceConstructor(
events[0].event.cat,
subName,
getEventColor(event, subName + j),
- timestampFromUs(events[startIndex].event.ts),
+ this.toModelTimeFromUs_(events[startIndex].event.ts),
this.deepCopyIfNeeded_(events[j].event.args),
- timestampFromUs(
+ this.toModelTimeFromUs_(
events[endIndex].event.ts - events[startIndex].event.ts),
undefined, undefined,
events[startIndex].event.argsStripped);
@@ -1561,17 +1622,17 @@ tr.exportTo('tr.e.importer', function() {
var isTopLevel = (eventStateEntry.parentEntry === undefined);
var asyncSliceConstructor =
- tr.model.AsyncSlice.getConstructor(
+ tr.model.AsyncSlice.subTypes.getConstructor(
eventStateEntry.event.cat,
eventStateEntry.event.name);
- var thread_start = undefined;
- var thread_duration = undefined;
+ var threadStart = undefined;
+ var threadDuration = undefined;
if (startState.event.tts && startState.event.use_async_tts) {
- thread_start = timestampFromUs(startState.event.tts);
+ threadStart = this.toModelTimeFromUs_(startState.event.tts);
if (endState.event.tts) {
- var thread_end = timestampFromUs(endState.event.tts);
- thread_duration = thread_end - thread_start;
+ var threadEnd = this.toModelTimeFromUs_(endState.event.tts);
+ threadDuration = threadEnd - threadStart;
}
}
@@ -1579,12 +1640,12 @@ tr.exportTo('tr.e.importer', function() {
eventStateEntry.event.cat,
eventStateEntry.event.name,
getEventColor(endState.event),
- timestampFromUs(startState.event.ts),
+ this.toModelTimeFromUs_(startState.event.ts),
sliceArgs,
- timestampFromUs(endState.event.ts - startState.event.ts),
+ this.toModelTimeFromUs_(endState.event.ts - startState.event.ts),
isTopLevel,
- thread_start,
- thread_duration,
+ threadStart,
+ threadDuration,
startState.event.argsStripped);
slice.startThread = startState.thread;
@@ -1613,7 +1674,7 @@ tr.exportTo('tr.e.importer', function() {
},
assertStepTypeMatches_: function(stepType, event) {
- if (stepType != event.event.ph) {
+ if (stepType !== event.event.ph) {
this.model_.importWarning({
type: 'async_slice_parse_error',
message: 'At ' + event.event.ts + ', a slice named ' +
@@ -1667,17 +1728,17 @@ tr.exportTo('tr.e.importer', function() {
return false;
}
- function createFlowEvent(thread, event, opt_slice) {
+ var createFlowEvent = function(thread, event, opt_slice) {
var startSlice, flowId, flowStartTs;
if (event.bind_id) {
// Support Flow API v2.
startSlice = opt_slice;
flowId = event.bind_id;
- flowStartTs = timestampFromUs(event.ts + event.dur);
+ flowStartTs = this.toModelTimeFromUs_(event.ts + event.dur);
} else {
// Support Flow API v1.
- var ts = timestampFromUs(event.ts);
+ var ts = this.toModelTimeFromUs_(event.ts);
startSlice = thread.sliceGroup.findSliceAtTs(ts);
if (startSlice === undefined)
return undefined;
@@ -1697,10 +1758,10 @@ tr.exportTo('tr.e.importer', function() {
flowEvent.endStackFrame = undefined;
startSlice.outFlowEvents.push(flowEvent);
return flowEvent;
- }
+ }.bind(this);
- function finishFlowEventWith(flowEvent, thread, event,
- refGuid, bindToParent, opt_slice) {
+ var finishFlowEventWith = function(
+ flowEvent, thread, event, refGuid, bindToParent, opt_slice) {
var endSlice;
if (event.bind_id) {
@@ -1708,7 +1769,7 @@ tr.exportTo('tr.e.importer', function() {
endSlice = opt_slice;
} else {
// Support Flow API v1.
- var ts = timestampFromUs(event.ts);
+ var ts = this.toModelTimeFromUs_(event.ts);
if (bindToParent) {
endSlice = thread.sliceGroup.findSliceAtTs(ts);
} else {
@@ -1720,14 +1781,15 @@ tr.exportTo('tr.e.importer', function() {
endSlice.inFlowEvents.push(flowEvent);
flowEvent.endSlice = endSlice;
- flowEvent.duration = timestampFromUs(event.ts) - flowEvent.start;
+ flowEvent.duration =
+ this.toModelTimeFromUs_(event.ts) - flowEvent.start;
flowEvent.endStackFrame = that.getStackFrameForEvent_(event);
that.mergeArgsInto_(flowEvent.args, event.args, flowEvent.title);
return true;
- }
+ }.bind(this);
- function processFlowConsumer(flowIdToEvent, sliceGuidToEvent, event,
- slice) {
+ function processFlowConsumer(
+ flowIdToEvent, sliceGuidToEvent, event, slice) {
var flowEvent = flowIdToEvent[event.bind_id];
if (flowEvent === undefined) {
that.model_.importWarning({
@@ -1778,14 +1840,12 @@ tr.exportTo('tr.e.importer', function() {
return false;
}
flowIdToEvent[event.bind_id] = flowEvent;
-
- return;
}
// Actual import.
this.allFlowEvents_.sort(function(x, y) {
var d = x.event.ts - y.event.ts;
- if (d != 0)
+ if (d !== 0)
return d;
return x.sequenceNumber - y.sequenceNumber;
});
@@ -1910,7 +1970,7 @@ tr.exportTo('tr.e.importer', function() {
if (this.allObjectEvents_.length === 0)
return;
- function processEvent(objectEventState) {
+ var processEvent = function(objectEventState) {
var event = objectEventState.event;
var scopedId = this.scopedIdForEvent_(event);
var thread = objectEventState.thread;
@@ -1930,7 +1990,7 @@ tr.exportTo('tr.e.importer', function() {
});
}
var process = thread.parent;
- var ts = timestampFromUs(event.ts);
+ var ts = this.toModelTimeFromUs_(event.ts);
var instance;
if (event.ph === 'N') {
try {
@@ -2000,11 +2060,11 @@ tr.exportTo('tr.e.importer', function() {
if (instance)
instance.colorId = getEventColor(event, instance.typeName);
- }
+ }.bind(this);
this.allObjectEvents_.sort(function(x, y) {
var d = x.event.ts - y.event.ts;
- if (d != 0)
+ if (d !== 0)
return d;
return x.sequenceNumber - y.sequenceNumber;
});
@@ -2158,7 +2218,7 @@ tr.exportTo('tr.e.importer', function() {
for (var pid in dumpIdEvents) {
var processEvents = dumpIdEvents[pid];
for (var i = 0; i < processEvents.length; i++)
- globalRange.addValue(timestampFromUs(processEvents[i].ts));
+ globalRange.addValue(this.toModelTimeFromUs_(processEvents[i].ts));
}
if (globalRange.isEmpty)
throw new Error('Internal error: Global memory dump without events');
@@ -2208,7 +2268,7 @@ tr.exportTo('tr.e.importer', function() {
// Calculate the range of the process memory dump.
var processRange = new tr.b.Range();
for (var i = 0; i < processEvents.length; i++)
- processRange.addValue(timestampFromUs(processEvents[i].ts));
+ processRange.addValue(this.toModelTimeFromUs_(processEvents[i].ts));
if (processRange.isEmpty)
throw new Error('Internal error: Process memory dump without events');
@@ -2258,7 +2318,7 @@ tr.exportTo('tr.e.importer', function() {
if (levelsOfDetail.process === undefined) {
// Infer level of detail from the presence of VM regions in legacy
// traces (where raw process memory dump events don't contain the
- // level_of_detail field).
+ // level_of_detail field). These traces will not have BACKGROUND mode.
levelsOfDetail.process = processMemoryDump.vmRegions ? DETAILED : LIGHT;
}
if (!this.updateMemoryDumpLevelOfDetail_(
@@ -2587,6 +2647,9 @@ tr.exportTo('tr.e.importer', function() {
var rawLevelOfDetail = dumps.level_of_detail;
var level;
switch (rawLevelOfDetail) {
+ case 'background':
+ level = BACKGROUND;
+ break;
case 'light':
level = LIGHT;
break;
@@ -2759,8 +2822,8 @@ tr.exportTo('tr.e.importer', function() {
break;
}
var unit = attrArgs.units === 'bytes' ?
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter :
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter :
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var value = parseInt(attrValue, 16);
allocatorDump.addNumeric(attrName,
new tr.v.ScalarNumeric(unit, value));
@@ -2977,6 +3040,31 @@ tr.exportTo('tr.e.importer', function() {
}
}
}
+ },
+
+ /**
+ * Converts |ts| (in microseconds) to a timestamp in the model clock domain
+ * (in milliseconds).
+ */
+ toModelTimeFromUs_: function(ts) {
+ if (!this.toModelTime_) {
+ this.toModelTime_ =
+ this.model_.clockSyncManager.getModelTimeTransformer(
+ this.clockDomainId_);
+ }
+
+ return this.toModelTime_(tr.b.Unit.timestampFromUs(ts));
+ },
+
+ /**
+ * Converts |ts| (in microseconds) to a timestamp in the model clock domain
+ * (in milliseconds). If |ts| is undefined, undefined is returned.
+ */
+ maybeToModelTimeFromUs_: function(ts) {
+ if (ts === undefined)
+ return undefined;
+
+ return this.toModelTimeFromUs_(ts);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html
index 9270fd150ee..2c5d67e448a 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html
@@ -5,7 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/time_display_modes.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/importer/battor_importer.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
<link rel="import" href="/tracing/extras/measure/measure.html">
<link rel="import" href="/tracing/importer/import.html">
@@ -14,8 +17,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/scoped_id.html">
<link rel="import" href="/tracing/model/vm_region.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -29,7 +30,7 @@ tr.b.unittest.testSuite(function() {
var VMRegion = tr.model.VMRegion;
var ScalarNumeric = tr.v.ScalarNumeric;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var checkDumpNumericsAndDiagnostics =
tr.model.MemoryDumpTestUtils.checkDumpNumericsAndDiagnostics;
var checkVMRegions = tr.model.MemoryDumpTestUtils.checkVMRegions;
@@ -441,7 +442,7 @@ tr.b.unittest.testSuite(function() {
});
test('taskColoring', function() {
- // The test below depends on hashing of 'a' != 'b'. Fail early if that
+ // The test below depends on hashing of 'a' !== 'b'. Fail early if that
// assumption is incorrect.
assert.notEqual(ColorScheme.getStringHash('a'),
ColorScheme.getStringHash('b'));
@@ -884,9 +885,9 @@ tr.b.unittest.testSuite(function() {
ph: 'C', id: 1},
{name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1,
ph: 'C', id: 1},
- {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1,
+ {name: 'ctr', args: {'value': 30}, pid: 1, ts: 20, cat: 'foo', tid: 1,
ph: 'C', id: 1},
- {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1,
+ {name: 'ctr', args: {'value': 40}, pid: 1, ts: 25, cat: 'bar', tid: 1,
ph: 'C', id: 2}
];
var m = makeModel(events);
@@ -909,7 +910,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(ctr.category, 'foo');
assert.equal(ctr.numSamples, 3);
assert.equal(ctr.numSeries, 1);
- assert.deepEqual(ctr.timestamps, [0.01, 0.015, 0.018]);
+ assert.deepEqual(ctr.timestamps, [0.01, 0.015, 0.02]);
samples = [];
ctr.series[0].samples.forEach(function(sample) {
@@ -922,7 +923,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(ctr.category, 'bar');
assert.equal(ctr.numSamples, 1);
assert.equal(ctr.numSeries, 1);
- assert.deepEqual(ctr.timestamps, [0.02]);
+ assert.deepEqual(ctr.timestamps, [0.025]);
var samples = [];
ctr.series[0].samples.forEach(function(sample) {
samples.push(sample.value);
@@ -2219,10 +2220,10 @@ tr.b.unittest.testSuite(function() {
// arguments of the snapshots to be mutated.
var m;
try {
- tr.model.ObjectSnapshot.register(ASnapshot, {typeName: 'a'});
+ tr.model.ObjectSnapshot.subTypes.register(ASnapshot, {typeName: 'a'});
m = makeModel(events);
} finally {
- tr.model.ObjectSnapshot.unregister(ASnapshot);
+ tr.model.ObjectSnapshot.subTypes.unregister(ASnapshot);
}
assert.isFalse(m.hasImportWarnings);
@@ -5253,7 +5254,7 @@ tr.b.unittest.testSuite(function() {
displayTimeUnit: 'ns'
};
var m = makeModel(JSON.stringify(eventData));
- assert.equal(m.intrinsicTimeUnit, tr.v.TimeDisplayModes.ns);
+ assert.equal(m.intrinsicTimeUnit, tr.b.TimeDisplayModes.ns);
});
test('extractBattorSubTraces', function() {
@@ -5274,8 +5275,7 @@ tr.b.unittest.testSuite(function() {
],
powerTraceAsString: battorLog
};
-
- var m = makeModel(eventData);
+ var m = new tr.Model();
var importer = new tr.e.importer.TraceEventImporter(m, eventData);
var subTraces = importer.extractSubtraces();
assert.isTrue(subTraces instanceof Array);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/codemap.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/codemap.html
index b7d80554373..c33cf6d7558 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/codemap.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/codemap.html
@@ -44,7 +44,7 @@ tr.exportTo('tr.e.importer.v8', function() {
* Map of memory pages occupied with static code.
*/
this.pages_ = [];
- };
+ }
/**
* The number of alignment bits in a page address.
@@ -128,16 +128,16 @@ tr.exportTo('tr.e.importer.v8', function() {
* @private
*/
CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
- var to_delete = [];
+ var toDelete = [];
var addr = end - 1;
while (addr >= start) {
var node = tree.findGreatestLessThan(addr);
if (!node) break;
var start2 = node.key, end2 = start2 + node.value.size;
- if (start2 < end && start < end2) to_delete.push(start2);
+ if (start2 < end && start < end2) toDelete.push(start2);
addr = start2 - 1;
}
- for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
+ for (var i = 0, l = toDelete.length; i < l; ++i) tree.remove(toDelete[i]);
};
/**
@@ -183,9 +183,9 @@ tr.exportTo('tr.e.importer.v8', function() {
}
var min = this.dynamics_.findMin();
var max = this.dynamics_.findMax();
- if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
+ if (max !== null && addr < (max.key + max.value.size) && addr >= min.key) {
var dynaEntry = this.findInTree_(this.dynamics_, addr);
- if (dynaEntry == null) return null;
+ if (dynaEntry === null) return null;
// Dedupe entry name.
if (!dynaEntry.nameUpdated_) {
dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name);
@@ -348,9 +348,9 @@ tr.exportTo('tr.e.importer.v8', function() {
*/
get name() {
var name = this.name_;
- if (name.length == 0) {
+ if (name.length === 0) {
name = '<anonymous>';
- } else if (name.charAt(0) == ' ') {
+ } else if (name.charAt(0) === ' ') {
// An anonymous function with location: " aaa.js:10".
name = '<anonymous>' + name;
}
@@ -379,4 +379,3 @@ tr.exportTo('tr.e.importer.v8', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/log_reader.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/log_reader.html
index 9b10ab69b96..5856237ed31 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/log_reader.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/log_reader.html
@@ -15,7 +15,7 @@ tr.exportTo('tr.e.importer.v8', function() {
/**
* Creates a CSV lines parser.
*/
- function CsvParser() { };
+ function CsvParser() { }
/**
* A regex for matching a CSV field.
@@ -84,7 +84,7 @@ tr.exportTo('tr.e.importer.v8', function() {
* @type {CsvParser}
*/
this.csvParser_ = new CsvParser();
- };
+ }
/**
* Used for printing error messages.
@@ -127,12 +127,12 @@ tr.exportTo('tr.e.importer.v8', function() {
for (var i = 0, n = stack.length; i < n; ++i) {
var frame = stack[i];
var firstChar = frame.charAt(0);
- if (firstChar == '+' || firstChar == '-') {
+ if (firstChar === '+' || firstChar === '-') {
// An offset from the previous frame.
prevFrame += parseInt(frame, 16);
fullStack.push(prevFrame);
// Filter out possible 'overflow' string.
- } else if (firstChar != 'o') {
+ } else if (firstChar !== 'o') {
fullStack.push(parseInt(frame, 16));
}
}
@@ -172,7 +172,7 @@ tr.exportTo('tr.e.importer.v8', function() {
var parser = dispatch.parsers[i];
if (parser === null) {
parsedFields.push(fields[1 + i]);
- } else if (typeof parser == 'function') {
+ } else if (typeof parser === 'function') {
parsedFields.push(parser(fields[1 + i]));
} else {
// var-args
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/splaytree.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/splaytree.html
index 05f803765db..a3d7a244f75 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/splaytree.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/splaytree.html
@@ -20,7 +20,7 @@ tr.exportTo('tr.e.importer.v8', function() {
*
* @constructor
*/
- function SplayTree() { };
+ function SplayTree() { }
/**
* Pointer to the root node of the tree.
@@ -53,7 +53,7 @@ tr.exportTo('tr.e.importer.v8', function() {
// Splay on the key to move the last node on the search path for
// the key to the root of the tree.
this.splay_(key);
- if (this.root_.key == key) {
+ if (this.root_.key === key) {
return;
}
var node = new SplayTree.Node(key, value);
@@ -83,7 +83,7 @@ tr.exportTo('tr.e.importer.v8', function() {
throw Error('Key not found: ' + key);
}
this.splay_(key);
- if (this.root_.key != key) {
+ if (this.root_.key !== key) {
throw Error('Key not found: ' + key);
}
var removed = this.root_;
@@ -115,7 +115,7 @@ tr.exportTo('tr.e.importer.v8', function() {
return null;
}
this.splay_(key);
- return this.root_.key == key ? this.root_ : null;
+ return this.root_.key === key ? this.root_ : null;
};
/**
@@ -269,7 +269,7 @@ tr.exportTo('tr.e.importer.v8', function() {
var nodesToVisit = [this.root_];
while (nodesToVisit.length > 0) {
var node = nodesToVisit.shift();
- if (node == null) {
+ if (node === null) {
continue;
}
f(node);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer.html
index 0fa1a9992c2..bcc9e77896f 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer.html
@@ -68,12 +68,12 @@ tr.exportTo('tr.e.importer.v8', function() {
if (typeof(eventData) !== 'string' && !(eventData instanceof String))
return false;
- return eventData.substring(0, 11) == 'v8-version,' ||
- eventData.substring(0, 12) == 'timer-event,' ||
- eventData.substring(0, 5) == 'tick,' ||
- eventData.substring(0, 15) == 'shared-library,' ||
- eventData.substring(0, 9) == 'profiler,' ||
- eventData.substring(0, 14) == 'code-creation,';
+ return eventData.substring(0, 11) === 'v8-version,' ||
+ eventData.substring(0, 12) === 'timer-event,' ||
+ eventData.substring(0, 5) === 'tick,' ||
+ eventData.substring(0, 15) === 'shared-library,' ||
+ eventData.substring(0, 9) === 'profiler,' ||
+ eventData.substring(0, 14) === 'code-creation,';
};
V8LogImporter.prototype = {
@@ -84,31 +84,35 @@ tr.exportTo('tr.e.importer.v8', function() {
return 'V8LogImporter';
},
- processTimerEvent_: function(name, start, length) {
+ processTimerEvent_: function(name, startInUs, lengthInUs) {
var args = TimerEventDefaultArgs[name];
if (args === undefined) return;
- start /= 1000; // Convert to milliseconds.
- length /= 1000;
+ var startInMs = tr.b.convertUnit(startInUs,
+ tr.b.UnitScale.Metric.MICRO, tr.b.UnitScale.Metric.MILLI);
+ var lengthInMs = tr.b.convertUnit(lengthInUs,
+ tr.b.UnitScale.Metric.MICRO, tr.b.UnitScale.Metric.MILLI);
var colorId = ColorScheme.getColorIdForGeneralPurposeString(name);
- var slice = new tr.model.Slice('v8', name, colorId, start,
- args, length);
+ var slice = new tr.model.ThreadSlice('v8', name, colorId, startInMs,
+ args, lengthInMs);
this.v8_timer_thread_.sliceGroup.pushSlice(slice);
},
- processTimerEventStart_: function(name, start) {
+ processTimerEventStart_: function(name, startInUs) {
var args = TimerEventDefaultArgs[name];
if (args === undefined) return;
- start /= 1000; // Convert to milliseconds.
- this.v8_timer_thread_.sliceGroup.beginSlice('v8', name, start, args);
+ var startInMs = tr.b.convertUnit(startInUs,
+ tr.b.UnitScale.Metric.MICRO, tr.b.UnitScale.Metric.MILLI);
+ this.v8_timer_thread_.sliceGroup.beginSlice('v8', name, startInMs, args);
},
- processTimerEventEnd_: function(name, end) {
- end /= 1000; // Convert to milliseconds.
- this.v8_timer_thread_.sliceGroup.endSlice(end);
+ processTimerEventEnd_: function(name, endInUs) {
+ var endInMs = tr.b.convertUnit(endInUs,
+ tr.b.UnitScale.Metric.MICRO, tr.b.UnitScale.Metric.MILLI);
+ this.v8_timer_thread_.sliceGroup.endSlice(endInMs);
},
processCodeCreateEvent_: function(type, kind, address, size, name,
- maybe_func) {
+ maybeFunc) {
function parseState(s) {
switch (s) {
case '': return CodeMap.CodeState.COMPILED;
@@ -118,9 +122,9 @@ tr.exportTo('tr.e.importer.v8', function() {
throw new Error('unknown code state: ' + s);
}
- if (maybe_func.length) {
- var funcAddr = parseInt(maybe_func[0]);
- var state = parseState(maybe_func[1]);
+ if (maybeFunc.length) {
+ var funcAddr = parseInt(maybeFunc[0]);
+ var state = parseState(maybeFunc[1]);
var func = this.code_map_.findDynamicEntryByStartAddress(funcAddr);
if (!func) {
func = new FunctionEntry(name);
@@ -142,9 +146,9 @@ tr.exportTo('tr.e.importer.v8', function() {
this.code_map_.addCode(address, entry);
}
} else {
- var code_entry = new CodeEntry(size, name);
- code_entry.kind = kind;
- this.code_map_.addCode(address, code_entry);
+ var codeEntry = new CodeEntry(size, name);
+ codeEntry.kind = kind;
+ this.code_map_.addCode(address, codeEntry);
}
},
@@ -157,32 +161,34 @@ tr.exportTo('tr.e.importer.v8', function() {
},
processSharedLibrary_: function(name, start, end) {
- var code_entry = new CodeEntry(end - start, name,
+ var codeEntry = new CodeEntry(end - start, name,
CodeEntry.TYPE.SHARED_LIB);
- code_entry.kind = -3; // External code kind.
+ codeEntry.kind = -3; // External code kind.
for (var i = 0; i < kV8BinarySuffixes.length; i++) {
var suffix = kV8BinarySuffixes[i];
if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
- code_entry.kind = -1; // V8 runtime code kind.
+ codeEntry.kind = -1; // V8 runtime code kind.
break;
}
}
- this.code_map_.addLibrary(start, code_entry);
+ this.code_map_.addLibrary(start, codeEntry);
},
processCppSymbol_: function(address, size, name) {
- var code_entry = new CodeEntry(size, name, CodeEntry.TYPE.CPP);
- code_entry.kind = -1;
- this.code_map_.addStaticCode(address, code_entry);
+ var codeEntry = new CodeEntry(size, name, CodeEntry.TYPE.CPP);
+ codeEntry.kind = -1;
+ this.code_map_.addStaticCode(address, codeEntry);
},
- processTickEvent_: function(pc, start, is_external_callback,
- tos_or_external_callback, vmstate, stack) {
- start /= 1000;
+ processTickEvent_: function(pc, startInUs, isExternalCallback,
+ tosOrExternalCallback, vmstate, stack) {
+
+ var startInMs = tr.b.convertUnit(startInUs,
+ tr.b.UnitScale.Metric.MICRO, tr.b.UnitScale.Metric.MILLI);
function findChildWithEntryID(stackFrame, entryID) {
for (var i = 0; i < stackFrame.children.length; i++) {
- if (stackFrame.children[i].entryID == entryID)
+ if (stackFrame.children[i].entryID === entryID)
return stackFrame.children[i];
}
return undefined;
@@ -207,22 +213,22 @@ tr.exportTo('tr.e.importer.v8', function() {
return fullStack;
}
- if (is_external_callback) {
+ if (isExternalCallback) {
// Don't use PC when in external callback code, as it can point
// inside callback's code, and we will erroneously report
- // that a callback calls itself. Instead use tos_or_external_callback,
+ // that a callback calls itself. Instead use tosOrExternalCallback,
// as simply resetting PC will produce unaccounted ticks.
- pc = tos_or_external_callback;
- tos_or_external_callback = 0;
- } else if (tos_or_external_callback) {
+ pc = tosOrExternalCallback;
+ tosOrExternalCallback = 0;
+ } else if (tosOrExternalCallback) {
// Find out, if top of stack was pointing inside a JS function
// meaning that we have encountered a frameless invocation.
- var funcEntry = this.code_map_.findEntry(tos_or_external_callback);
+ var funcEntry = this.code_map_.findEntry(tosOrExternalCallback);
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction())
- tos_or_external_callback = 0;
+ tosOrExternalCallback = 0;
}
- var processedStack = processStack(pc, tos_or_external_callback, stack);
+ var processedStack = processStack(pc, tosOrExternalCallback, stack);
var lastStackFrame = this.root_stack_frame_;
// v8 log stacks are inverted, leaf first and the root at the end.
processedStack = processedStack.reverse();
@@ -261,12 +267,12 @@ tr.exportTo('tr.e.importer.v8', function() {
if (lastStackFrame !== this.root_stack_frame_) {
var sample = new tr.model.Sample(
undefined, this.v8_thread_, 'V8 PC',
- start, lastStackFrame, 1);
+ startInMs, lastStackFrame, 1);
this.model_.samples.push(sample);
}
},
- processDistortion_: function(distortion_in_picoseconds) {
+ processDistortion_: function(distortionInPicoseconds) {
// Do nothing.
},
@@ -355,7 +361,7 @@ tr.exportTo('tr.e.importer.v8', function() {
function addSlices(slices, thread) {
for (var i = 0; i < slices.length; i++) {
var duration = slices[i].end - slices[i].start;
- var slice = new tr.model.Slice('v8', slices[i].name,
+ var slice = new tr.model.ThreadSlice('v8', slices[i].name,
ColorScheme.getColorIdForGeneralPurposeString(slices[i].name),
slices[i].start, {}, duration);
thread.sliceGroup.pushSlice(slice);
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
index fdbe447ca60..f4fb66f9d3b 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
@@ -172,7 +172,7 @@ tr.b.unittest.testSuite(function() {
'tick,0x7fd2a534,536213,0,0x81d8d080,0,0x2905d304,0x2904d6e8',
'code-creation,Script,0,0x2906a7c0,792,"http://www.google.com/",0x5b12fe50,~', // @suppress longLineCheck
'tick,0xb6f51d30,794049,0,0xb6f7b368,2,0x2906a914',
- 'tick,0xb6f51d30,799146,0,0xb6f7b368,0,0x2906a914'
+ 'tick,0xb6f51d30,799145,0,0xb6f7b368,0,0x2906a914'
];
var m = newModel(lines.join('\n'));
var p = m.processes[-32];
@@ -184,7 +184,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(t.samples[1].start, 528674 / 1000);
assert.equal(t.samples[2].start, 536213 / 1000);
assert.equal(t.samples[3].start, 794049 / 1000);
- assert.equal(t.samples[4].start, 799146 / 1000);
+ assert.equal(t.samples[4].start, 799145 / 1000);
assert.deepEqual(
['~Instantiate native apinatives.js:9:21'],
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice.html
index 427a401bf7b..7f951abd17e 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice.html
@@ -38,7 +38,7 @@ tr.exportTo('tr.e.measure', function() {
}
};
- AsyncSlice.register(
+ AsyncSlice.subTypes.register(
MeasureAsyncSlice,
{
categoryParts: ['blink.user_timing']
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice_test.html b/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice_test.html
index d175d4e8928..6b534b91b85 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/measure/measure_async_slice_test.html
@@ -21,7 +21,7 @@ tr.b.unittest.testSuite(function() {
'blink.user_timing', 'createImports', 7, 0, {});
s.duration = 100;
- assert.equal(AsyncSlice.getConstructor(
+ assert.equal(AsyncSlice.subTypes.getConstructor(
'blink.user_timing', 'createImports'),
MeasureAsyncSlice);
assert.equal(s.viewSubGroupTitle, 'Ungrouped Measure');
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice.html
index 21d52d4cc25..948316da1ed 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice.html
@@ -86,7 +86,7 @@ tr.exportTo('tr.e.net', function() {
}
};
- AsyncSlice.register(
+ AsyncSlice.subTypes.register(
NetAsyncSlice,
{
categoryParts: ['netlog', 'disabled-by-default-netlog']
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice_test.html b/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice_test.html
index 96c623dbf83..e8a2bd750fa 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/net/net_async_slice_test.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/extras/net/net.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
+<link rel="import" href="/tracing/extras/net/net.html">
<link rel="import" href="/tracing/model/model.html">
<script>
@@ -21,8 +21,9 @@ tr.b.unittest.testSuite(function() {
var s = new NetAsyncSlice('netlog', 'HTTP_STREAM_JOB', 7, 0, {});
s.duration = 100;
- assert.equal(AsyncSlice.getConstructor('netlog', 'HTTP_STREAM_JOB'),
- NetAsyncSlice);
+ assert.equal(
+ AsyncSlice.subTypes.getConstructor('netlog', 'HTTP_STREAM_JOB'),
+ NetAsyncSlice);
assert.equal(s.viewSubGroupTitle, 'NetLog');
});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/system_stats/system_stats_snapshot.html b/chromium/third_party/catapult/tracing/tracing/extras/system_stats/system_stats_snapshot.html
index 2dbcc986dee..46c7259d742 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/system_stats/system_stats_snapshot.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/system_stats/system_stats_snapshot.html
@@ -28,7 +28,7 @@ tr.exportTo('tr.e.system_stats', function() {
__proto__: ObjectSnapshot.prototype,
initialize: function() {
- if (this.args.length == 0)
+ if (this.args.length === 0)
throw new Error('No system stats snapshot data.');
this.stats_ = this.args;
},
@@ -42,7 +42,7 @@ tr.exportTo('tr.e.system_stats', function() {
}
};
- ObjectSnapshot.register(
+ ObjectSnapshot.subTypes.register(
SystemStatsSnapshot,
{typeName: 'base::TraceEventSystemStatsMonitor::SystemStats'});
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/tquery/filter.html b/chromium/third_party/catapult/tracing/tracing/extras/tquery/filter.html
index 99532e4dd75..17cf644aa70 100644
--- a/chromium/third_party/catapult/tracing/tracing/extras/tquery/filter.html
+++ b/chromium/third_party/catapult/tracing/tracing/extras/tquery/filter.html
@@ -19,7 +19,7 @@ tr.exportTo('tr.e.tquery', function() {
// Shortcut: naked strings and regexps can be used to match against slice
// titles.
if (filterExpression instanceof String ||
- typeof(filterExpression) == 'string' ||
+ typeof(filterExpression) === 'string' ||
filterExpression instanceof RegExp) {
var filter = new tr.e.tquery.FilterHasTitle(filterExpression);
return filter;
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_gc_stats_thread_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_gc_stats_thread_slice.html
new file mode 100644
index 00000000000..3de404f7f65
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_gc_stats_thread_slice.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/model/thread_slice.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.e.v8', function() {
+ var ThreadSlice = tr.model.ThreadSlice;
+
+ function V8GCStatsThreadSlice() {
+ ThreadSlice.apply(this, arguments);
+ this.liveObjects_ = JSON.parse(this.args['live']);
+ delete this.args['live'];
+ this.deadObjects_ = JSON.parse(this.args['dead']);
+ delete this.args['dead'];
+ }
+
+ V8GCStatsThreadSlice.prototype = {
+ __proto__: ThreadSlice.prototype,
+
+ get liveObjects() {
+ return this.liveObjects_;
+ },
+
+ get deadObjects() {
+ return this.deadObjects_;
+ }
+ };
+
+ ThreadSlice.subTypes.register(
+ V8GCStatsThreadSlice,
+ {
+ categoryParts: ['disabled-by-default-v8.gc_stats'],
+ name: 'v8 gc stats slice',
+ pluralName: 'v8 gc stats slices'
+ }
+ );
+
+ return {
+ V8GCStatsThreadSlice: V8GCStatsThreadSlice
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_thread_slice.html b/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_thread_slice.html
new file mode 100644
index 00000000000..a0911d058b0
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/extras/v8/v8_thread_slice.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2013 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/model/thread_slice.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.e.v8', function() {
+ var ThreadSlice = tr.model.ThreadSlice;
+
+ function V8ThreadSlice() {
+ ThreadSlice.apply(this, arguments);
+ this.runtimeCallStats_ = undefined;
+ }
+
+ V8ThreadSlice.prototype = {
+ __proto__: ThreadSlice.prototype,
+
+ get runtimeCallStats() {
+ if ('runtime-call-stats' in this.args) {
+ this.runtimeCallStats_ = this.args['runtime-call-stats'];
+ delete this.args['runtime-call-stats'];
+ }
+ return this.runtimeCallStats_;
+ }
+ };
+
+ ThreadSlice.subTypes.register(
+ V8ThreadSlice,
+ {
+ categoryParts: ['v8'],
+ name: 'v8 slice',
+ pluralName: 'v8 slices'
+ }
+ );
+
+ return {
+ V8ThreadSlice: V8ThreadSlice
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/extras/v8_config.html b/chromium/third_party/catapult/tracing/tracing/extras/v8_config.html
new file mode 100644
index 00000000000..b9ed173ba4f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/extras/v8_config.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/empty_importer.html b/chromium/third_party/catapult/tracing/tracing/importer/empty_importer.html
index dc5f867b3ff..028a7d427ec 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/empty_importer.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/empty_importer.html
@@ -20,13 +20,13 @@ tr.exportTo('tr.importer', function() {
*/
function EmptyImporter(events) {
this.importPriority = 0;
- };
+ }
EmptyImporter.canImport = function(eventData) {
- if (eventData instanceof Array && eventData.length == 0)
+ if (eventData instanceof Array && eventData.length === 0)
return true;
if (typeof(eventData) === 'string' || eventData instanceof String) {
- return eventData.length == 0;
+ return eventData.length === 0;
}
return false;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/find_input_expectations.html b/chromium/third_party/catapult/tracing/tracing/importer/find_input_expectations.html
index 36e77d32ba5..3f9245849ef 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/find_input_expectations.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/find_input_expectations.html
@@ -8,13 +8,14 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/range_utils.html">
<link rel="import" href="/tracing/extras/chrome/cc/input_latency_async_slice.html">
<link rel="import" href="/tracing/importer/proto_expectation.html">
+<link rel="import" href="/tracing/model/user_model/user_expectation.html">
<script>
'use strict';
tr.exportTo('tr.importer', function() {
var ProtoExpectation = tr.importer.ProtoExpectation;
-
+ var INITIATOR_TYPE = tr.model.um.INITIATOR_TYPE;
var INPUT_TYPE = tr.e.cc.INPUT_EVENT_TYPE_NAMES;
var KEYBOARD_TYPE_NAMES = [
@@ -72,37 +73,32 @@ tr.exportTo('tr.importer', function() {
);
var RENDERER_FLING_TITLE = 'InputHandlerProxy::HandleGestureFling::started';
+ var PLAYBACK_EVENT_TITLE = 'VideoPlayback';
- // TODO(benjhayden) share with rail_ir_finder
var CSS_ANIMATION_TITLE = 'Animation';
- // If there's less than this much time between the end of one event and the
- // start of the next, then they might be merged.
- // There was not enough thought given to this value, so if you have any slight
- // reason to change it, then please do so. It might also be good to split this
- // into multiple values.
+ /**
+ * If there's less than this much time between the end of one event and the
+ * start of the next, then they might be merged.
+ * There was not enough thought given to this value, so if you have any slight
+ * reason to change it, then please do so. It might also be good to split this
+ * into multiple values.
+ */
var INPUT_MERGE_THRESHOLD_MS = 200;
- var ANIMATION_MERGE_THRESHOLD_MS = 32; // 2x 60FPS frames
+ var ANIMATION_MERGE_THRESHOLD_MS = 32; // 2x 60FPS frames
- // If two MouseWheel events begin this close together, then they're an
- // Animation, not two responses.
+ /**
+ * If two MouseWheel events begin this close together, then they're an
+ * Animation, not two responses.
+ */
var MOUSE_WHEEL_THRESHOLD_MS = 40;
- // If two MouseMoves are more than this far apart, then they're two Responses,
- // not Animation.
+ /**
+ * If two MouseMoves are more than this far apart, then they're two Responses,
+ * not Animation.
+ */
var MOUSE_MOVE_THRESHOLD_MS = 40;
- // Strings used to name IRs.
- var KEYBOARD_IR_NAME = 'Keyboard';
- var MOUSE_IR_NAME = 'Mouse';
- var MOUSEWHEEL_IR_NAME = 'MouseWheel';
- var TAP_IR_NAME = 'Tap';
- var PINCH_IR_NAME = 'Pinch';
- var FLING_IR_NAME = 'Fling';
- var TOUCH_IR_NAME = 'Touch';
- var SCROLL_IR_NAME = 'Scroll';
- var CSS_IR_NAME = 'CSS';
-
// TODO(benjhayden) Find a better home for this.
function compareEvents(x, y) {
if (x.start !== y.start)
@@ -127,6 +123,15 @@ tr.exportTo('tr.importer', function() {
x => x.title === tr.model.helpers.IMPL_RENDERING_STATS);
}
+ function getSortedFrameEventsByProcess(modelHelper) {
+ var frameEventsByPid = {};
+ tr.b.iterItems(modelHelper.rendererHelpers, function(pid, rendererHelper) {
+ frameEventsByPid[pid] = rendererHelper.getFrameEventsInRange(
+ tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds);
+ });
+ return frameEventsByPid;
+ }
+
function getSortedInputEvents(modelHelper) {
var inputEvents = [];
@@ -166,7 +171,9 @@ tr.exportTo('tr.importer', function() {
handleFlingEvents,
handleTouchEvents,
handleScrollEvents,
- handleCSSAnimations
+ handleCSSAnimations,
+ handleWebGLAnimations,
+ handleVideoAnimations
];
handlers.forEach(function(handler) {
protoExpectations.push.apply(protoExpectations, handler(
@@ -176,41 +183,46 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // Every keyboard event is a Response.
+ /**
+ * Every keyboard event is a Response.
+ */
function handleKeyboardEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
forEventTypesIn(sortedInputEvents, KEYBOARD_TYPE_NAMES, function(event) {
var pe = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, KEYBOARD_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.KEYBOARD);
pe.pushEvent(event);
protoExpectations.push(pe);
});
return protoExpectations;
}
- // Some mouse events can be translated directly into Responses.
+ /**
+ * Some mouse events can be translated directly into Responses.
+ */
function handleMouseResponseEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
forEventTypesIn(
sortedInputEvents, MOUSE_RESPONSE_TYPE_NAMES, function(event) {
var pe = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, MOUSE_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.MOUSE);
pe.pushEvent(event);
protoExpectations.push(pe);
});
return protoExpectations;
}
-
- // MouseWheel events are caused either by a physical wheel on a physical
- // mouse, or by a touch-drag gesture on a track-pad. The physical wheel
- // causes MouseWheel events that are much more spaced out, and have no
- // chance of hitting 60fps, so they are each turned into separate Response
- // IRs. The track-pad causes MouseWheel events that are much closer
- // together, and are expected to be 60fps, so the first event in a sequence
- // is turned into a Response, and the rest are merged into an Animation.
- // NB this threshold uses the two events' start times, unlike
- // ProtoExpectation.isNear, which compares the end time of the previous event
- // with the start time of the next.
+ /**
+ * MouseWheel events are caused either by a physical wheel on a physical
+ * mouse, or by a touch-drag gesture on a track-pad. The physical wheel
+ * causes MouseWheel events that are much more spaced out, and have no
+ * chance of hitting 60fps, so they are each turned into separate Response
+ * IRs. The track-pad causes MouseWheel events that are much closer
+ * together, and are expected to be 60fps, so the first event in a sequence
+ * is turned into a Response, and the rest are merged into an Animation.
+ * NB this threshold uses the two events' start times, unlike
+ * ProtoExpectation.isNear, which compares the end time of the previous event
+ * with the start time of the next.
+ */
function handleMouseWheelEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -227,33 +239,34 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,
- MOUSEWHEEL_IR_NAME);
+ INITIATOR_TYPE.MOUSE_WHEEL);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
return;
}
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, MOUSEWHEEL_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.MOUSE_WHEEL);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
});
return protoExpectations;
}
- // Down events followed closely by Up events are click Responses, but the
- // Response doesn't start until the Up event.
- //
- // RRR
- // DDD UUU
- //
- // If there are any Move events in between a Down and an Up, then the Down
- // and the first Move are a Response, then the rest of the Moves are an
- // Animation:
- //
- // RRRRRRRAAAAAAAAAAAAAAAAAAAA
- // DDD MMM MMM MMM MMM MMM UUU
- //
+ /**
+ * Down events followed closely by Up events are click Responses, but the
+ * Response doesn't start until the Up event.
+ *
+ * RRR
+ * DDD UUU
+ *
+ * If there are any Move events in between a Down and an Up, then the Down
+ * and the first Move are a Response, then the rest of the Moves are an
+ * Animation:
+ *
+ * RRRRRRRAAAAAAAAAAAAAAAAAAAA
+ * DDD MMM MMM MMM MMM MMM UUU
+ */
function handleMouseDragEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -264,7 +277,7 @@ tr.exportTo('tr.importer', function() {
case INPUT_TYPE.MOUSE_DOWN:
if (causedFrame(event)) {
var pe = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, MOUSE_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.MOUSE);
pe.pushEvent(event);
protoExpectations.push(pe);
} else {
@@ -273,6 +286,7 @@ tr.exportTo('tr.importer', function() {
mouseDownEvent = event;
}
break;
+
// There may be more than 100ms between the start of the mouse down
// and the start of the mouse up. Chrome and the web don't start to
// respond until the mouse up. ResponseIRs start deducting comfort
@@ -296,7 +310,7 @@ tr.exportTo('tr.importer', function() {
// The first MouseMove after a MouseDown or after a while is a
// Response.
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, MOUSE_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.MOUSE);
currentPE.pushEvent(event);
if (mouseDownEvent) {
currentPE.associatedEvents.push(mouseDownEvent);
@@ -309,7 +323,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, MOUSE_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.MOUSE);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
@@ -321,7 +335,7 @@ tr.exportTo('tr.importer', function() {
var pe = new ProtoExpectation(
causedFrame(event) ? ProtoExpectation.RESPONSE_TYPE :
ProtoExpectation.IGNORED_TYPE,
- MOUSE_IR_NAME);
+ INITIATOR_TYPE.MOUSE);
pe.pushEvent(event);
protoExpectations.push(pe);
break;
@@ -331,7 +345,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, MOUSE_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.MOUSE);
if (mouseDownEvent)
currentPE.associatedEvents.push(mouseDownEvent);
currentPE.pushEvent(event);
@@ -350,25 +364,26 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // Solitary Tap events are simple Responses:
- //
- // RRR
- // TTT
- //
- // TapDowns are part of Responses.
- //
- // RRRRRRR
- // DDD TTT
- //
- // TapCancels are part of Responses, which seems strange. They always go
- // with scrolls, so they'll probably be merged with scroll Responses.
- // TapCancels can take a significant amount of time and account for a
- // significant amount of work, which should be grouped with the scroll IRs
- // if possible.
- //
- // RRRRRRR
- // DDD CCC
- //
+ /**
+ * Solitary Tap events are simple Responses:
+ *
+ * RRR
+ * TTT
+ *
+ * TapDowns are part of Responses.
+ *
+ * RRRRRRR
+ * DDD TTT
+ *
+ * TapCancels are part of Responses, which seems strange. They always go
+ * with scrolls, so they'll probably be merged with scroll Responses.
+ * TapCancels can take a significant amount of time and account for a
+ * significant amount of work, which should be grouped with the scroll IRs
+ * if possible.
+ *
+ * RRRRRRR
+ * DDD CCC
+ **/
function handleTapResponseEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -376,7 +391,7 @@ tr.exportTo('tr.importer', function() {
switch (event.typeName) {
case INPUT_TYPE.TAP_DOWN:
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, TAP_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.TAP);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
break;
@@ -388,7 +403,7 @@ tr.exportTo('tr.importer', function() {
// Sometimes we get Tap events with no TapDown, sometimes we get
// TapDown events. Handle both.
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, TAP_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.TAP);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
@@ -407,7 +422,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, TAP_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.TAP);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
@@ -418,12 +433,13 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // The PinchBegin and the first PinchUpdate comprise a Response, then the
- // rest of the PinchUpdates comprise an Animation.
- //
- // RRRRRRRAAAAAAAAAAAAAAAAAAAA
- // BBB UUU UUU UUU UUU UUU EEE
- //
+ /**
+ * The PinchBegin and the first PinchUpdate comprise a Response, then the
+ * rest of the PinchUpdates comprise an Animation.
+ *
+ * RRRRRRRAAAAAAAAAAAAAAAAAAAA
+ * BBB UUU UUU UUU UUU UUU EEE
+ */
function handlePinchEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -438,7 +454,7 @@ tr.exportTo('tr.importer', function() {
break;
}
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, PINCH_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.PINCH);
currentPE.pushEvent(event);
currentPE.isAnimationBegin = true;
protoExpectations.push(currentPE);
@@ -456,7 +472,7 @@ tr.exportTo('tr.importer', function() {
sawFirstUpdate) ||
!currentPE.isNear(event, INPUT_MERGE_THRESHOLD_MS)) {
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, PINCH_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.PINCH);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
} else {
@@ -480,19 +496,20 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // Flings are defined by 3 types of events: FlingStart, FlingCancel, and the
- // renderer fling event. Flings do not begin with a Response. Flings end
- // either at the beginning of a FlingCancel, or at the end of the renderer
- // fling event.
- //
- // AAAAAAAAAAAAAAAAAAAAAAAAAA
- // SSS
- // RRRRRRRRRRRRRRRRRRRRRR
- //
- //
- // AAAAAAAAAAA
- // SSS CCC
- //
+ /**
+ * Flings are defined by 3 types of events: FlingStart, FlingCancel, and the
+ * renderer fling event. Flings do not begin with a Response. Flings end
+ * either at the beginning of a FlingCancel, or at the end of the renderer
+ * fling event.
+ *
+ * AAAAAAAAAAAAAAAAAAAAAAAAAA
+ * SSS
+ * RRRRRRRRRRRRRRRRRRRRRR
+ *
+ *
+ * AAAAAAAAAAA
+ * SSS CCC
+ */
function handleFlingEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -515,7 +532,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, FLING_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.FLING);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
@@ -529,7 +546,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, FLING_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.FLING);
currentPE.pushEvent(event);
// Set end to an invalid value so that it can be noticed and fixed
// later.
@@ -566,18 +583,19 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // The TouchStart and the first TouchMove comprise a Response, then the
- // rest of the TouchMoves comprise an Animation.
- //
- // RRRRRRRAAAAAAAAAAAAAAAAAAAA
- // SSS MMM MMM MMM MMM MMM EEE
- //
- // If there are no TouchMove events in between a TouchStart and a TouchEnd,
- // then it's just a Response.
- //
- // RRRRRRR
- // SSS EEE
- //
+ /**
+ * The TouchStart and the first TouchMove comprise a Response, then the
+ * rest of the TouchMoves comprise an Animation.
+ *
+ * RRRRRRRAAAAAAAAAAAAAAAAAAAA
+ * SSS MMM MMM MMM MMM MMM EEE
+ *
+ * If there are no TouchMove events in between a TouchStart and a TouchEnd,
+ * then it's just a Response.
+ *
+ * RRRRRRR
+ * SSS EEE
+ */
function handleTouchEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -593,7 +611,7 @@ tr.exportTo('tr.importer', function() {
currentPE.pushEvent(event);
} else {
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, TOUCH_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.TOUCH);
currentPE.pushEvent(event);
currentPE.isAnimationBegin = true;
protoExpectations.push(currentPE);
@@ -604,7 +622,7 @@ tr.exportTo('tr.importer', function() {
case INPUT_TYPE.TOUCH_MOVE:
if (!currentPE) {
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, TOUCH_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.TOUCH);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
break;
@@ -620,7 +638,7 @@ tr.exportTo('tr.importer', function() {
// near event, then finish it and start a new animation.
var prevEnd = currentPE.end;
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, TOUCH_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.TOUCH);
currentPE.pushEvent(event);
// It's possible for there to be a gap between TouchMoves, but
// that doesn't mean that there should be an Idle IR there.
@@ -653,12 +671,13 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // The first ScrollBegin and the first ScrollUpdate comprise a Response,
- // then the rest comprise an Animation.
- //
- // RRRRRRRAAAAAAAAAAAAAAAAAAAA
- // BBB UUU UUU UUU UUU UUU EEE
- //
+ /**
+ * The first ScrollBegin and the first ScrollUpdate comprise a Response,
+ * then the rest comprise an Animation.
+ *
+ * RRRRRRRAAAAAAAAAAAAAAAAAAAA
+ * BBB UUU UUU UUU UUU UUU EEE
+ */
function handleScrollEvents(modelHelper, sortedInputEvents) {
var protoExpectations = [];
var currentPE = undefined;
@@ -669,7 +688,7 @@ tr.exportTo('tr.importer', function() {
// Always begin a new PE even if there already is one, unlike
// PinchBegin.
currentPE = new ProtoExpectation(
- ProtoExpectation.RESPONSE_TYPE, SCROLL_IR_NAME);
+ ProtoExpectation.RESPONSE_TYPE, INITIATOR_TYPE.SCROLL);
currentPE.pushEvent(event);
currentPE.isAnimationBegin = true;
protoExpectations.push(currentPE);
@@ -685,14 +704,14 @@ tr.exportTo('tr.importer', function() {
sawFirstUpdate = true;
} else {
currentPE = new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,
- SCROLL_IR_NAME);
+ INITIATOR_TYPE.SCROLL);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
} else {
- // ScrollUpdate without ScrollBegin.
+ // ScrollUpdate without ScrollBegin.
currentPE = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, SCROLL_IR_NAME);
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.SCROLL);
currentPE.pushEvent(event);
protoExpectations.push(currentPE);
}
@@ -714,7 +733,41 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // CSS Animations are merged into AnimationExpectations when they intersect.
+ /**
+ * Returns proto expectations for video animation events.
+ *
+ * Video animations represent video playback, and are based on
+ * VideoPlayback async events (going from the VideoFrameCompositor::Start
+ * to VideoFrameCompositor::Stop calls)
+ */
+ function handleVideoAnimations(modelHelper, sortedInputEvents) {
+ var events = [];
+ for (var pid in modelHelper.rendererHelpers) {
+ for (var asyncSlice of
+ modelHelper.rendererHelpers[pid].mainThread.asyncSliceGroup.slices) {
+ if (asyncSlice.title === PLAYBACK_EVENT_TITLE)
+ events.push(asyncSlice);
+ }
+ }
+
+ events.sort(tr.importer.compareEvents);
+
+ var protoExpectations = [];
+ for (var event of events) {
+ var currentPE = new ProtoExpectation(
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.VIDEO);
+ currentPE.start = event.start;
+ currentPE.end = event.end;
+ currentPE.pushEvent(event);
+ protoExpectations.push(currentPE);
+ }
+
+ return protoExpectations;
+ }
+
+ /**
+ * CSS Animations are merged into AnimationExpectations when they intersect.
+ */
function handleCSSAnimations(modelHelper, sortedInputEvents) {
// First find all the top-level CSS Animation async events.
var animationEvents = modelHelper.browserHelper.
@@ -724,55 +777,16 @@ tr.exportTo('tr.importer', function() {
(event.duration > 0));
});
- // Memoize the frame events per process.
- // There may be many Animation events for each process. We can save a
- // significant amount of processing time by avoiding re-computing them for
- // each animation.
- var framesForProcess = {};
-
- function getFramesForAnimationProcess(animation) {
- var frames = framesForProcess[animation.parentContainer.parent.guid];
- if (frames === undefined) {
- var rendererHelper = new tr.model.helpers.ChromeRendererHelper(
- modelHelper, animation.parentContainer.parent);
- // Collect all the frame events in the same renderer process as the css
- // animation, and memoize them.
- frames = rendererHelper.getFrameEventsInRange(
- tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds);
- framesForProcess[animation.parentContainer.parent.guid] = frames;
- }
- return frames;
- }
// Time ranges where animations are actually running will be collected here.
- // Each element will contain {min, max, animation, frames}.
+ // Each element will contain {min, max, animation}.
var animationRanges = [];
// This helper function will be called when a time range is found
// during which the animation is actually running.
- // This helper function collects the frames that happened during the time
- // range, and pushes it all to |animationRanges|.
function pushAnimationRange(start, end, animation) {
var range = tr.b.Range.fromExplicitRange(start, end);
range.animation = animation;
-
- // Collect the frames that happened while the animation was running.
- // A more general way to find these frames would be to collect all of
- // the trace events caused by this animation, but that will require
- // adding flow events to chrome:
- // https://github.com/catapult-project/catapult/issues/1433
- range.frames = range.filterArray(
- getFramesForAnimationProcess(animation),
- function(frameEvent) { return frameEvent.start; });
-
- // If a tree falls in a forest...
- // If there were not actually any frames while the animation was
- // running, then it wasn't really an animation, now, was it?
- // Philosophy aside, the system_health Animation metrics fail hard if
- // there are no frames in an AnimationExpectation.
- if (range.frames.length === 0)
- return;
-
animationRanges.push(range);
}
@@ -785,22 +799,22 @@ tr.exportTo('tr.importer', function() {
// find ranges where the animation was actually running.
var start = undefined;
animation.subSlices.forEach(function(sub) {
- if ((sub.args.state === 'running') &&
+ if ((sub.args.data.state === 'running') &&
(start === undefined)) {
// It's possible for the state to alternate between running and
// pending, but the animation is still running in that case,
// so only set start if the state is changing from one of the halted
// states.
start = sub.start;
- } else if ((sub.args.state === 'paused') ||
- (sub.args.state === 'idle') ||
- (sub.args.state === 'finished')) {
+ } else if ((sub.args.data.state === 'paused') ||
+ (sub.args.data.state === 'idle') ||
+ (sub.args.data.state === 'finished')) {
if (start === undefined) {
// An animation was already running when the trace started.
// (Actually, it's possible that the animation was in the 'idle'
// state when tracing started, but that should be rare, and will
// be fixed when async events are buffered.)
- // http://crbug.com/565627
+ // http: //crbug.com/565627
start = modelHelper.model.bounds.min;
}
@@ -809,37 +823,132 @@ tr.exportTo('tr.importer', function() {
}
});
- // An animation was still running when the trace ended.
+ // An animation was still running when the
+ // top-level animation event ended.
if (start !== undefined)
- pushAnimationRange(start, modelHelper.model.bounds.max, animation);
+ pushAnimationRange(start, animation.end, animation);
}
});
// Now we have a set of time ranges when css animations were actually
- // running, along with their frames.
- // Now all that's left for this function is to merge over-lapping ranges
- // into ProtoExpectations.
+ // running.
+ // Leave merging intersecting animations to mergeIntersectingAnimations(),
+ // after findFrameEventsForAnimations removes frame-less animations.
- function merge(ranges) {
+ return animationRanges.map(function(range) {
var protoExpectation = new ProtoExpectation(
- ProtoExpectation.ANIMATION_TYPE, CSS_IR_NAME);
- ranges.forEach(function(range) {
- protoExpectation.start = Math.min(protoExpectation.start, range.min);
- protoExpectation.end = Math.max(protoExpectation.end, range.max);
- protoExpectation.associatedEvents.push(range.animation);
- protoExpectation.associatedEvents.addEventSet(range.frames);
- });
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.CSS);
+ protoExpectation.start = range.min;
+ protoExpectation.end = range.max;
+ protoExpectation.associatedEvents.push(range.animation);
return protoExpectation;
+ });
+ }
+
+ /**
+ * Get all the events (prepareMailbox and serviceScriptedAnimations)
+ * relevant to WebGL. Note that modelHelper is the helper object containing
+ * the model, and mailboxEvents and animationEvents are arrays where the
+ * events are being pushed into (DrawingBuffer::prepareMailbox events go
+ * into mailboxEvents; PageAnimator::serviceScriptedAnimations events go
+ * into animationEvents). The function does not return anything but
+ * modifies mailboxEvents and animationEvents.
+ */
+ function findWebGLEvents(modelHelper, mailboxEvents, animationEvents) {
+ for (var event of modelHelper.model.getDescendantEvents()) {
+ if (event.title === 'DrawingBuffer::prepareMailbox')
+ mailboxEvents.push(event);
+ else if (event.title === 'PageAnimator::serviceScriptedAnimations')
+ animationEvents.push(event);
}
+ }
- return tr.b.mergeRanges(animationRanges,
- ANIMATION_MERGE_THRESHOLD_MS,
- merge);
+ /**
+ * Returns a list of events in mailboxEvents that have an event in
+ * animationEvents close by (within ANIMATION_MERGE_THRESHOLD_MS).
+ */
+ function findMailboxEventsNearAnimationEvents(
+ mailboxEvents, animationEvents) {
+ if (animationEvents.length === 0)
+ return [];
+
+ mailboxEvents.sort(compareEvents);
+ animationEvents.sort(compareEvents);
+ var animationIterator = animationEvents[Symbol.iterator]();
+ var animationEvent = animationIterator.next().value;
+
+ var filteredEvents = [];
+
+ // We iterate through the mailboxEvents. With each event, we check if
+ // there is a animationEvent near it, and if so, add it to the result.
+ for (var event of mailboxEvents) {
+ // If the current animationEvent is too far before the mailboxEvent,
+ // we advance until we get to the next animationEvent that is not too
+ // far before the animationEvent.
+ while (animationEvent &&
+ (animationEvent.start < (
+ event.start - ANIMATION_MERGE_THRESHOLD_MS)))
+ animationEvent = animationIterator.next().value;
+
+ // If there aren't any more animationEvents, then that means all the
+ // remaining mailboxEvents are too far after the animationEvents, so
+ // we can quit now.
+ if (!animationEvent)
+ break;
+
+ // If there's a animationEvent close to the mailboxEvent, then we push
+ // the current mailboxEvent onto the stack.
+ if (animationEvent.start < (event.start + ANIMATION_MERGE_THRESHOLD_MS))
+ filteredEvents.push(event);
+ }
+ return filteredEvents;
}
- function postProcessProtoExpectations(protoExpectations) {
+ /**
+ * Merge consecutive mailbox events into a ProtoExpectation. Note: Only
+ * the drawingBuffer::prepareMailbox events will end up in the
+ * associatedEvents. The PageAnimator::serviceScriptedAnimations events
+ * will not end up in the associatedEvents.
+ */
+ function createProtoExpectationsFromMailboxEvents(mailboxEvents) {
+ var protoExpectations = [];
+ var currentPE = undefined;
+ for (var event of mailboxEvents) {
+ if (currentPE === undefined || !currentPE.isNear(
+ event, ANIMATION_MERGE_THRESHOLD_MS)) {
+ currentPE = new ProtoExpectation(
+ ProtoExpectation.ANIMATION_TYPE, INITIATOR_TYPE.WEBGL);
+ currentPE.pushEvent(event);
+ protoExpectations.push(currentPE);
+ }
+ else {
+ currentPE.pushEvent(event);
+ }
+ }
+ return protoExpectations;
+ }
+
+ // WebGL animations are identified by the DrawingBuffer::prepareMailbox
+ // and PageAnimator::serviceScriptedAnimations events (one of each per frame)
+ // and consecutive frames are merged into the same animation.
+ function handleWebGLAnimations(modelHelper, sortedInputEvents) {
+ // Get the prepareMailbox and scriptedAnimation events.
+ var prepareMailboxEvents = [];
+ var scriptedAnimationEvents = [];
+
+ findWebGLEvents(modelHelper, prepareMailboxEvents, scriptedAnimationEvents);
+ var webGLMailboxEvents = findMailboxEventsNearAnimationEvents(
+ prepareMailboxEvents, scriptedAnimationEvents);
+
+ return createProtoExpectationsFromMailboxEvents(webGLMailboxEvents);
+ }
+
+
+ function postProcessProtoExpectations(modelHelper, protoExpectations) {
// protoExpectations is input only. Returns a modified set of
// ProtoExpectations. The order is important.
+ protoExpectations = findFrameEventsForAnimations(
+ modelHelper, protoExpectations);
protoExpectations = mergeIntersectingResponses(protoExpectations);
protoExpectations = mergeIntersectingAnimations(protoExpectations);
protoExpectations = fixResponseAnimationStarts(protoExpectations);
@@ -847,18 +956,20 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // TouchStarts happen at the same time as ScrollBegins.
- // It's easier to let multiple handlers create multiple overlapping
- // Responses and then merge them, rather than make the handlers aware of the
- // other handlers' PEs.
- //
- // For example:
- // RR
- // RRR -> RRRRR
- // RR
- //
- // protoExpectations is input only.
- // Returns a modified set of ProtoExpectations.
+ /**
+ * TouchStarts happen at the same time as ScrollBegins.
+ * It's easier to let multiple handlers create multiple overlapping
+ * Responses and then merge them, rather than make the handlers aware of the
+ * other handlers' PEs.
+ *
+ * For example:
+ * RR
+ * RRR -> RRRRR
+ * RR
+ *
+ * protoExpectations is input only.
+ * Returns a modified set of ProtoExpectations.
+ */
function mergeIntersectingResponses(protoExpectations) {
var newPEs = [];
while (protoExpectations.length) {
@@ -889,6 +1000,7 @@ tr.exportTo('tr.importer', function() {
pe.merge(otherPE);
protoExpectations.splice(i, 1);
+
// Don't skip the next otherPE!
--i;
}
@@ -896,16 +1008,18 @@ tr.exportTo('tr.importer', function() {
return newPEs;
}
- // An animation is simply an expectation of 60fps between start and end.
- // If two animations overlap, then merge them.
- //
- // For example:
- // AA
- // AAA -> AAAAA
- // AA
- //
- // protoExpectations is input only.
- // Returns a modified set of ProtoExpectations.
+ /**
+ * An animation is simply an expectation of 60fps between start and end.
+ * If two animations overlap, then merge them.
+ *
+ * For example:
+ * AA
+ * AAA -> AAAAA
+ * AA
+ *
+ * protoExpectations is input only.
+ * Returns a modified set of ProtoExpectations.
+ */
function mergeIntersectingAnimations(protoExpectations) {
var newPEs = [];
while (protoExpectations.length) {
@@ -918,6 +1032,7 @@ tr.exportTo('tr.importer', function() {
var isCSS = pe.containsSliceTitle(CSS_ANIMATION_TITLE);
var isFling = pe.containsTypeNames([INPUT_TYPE.FLING_START]);
+ var isVideo = pe.containsTypeNames([INITIATOR_TYPE.VIDEO]);
for (var i = 0; i < protoExpectations.length; ++i) {
var otherPE = protoExpectations[i];
@@ -926,14 +1041,22 @@ tr.exportTo('tr.importer', function() {
continue;
// Don't merge CSS Animations with any other types.
- if (isCSS != otherPE.containsSliceTitle(CSS_ANIMATION_TITLE))
+ if (isCSS !== otherPE.containsSliceTitle(CSS_ANIMATION_TITLE))
continue;
- if (!otherPE.intersects(pe))
+ if (isCSS) {
+ if (!pe.isNear(otherPE, ANIMATION_MERGE_THRESHOLD_MS))
+ continue;
+ } else if (!otherPE.intersects(pe)) {
continue;
+ }
// Don't merge Fling Animations with any other types.
- if (isFling != otherPE.containsTypeNames([INPUT_TYPE.FLING_START]))
+ if (isFling !== otherPE.containsTypeNames([INPUT_TYPE.FLING_START]))
+ continue;
+
+ // Don't merge Video Animations with any other types.
+ if (isVideo !== otherPE.containsTypeNames([INITIATOR_TYPE.VIDEO]))
continue;
pe.merge(otherPE);
@@ -945,16 +1068,18 @@ tr.exportTo('tr.importer', function() {
return newPEs;
}
- // The ends of responses frequently overlap the starts of animations.
- // Fix the animations to reflect the fact that the user can only start to
- // expect 60fps after the response.
- //
- // For example:
- // RRR -> RRRAA
- // AAAA
- //
- // protoExpectations is input only.
- // Returns a modified set of ProtoExpectations.
+ /**
+ * The ends of responses frequently overlap the starts of animations.
+ * Fix the animations to reflect the fact that the user can only start to
+ * expect 60fps after the response.
+ *
+ * For example:
+ * RRR -> RRRAA
+ * AAAA
+ *
+ * protoExpectations is input only.
+ * Returns a modified set of ProtoExpectations.
+ */
function fixResponseAnimationStarts(protoExpectations) {
protoExpectations.forEach(function(ape) {
// Only consider animations for now.
@@ -981,8 +1106,10 @@ tr.exportTo('tr.importer', function() {
return protoExpectations;
}
- // Merge Tap Responses that overlap Touch-only Animations.
- // https://github.com/catapult-project/catapult/issues/1431
+ /**
+ * Merge Tap Responses that overlap Touch-only Animations.
+ * https: *github.com/catapult-project/catapult/issues/1431
+ */
function fixTapResponseTouchAnimations(protoExpectations) {
function isTapResponse(pe) {
return (pe.irType === ProtoExpectation.RESPONSE_TYPE) &&
@@ -1031,7 +1158,50 @@ tr.exportTo('tr.importer', function() {
return newPEs;
}
- // Check that none of the handlers accidentally ignored an input event.
+ function findFrameEventsForAnimations(modelHelper, protoExpectations) {
+ var newPEs = [];
+ var frameEventsByPid = getSortedFrameEventsByProcess(modelHelper);
+
+ for (var pe of protoExpectations) {
+ if (pe.irType !== ProtoExpectation.ANIMATION_TYPE) {
+ newPEs.push(pe);
+ continue;
+ }
+
+ var frameEvents = [];
+ // TODO(benjhayden): Use frame blame contexts here.
+ for (var pid of Object.keys(modelHelper.rendererHelpers)) {
+ var range = tr.b.Range.fromExplicitRange(pe.start, pe.end);
+ frameEvents.push.apply(frameEvents,
+ range.filterArray(frameEventsByPid[pid], e => e.start));
+ }
+
+ // If a tree falls in a forest...
+ // If there were not actually any frames while the animation was
+ // running, then it wasn't really an animation, now, was it?
+ // Philosophy aside, the system_health Animation metrics fail hard if
+ // there are no frames in an AnimationExpectation.
+ // Since WebGL animations don't generate this type of frame event,
+ // don't remove them if it's a WebGL animation.
+ // TODO(alexandermont): Identify what the correct frame event to
+ // use here is.
+ if (frameEvents.length === 0 &&
+ !(pe.initiatorType === INITIATOR_TYPE.WEBGL)) {
+ pe.irType = ProtoExpectation.IGNORED_TYPE;
+ newPEs.push(pe);
+ continue;
+ }
+
+ pe.associatedEvents.addEventSet(frameEvents);
+ newPEs.push(pe);
+ }
+
+ return newPEs;
+ }
+
+ /**
+ * Check that none of the handlers accidentally ignored an input event.
+ */
function checkAllInputEventsHandled(sortedInputEvents, protoExpectations) {
var handledEvents = [];
protoExpectations.forEach(function(protoExpectation) {
@@ -1041,7 +1211,8 @@ tr.exportTo('tr.importer', function() {
(event.subSlices.length > 0))
return;
- if (handledEvents.indexOf(event) >= 0) {
+ if ((handledEvents.indexOf(event) >= 0) &&
+ (event.title !== tr.model.helpers.IMPL_RENDERING_STATS)) {
console.error('double-handled event', event.typeName,
parseInt(event.start), parseInt(event.end), protoExpectation);
return;
@@ -1058,12 +1229,15 @@ tr.exportTo('tr.importer', function() {
});
}
- // Find ProtoExpectations, post-process them, convert them to real IRs.
+ /**
+ * Find ProtoExpectations, post-process them, convert them to real IRs.
+ */
function findInputExpectations(modelHelper) {
var sortedInputEvents = getSortedInputEvents(modelHelper);
var protoExpectations = findProtoExpectations(
modelHelper, sortedInputEvents);
- protoExpectations = postProcessProtoExpectations(protoExpectations);
+ protoExpectations = postProcessProtoExpectations(
+ modelHelper, protoExpectations);
checkAllInputEventsHandled(sortedInputEvents, protoExpectations);
var irs = [];
@@ -1078,7 +1252,8 @@ tr.exportTo('tr.importer', function() {
return {
findInputExpectations: findInputExpectations,
compareEvents: compareEvents,
- CSS_ANIMATION_TITLE: CSS_ANIMATION_TITLE
+ CSS_ANIMATION_TITLE: CSS_ANIMATION_TITLE,
+ INITIATOR_TYPE: INITIATOR_TYPE
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/import.html b/chromium/third_party/catapult/tracing/tracing/importer/import.html
index 8fe21637c8c..7ee18d90d34 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/import.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/import.html
@@ -5,11 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel='import' href='/tracing/base/base.html'>
-<link rel='import' href='/tracing/base/timing.html'>
+<link rel="import" href="/tracing/base/base.html">
+<link rel="import" href="/tracing/base/timing.html">
<link rel="import" href="/tracing/importer/empty_importer.html">
<link rel="import" href="/tracing/importer/importer.html">
<link rel="import" href="/tracing/importer/user_model_builder.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
<script>
'use strict';
@@ -86,10 +87,10 @@ tr.exportTo('tr.importer', function() {
overlay.title = 'Importing...';
overlay.userCanClose = false;
overlay.msgEl = document.createElement('div');
- overlay.appendChild(overlay.msgEl);
+ Polymer.dom(overlay).appendChild(overlay.msgEl);
overlay.msgEl.style.margin = '20px';
overlay.update = function(msg) {
- this.msgEl.textContent = msg;
+ Polymer.dom(this.msgEl).textContent = msg;
};
overlay.visible = true;
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/proto_expectation.html b/chromium/third_party/catapult/tracing/tracing/importer/proto_expectation.html
index c3b655c00e6..58fea74fc0c 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/proto_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/proto_expectation.html
@@ -11,6 +11,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/event_info.html">
<link rel="import" href="/tracing/model/user_model/animation_expectation.html">
<link rel="import" href="/tracing/model/user_model/response_expectation.html">
+<link rel="import" href="/tracing/model/user_model/user_expectation.html">
<script>
'use strict';
@@ -18,9 +19,9 @@ found in the LICENSE file.
tr.exportTo('tr.importer', function() {
// This is an intermediate data format between InputLatencyAsyncSlices and
// Response and Animation IRs.
- function ProtoExpectation(irType, name) {
+ function ProtoExpectation(irType, initiatorType) {
this.irType = irType;
- this.names = new Set(name ? [name] : undefined);
+ this.initiatorType = initiatorType;
this.start = Infinity;
this.end = -Infinity;
this.associatedEvents = new tr.model.EventSet();
@@ -35,6 +36,33 @@ tr.exportTo('tr.importer', function() {
// were unintentionally ignored due to a bug.
ProtoExpectation.IGNORED_TYPE = 'ignored';
+ /**
+ * Combine initiator titles by selecting the initiator title first in a
+ * hard-coded hierarchy. Higher up in the hierarchy are more "specific"
+ * initiator titles (e.g. a scroll is higher than a touch, because a
+ * touch could mean many different things, of which a scroll is one)
+ */
+ var INITIATOR_HIERARCHY = [
+ tr.model.um.INITIATOR_TYPE.PINCH,
+ tr.model.um.INITIATOR_TYPE.FLING,
+ tr.model.um.INITIATOR_TYPE.MOUSE_WHEEL,
+ tr.model.um.INITIATOR_TYPE.SCROLL,
+ tr.model.um.INITIATOR_TYPE.VIDEO,
+ tr.model.um.INITIATOR_TYPE.WEBGL,
+ tr.model.um.INITIATOR_TYPE.CSS,
+ tr.model.um.INITIATOR_TYPE.MOUSE,
+ tr.model.um.INITIATOR_TYPE.KEYBOARD,
+ tr.model.um.INITIATOR_TYPE.TAP,
+ tr.model.um.INITIATOR_TYPE.TOUCH
+ ];
+
+ function combineInitiatorTypes(title1, title2) {
+ for (var item of INITIATOR_HIERARCHY)
+ if (title1 === item || title2 === item) return item;
+ console.error('Invalid titles in combineInitiatorTypes')
+ return undefined;
+ }
+
ProtoExpectation.prototype = {
get isValid() {
return this.end > this.start;
@@ -57,24 +85,18 @@ tr.exportTo('tr.importer', function() {
return undefined;
}
- var initiatorTitles = [];
- this.names.forEach(function(name) {
- initiatorTitles.push(name);
- });
- initiatorTitles = initiatorTitles.sort().join(',');
-
var duration = this.end - this.start;
var ir = undefined;
switch (this.irType) {
case ProtoExpectation.RESPONSE_TYPE:
ir = new tr.model.um.ResponseExpectation(
- model, initiatorTitles, this.start, duration,
+ model, this.initiatorType, this.start, duration,
this.isAnimationBegin);
break;
case ProtoExpectation.ANIMATION_TYPE:
ir = new tr.model.um.AnimationExpectation(
- model, initiatorTitles, this.start, duration);
+ model, this.initiatorType, this.start, duration);
break;
}
if (!ir)
@@ -108,7 +130,8 @@ tr.exportTo('tr.importer', function() {
// into overlapping ProtoExpectations, and Touch-only Animations are merged
// into Tap Responses.
merge: function(other) {
- other.names.forEach(function(name) { this.names.add(name); }.bind(this));
+ this.initiatorType = combineInitiatorTypes(
+ this.initiatorType, other.initiatorType)
// Don't use pushEvent(), which would lose special start, end.
this.associatedEvents.addEventSet(other.associatedEvents);
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/user_expectation_verifier.html b/chromium/third_party/catapult/tracing/tracing/importer/user_expectation_verifier.html
index 18c080d4424..2bc8c9e0787 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/user_expectation_verifier.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/user_expectation_verifier.html
@@ -41,9 +41,9 @@ tr.exportTo('tr.importer', function() {
var i = 0;
assert.lengthOf(model.userModel.expectations,
this.expectedIRs_.length);
- var actualUE_iterator = model.userModel.expectations[Symbol.iterator]();
+ var actualUEIterator = model.userModel.expectations[Symbol.iterator]();
for (var expectedIR of this.expectedIRs_) {
- var actualUE = actualUE_iterator.next();
+ var actualUE = actualUEIterator.next();
assert.equal(false, actualUE.done);
var at = 'IRs[' + (i++) + '].';
assert.equal(expectedIR.title, actualUE.value.title, at + 'title');
@@ -60,6 +60,9 @@ tr.exportTo('tr.importer', function() {
}
} catch (caught) {
failure = caught;
+ for (var i = 0; i < model.userModel.expectations.length; ++i) {
+ console.debug(i, model.userModel.expectations[i]);
+ }
}
var debug = !tr.isHeadless && (
diff --git a/chromium/third_party/catapult/tracing/tracing/importer/user_model_builder_test.html b/chromium/third_party/catapult/tracing/tracing/importer/user_model_builder_test.html
index 9938675bc42..97ec7cd981a 100644
--- a/chromium/third_party/catapult/tracing/tracing/importer/user_model_builder_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/importer/user_model_builder_test.html
@@ -14,11 +14,11 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var INPUT_TYPE = tr.e.cc.INPUT_EVENT_TYPE_NAMES;
- var chrome_test_utils = tr.e.chrome.ChromeTestUtils;
+ var ChromeTestUtils = tr.e.chrome.ChromeTestUtils;
var UserExpectationVerifier = tr.importer.UserExpectationVerifier;
function addFrameEventForInput(model, event) {
- var frame = chrome_test_utils.addFrameEvent(model,
+ var frame = ChromeTestUtils.addFrameEvent(model,
{start: event.start, end: event.end, isTopLevel: true});
model.flowEvents.push(tr.c.TestUtils.newFlowEventEx({
id: event.id,
@@ -38,20 +38,70 @@ tr.b.unittest.testSuite(function() {
verifier.verify();
});
+ test('videoExpectations_gapInMiddle', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 0, end: 100, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 10, end: 20});
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 200, end: 300, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 210, end: 220});
+ };
+ verifier.expectedIRs = [
+ {title: 'Video Animation', start: 0, end: 100, eventCount: 2},
+ {title: 'Idle', start: 100, end: 200, eventCount: 0},
+ {title: 'Video Animation', start: 200, end: 300, eventCount: 2},
+ ];
+ verifier.verify();
+ });
+
+ test('videoExpectations_overlapping', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 0, end: 200, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 10, end: 20});
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 100, end: 300, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 210, end: 220});
+ };
+ verifier.expectedIRs = [
+ {title: 'Video Animation', start: 0, end: 300, eventCount: 4},
+ ];
+ verifier.verify();
+ });
+
+ test('videoExpectations_oneInTheOther', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 0, end: 300, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 10, end: 20});
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'VideoPlayback', start: 100, end: 200, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 110, end: 120});
+ };
+ verifier.expectedIRs = [
+ {title: 'Video Animation', start: 0, end: 300, eventCount: 4},
+ ];
+ verifier.verify();
+ });
+
test('slowMouseMoveResponses', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(
+ ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 10});
- var mouseMove = chrome_test_utils.addInputEvent(
+ var mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 10, end: 20, id: '0x100'});
addFrameEventForInput(model, mouseMove);
- mouseMove = chrome_test_utils.addInputEvent(
+ mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 70, end: 80, id: '0x101'});
addFrameEventForInput(model, mouseMove);
- mouseMove = chrome_test_utils.addInputEvent(
+ mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 130, end: 140, id: '0x102'});
addFrameEventForInput(model, mouseMove);
};
@@ -69,15 +119,15 @@ tr.b.unittest.testSuite(function() {
test('mouseEventResponses', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- var mouseDown = chrome_test_utils.addInputEvent(
+ var mouseDown = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 50, id: '0x100'});
addFrameEventForInput(model, mouseDown);
- var mouseUp = chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
+ var mouseUp = ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
{start: 50, end: 100, id: '0x101'});
addFrameEventForInput(model, mouseUp);
- var mouseMove = chrome_test_utils.addInputEvent(
+ var mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 200, end: 250, id: '0x102'});
addFrameEventForInput(model, mouseMove);
};
@@ -93,9 +143,9 @@ tr.b.unittest.testSuite(function() {
test('mouseEventsIgnored', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
{start: 0, end: 50});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
{start: 50, end: 100});
};
verifier.expectedIRs = [
@@ -129,13 +179,13 @@ tr.b.unittest.testSuite(function() {
test('stillLoading', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
- chrome_test_utils.addNavigationStartEvent(model, {start: 10});
- chrome_test_utils.addFrameEvent(model, {start: 19, end: 20});
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addNavigationStartEvent(model, {start: 10});
+ ChromeTestUtils.addFrameEvent(model, {start: 19, end: 20});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 10, eventCount: 0},
- {title: 'Successful Load', start: 10, end: 20, eventCount: 0}
+ {title: 'Idle', start: 0, end: 10, eventCount: 1},
+ {title: 'Successful Load', start: 10, end: 20, eventCount: 1}
];
verifier.verify();
});
@@ -143,21 +193,21 @@ tr.b.unittest.testSuite(function() {
test('overlappingIdleAndLoadCollectUnassociatedEvents', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
- chrome_test_utils.addNavigationStartEvent(model, {start: 10});
- chrome_test_utils.addFirstContentfulPaintEvent(model, {start: 30});
- chrome_test_utils.addFrameEvent(model, {start: 35, end: 40});
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addNavigationStartEvent(model, {start: 10});
+ ChromeTestUtils.addFirstContentfulPaintEvent(model, {start: 30});
+ ChromeTestUtils.addFrameEvent(model, {start: 35, end: 40});
// 3 Idle events.
- chrome_test_utils.addRenderingEvent(model, {start: 5, end: 15});
- chrome_test_utils.addRenderingEvent(model, {start: 11, end: 15});
- chrome_test_utils.addRenderingEvent(model, {start: 13, end: 15});
+ ChromeTestUtils.addRenderingEvent(model, {start: 5, end: 15});
+ ChromeTestUtils.addRenderingEvent(model, {start: 11, end: 15});
+ ChromeTestUtils.addRenderingEvent(model, {start: 13, end: 15});
// 1 Idle event.
- chrome_test_utils.addRenderingEvent(model, {start: 35, end: 36});
+ ChromeTestUtils.addRenderingEvent(model, {start: 35, end: 36});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 10, eventCount: 3},
+ {title: 'Idle', start: 0, end: 10, eventCount: 4},
{title: 'Successful Load', start: 10, end: 30, eventCount: 0},
- {title: 'Idle', start: 30, end: 40, eventCount: 1}
+ {title: 'Idle', start: 30, end: 40, eventCount: 2}
];
verifier.verify();
});
@@ -168,71 +218,81 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/cnet_fling_up_fling_down_motox_2013.json
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 919, end: 998});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 919, end: 1001});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 919, end: 1001});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 974, end: 1020});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 974, end: 1020});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 974, end: 1040});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 1039, end: 1040, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 974, end: 1054});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 990, end: 1021});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 990, end: 1052});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 1051, end: 1052, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1006, end: 1021});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1022, end: 1036});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1022, end: 1052});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1038, end: 1049});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1038, end: 1068});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 1067, end: 1068, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1046, end: 1050});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1046, end: 1077});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 1432, end: 2238});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 1432, end: 2241});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1516, end: 2605});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 1532, end: 2274});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1532, end: 2294});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 2293, end: 2294, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1549, end: 2310});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 2309, end: 2310, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1627, end: 2275});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1627, end: 2310});
- chrome_test_utils.addFrameEvent(model, {start: 2990, end: 3000});
+ ChromeTestUtils.addFrameEvent(model, {start: 2990, end: 3000});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 919, eventCount: 0},
- {title: 'Scroll,Tap,Touch Response', start: 919, end: 1054,
+ {title: 'Idle', start: 0, end: 919, eventCount: 1},
+ {title: 'Scroll Response', start: 919, end: 1054,
eventCount: 6, isAnimationBegin: true},
- {title: 'Scroll,Touch Animation', start: 1054, end: 1068,
- eventCount: 8},
+ {title: 'Scroll Animation', start: 1054, end: 1068,
+ eventCount: 11},
{title: 'Fling Animation', start: 1054, end: 1432,
- eventCount: 2},
- {title: 'Scroll,Touch Response', start: 1432, end: 2605,
+ eventCount: 4},
+ {title: 'Scroll Response', start: 1432, end: 2605,
eventCount: 5, isAnimationBegin: true},
{title: 'Scroll Animation', start: 1549, end: 2310,
- eventCount: 1},
+ eventCount: 3},
{title: 'Fling Animation', start: 2605, end: 3000,
- eventCount: 1}
+ eventCount: 4}
];
verifier.verify();
});
@@ -240,9 +300,9 @@ tr.b.unittest.testSuite(function() {
test('keyboardEvents', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.KEY_DOWN_RAW,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.KEY_DOWN_RAW,
{start: 0, end: 45});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.CHAR,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.CHAR,
{start: 10, end: 50});
};
verifier.expectedIRs = [
@@ -254,11 +314,11 @@ tr.b.unittest.testSuite(function() {
test('mouseResponses', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.CLICK,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.CLICK,
{start: 0, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.CONTEXT_MENU,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.CONTEXT_MENU,
{start: 200, end: 300});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 400, end: 500});
};
verifier.expectedIRs = [
@@ -275,25 +335,37 @@ tr.b.unittest.testSuite(function() {
test('mouseWheelAnimation', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 0, end: 20});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 19, end: 20, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 16, end: 36});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 35, end: 36, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 55, end: 75});
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 74, end: 75, isTopLevel: true});
// This threshold uses both events' start times, not end...start.
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 100, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 149, end: 150, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 141, end: 191});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 190, end: 191, isTopLevel: true});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 182, end: 200});
+ ChromeTestUtils.addFrameEvent(model,
+ {start: 199, end: 200, isTopLevel: true});
};
verifier.expectedIRs = [
{title: 'MouseWheel Response', start: 0, end: 20, eventCount: 1},
{title: 'MouseWheel Animation', start: 20, end: 75,
- eventCount: 2},
+ eventCount: 5},
{title: 'Idle', start: 75, end: 100, eventCount: 0},
{title: 'MouseWheel Response', start: 100, end: 150,
eventCount: 1},
@@ -308,9 +380,9 @@ tr.b.unittest.testSuite(function() {
test('mouseDownUpResponse', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
{start: 0, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
{start: 200, end: 210});
};
verifier.expectedIRs = [
@@ -323,7 +395,7 @@ tr.b.unittest.testSuite(function() {
test('ignoreLoneMouseMoves', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
{start: 0, end: 100});
};
verifier.expectedIRs = [
@@ -335,15 +407,15 @@ tr.b.unittest.testSuite(function() {
test('mouseDrags', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(
+ ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 100});
- var mouseMove = chrome_test_utils.addInputEvent(
+ var mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 200, end: 215});
addFrameEventForInput(model, mouseMove);
- mouseMove = chrome_test_utils.addInputEvent(
+ mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 210, end: 220});
addFrameEventForInput(model, mouseMove);
- mouseMove = chrome_test_utils.addInputEvent(
+ mouseMove = ChromeTestUtils.addInputEvent(
model, INPUT_TYPE.MOUSE_MOVE, {start: 221, end: 240});
addFrameEventForInput(model, mouseMove);
};
@@ -358,39 +430,205 @@ tr.b.unittest.testSuite(function() {
test('twoScrollsNoFling', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 0, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 20, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 40, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 60, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addFrameEvent(model, {start: 149, end: 150});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 70, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
{start: 80, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 300, end: 400});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 320, end: 400});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 330, end: 450});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 340, end: 450});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 350, end: 500});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
+ ChromeTestUtils.addFrameEvent(model, {start: 499, end: 500});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
{start: 360, end: 500});
};
verifier.expectedIRs = [
{title: 'Scroll Response', start: 0, end: 100, eventCount: 2,
isAnimationBegin: true},
- {title: 'Scroll Animation', start: 100, end: 150, eventCount: 4},
+ {title: 'Scroll Animation', start: 100, end: 150, eventCount: 5},
{title: 'Idle', start: 150, end: 300, eventCount: 0},
{title: 'Scroll Response', start: 300, end: 400, eventCount: 2,
isAnimationBegin: true},
- {title: 'Scroll Animation', start: 400, end: 500, eventCount: 4}
+ {title: 'Scroll Animation', start: 400, end: 500, eventCount: 5}
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_oneAnimation', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'DrawingBuffer::prepareMailbox', start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 18, end: 19});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 20, end: 22});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 38, end: 39});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 40, end: 42});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 58, end: 59});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 60, end: 62});
+ };
+ verifier.expectedIRs = [
+ {title: 'WebGL Animation', start: 0, end: 62, eventCount: 4},
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_twoAnimations', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'DrawingBuffer::prepareMailbox', start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 18, end: 19});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 20, end: 22});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 38, end: 39});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 40, end: 42});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 58, end: 59});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 60, end: 62});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 218, end: 19});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 220, end: 222});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 238, end: 39});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 240, end: 242});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 258, end: 59});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 260, end: 262});
+ };
+ verifier.expectedIRs = [
+ {title: 'WebGL Animation', start: 0, end: 62, eventCount: 4},
+ {title: 'Idle', start: 62, end: 220, eventCount: 0},
+ {title: 'WebGL Animation', start: 220, end: 262, eventCount: 3}
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_oneWithAnimationEventsOneWithout', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'DrawingBuffer::prepareMailbox', start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 18, end: 19});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 20, end: 22});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 38, end: 39});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 40, end: 42});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 58, end: 59});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 60, end: 62});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 220, end: 222});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 240, end: 242});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 260, end: 262});
+ };
+ verifier.expectedIRs = [
+ {title: 'WebGL Animation', start: 0, end: 62, eventCount: 4},
+ {title: 'Idle', start: 62, end: 262, eventCount: 0},
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_noAnimationEvents', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'DrawingBuffer::prepareMailbox', start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 20, end: 22});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 40, end: 42});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 60, end: 62});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 220, end: 222});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 240, end: 242});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'DrawingBuffer::prepareMailbox', start: 260, end: 262});
+ };
+ verifier.expectedIRs = [
+ {title: 'Idle', start: 0, end: 262, eventCount: 0},
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_animationEventsOnly', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'PageAnimator::serviceScriptedAnimations',
+ start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 20, end: 22});
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 40, end: 42});
+ };
+ verifier.expectedIRs = [
+ {title: 'Idle', start: 0, end: 42, eventCount: 0},
+ ];
+ verifier.verify();
+ });
+
+ test('webGLAnimations_oneEvent', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'DrawingBuffer::prepareMailbox', start: 0, end: 2}));
+ ChromeTestUtils.addEvent(model.rendererMain, {
+ title: 'PageAnimator::serviceScriptedAnimations',
+ start: 4, end: 6});
+ };
+ verifier.expectedIRs = [
+ {title: 'WebGL Animation', start: 0, end: 2, eventCount: 1},
+ {title: 'Idle', start: 2, end: 6, eventCount: 0},
];
verifier.verify();
});
@@ -401,19 +639,54 @@ tr.b.unittest.testSuite(function() {
// They are merged with other kinds of animations.
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addEvent(model.rendererMain, {
- title: 'Animation', start: 0, end: 100, isTopLevel: true});
- chrome_test_utils.addFrameEvent(model, {start: 10, end: 20});
- chrome_test_utils.addEvent(model.rendererMain, {
+ model.rendererMain.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'Animation', start: 0, end: 130, isTopLevel: true}));
+ ChromeTestUtils.addFrameEvent(model, {start: 10, end: 20});
+ ChromeTestUtils.addEvent(model.rendererMain, {
title: 'Animation', start: 131, end: 200, isTopLevel: true});
- chrome_test_utils.addFrameEvent(model, {start: 150, end: 160});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 150, end: 160});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 150, end: 180});
- chrome_test_utils.addFrameEvent(model, {start: 290, end: 300});
+ ChromeTestUtils.addFrameEvent(model, {start: 290, end: 300});
};
verifier.expectedIRs = [
{title: 'CSS Animation', start: 0, end: 200, eventCount: 4},
- {title: 'Fling Animation', start: 150, end: 300, eventCount: 1}
+ {title: 'Fling Animation', start: 150, end: 300, eventCount: 3}
+ ];
+ verifier.verify();
+ });
+
+ test('cssAnimationStatesRunningAtEnd', function() {
+ var verifier = new UserExpectationVerifier();
+ verifier.customizeModelCallback = function(model) {
+ // If a top-level Animation async slice has state-change instant
+ // events and the last one is a "running" event, then it will run
+ // to the end of the top level event.
+ var animationA = tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'Animation', start: 0, end: 500, isTopLevel: true});
+ animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
+ {title: 'Animation', start: 100, args: {data: {state: 'running'}}}));
+ animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
+ {title: 'Animation', start: 200, args: {data: {state: 'idle'}}}));
+ animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
+ {title: 'Animation', start: 300, args: {data: {state: 'running'}}}));
+ model.rendererMain.asyncSliceGroup.push(animationA);
+ ChromeTestUtils.addFrameEvent(model, {start: 50, end: 60});
+ ChromeTestUtils.addFrameEvent(model, {start: 150, end: 160});
+ ChromeTestUtils.addFrameEvent(model, {start: 250, end: 260});
+ ChromeTestUtils.addFrameEvent(model, {start: 350, end: 360});
+ ChromeTestUtils.addFrameEvent(model, {start: 450, end: 460});
+ // We include a frame event off the end of the top level animation slice
+ // so we can test that it correctly stops the AnimationExpectation
+ // at the end of the top-level event, not tne end of the whole trace,
+ ChromeTestUtils.addFrameEvent(model, {start: 1050, end: 1060});
+ };
+ verifier.expectedIRs = [
+ {title: 'Idle', start: 0, end: 100, eventCount: 1},
+ {title: 'CSS Animation', start: 100, end: 200, eventCount: 5},
+ {title: 'Idle', start: 200, end: 300, eventCount: 1},
+ {title: 'CSS Animation', start: 300, end: 500, eventCount: 6},
+ {title: 'Idle', start: 500, end: 1060, eventCount: 1},
];
verifier.verify();
});
@@ -424,9 +697,9 @@ tr.b.unittest.testSuite(function() {
// If a top-level Animation async slice does not have state-change instant
// subSlices, then assume that the animation was running throughout the
// async slice.
- chrome_test_utils.addEvent(model.rendererMain, {
+ ChromeTestUtils.addEvent(model.rendererMain, {
title: 'Animation', start: 181, end: 250, isTopLevel: true});
- chrome_test_utils.addFrameEvent(model, {start: 200, end: 240});
+ ChromeTestUtils.addFrameEvent(model, {start: 200, end: 240});
// Animation ranges should be merged if there is less than 32ms dead time
// between them.
@@ -439,39 +712,42 @@ tr.b.unittest.testSuite(function() {
var animationA = tr.c.TestUtils.newAsyncSliceEx(
{title: 'Animation', start: 50, end: 500, isTopLevel: true});
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 71, args: {state: 'running'}}));
+ {title: 'Animation', start: 71, args: {data: {state: 'running'}}}));
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 104, args: {state: 'pending'}}));
+ {title: 'Animation', start: 104, args: {data: {state: 'pending'}}}));
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 137, args: {state: 'running'}}));
+ {title: 'Animation', start: 137, args: {data: {state: 'running'}}}));
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 150, args: {state: 'paused'}}));
+ {title: 'Animation', start: 150, args: {data: {state: 'paused'}}}));
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 281, args: {state: 'running'}}));
+ {title: 'Animation', start: 281, args: {data: {state: 'running'}}}));
animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 350, args: {state: 'idle'}}));
+ {title: 'Animation', start: 350, args: {data: {state: 'idle'}}}));
model.rendererMain.asyncSliceGroup.push(animationA);
- chrome_test_utils.addFrameEvent(model, {start: 80, end: 90});
- chrome_test_utils.addFrameEvent(model, {start: 290, end: 300});
+ ChromeTestUtils.addFrameEvent(model, {start: 80, end: 90});
+ ChromeTestUtils.addFrameEvent(model, {start: 290, end: 300});
// An animation without a frame event isn't really an animation.
- chrome_test_utils.addEvent(model.rendererMain, {
- title: 'Animation', start: 350, end: 382, isTopLevel: true});
+ var animationC = tr.c.TestUtils.newAsyncSliceEx(
+ {title: 'Animation', start: 350, end: 382, isTopLevel: true});
+ model.rendererMain.asyncSliceGroup.push(animationC);
+ animationA.subSlices.push(tr.c.TestUtils.newInstantEvent(
+ {title: 'Animation', start: 350, args: {data: {state: 'idle'}}}));
// This animation was running from model.bounds.min-50 and
// 70-model.bounds.max.
var animationB = tr.c.TestUtils.newAsyncSliceEx(
{title: 'Animation', start: 0, end: 500, isTopLevel: true});
animationB.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 40, args: {state: 'finished'}}));
+ {title: 'Animation', start: 40, args: {data: {state: 'finished'}}}));
animationB.subSlices.push(tr.c.TestUtils.newInstantEvent(
- {title: 'Animation', start: 382, args: {state: 'running'}}));
+ {title: 'Animation', start: 382, args: {data: {state: 'running'}}}));
model.rendererMain.asyncSliceGroup.push(animationB);
- chrome_test_utils.addFrameEvent(model, {start: 10, end: 20});
- chrome_test_utils.addFrameEvent(model, {start: 390, end: 400});
+ ChromeTestUtils.addFrameEvent(model, {start: 10, end: 20});
+ ChromeTestUtils.addFrameEvent(model, {start: 390, end: 400});
};
verifier.expectedIRs = [
- {title: 'CSS Animation', start: 0, end: 350, eventCount: 15},
+ {title: 'CSS Animation', start: 0, end: 350, eventCount: 16},
{title: 'Idle', start: 350, end: 382, eventCount: 0},
{title: 'CSS Animation', start: 382, end: 500, eventCount: 4},
];
@@ -481,14 +757,15 @@ tr.b.unittest.testSuite(function() {
test('flingThatIsntstopped', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 32, end: 100});
- chrome_test_utils.addFlingAnimationEvent(model, {start: 38, end: 200});
- chrome_test_utils.addFrameEvent(model, {start: 290, end: 300});
+ ChromeTestUtils.addFlingAnimationEvent(model, {start: 38, end: 200});
+ ChromeTestUtils.addFrameEvent(model, {start: 199, end: 200});
+ ChromeTestUtils.addFrameEvent(model, {start: 290, end: 300});
};
verifier.expectedIRs = [
- {title: 'Fling Animation', start: 32, end: 200, eventCount: 2},
- {title: 'Idle', start: 200, end: 300, eventCount: 0}
+ {title: 'Fling Animation', start: 32, end: 200, eventCount: 3},
+ {title: 'Idle', start: 200, end: 300, eventCount: 1}
];
verifier.verify();
});
@@ -496,14 +773,16 @@ tr.b.unittest.testSuite(function() {
test('flingThatIsStopped', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 32, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 105, end: 150});
+ ChromeTestUtils.addFrameEvent(model, {start: 104, end: 105});
+ ChromeTestUtils.addFrameEvent(model, {start: 149, end: 150});
};
verifier.expectedIRs = [
- {title: 'Fling Animation', start: 32, end: 105, eventCount: 2},
- {title: 'Idle', start: 105, end: 150, eventCount: 0}
+ {title: 'Fling Animation', start: 32, end: 105, eventCount: 3},
+ {title: 'Idle', start: 105, end: 150, eventCount: 1}
];
verifier.verify();
});
@@ -512,28 +791,30 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/facebook_obama_scroll_dialog_box.html
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 0, end: 30});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 40, end: 41});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 100, end: 130});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 100, end: 130});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 110, end: 140});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 170, end: 180});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addFrameEvent(model, {start: 150, end: 151});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 210});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 200, end: 220});
- chrome_test_utils.addFrameEvent(model, {start: 230, end: 240});
+ ChromeTestUtils.addFrameEvent(model, {start: 230, end: 240});
};
verifier.expectedIRs = [
- {title: 'Fling Animation', start: 0, end: 100, eventCount: 2},
+ {title: 'Fling Animation', start: 0, end: 100, eventCount: 3},
{title: 'Touch Response', start: 100, end: 140, eventCount: 2,
isAnimationBegin: true},
- {title: 'Touch Animation', start: 140, end: 210, eventCount: 2},
- {title: 'Fling Animation', start: 200, end: 240, eventCount: 1}
+ {title: 'Touch Animation', start: 140, end: 210, eventCount: 3},
+ {title: 'Fling Animation', start: 200, end: 240, eventCount: 2}
];
verifier.verify();
});
@@ -541,8 +822,8 @@ tr.b.unittest.testSuite(function() {
test('load', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addNavigationStartEvent(model, {start: 0});
- chrome_test_utils.addFirstContentfulPaintEvent(model, {start: 20});
+ ChromeTestUtils.addNavigationStartEvent(model, {start: 0});
+ ChromeTestUtils.addFirstContentfulPaintEvent(model, {start: 20});
};
verifier.expectedIRs = [
{title: 'Successful Load', start: 0, end: 20, eventCount: 0}
@@ -553,15 +834,15 @@ tr.b.unittest.testSuite(function() {
test('loadStartup', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addRenderingEvent(model, {start: 2, end: 3});
- chrome_test_utils.addCreateThreadsEvent(model, {start: 5, end: 10});
+ ChromeTestUtils.addRenderingEvent(model, {start: 2, end: 3});
+ ChromeTestUtils.addCreateThreadsEvent(model, {start: 5, end: 10});
// Throw an second one in there, just to try to confuse the algo.
- chrome_test_utils.addCreateThreadsEvent(model, {start: 25, end: 30});
- chrome_test_utils.addFrameEvent(model, {start: 11, end: 20});
+ ChromeTestUtils.addCreateThreadsEvent(model, {start: 25, end: 30});
+ ChromeTestUtils.addFrameEvent(model, {start: 11, end: 20});
};
verifier.expectedIRs = [
- {title: 'Startup', start: 2, end: 20, eventCount: 2},
- {title: 'Idle', start: 20, end: 30, eventCount: 0}
+ {title: 'Startup', start: 2, end: 20, eventCount: 3},
+ {title: 'Idle', start: 20, end: 30, eventCount: 1}
];
verifier.verify();
});
@@ -569,10 +850,10 @@ tr.b.unittest.testSuite(function() {
test('totalIdle', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 10, eventCount: 0}
+ {title: 'Idle', start: 0, end: 10, eventCount: 1}
];
verifier.verify();
});
@@ -580,15 +861,15 @@ tr.b.unittest.testSuite(function() {
test('multipleIdles', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 1});
- chrome_test_utils.addNavigationStartEvent(model, {start: 1});
- chrome_test_utils.addFirstContentfulPaintEvent(model, {start: 4});
- chrome_test_utils.addFrameEvent(model, {start: 12, end: 13});
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 1});
+ ChromeTestUtils.addNavigationStartEvent(model, {start: 1});
+ ChromeTestUtils.addFirstContentfulPaintEvent(model, {start: 4});
+ ChromeTestUtils.addFrameEvent(model, {start: 12, end: 13});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 1, eventCount: 0},
+ {title: 'Idle', start: 0, end: 1, eventCount: 1},
{title: 'Successful Load', start: 1, end: 4, eventCount: 0},
- {title: 'Idle', start: 4, end: 13, eventCount: 0}
+ {title: 'Idle', start: 4, end: 13, eventCount: 1}
];
verifier.verify();
});
@@ -596,9 +877,9 @@ tr.b.unittest.testSuite(function() {
test('touchStartTouchEndTap', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 210});
};
verifier.expectedIRs = [
@@ -611,19 +892,20 @@ tr.b.unittest.testSuite(function() {
test('touchMoveResponseAnimation', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 50, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 70, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 300});
+ ChromeTestUtils.addFrameEvent(model, {start: 299, end: 300});
};
verifier.expectedIRs = [
{title: 'Touch Response', start: 0, end: 100, eventCount: 2,
isAnimationBegin: true},
- {title: 'Touch Animation', start: 100, end: 300, eventCount: 2}
+ {title: 'Touch Animation', start: 100, end: 300, eventCount: 3}
];
verifier.verify();
});
@@ -631,11 +913,11 @@ tr.b.unittest.testSuite(function() {
test('tapEvents', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP,
{start: 0, end: 50});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 300, end: 310});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP,
{start: 320, end: 350});
};
verifier.expectedIRs = [
@@ -649,9 +931,9 @@ tr.b.unittest.testSuite(function() {
test('tapAndTapCancelResponses', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 0, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 300, end: 350});
};
verifier.expectedIRs = [
@@ -665,9 +947,9 @@ tr.b.unittest.testSuite(function() {
test('tapCancelResponse', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 0, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 150, end: 200});
};
verifier.expectedIRs = [
@@ -679,30 +961,35 @@ tr.b.unittest.testSuite(function() {
test('pinchResponseAnimation', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
{start: 100, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 130, end: 160});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addFrameEvent(model, {start: 159, end: 160});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 140, end: 200});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addFrameEvent(model, {start: 199, end: 200});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 150, end: 205});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addFrameEvent(model, {start: 204, end: 205});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 210, end: 220});
+ ChromeTestUtils.addFrameEvent(model, {start: 219, end: 220});
// pause > 200ms
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 421, end: 470});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_END,
+ ChromeTestUtils.addFrameEvent(model, {start: 469, end: 470});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_END,
{start: 460, end: 500});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 100, eventCount: 0},
+ {title: 'Idle', start: 0, end: 100, eventCount: 1},
{title: 'Pinch Response', start: 100, end: 160, eventCount: 2,
isAnimationBegin: true},
- {title: 'Pinch Animation', start: 160, end: 220, eventCount: 3},
+ {title: 'Pinch Animation', start: 160, end: 220, eventCount: 7},
{title: 'Idle', start: 220, end: 421, eventCount: 0},
- {title: 'Pinch Animation', start: 421, end: 500, eventCount: 2}
+ {title: 'Pinch Animation', start: 421, end: 500, eventCount: 3}
];
verifier.verify();
});
@@ -711,23 +998,24 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/google_io_instrument_strumming.json
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 20});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 40, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 50, end: 120});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 80, end: 150});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 180, end: 200});
+ ChromeTestUtils.addFrameEvent(model, {start: 199, end: 200});
};
verifier.expectedIRs = [
{title: 'Touch Response', start: 0, end: 100, eventCount: 2,
isAnimationBegin: true},
{title: 'Touch Response', start: 50, end: 150, eventCount: 2,
isAnimationBegin: true},
- {title: 'Touch Animation', start: 150, end: 200, eventCount: 1}
+ {title: 'Touch Animation', start: 150, end: 200, eventCount: 2}
];
verifier.verify();
});
@@ -735,50 +1023,52 @@ tr.b.unittest.testSuite(function() {
test('pinchFlingTapTouchEventsOverlap', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 0, end: 10});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 20, end: 50});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 20, end: 30});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 20, end: 50});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 60, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 60, end: 110});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
{start: 60, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 65, end: 75});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 70, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 70, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 75, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 80, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 85, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 75, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 150, end: 200});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 150, end: 200});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 199, end: 200});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 180, end: 210});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addFrameEvent(model, {start: 209, end: 210});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 190, end: 210});
- chrome_test_utils.addFrameEvent(model, {start: 215, end: 220});
+ ChromeTestUtils.addFrameEvent(model, {start: 215, end: 220});
};
verifier.expectedIRs = [
- {title: 'Idle', start: 0, end: 20, eventCount: 0},
- {title: 'Pinch,Scroll,Tap,Touch Response', start: 20, end: 110,
+ {title: 'Idle', start: 0, end: 20, eventCount: 1},
+ {title: 'Pinch Response', start: 20, end: 110,
eventCount: 9, isAnimationBegin: true},
- {title: 'Scroll,Touch Animation', start: 110, end: 210,
- eventCount: 6},
- {title: 'Fling Animation', start: 180, end: 220, eventCount: 1}
+ {title: 'Scroll Animation', start: 110, end: 210,
+ eventCount: 7},
+ {title: 'Fling Animation', start: 180, end: 220, eventCount: 4}
];
verifier.verify();
});
@@ -786,17 +1076,18 @@ tr.b.unittest.testSuite(function() {
test('scrollThenFling', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 0, end: 40});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 50, end: 100});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addFrameEvent(model, {start: 99, end: 100});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 80, end: 100});
- chrome_test_utils.addFrameEvent(model, {start: 190, end: 200});
+ ChromeTestUtils.addFrameEvent(model, {start: 190, end: 200});
};
verifier.expectedIRs = [
- {title: 'Scroll Animation', start: 0, end: 100, eventCount: 2},
- {title: 'Fling Animation', start: 80, end: 200, eventCount: 1}
+ {title: 'Scroll Animation', start: 0, end: 100, eventCount: 3},
+ {title: 'Fling Animation', start: 80, end: 200, eventCount: 3}
];
verifier.verify();
});
@@ -808,54 +1099,56 @@ tr.b.unittest.testSuite(function() {
test('flingHNToRest', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addEvent(model.browserMain,
+ ChromeTestUtils.addEvent(model.browserMain,
{title: 'model start', start: 0, end: 1});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 1274, end: 1297});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 1274, end: 1305});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1343, end: 1350});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1359, end: 1366});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 1359, end: 1366});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 1359, end: 1367});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1359, end: 1387});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1375, end: 1385});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1375, end: 1416});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1389, end: 1404});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1389, end: 1429});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1405, end: 1418});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1405, end: 1449});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1419, end: 1432});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ ChromeTestUtils.addFrameEvent(model, {start: 1431, end: 1432});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1419, end: 1474});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ ChromeTestUtils.addFrameEvent(model, {start: 1473, end: 1474});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1427, end: 1435});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1427, end: 1474});
- chrome_test_utils.addFlingAnimationEvent(model, {start: 1440, end: 2300});
- chrome_test_utils.addEvent(model.browserMain,
+ ChromeTestUtils.addFlingAnimationEvent(model, {start: 1440, end: 2300});
+ ChromeTestUtils.addEvent(model.browserMain,
{title: 'model end', start: 3184, end: 3185});
};
verifier.expectedIRs = [
{title: 'Idle', start: 0, end: 1274, eventCount: 0},
- {title: 'Scroll,Tap,Touch Response', start: 1274, end: 1387,
+ {title: 'Scroll Response', start: 1274, end: 1387,
eventCount: 6, isAnimationBegin: true},
- {title: 'Scroll,Touch Animation', start: 1387, end: 1474,
- eventCount: 10},
+ {title: 'Scroll Animation', start: 1387, end: 1474,
+ eventCount: 12},
{title: 'Fling Animation', start: 1427, end: 2300,
- eventCount: 2},
+ eventCount: 4},
{title: 'Idle', start: 2300, end: 3185, eventCount: 0}
];
verifier.verify();
@@ -864,18 +1157,19 @@ tr.b.unittest.testSuite(function() {
test('TapResponseOverlappingTouchAnimation', function() {
var verifier = new UserExpectationVerifier();
verifier.customizeModelCallback = function(model) {
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 0, end: 10});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 5, end: 15});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 10, end: 20});
- chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP,
+ ChromeTestUtils.addFrameEvent(model, {start: 19, end: 20});
+ ChromeTestUtils.addInputEvent(model, INPUT_TYPE.TAP,
{start: 15, end: 100});
};
verifier.expectedIRs = [
- {title: 'Tap,Touch Response', start: 0, end: 100,
- eventCount: 4}
+ {title: 'Tap Response', start: 0, end: 100,
+ eventCount: 5}
];
verifier.verify();
});
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html b/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html
index 16a0591b9f4..7232c17fd62 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html
@@ -5,11 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/metrics/blink/gc_metric.html">
+<link rel="import" href="/tracing/metrics/cpu_process_metric.html">
<link rel="import" href="/tracing/metrics/sample_metric.html">
<link rel="import" href="/tracing/metrics/system_health/clock_sync_latency_metric.html">
-<link rel="import" href="/tracing/metrics/system_health/efficiency_metric.html">
-<link rel="import" href="/tracing/metrics/system_health/first_paint_metric.html">
<link rel="import" href="/tracing/metrics/system_health/hazard_metric.html">
+<link rel="import" href="/tracing/metrics/system_health/loading_metric.html">
<link rel="import" href="/tracing/metrics/system_health/memory_metric.html">
<link rel="import" href="/tracing/metrics/system_health/power_metric.html">
<link rel="import" href="/tracing/metrics/system_health/responsiveness_metric.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric.html
new file mode 100644
index 00000000000..ee76d0ca565
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric.html
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/metrics/metric_registry.html">
+<link rel="import" href="/tracing/metrics/v8/utils.html">
+<link rel="import" href="/tracing/value/histogram.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.metrics.blink', function() {
+ // Maps the Blink GC events in timeline to telemetry friendly names.
+ var BLINK_GC_EVENTS = {
+ 'BlinkGCMarking': 'blink-gc-marking',
+ 'ThreadState::completeSweep': 'blink-gc-complete-sweep',
+ 'ThreadState::performIdleLazySweep': 'blink-gc-idle-lazy-sweep'
+ };
+
+ function isBlinkGarbageCollectionEvent(event) {
+ return event.title in BLINK_GC_EVENTS;
+ }
+
+ function blinkGarbageCollectionEventName(event) {
+ return BLINK_GC_EVENTS[event.title];
+ }
+
+ function blinkGcMetric(values, model) {
+ addDurationOfTopEvents(values, model);
+ addTotalDurationOfTopEvents(values, model);
+ addIdleTimesOfTopEvents(values, model);
+ addTotalIdleTimesOfTopEvents(values, model);
+ }
+
+ tr.metrics.MetricRegistry.register(blinkGcMetric);
+
+ var timeDurationInMs_smallerIsBetter =
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
+ var percentage_biggerIsBetter =
+ tr.b.Unit.byName.normalizedPercentage_biggerIsBetter;
+
+ // 0.1 steps from 0 to 20 since it is the most common range.
+ // Exponentially increasing steps from 20 to 200.
+ var CUSTOM_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 20, 200)
+ .addExponentialBins(200, 100);
+
+ function createNumericForTopEventTime(name) {
+ var n = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ n.customizeSummaryOptions({
+ avg: true,
+ count: true,
+ max: true,
+ min: false,
+ std: true,
+ sum: true,
+ percentile: [0.90]});
+ return n;
+ }
+
+ function createNumericForIdleTime(name) {
+ var n = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ n.customizeSummaryOptions({
+ avg: true,
+ count: false,
+ max: true,
+ min: false,
+ std: false,
+ sum: true,
+ percentile: []
+ });
+ return n;
+ }
+
+ function createPercentage(name, numerator, denominator) {
+ var histogram = new tr.v.Histogram(name, percentage_biggerIsBetter);
+ if (denominator === 0)
+ histogram.addSample(0);
+ else
+ histogram.addSample(numerator / denominator);
+ return histogram;
+ }
+
+ /**
+ * Example output:
+ * - blink-gc-marking.
+ */
+ function addDurationOfTopEvents(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isBlinkGarbageCollectionEvent,
+ blinkGarbageCollectionEventName,
+ function(name, events) {
+ var cpuDuration = createNumericForTopEventTime(name);
+ events.forEach(function(event) {
+ cpuDuration.addSample(event.cpuDuration);
+ });
+ values.addHistogram(cpuDuration);
+ }
+ );
+ }
+
+ /**
+ * Example output:
+ * - blink-gc-total
+ */
+ function addTotalDurationOfTopEvents(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isBlinkGarbageCollectionEvent,
+ event => 'blink-gc-total',
+ function(name, events) {
+ var cpuDuration = createNumericForTopEventTime(name);
+ events.forEach(function(event) {
+ cpuDuration.addSample(event.cpuDuration);
+ });
+ values.addHistogram(cpuDuration);
+ }
+ );
+ }
+
+ /**
+ * Example output:
+ * - blink-gc-marking_idle_deadline_overrun,
+ * - blink-gc-marking_outside_idle,
+ * - blink-gc-marking_percentage_idle.
+ */
+ function addIdleTimesOfTopEvents(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isBlinkGarbageCollectionEvent,
+ blinkGarbageCollectionEventName,
+ function(name, events) {
+ addIdleTimes(values, model, name, events);
+ }
+ );
+ }
+
+ /**
+ * Example output:
+ * - blink-gc-total_idle_deadline_overrun,
+ * - blink-gc-total_outside_idle,
+ * - blink-gc-total_percentage_idle.
+ */
+ function addTotalIdleTimesOfTopEvents(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isBlinkGarbageCollectionEvent,
+ event => 'blink-gc-total',
+ function(name, events) {
+ addIdleTimes(values, model, name, events);
+ }
+ );
+ }
+
+ function addIdleTimes(values, model, name, events) {
+ var cpuDuration = createNumericForIdleTime(name + '_cpu');
+ var insideIdle = createNumericForIdleTime(name + '_inside_idle');
+ var outsideIdle = createNumericForIdleTime(name + '_outside_idle');
+ var idleDeadlineOverrun = createNumericForIdleTime(
+ name + '_idle_deadline_overrun');
+ events.forEach(function(event) {
+ var idleTask = tr.metrics.v8.utils.findParent(
+ event, tr.metrics.v8.utils.isIdleTask);
+ var inside = 0;
+ var overrun = 0;
+ if (idleTask) {
+ var allottedTime = idleTask['args']['allotted_time_ms'];
+ if (event.duration > allottedTime) {
+ overrun = event.duration - allottedTime;
+ // Don't count time over the deadline as being inside idle time.
+ // Since the deadline should be relative to wall clock we
+ // compare allotted_time_ms with wall duration instead of thread
+ // duration, and then assume the thread duration was inside idle
+ // for the same percentage of time.
+ inside = event.cpuDuration * allottedTime / event.duration;
+ } else {
+ inside = event.cpuDuration;
+ }
+ }
+ cpuDuration.addSample(event.cpuDuration);
+ insideIdle.addSample(inside);
+ outsideIdle.addSample(event.cpuDuration - inside);
+ idleDeadlineOverrun.addSample(overrun);
+ });
+ values.addHistogram(idleDeadlineOverrun);
+ values.addHistogram(outsideIdle);
+ var percentage = createPercentage(
+ name + '_percentage_idle', insideIdle.sum, cpuDuration.sum);
+ values.addHistogram(percentage);
+ }
+
+ return {
+ blinkGcMetric: blinkGcMetric
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric_test.html
new file mode 100644
index 00000000000..9a9fb72b342
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/blink/gc_metric_test.html
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
+<link rel="import" href="/tracing/metrics/blink/gc_metric.html">
+<link rel="import" href="/tracing/model/slice_group.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+
+ function createModel(start, end, slices) {
+ var opts = {
+ customizeModelCallback: function(model) {
+ var process = model.getOrCreateProcess(1);
+ var thread = process.getOrCreateThread(2);
+ var group = thread.sliceGroup;
+ slices.forEach(function(slice) {
+ group.pushSlice(tr.c.TestUtils.newSliceEx(slice));
+ });
+ group.createSubSlices();
+ }
+ };
+ var model = tr.c.TestUtils.newModelWithEvents([], opts);
+ return model;
+ }
+
+ function constructName(name, suffix) {
+ return name + '_' + suffix;
+ }
+
+ function run(slices) {
+ var values = new tr.v.ValueSet();
+ var startTime = slices.reduce((acc, slice) => (Math.min(acc, slice.start)));
+ var endTime = slices.reduce((acc, slice) => (Math.max(acc, slice.end)));
+ var model = createModel(startTime - 1, endTime + 1, slices);
+ tr.metrics.blink.blinkGcMetric(values, model);
+ return values;
+ }
+
+ test('topEvents', function() {
+ var events = {
+ 'BlinkGCMarking': 'blink-gc-marking',
+ 'ThreadState::completeSweep': 'blink-gc-complete-sweep',
+ 'ThreadState::performIdleLazySweep': 'blink-gc-idle-lazy-sweep'
+ };
+ tr.b.iterItems(events, function(timelineName, telemetryName) {
+ var slices = [
+ {
+ title: timelineName, args: {}, start: 100, end: 200,
+ cpuStart: 100, cpuEnd: 200
+ }
+ ];
+ var actual = run(slices);
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(telemetryName));
+ assert.strictEqual(value.running.sum, 100);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 100);
+ assert.strictEqual(value.running.max, 100);
+ assert.closeTo(value.getApproximatePercentile(0.90), 100, 1);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_outside_idle'));
+ assert.strictEqual(value.running.sum, 100);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_percentage_idle'));
+ assert.strictEqual(value.average, 0);
+ });
+ });
+
+ test('idleTimes', function() {
+ var values = new tr.v.ValueSet();
+ var slices = [
+ {
+ title: 'SingleThreadIdleTaskRunner::RunTask',
+ args: {'allotted_time_ms' : 100}, start: 100, end: 200,
+ cpuStart: 100, cpuEnd: 200
+ },
+ {
+ title: 'BlinkGCMarking', args: {}, start: 110, end: 190,
+ cpuStart: 110, cpuEnd: 190
+ }
+ ];
+ var actual = run(slices);
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed('blink-gc-marking'));
+ assert.strictEqual(value.running.sum, 80);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 80);
+ assert.strictEqual(value.running.max, 80);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_outside_idle'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_percentage_idle'));
+ assert.strictEqual(value.average, 1);
+ });
+
+ test('idleTimeOverrun', function() {
+ var values = new tr.v.ValueSet();
+ var slices = [
+ {
+ title: 'SingleThreadIdleTaskRunner::RunTask',
+ args: {'allotted_time_ms' : 10}, start: 100, end: 200,
+ cpuStart: 100, cpuEnd: 200
+ },
+ {
+ title: 'BlinkGCMarking', args: {}, start: 110, end: 190,
+ cpuStart: 110, cpuEnd: 190
+ }
+ ];
+ var actual = run(slices);
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed('blink-gc-marking'));
+ assert.strictEqual(value.running.sum, 80);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 80);
+ assert.strictEqual(value.running.max, 80);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 70);
+ assert.strictEqual(value.average, 70);
+ assert.strictEqual(value.running.max, 70);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_outside_idle'));
+ assert.strictEqual(value.running.sum, 70);
+ assert.strictEqual(value.average, 70);
+ assert.strictEqual(value.running.max, 70);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-marking_percentage_idle'));
+ assert.closeTo(value.average, 1 / 8, 1e-6);
+ });
+
+ test('total', function() {
+ var values = new tr.v.ValueSet();
+ var slices = [
+ {
+ title: 'BlinkGCMarking', args: {}, start: 100, end: 200,
+ cpuStart: 100, cpuEnd: 200
+ },
+ {
+ title: 'ThreadState::performIdleLazySweep', args: {}, start: 210,
+ end: 290, cpuStart: 210, cpuEnd: 290
+ }
+ ];
+ var actual = run(slices);
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed('blink-gc-total'));
+ assert.strictEqual(value.running.sum, 180);
+ assert.strictEqual(value.numValues, 2);
+ assert.strictEqual(value.average, 90);
+ assert.strictEqual(value.running.max, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-total_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-total_outside_idle'));
+ assert.strictEqual(value.running.sum, 180);
+ assert.strictEqual(value.average, 90);
+ assert.strictEqual(value.running.max, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'blink-gc-total_percentage_idle'));
+ assert.strictEqual(value.average, 0);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/buildbot_output_for_compare_samples_test.txt b/chromium/third_party/catapult/tracing/tracing/metrics/buildbot_output_for_compare_samples_test.txt
new file mode 100644
index 00000000000..a8d19745dae
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/buildbot_output_for_compare_samples_test.txt
@@ -0,0 +1,187 @@
+IMPORTANT DEBUGGING NOTE: batches of tests are run inside their
+own process. For debugging a test inside a debugger, use the
+--gtest_filter=<your_test_name> flag along with
+--single-process-tests.
+Using sharding settings from environment. This is shard 0/1
+Using 1 parallel jobs.
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D31.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_13273\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D31.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_13273\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D31.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_13273\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D31.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_13273\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D31.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_13273\test_results.xml" --test-launcher-print-test-stdio=always
+[ RUN ] IndexDataManagerPerfTest.Run
+*RESULT IndexDataManger_run: score= 281471 score
+[ OK ] IndexDataManagerPerfTest.Run (5008 ms)
+[1/37] IndexDataManagerPerfTest.Run (5008 ms)
+[ RUN ] BufferSubDataBenchmark.Run/d3d11_float4_every1
+*RESULT BufferSubData_d3d11_float4_every1: score= 232 score
+[ OK ] BufferSubDataBenchmark.Run/d3d11_float4_every1 (5117 ms)
+[2/37] BufferSubDataBenchmark.Run/d3d11_float4_every1 (5117 ms)
+[ RUN ] BufferSubDataBenchmark.Run/d3d9_float4_every1
+*RESULT BufferSubData_d3d9_float4_every1: score= 237 score
+[ OK ] BufferSubDataBenchmark.Run/d3d9_float4_every1 (5386 ms)
+[3/37] BufferSubDataBenchmark.Run/d3d9_float4_every1 (5386 ms)
+[ RUN ] BufferSubDataBenchmark.Run/gl_float4_every1
+*RESULT BufferSubData_gl_float4_every1: score= 245 score
+[ OK ] BufferSubDataBenchmark.Run/gl_float4_every1 (5195 ms)
+[4/37] BufferSubDataBenchmark.Run/gl_float4_every1 (5195 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/d3d9
+*RESULT DrawCallPerf_d3d9: score= 2993 score
+[ OK ] DrawCallPerfBenchmark.Run/d3d9 (10062 ms)
+[5/37] DrawCallPerfBenchmark.Run/d3d9 (10062 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/d3d9_null
+*RESULT DrawCallPerf_d3d9_null: score= 25046 score
+[ OK ] DrawCallPerfBenchmark.Run/d3d9_null (10047 ms)
+[6/37] DrawCallPerfBenchmark.Run/d3d9_null (10047 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/d3d11
+*RESULT DrawCallPerf_d3d11: score= 2741 score
+[ OK ] DrawCallPerfBenchmark.Run/d3d11 (10015 ms)
+[7/37] DrawCallPerfBenchmark.Run/d3d11 (10015 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/d3d11_null
+*RESULT DrawCallPerf_d3d11_null: score= 28607 score
+[ OK ] DrawCallPerfBenchmark.Run/d3d11_null (9999 ms)
+[8/37] DrawCallPerfBenchmark.Run/d3d11_null (9999 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/d3d11_render_to_texture_null
+*RESULT DrawCallPerf_d3d11_render_to_texture_null: score= 25868 score
+[ OK ] DrawCallPerfBenchmark.Run/d3d11_render_to_texture_null (10015 ms)
+[9/37] DrawCallPerfBenchmark.Run/d3d11_render_to_texture_null (10015 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/gl
+*RESULT DrawCallPerf_gl: score= 4123 score
+[ OK ] DrawCallPerfBenchmark.Run/gl (10031 ms)
+[10/37] DrawCallPerfBenchmark.Run/gl (10031 ms)
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D32.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_8457\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D32.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_8457\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D32.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_8457\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D32.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_8457\test_results.xml" --test-launcher-print-test-stdio=always
+[ RUN ] DrawCallPerfBenchmark.Run/gl_null
+*RESULT DrawCallPerf_gl_null: score= 189804 score
+[ OK ] DrawCallPerfBenchmark.Run/gl_null (10015 ms)
+[11/37] DrawCallPerfBenchmark.Run/gl_null (10015 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/gl_render_to_texture_null
+*RESULT DrawCallPerf_gl_render_to_texture_null: score= 189155 score
+[ OK ] DrawCallPerfBenchmark.Run/gl_render_to_texture_null (10031 ms)
+[12/37] DrawCallPerfBenchmark.Run/gl_render_to_texture_null (10031 ms)
+[ RUN ] DrawCallPerfBenchmark.Run/default_validation_only
+*RESULT DrawCallPerf_default_validation_only: score= 2690 score
+[ OK ] DrawCallPerfBenchmark.Run/default_validation_only (5023 ms)
+[13/37] DrawCallPerfBenchmark.Run/default_validation_only (5023 ms)
+[ RUN ] DynamicPromotionPerfTest.Run/d3d11
+*RESULT DynamicPromotion_d3d11: score= 39354 score
+[ OK ] DynamicPromotionPerfTest.Run/d3d11 (6552 ms)
+[14/37] DynamicPromotionPerfTest.Run/d3d11 (6552 ms)
+[ RUN ] DynamicPromotionPerfTest.Run/d3d9
+*RESULT DynamicPromotion_d3d9: score= 21060 score
+[ OK ] DynamicPromotionPerfTest.Run/d3d9 (5522 ms)
+[15/37] DynamicPromotionPerfTest.Run/d3d9 (5522 ms)
+[ RUN ] EGLInitializePerfTest.Run/ES2_D3D11
+*RESULT EGLInitialize_run: score= 155 score
+*RESULT EGLInitialize_run: LoadDLLs= 0.0000000000 ms
+*RESULT EGLInitialize_run: D3D11CreateDevice= 4.0051480051 ms
+*RESULT EGLInitialize_run: InitResources= 0.0000000000 ms
+[ OK ] EGLInitializePerfTest.Run/ES2_D3D11 (5008 ms)
+[16/37] EGLInitializePerfTest.Run/ES2_D3D11 (5008 ms)
+[ RUN ] IndexConversionPerfTest.Run/d3d11
+*RESULT IndexConversionPerfTest_d3d11: score= 5135 score
+[ OK ] IndexConversionPerfTest.Run/d3d11 (3166 ms)
+[17/37] IndexConversionPerfTest.Run/d3d11 (3166 ms)
+[ RUN ] IndexConversionPerfTest.Run/index_range_d3d11
+*RESULT IndexConversionPerfTest_index_range_d3d11: score= 68785 score
+[ OK ] IndexConversionPerfTest.Run/index_range_d3d11 (3011 ms)
+[18/37] IndexConversionPerfTest.Run/index_range_d3d11 (3011 ms)
+[ RUN ] InstancingPerfBenchmark.Run/d3d11
+*RESULT InstancingPerf_d3d11: score= 479 score
+[ OK ] InstancingPerfBenchmark.Run/d3d11 (10046 ms)
+[19/37] InstancingPerfBenchmark.Run/d3d11 (10046 ms)
+[ RUN ] InstancingPerfBenchmark.Run/d3d9
+*RESULT InstancingPerf_d3d9: score= 464 score
+[ OK ] InstancingPerfBenchmark.Run/d3d9 (10057 ms)
+[20/37] InstancingPerfBenchmark.Run/d3d9 (10057 ms)
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D44.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_12336\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D44.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_12336\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D44.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_12336\test_results.xml" --test-launcher-print-test-stdio=always
+[ RUN ] InstancingPerfBenchmark.Run/gl
+*RESULT InstancingPerf_gl: score= 427 score
+[ OK ] InstancingPerfBenchmark.Run/gl (10124 ms)
+[21/37] InstancingPerfBenchmark.Run/gl (10124 ms)
+[ RUN ] InterleavedAttributeDataBenchmark.Run/d3d11
+*RESULT InterleavedAttributeData_d3d11: score= 19 score
+[ OK ] InterleavedAttributeDataBenchmark.Run/d3d11 (5117 ms)
+[22/37] InterleavedAttributeDataBenchmark.Run/d3d11 (5117 ms)
+[ RUN ] InterleavedAttributeDataBenchmark.Run/d3d11_9_3
+*RESULT InterleavedAttributeData_d3d11: score= 25 score
+[ OK ] InterleavedAttributeDataBenchmark.Run/d3d11_9_3 (5225 ms)
+[23/37] InterleavedAttributeDataBenchmark.Run/d3d11_9_3 (5225 ms)
+[ RUN ] InterleavedAttributeDataBenchmark.Run/d3d9
+*RESULT InterleavedAttributeData_d3d9: score= 25 score
+[ OK ] InterleavedAttributeDataBenchmark.Run/d3d9 (5211 ms)
+[24/37] InterleavedAttributeDataBenchmark.Run/d3d9 (5211 ms)
+[ RUN ] InterleavedAttributeDataBenchmark.Run/gl
+*RESULT InterleavedAttributeData_gl: score= 25 score
+[ OK ] InterleavedAttributeDataBenchmark.Run/gl (5101 ms)
+[25/37] InterleavedAttributeDataBenchmark.Run/gl (5101 ms)
+[ RUN ] PointSpritesBenchmark.Run/d3d11_10_3px_3vars
+*RESULT PointSprites_d3d11_10_3px_3vars: score= 644 score
+[ OK ] PointSpritesBenchmark.Run/d3d11_10_3px_3vars (5023 ms)
+[26/37] PointSpritesBenchmark.Run/d3d11_10_3px_3vars (5023 ms)
+[ RUN ] PointSpritesBenchmark.Run/d3d9_10_3px_3vars
+*RESULT PointSprites_d3d9_10_3px_3vars: score= 730 score
+[ OK ] PointSpritesBenchmark.Run/d3d9_10_3px_3vars (5141 ms)
+[27/37] PointSpritesBenchmark.Run/d3d9_10_3px_3vars (5141 ms)
+[ RUN ] PointSpritesBenchmark.Run/gl_10_3px_3vars
+*RESULT PointSprites_gl_10_3px_3vars: score= 2159 score
+[ OK ] PointSpritesBenchmark.Run/gl_10_3px_3vars (5086 ms)
+[28/37] PointSpritesBenchmark.Run/gl_10_3px_3vars (5086 ms)
+[ RUN ] TexSubImageBenchmark.Run/d3d11
+*RESULT TexSubImage_d3d11: score= 294 score
+[ OK ] TexSubImageBenchmark.Run/d3d11 (5023 ms)
+[29/37] TexSubImageBenchmark.Run/d3d11 (5023 ms)
+[ RUN ] TexSubImageBenchmark.Run/d3d9
+*RESULT TexSubImage_d3d9: score= 298 score
+[ OK ] TexSubImageBenchmark.Run/d3d9 (5305 ms)
+[30/37] TexSubImageBenchmark.Run/d3d9 (5305 ms)
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D45.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_4706\test_results.xml" --test-launcher-print-test-stdio=always
+Still waiting for the following processes to finish:
+ "C:\b\c\b\Win_7_ATI_GPU_Perf__2_\src\out\Release_x64\angle_perftests.exe" --gtest_flagfile="C:\Users\chrome-bot\AppData\Local\Temp\scoped_dir3192_23891\8D45.tmp" --single-process-tests --test-launcher-jobs=1 --test-launcher-output="C:\Users\CHROME~1\AppData\Local\Temp\3192_4706\test_results.xml" --test-launcher-print-test-stdio=always
+[ RUN ] TexSubImageBenchmark.Run/gl
+*RESULT TexSubImage_gl: score= 323 score
+[ OK ] TexSubImageBenchmark.Run/gl (5070 ms)
+[31/37] TexSubImageBenchmark.Run/gl (5070 ms)
+[ RUN ] TextureSamplingBenchmark.Run/d3d11_2samplers
+*RESULT TextureSampling_d3d11_2samplers: score= 128 score
+[ OK ] TextureSamplingBenchmark.Run/d3d11_2samplers (5070 ms)
+[32/37] TextureSamplingBenchmark.Run/d3d11_2samplers (5070 ms)
+[ RUN ] TextureSamplingBenchmark.Run/d3d9_2samplers
+*RESULT TextureSampling_d3d9_2samplers: score= 128 score
+[ OK ] TextureSamplingBenchmark.Run/d3d9_2samplers (5668 ms)
+[33/37] TextureSamplingBenchmark.Run/d3d9_2samplers (5668 ms)
+[ RUN ] TextureSamplingBenchmark.Run/gl_2samplers
+*RESULT TextureSampling_gl_2samplers: score= 136 score
+[ OK ] TextureSamplingBenchmark.Run/gl_2samplers (5054 ms)
+[34/37] TextureSamplingBenchmark.Run/gl_2samplers (5054 ms)
+[ RUN ] UniformsBenchmark.Run/d3d11_200_vertex_uniforms_200_fragment_uniforms
+*RESULT Uniforms_d3d11_200_vertex_uniforms_200_fragment_uniforms: score= 1797 score
+[ OK ] UniformsBenchmark.Run/d3d11_200_vertex_uniforms_200_fragment_uniforms (5195 ms)
+[35/37] UniformsBenchmark.Run/d3d11_200_vertex_uniforms_200_fragment_uniforms (5195 ms)
+[ RUN ] UniformsBenchmark.Run/d3d9_200_vertex_uniforms_200_fragment_uniforms
+*RESULT Uniforms_d3d9_200_vertex_uniforms_200_fragment_uniforms: score= 1912 score
+[ OK ] UniformsBenchmark.Run/d3d9_200_vertex_uniforms_200_fragment_uniforms (5223 ms)
+[36/37] UniformsBenchmark.Run/d3d9_200_vertex_uniforms_200_fragment_uniforms (5223 ms)
+[ RUN ] UniformsBenchmark.Run/gl_200_vertex_uniforms_200_fragment_uniforms
+*RESULT Uniforms_gl_200_vertex_uniforms_200_fragment_uniforms: score= 5509 score
+[ OK ] UniformsBenchmark.Run/gl_200_vertex_uniforms_200_fragment_uniforms (5070 ms)
+[37/37] UniformsBenchmark.Run/gl_200_vertex_uniforms_200_fragment_uniforms (5070 ms)
+SUCCESS: all tests passed.
+Tests took 243 seconds.
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples.py b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples.py
new file mode 100644
index 00000000000..6ce61c6e7fd
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples.py
@@ -0,0 +1,55 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+
+import tracing_project
+import vinn
+
+FORMAT_TO_METHOD = {
+ 'chartjson': 'compareCharts',
+ 'valueset': 'compareValuesets',
+ 'buildbot': 'compareBuildbotOutputs'
+}
+
+_COMPARE_SAMPLES_CMD_LINE = os.path.join(
+ os.path.dirname(__file__), 'compare_samples_cmdline.html')
+
+
+def CompareSamples(sample_a, sample_b, metric, data_format='chartjson'):
+ """Compare the values of a metric from two samples from benchmark output.
+
+ Args:
+ sample_a, sample_b (str): comma-separated lists of paths to the benchmark
+ output.
+ metric (str): Metric name in slash-separated format [2 or 3 part].
+ data_format (str): The format the samples are in. Supported values are:
+ 'chartjson', 'valueset', 'buildbot'.
+ Returns:
+ JSON encoded dict with the values parsed form the samples and the result of
+ the hypothesis testing comparison of the samples under the 'result' key.
+ Possible values for the result key are:
+ 'NEED_MORE_DATA', 'REJECT' and 'FAIL_TO_REJECT'.
+ Where the null hypothesis is that the samples belong to the same population.
+ i.e. a 'REJECT' result would make it reasonable to conclude that
+ there is a significant difference between the samples. (e.g. a perf
+ regression).
+ """
+
+ method = FORMAT_TO_METHOD[data_format]
+ project = tracing_project.TracingProject()
+ all_source_paths = list(project.source_paths)
+
+ def MakeAbsPaths(l):
+ return ','.join(map(os.path.abspath, l.split(',')))
+
+ return vinn.RunFile(
+ _COMPARE_SAMPLES_CMD_LINE,
+ source_paths=all_source_paths,
+ js_args=[
+ method,
+ MakeAbsPaths(sample_a),
+ MakeAbsPaths(sample_b),
+ metric
+ ])
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_cmdline.html b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_cmdline.html
new file mode 100644
index 00000000000..754267d9078
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_cmdline.html
@@ -0,0 +1,253 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/xhr.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+var escapeChars = s => s.replace(/[\:|=\/#&,]/g, '_');
+
+function findUnescapedKey(escaped, d) {
+ for (var k of tr.b.dictionaryKeys(d)) {
+ if (escapeChars(k) === escaped) {
+ return k;
+ }
+ }
+ throw new Error('did not find key ' + escaped + ' in ' +
+ tr.b.dictionaryKeys(d));
+}
+
+function geoMeanFromHistogram(h) {
+ if (!h.hasOwnProperty('buckets')) return 0.0;
+ var count = 0;
+ var sumOfLogs = 0;
+ for (var bucket of h.buckets) {
+ if (bucket.hasOwnProperty('high')) {
+ bucket.mean = (bucket.low + bucket.high) / 2.0;
+ } else {
+ bucket.mean = bucket.low;
+ }
+
+ if (bucket.mean > 0) {
+ sumOfLogs += Math.log(bucket.mean) * bucket.count;
+ count += bucket.count;
+ }
+ }
+ if (count === 0) return 0.0;
+ return Math.exp(sumOfLogs / count);
+}
+
+function splitMetric(metricName) {
+ var parts = metricName.split('/');
+ var interactionName;
+ var traceName = 'summary';
+ var chartName = parts[0];
+ if (parts.length === 3) {
+ // parts[1] is the interactionName
+ if (parts[1]) chartName = parts[1] + '@@' + chartName;
+ traceName = parts[2];
+ } else if (parts.length === 2) {
+ if (chartName !== parts[1]) traceName = parts[1];
+ } else throw new Error('Could not parse metric name.');
+ return [chartName, traceName];
+}
+
+function valuesFromCharts(listOfCharts, metricName) {
+ var allValues = [];
+ var chartAndTrace = splitMetric(metricName);
+ for (var charts of listOfCharts) {
+ var chartName = findUnescapedKey(chartAndTrace[0], charts.charts);
+ if (chartName) {
+ var traceName = findUnescapedKey(
+ chartAndTrace[1], charts.charts[chartName]);
+ if (traceName) {
+ if (charts.charts[chartName][traceName].type ===
+ 'list_of_scalar_values')
+ allValues.push(...charts.charts[chartName][traceName].values);
+ if (charts.charts[chartName][traceName].type === 'histogram')
+ allValues.push(
+ geoMeanFromHistogram(charts.charts[chartName][traceName]));
+ }
+ }
+ }
+ return allValues;
+}
+
+function rawValuesByMetricName(valueSet, metricName) {
+ var interactionRecord, valueName;
+ var [itrPlusChart, story] = splitMetric(metricName);
+ if (itrPlusChart.indexOf('@@') > -1) {
+ [interactionRecord, valueName] = itrPlusChart.split('@@');
+ } else if (itrPlusChart.indexOf('-') > -1) {
+ [interactionRecord, ...valueName] = itrPlusChart.split('-');
+ valueName = valueName.join('');
+ } else valueName = itrPlusChart;
+ var values = valueSet.getValuesNamed(valueName);
+ if (!values || values.length === 0) {
+ // If there was a dash in the chart name, but it wasn't an
+ // interaction record.
+ valueName = itrPlusChart;
+ values = valueSet.getValuesNamed(valueName);
+ interactionRecord = undefined;
+ if (!values || values.length === 0) {
+ throw new Error('No values with name ' + valueName);
+ }
+ }
+ var filtered = [];
+ for (var value of values) {
+ if (value.name !== valueName) continue;
+ var ii = tr.v.d.IterationInfo.getFromValue(value);
+ if (interactionRecord) {
+ var irParts = [];
+ var keys = Object.keys(ii.storyGroupingKeys);
+ keys.sort();
+ for (var key of keys)
+ irParts.push(ii.storyGroupingKeys[key]);
+ if (interactionRecord === irParts.join('_') &&
+ escapeChars(ii.storyDisplayName) ===
+ escapeChars(story)) {
+ filtered.push(value);
+ }
+ } else if (escapeChars(ii.storyDisplayName) ===
+ escapeChars(story)) {
+ filtered.push(value);
+ }
+ }
+
+ var rawValues = [];
+ for (var val of filtered) {
+ if (val instanceof tr.v.Histogram) {
+ rawValues = rawValues.concat(val.sampleValues);
+ } else throw new Error('Only tr.v.Histogram values are supported');
+ }
+ return rawValues;
+}
+
+function parseFiles(files) {
+ var results = [];
+ for (var path of files) {
+ var current = tr.b.getSync('file://' + path);
+ results.push(JSON.parse(current));
+ }
+ return results;
+}
+
+var escapeForRegExp = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+
+var strFromRE = re => re.toString().split('/')[1];
+
+function valuesFromBuildbotOutput(out, metric) {
+ if (!out)
+ return [];
+ var stringVals = [];
+ var floatVals = [];
+ var chartAndTrace = splitMetric(metric);
+ var metricRE = escapeForRegExp(
+ 'RESULT ' + chartAndTrace[0] + ': ' + chartAndTrace[1] + '=');
+ var singleResultRE = new RegExp(metricRE +
+ strFromRE(/\s*([-]?[\d\.]+)/), 'g');
+ var multiResultsRE = new RegExp(metricRE +
+ strFromRE(/\s*\[\s*([\d\., -]+)\s*\]/), 'g');
+ var meanStdDevRE = new RegExp(metricRE +
+ strFromRE(/\s*\{\s*([-]?\d*(?:\.\d*)?),\s*([-]?\d*(?:\.\d*)?)\}/), 'g');
+ for (var line of out.split(/\r?\n/)) {
+ var singleResultMatch = singleResultRE.exec(line);
+ var multiResultsMatch = multiResultsRE.exec(line);
+ var meanStdDevMatch = meanStdDevRE.exec(line);
+ if (singleResultMatch && singleResultMatch.length > 1)
+ stringVals.push(singleResultMatch[1]);
+ else if (multiResultsMatch && multiResultsMatch.length > 1) {
+ var values = multiResultsMatch[1].split(',');
+ stringVals = stringVals.concat(values);
+ } else if (meanStdDevMatch && meanStdDevMatch.length > 1)
+ stringVals.push(meanStdDevMatch[1]);
+ }
+ for (var val of stringVals) {
+ var f = parseFloat(val);
+ if (!isNaN(f))
+ floatVals.push(f);
+ }
+ return floatVals;
+}
+
+function parseMultipleBuildbotStreams(files, metric) {
+ var allValues = [];
+ for (var path of files) {
+ try {
+ var contents = tr.b.getSync('file://' + path);
+ }
+ catch (ex) {
+ var err = new Error('Could not open' + path);
+ err.name = 'File loading error';
+ throw err;
+ }
+ allValues = allValues.concat(valuesFromBuildbotOutput(contents, metric));
+ }
+ return allValues;
+}
+
+var buildComparisonResultOutput = function(a, b) {
+ return {
+ sampleA: a,
+ sampleB: b,
+ result: tr.b.Statistics.mwu(
+ a, b, tr.b.Statistics.DEFAULT_ALPHA,
+ tr.b.Statistics.MAX_SUGGESTED_SAMPLE_SIZE)
+ };
+};
+
+var SampleComparison = {
+
+ compareBuildbotOutputs: function(
+ buildbotOutputAPathList, buildbotOutputBPathList, metric) {
+ var aPaths = buildbotOutputAPathList.split(',');
+ var bPaths = buildbotOutputBPathList.split(',');
+ var sampleA = parseMultipleBuildbotStreams(aPaths, metric);
+ var sampleB = parseMultipleBuildbotStreams(bPaths, metric);
+ return buildComparisonResultOutput(sampleA, sampleB);
+ },
+
+ compareValuesets: function(valueSetAPathList, valueSetBPathList, metric) {
+ var aPaths = valueSetAPathList.split(',');
+ var bPaths = valueSetBPathList.split(',');
+ var valueSetA = new tr.v.ValueSet();
+ var valueSetB = new tr.v.ValueSet();
+ var dictsA = parseFiles(aPaths);
+ var dictsB = parseFiles(bPaths);
+ for (var d of dictsA)
+ valueSetA.addValuesFromDicts(d);
+ for (var d of dictsB)
+ valueSetB.addValuesFromDicts(d);
+
+ var sampleA = rawValuesByMetricName(valueSetA, metric);
+ var sampleB = rawValuesByMetricName(valueSetB, metric);
+ return buildComparisonResultOutput(sampleA, sampleB);
+ },
+
+ compareCharts: function(chartPathListA, chartPathListB, metric) {
+ var aPaths = chartPathListA.split(',');
+ var bPaths = chartPathListB.split(',');
+ var chartsA = parseFiles(aPaths);
+ var chartsB = parseFiles(bPaths);
+ var sampleA = valuesFromCharts(chartsA, metric);
+ var sampleB = valuesFromCharts(chartsB, metric);
+ return buildComparisonResultOutput(sampleA, sampleB);
+ }
+
+};
+
+if (tr.isHeadless) {
+ var method, rest;
+ [method, ...rest] = sys.argv.slice(1);
+ if (SampleComparison[method])
+ console.log(JSON.stringify(SampleComparison[method](...rest)));
+}
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_unittest.py b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_unittest.py
new file mode 100644
index 00000000000..730f7915d67
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/compare_samples_unittest.py
@@ -0,0 +1,225 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import math
+import os
+import random
+import tempfile
+import unittest
+
+from tracing.metrics import compare_samples
+
+
+REJECT = 'REJECT'
+FAIL_TO_REJECT = 'FAIL_TO_REJECT'
+NEED_MORE_DATA = 'NEED_MORE_DATA'
+
+
+def Mean(l):
+ if len(l):
+ return float(sum(l))/len(l)
+ return 0
+
+
+class CompareSamplesUnittest(unittest.TestCase):
+ def setUp(self):
+ self._tempfiles = []
+ self._tempdir = tempfile.mkdtemp()
+
+ def tearDown(self):
+ for tf in self._tempfiles:
+ try:
+ os.remove(tf)
+ except OSError:
+ pass
+ try:
+ os.rmdir(self._tempdir)
+ except OSError:
+ pass
+
+ def NewJsonTempfile(self, jsonable_contents):
+ f_handle, new_json_file = tempfile.mkstemp(
+ suffix='.json',
+ dir=self._tempdir,
+ text=True)
+ os.close(f_handle)
+ self._tempfiles.append(new_json_file)
+ with open(new_json_file, 'w') as f:
+ json.dump(jsonable_contents, f)
+ return new_json_file
+
+ def MakeMultipleChartJSONHistograms(self, metric, seed, mu, sigma, n, m):
+ result = []
+ random.seed(seed)
+ for _ in range(m):
+ result.append(self.MakeChartJSONHistogram(metric, mu, sigma, n))
+ return result
+
+ def MakeChartJSONHistogram(self, metric, mu, sigma, n):
+ """Creates a histogram for a normally distributed pseudo-random sample.
+
+ This function creates a deterministic pseudo-random sample and stores it in
+ chartjson histogram format to facilitate the testing of the sample
+ comparison logic.
+
+ For simplicity we use sqrt(n) buckets with equal widths.
+
+ Args:
+ metric (str pair): name of chart, name of the trace.
+ seed (hashable obj): to make the sequences deterministic we seed the RNG.
+ mu (float): desired mean for the sample
+ sigma (float): desired standard deviation for the sample
+ n (int): number of values to generate.
+ """
+ chart_name, trace_name = metric
+ values = [random.gauss(mu, sigma) for _ in range(n)]
+ bucket_count = int(math.ceil(math.sqrt(len(values))))
+ width = (max(values) - min(values))/(bucket_count - 1)
+ prev_bucket = min(values)
+ buckets = []
+ for _ in range(bucket_count):
+ buckets.append({'low': prev_bucket,
+ 'high': prev_bucket + width,
+ 'count': 0})
+ prev_bucket += width
+ for value in values:
+ for bucket in buckets:
+ if value >= bucket['low'] and value < bucket['high']:
+ bucket['count'] += 1
+ break
+ charts = {
+ 'charts': {
+ chart_name: {
+ trace_name: {
+ 'type': 'histogram',
+ 'buckets': buckets
+ }
+ }
+ }
+ }
+ return self.NewJsonTempfile(charts)
+
+ def MakeChart(self, metric, seed, mu, sigma, n):
+ """Creates a normally distributed pseudo-random sample. (continuous).
+
+ This function creates a deterministic pseudo-random sample and stores it in
+ chartjson format to facilitate the testing of the sample comparison logic.
+
+ Args:
+ metric (str pair): name of chart, name of the trace.
+ seed (hashable obj): to make the sequences deterministic we seed the RNG.
+ mu (float): desired mean for the sample
+ sigma (float): desired standard deviation for the sample
+ n (int): number of values to generate.
+ """
+ chart_name, trace_name = metric
+ random.seed(seed)
+ values = [random.gauss(mu, sigma) for _ in range(n)]
+ charts = {
+ 'charts': {
+ chart_name: {
+ trace_name: {
+ 'type': 'list_of_scalar_values',
+ 'values': values}
+ }
+ }
+ }
+ return self.NewJsonTempfile(charts)
+
+ def testCompareClearRegression(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([self.MakeChart(metric=metric, seed='lower',
+ mu=10, sigma=1, n=10)])
+ higher_values = ','.join([self.MakeChart(metric=metric, seed='higher',
+ mu=20, sigma=2, n=10)])
+ result = json.loads(compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric)).stdout)
+ self.assertEqual(result['result']['significance'], REJECT)
+
+ def testCompareUnlikelyRegressionWithMultipleRuns(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([
+ self.MakeChart(
+ metric=metric, seed='lower%d' % i, mu=10, sigma=1, n=5)
+ for i in range(4)])
+ higher_values = ','.join([
+ self.MakeChart(
+ metric=metric, seed='higher%d' % i, mu=10.01, sigma=0.95, n=5)
+ for i in range(4)])
+ result = json.loads(compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric)).stdout)
+ self.assertEqual(result['result']['significance'], FAIL_TO_REJECT)
+
+ def testCompareInsufficientData(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([self.MakeChart(metric=metric, seed='lower',
+ mu=10, sigma=1, n=5)])
+ higher_values = ','.join([self.MakeChart(metric=metric, seed='higher',
+ mu=10.40, sigma=0.95, n=5)])
+ result = json.loads(compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric)).stdout)
+ self.assertEqual(result['result']['significance'], NEED_MORE_DATA)
+
+ def testCompareMissingFile(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([self.MakeChart(metric=metric, seed='lower',
+ mu=10, sigma=1, n=5)])
+ higher_values = '/path/does/not/exist.json'
+ with self.assertRaises(RuntimeError):
+ compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric))
+
+ def testCompareMissingMetric(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([self.MakeChart(metric=metric, seed='lower',
+ mu=10, sigma=1, n=5)])
+ higher_values = ','.join([self.MakeChart(metric=metric, seed='higher',
+ mu=20, sigma=2, n=5)])
+ metric = ('some_chart', 'missing_trace')
+ with self.assertRaises(RuntimeError):
+ compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric))
+
+ def testCompareBadChart(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join([self.MakeChart(metric=metric, seed='lower',
+ mu=10, sigma=1, n=5)])
+ higher_values = self.NewJsonTempfile(['obviously', 'not', 'a', 'chart]'])
+ with self.assertRaises(RuntimeError):
+ compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric))
+
+ def testCompareValuesets(self):
+ vs = os.path.join(os.path.dirname(__file__),
+ 'valueset_output_for_compare_samples_test.json')
+ result = compare_samples.CompareSamples(
+ vs, vs, 'timeToFirstContentfulPaint/pcv1-cold/'
+ 'http___www.rambler.ru_', data_format='valueset')
+ result = json.loads(result.stdout)
+ self.assertEqual(result['result']['significance'], NEED_MORE_DATA)
+ self.assertAlmostEqual(Mean(result['sampleA']), 75.3177999958396)
+ self.assertAlmostEqual(Mean(result['sampleB']), 75.3177999958396)
+
+ def testCompareBuildbotOutput(self):
+ bb = os.path.join(os.path.dirname(__file__),
+ 'buildbot_output_for_compare_samples_test.txt')
+ result = compare_samples.CompareSamples(
+ bb, bb, 'DrawCallPerf_gl/score',
+ data_format='buildbot')
+ result = json.loads(result.stdout)
+ self.assertEqual(result['result']['significance'], NEED_MORE_DATA)
+ self.assertEqual(Mean(result['sampleA']), 4123)
+ self.assertEqual(Mean(result['sampleB']), 4123)
+
+ def testCompareChartJsonHistogram(self):
+ metric = ('some_chart', 'some_trace')
+ lower_values = ','.join(self.MakeMultipleChartJSONHistograms(
+ metric=metric, seed='lower', mu=10, sigma=1, n=100, m=10))
+ higher_values = ','.join(self.MakeMultipleChartJSONHistograms(
+ metric=metric, seed='higher', mu=20, sigma=2, n=100, m=10))
+ result = json.loads(compare_samples.CompareSamples(
+ lower_values, higher_values, '/'.join(metric)).stdout)
+ self.assertEqual(result['result']['significance'], REJECT)
+
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric.html
new file mode 100644
index 00000000000..2a0a9bae3c1
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/metrics/metric_registry.html">
+<link rel="import" href="/tracing/value/histogram.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.metrics.sh', function() {
+ function getCpuSnapshotsFromModel(model) {
+ var snapshots = [];
+ for (var pid in model.processes) {
+ var snapshotInstances = model.processes[pid].objects.getAllInstancesNamed(
+ 'CPUSnapshots');
+ if (!snapshotInstances)
+ continue;
+ for (var object of snapshotInstances[0].snapshots)
+ snapshots.push(object.args.processes);
+ }
+ return snapshots;
+ }
+
+ function getProcessSumsFromSnapshot(snapshot) {
+ var processSums = new Map();
+ for (var processData of snapshot) {
+ var processName = processData.name;
+ if (!(processSums.has(processName)))
+ processSums.set(processName, {sum: 0.0, paths: new Set()});
+ processSums.get(processName).sum += parseFloat(processData.pCpu);
+ // The process path may be missing on Windows because of AccessDenied
+ // error thrown by psutil package used by CPU tracing agent.
+ if (processData.path)
+ processSums.get(processName).paths.add(processData.path);
+ }
+ return processSums;
+ }
+
+ function buildNumericsFromSnapshots(snapshots) {
+ var processNumerics = new Map();
+ for (var snapshot of snapshots) {
+ var processSums = getProcessSumsFromSnapshot(snapshot);
+ for (var [processName, processData] of processSums.entries()) {
+ if (!(processNumerics.has(processName))) {
+ processNumerics.set(processName, {
+ numeric: new tr.v.Histogram('cpu:percent:' + processName,
+ tr.b.Unit.byName.normalizedPercentage_smallerIsBetter),
+ paths: new Set()
+ });
+ }
+ processNumerics.get(processName).numeric.addSample(
+ processData.sum / 100.0);
+ for (var path of processData.paths)
+ processNumerics.get(processName).paths.add(path);
+ }
+ }
+ return processNumerics;
+ }
+
+ function cpuProcessMetric(values, model) {
+ var snapshots = getCpuSnapshotsFromModel(model);
+ var processNumerics = buildNumericsFromSnapshots(snapshots);
+ for (var [processName, processData] of processNumerics) {
+ var numeric = processData.numeric;
+ // Treat missing snapshots as zeros. A process is missing from a snapshots
+ // when its CPU usage was below minimum threshold when the snapshot was
+ // taken.
+ var missingSnapshotCount = snapshots.length - numeric.numValues;
+ for (var i = 0; i < missingSnapshotCount; i++)
+ numeric.addSample(0);
+ numeric.diagnostics.set('paths', new
+ tr.v.d.Generic([...processData.paths]));
+ values.addHistogram(numeric);
+ }
+ }
+
+ tr.metrics.MetricRegistry.register(cpuProcessMetric);
+
+ return {
+ cpuProcessMetric: cpuProcessMetric
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric_test.html
new file mode 100644
index 00000000000..a9e3dce210b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/cpu_process_metric_test.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
+<link rel="import" href="/tracing/metrics/cpu_process_metric.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+
+ function makeModel(events) {
+ return tr.c.TestUtils.newModelWithEvents([events]);
+ }
+
+ test('cpuProcessMetric_noData', function() {
+ var values = new tr.v.ValueSet();
+ var events = [
+ {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
+ {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'B'}
+ ];
+ tr.metrics.sh.cpuProcessMetric(values, makeModel(events));
+ assert.lengthOf(values.toArray(), 0);
+ });
+
+ test('cpuProcessMetric_singleSnapshots', function() {
+ var values = new tr.v.ValueSet();
+ var events = [
+ {
+ 'name': 'CPUSnapshots',
+ 'args': {
+ 'snapshot': {
+ 'processes': [
+ {'path': '/usr/sbin/crudd', 'pCpu': '99.0', 'pid': '13495',
+ 'pMem': '0.0', 'name': 'crudd'},
+ {'path': '/opt/chrome/chrome', 'pCpu': '0.8',
+ 'pid': '29660', 'pMem': '0.9', 'name': 'chrome'},
+ {'path': '/opt/chrome/chrome', 'pCpu': '0.3',
+ 'pid': '29661', 'pMem': '0.9', 'name': 'chrome'}
+ ]
+ }
+ },
+ 'pid': 52, 'ts': '2226221225693.658', tid: 53,
+ 'tid': undefined, 'ph': 'O', 'local': true, 'id': '0x1000'
+ }
+ ];
+ tr.metrics.sh.cpuProcessMetric(values, makeModel(events));
+ assert.lengthOf(values.getValuesNamed('cpu:percent:chrome'), 1);
+ assert.lengthOf(values.getValuesNamed('cpu:percent:crudd'), 1);
+ var chromeValue = values.getValuesNamed('cpu:percent:chrome')[0];
+ var chromeStatistics = chromeValue.running;
+ assert.strictEqual(chromeStatistics.count, 1);
+ assert.closeTo(chromeStatistics.mean, 0.011, 1e-5);
+ assert.closeTo(chromeStatistics.max, 0.011, 1e-5);
+ assert.instanceOf(chromeValue.diagnostics.get('paths'), tr.v.d.Generic);
+ assert.lengthOf(chromeValue.diagnostics.get('paths').value, 1);
+ assert.strictEqual(chromeValue.diagnostics.get('paths').value[0],
+ '/opt/chrome/chrome');
+ });
+
+ test('cpuProcessMetric_multipleSnapshots', function() {
+ var values = new tr.v.ValueSet();
+ var events = [
+ {
+ 'name': 'CPUSnapshots',
+ 'args': {
+ 'snapshot': {
+ 'processes': [
+ {'path': '/usr/sbin/crudd', 'pCpu': '99.0', 'pid': '13495',
+ 'pMem': '0.0', 'name': 'crudd'},
+ {'path': '/opt/chrome/chrome', 'pCpu': '0.8',
+ 'pid': '29660', 'pMem': '0.9', 'name': 'chrome'}
+ ]
+ }
+ },
+ 'pid': 52, 'ts': '2226221225693.658', tid: 53,
+ 'tid': undefined, 'ph': 'O', 'local': true, 'id': '0x1000'
+ },
+ {
+ 'name': 'CPUSnapshots',
+ 'args': {
+ 'snapshot': {
+ 'processes': [
+ {'path': '/usr/sbin/crudd', 'pCpu': '1.3', 'pid': '13495',
+ 'pMem': '0.0', 'name': 'crudd'},
+ {'path': '/opt/chrome/chrome', 'pCpu': '0.6',
+ 'pid': '29660', 'pMem': '0.9', 'name': 'chrome'},
+ {'path': '/opt/chromium/chrome', 'pCpu': '0.1',
+ 'pid': '29660', 'pMem': '0.9', 'name': 'chrome'},
+ {'path': '/usr/sbin/mnp_logger', 'pCpu': '0.2', 'pid': '6543',
+ 'pMem': '0.1', 'name': 'mnp_logger'}
+ ]
+ }
+ },
+ 'pid': 52, 'ts': '2226222262064.4473', tid: 53,
+ 'tid': undefined, 'ph': 'O', 'local': true, 'id': '0x1000'
+ }
+ ];
+ tr.metrics.sh.cpuProcessMetric(values, makeModel(events));
+ assert.lengthOf(values.getValuesNamed('cpu:percent:chrome'), 1);
+ assert.lengthOf(values.getValuesNamed('cpu:percent:crudd'), 1);
+ assert.lengthOf(values.getValuesNamed('cpu:percent:mnp_logger'), 1);
+ var chromeValue = values.getValuesNamed('cpu:percent:chrome')[0];
+ var chromeStatistics = chromeValue.running;
+ assert.strictEqual(chromeStatistics.count, 2);
+ assert.closeTo(chromeStatistics.mean, 0.0075, 1e-5);
+ assert.strictEqual(chromeStatistics.max, 0.008);
+ assert.instanceOf(chromeValue.diagnostics.get('paths'), tr.v.d.Generic);
+ assert.lengthOf(chromeValue.diagnostics.get('paths').value, 2);
+ assert.strictEqual(chromeValue.diagnostics.get('paths').value[0],
+ '/opt/chrome/chrome');
+
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/discover_cmdline.html b/chromium/third_party/catapult/tracing/tracing/metrics/discover_cmdline.html
index 8cf7f307aee..259738036db 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/discover_cmdline.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/discover_cmdline.html
@@ -16,11 +16,11 @@ function discoverMetrics(args) {
}
var metrics = tr.metrics.MetricRegistry.getAllRegisteredTypeInfos();
- var discovered_metric_names = [];
+ var discoveredMetricNames = [];
for (var i = 0; i < metrics.length; i++) {
- discovered_metric_names.push(metrics[i].constructor.name);
+ discoveredMetricNames.push(metrics[i].constructor.name);
}
- console.log(JSON.stringify(discovered_metric_names));
+ console.log(JSON.stringify(discoveredMetricNames));
return 0;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/discover_unittest.py b/chromium/third_party/catapult/tracing/tracing/metrics/discover_unittest.py
index f81417df2c8..10b81b547c8 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/discover_unittest.py
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/discover_unittest.py
@@ -11,10 +11,8 @@ class MetricsDiscoverUnittest(unittest.TestCase):
self.assertFalse(discover.DiscoverMetrics([]))
def testMetricsDiscoverNonEmpty(self):
- self.assertEquals(
- ['sampleMetric'],
- discover.DiscoverMetrics(
- ['/tracing/metrics/sample_metric.html']))
+ self.assertEquals(['sampleMetric'], discover.DiscoverMetrics(
+ ['/tracing/metrics/sample_metric.html']))
def testMetricsDiscoverMultipleMetrics(self):
self.assertGreater(
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function.html b/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function.html
index bbfa316d771..c841ab84494 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/perf_insights/mre/function_handle.html">
<link rel="import" href="/tracing/metrics/all_metrics.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
+<link rel="import" href="/tracing/mre/function_handle.html">
<link rel="import" href="/tracing/value/value_set.html">
<script>
@@ -15,44 +15,82 @@ found in the LICENSE file.
tr.exportTo('tr.metrics', function() {
/**
- * @param {!pi.mre.MreResult} result
* @param {!tr.model.Model} model
* @param {!Object} options
+ * @param {!Array.<string>} options.metrics
+ * @return {!tr.v.ValueSet}
*/
- function metricMapFunction(result, model, options) {
+ function runMetrics(model, options) {
if (options === undefined)
- throw new Error('Expected an options dict.');
+ throw new Error('Options are required.');
- var metricName = options.metric;
- if (metricName === undefined)
- throw new Error('A metric name should be specified.');
+ var metricNames = options.metrics;
+ if (!metricNames)
+ throw new Error('Metric names should be specified.');
var values = new tr.v.ValueSet();
- var metric = tr.metrics.MetricRegistry.findTypeInfoWithName(metricName);
- if (metric === undefined)
- throw new Error('"' + metricName + '" is not a registered metric.');
- metric.constructor(values, model);
+ for (var metricName of metricNames) {
+ var metric = tr.metrics.MetricRegistry.findTypeInfoWithName(metricName);
+ if (metric === undefined)
+ throw new Error('"' + metricName + '" is not a registered metric.');
+ metric.constructor(values, model, options);
+ }
+ return values;
+ }
+
+ /**
+ * @param {!tr.v.ValueSet} values
+ * @param {!tr.model.Model} model
+ */
+ function addIterationInfo(values, model) {
+ var iterationInfo = new tr.v.d.IterationInfo();
for (var metadata of model.metadata) {
- if (!metadata.value || !metadata.value['iteration-info'])
+ if (!metadata.value)
continue;
- var iteration = new tr.v.d.IterationInfo(
- metadata.value['iteration-info']);
- // Values can be separated from their ValueSet and mixed into ValueSets
- // with Values from other iterations, so add IterationInfo to each Value.
- values.map(function(value) {
- value.diagnostics.add(tr.v.ITERATION_INFO_DIAGNOSTIC_NAME, iteration);
- });
+
+ if (metadata.value['iteration-info'])
+ iterationInfo.addInfo(metadata.value['iteration-info']);
+
+ if (metadata.value['os-version'])
+ iterationInfo.addInfo(metadata.value);
}
+ // Values can be separated from their ValueSet and mixed into ValueSets
+ // with Values from other iterations, so add IterationInfo to each Value.
+ values.map(v => iterationInfo.addToValue(v));
+ }
- result.addPair('values', values.valueDicts);
+ /**
+ * @param {!tr.mre.MreResult} result
+ * @param {!tr.model.Model} model
+ * @param {!Object} options
+ * @param {!Array.<string>} options.metrics
+ */
+ function metricMapFunction(result, model, options) {
+ var values = runMetrics(model, options);
+ addIterationInfo(values, model);
+
+ result.addPair('histograms', values.valueDicts);
+
+ var scalarDicts = [];
+ for (var value of values) {
+ for (var [statName, scalar] of value.statisticsScalars) {
+ scalarDicts.push({
+ name: value.name + '_' + statName,
+ numeric: scalar.asDict(),
+ description: value.description,
+ });
+ }
+ }
+ result.addPair('scalars', scalarDicts);
}
- pi.FunctionRegistry.register(metricMapFunction);
+ tr.mre.FunctionRegistry.register(metricMapFunction);
return {
- metricMapFunction: metricMapFunction
+ metricMapFunction: metricMapFunction,
+ runMetrics: runMetrics
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function_test.html
index f66ed23949c..8e5048f3e13 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/metric_map_function_test.html
@@ -5,17 +5,17 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/perf_insights/mre/mre_result.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
<link rel="import" href="/tracing/metrics/metric_map_function.html">
<link rel="import" href="/tracing/metrics/sample_metric.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.TestUtils;
+ var TestUtils = tr.c.TestUtils;
var ThreadSlice = tr.model.ThreadSlice;
test('metricMapTest', function() {
@@ -23,19 +23,19 @@ tr.b.unittest.testSuite(function() {
{name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
{name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
];
- var m = test_utils.newModelWithEvents(JSON.stringify(events), {
+ var m = TestUtils.newModelWithEvents(JSON.stringify(events), {
shiftWorldToZero: false,
pruneEmptyContainers: false,
trackDetailedModelStats: true,
customizeModelCallback: function(m) {
var p1 = m.getOrCreateProcess(1);
var t2 = p1.getOrCreateThread(2);
- var t2_s1 = t2.sliceGroup.pushSlice(test_utils.newSliceEx({
+ t2.sliceGroup.pushSlice(TestUtils.newSliceEx({
type: ThreadSlice,
name: 'some_slice',
start: 0, end: 10
}));
- var t2_s2 = t2.sliceGroup.pushSlice(test_utils.newSliceEx({
+ t2.sliceGroup.pushSlice(TestUtils.newSliceEx({
type: ThreadSlice,
name: 'some_slice',
start: 20, end: 30
@@ -44,18 +44,21 @@ tr.b.unittest.testSuite(function() {
});
assert.throw(function() {
- var result = new pi.mre.MreResult();
+ var result = new tr.mre.MreResult();
tr.metrics.metricMapFunction(result, m, {});
- }, Error, 'A metric name should be specified.');
+ }, Error, 'Metric names should be specified.');
assert.throw(function() {
- var result = new pi.mre.MreResult();
- tr.metrics.metricMapFunction(result, m, {'metric': 'wrongMetric'});
+ var result = new tr.mre.MreResult();
+ tr.metrics.metricMapFunction(result, m, {'metrics': ['wrongMetric']});
}, Error, '"wrongMetric" is not a registered metric.');
- var result = new pi.mre.MreResult();
- tr.metrics.metricMapFunction(result, m, {'metric': 'sampleMetric'});
- assert.property(result.pairs, 'values');
+ var result = new tr.mre.MreResult();
+ tr.metrics.metricMapFunction(result, m, {'metrics': ['sampleMetric']});
+ assert.property(result.pairs, 'histograms');
+ assert.equal(result.pairs.histograms.length, 1);
+ assert.property(result.pairs, 'scalars');
+ assert.equal(result.pairs.scalars.length, 6);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/metric_registry_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/metric_registry_test.html
index 21a3584a3ab..135f2518a8b 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/metric_registry_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/metric_registry_test.html
@@ -4,48 +4,49 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
-
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.TestUtils;
- var ThreadSlice = tr.model.ThreadSlice;
-
test('FindMetricByName', function() {
function sampleMetricA(values, model) {
- var unit = tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
- var n1 = new tr.v.ScalarNumeric(unit, 1);
- values.addValue(new tr.v.NumericValue('foo', n1));
+ var n1 = new tr.v.Histogram('foo', tr.b.Unit.byName.count);
+ n1.addSample(1);
+ values.addHistogram(n1);
}
tr.metrics.MetricRegistry.register(sampleMetricA);
function sampleMetricB(values, model) {
- var unit = tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
- var n1 = new tr.v.ScalarNumeric(unit, 1);
- var n2 = new tr.v.ScalarNumeric(unit, 2);
- values.addValue(new tr.v.NumericValue('foo', n1));
- values.addValue(new tr.v.NumericValue('bar', n2));
+ var n1 = new tr.v.Histogram('foo', tr.b.Unit.byName.count);
+ var n2 = new tr.v.Histogram('bar', tr.b.Unit.byName.count);
+ n1.addSample(1);
+ n2.addSample(2);
+ values.addHistogram(n1);
+ values.addHistogram(n2);
}
tr.metrics.MetricRegistry.register(sampleMetricB);
function sampleMetricC(values, model) {
- var unit = tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
- var n1 = new tr.v.ScalarNumeric(unit, 1);
- var n2 = new tr.v.ScalarNumeric(unit, 2);
- var n3 = new tr.v.ScalarNumeric(unit, 3);
- values.addValue(new tr.v.NumericValue('foo', n1));
- values.addValue(new tr.v.NumericValue('bar', n2));
- values.addValue(new tr.v.NumericValue('baz', n3));
+ var n1 = new tr.v.Histogram('foo', tr.b.Unit.byName.count);
+ var n2 = new tr.v.Histogram('bar', tr.b.Unit.byName.count);
+ var n3 = new tr.v.Histogram('baz', tr.b.Unit.byName.count);
+ n1.addSample(1);
+ n2.addSample(2);
+ n3.addSample(3);
+ values.addHistogram(n1);
+ values.addHistogram(n2);
+ values.addHistogram(n3);
}
tr.metrics.MetricRegistry.register(sampleMetricC);
- assert.isTrue(tr.metrics.MetricRegistry.findTypeInfoWithName('sampleMetricB').constructor === sampleMetricB); // @suppress longLineCheck
+ var typeInfo = tr.metrics.MetricRegistry.findTypeInfoWithName(
+ 'sampleMetricB');
+ assert.strictEqual(typeInfo.constructor, sampleMetricB);
});
test('registerNonFunctionThrows', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/metric_runner.py b/chromium/third_party/catapult/tracing/tracing/metrics/metric_runner.py
index 62ac454ed42..b691cc44f7d 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/metric_runner.py
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/metric_runner.py
@@ -3,11 +3,11 @@
# found in the LICENSE file.
import os
-from perf_insights.mre import function_handle
-from perf_insights.mre import map_runner
-from perf_insights.mre import progress_reporter
-from perf_insights.mre import file_handle
-from perf_insights.mre import job as job_module
+from tracing.mre import function_handle
+from tracing.mre import gtest_progress_reporter
+from tracing.mre import map_runner
+from tracing.mre import file_handle
+from tracing.mre import job as job_module
_METRIC_MAP_FUNCTION_FILENAME = 'metric_map_function.html'
@@ -16,30 +16,31 @@ _METRIC_MAP_FUNCTION_NAME = 'metricMapFunction'
def _GetMetricsDir():
return os.path.dirname(os.path.abspath(__file__))
-def _GetMetricRunnerHandle(metric):
- assert isinstance(metric, basestring)
+def _GetMetricRunnerHandle(metrics):
+ assert isinstance(metrics, list)
+ for metric in metrics:
+ assert isinstance(metric, basestring)
metrics_dir = _GetMetricsDir()
metric_mapper_path = os.path.join(metrics_dir, _METRIC_MAP_FUNCTION_FILENAME)
modules_to_load = [function_handle.ModuleToLoad(filename=metric_mapper_path)]
- options = {'metric': metric}
+ options = {'metrics': metrics}
map_function_handle = function_handle.FunctionHandle(
modules_to_load, _METRIC_MAP_FUNCTION_NAME, options)
return job_module.Job(map_function_handle, None)
-def RunMetric(filename, metric, extra_import_options=None):
- result = RunMetricOnTraces([filename], metric, extra_import_options)
+def RunMetric(filename, metrics, extra_import_options=None):
+ result = RunMetricOnTraces([filename], metrics, extra_import_options)
return result[filename]
-def RunMetricOnTraces(filenames, metric,
+def RunMetricOnTraces(filenames, metrics,
extra_import_options=None):
trace_handles = [
file_handle.URLFileHandle(f, 'file://%s' % f) for f in filenames]
- job = _GetMetricRunnerHandle(metric)
+ job = _GetMetricRunnerHandle(metrics)
runner = map_runner.MapRunner(
- trace_handles, job,
- extra_import_options=extra_import_options,
- progress_reporter=progress_reporter.ProgressReporter())
+ trace_handles, job, extra_import_options=extra_import_options,
+ progress_reporter=gtest_progress_reporter.GTestProgressReporter())
map_results = runner.RunMapper()
return map_results
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/sample_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/sample_metric.html
index 43ae5dae567..34e0c700c9c 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/sample_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/sample_metric.html
@@ -4,29 +4,36 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics', function() {
- var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ function sampleMetric(values, model) {
+ var hist = new tr.v.Histogram(
+ 'foo', tr.b.Unit.byName.sizeInBytes_smallerIsBetter);
+ hist.addSample(9);
+ hist.addSample(91, {bar: new tr.v.d.Generic({hello: 42})});
- var SIZE_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- sizeInBytes_smallerIsBetter, tr.b.Range.fromExplicitRange(1, 100), 100);
+ for (var expectation of model.userModel.expectations) {
+ if (expectation instanceof tr.model.um.ResponseExpectation) {
+ } else if (expectation instanceof tr.model.um.AnimationExpectation) {
+ } else if (expectation instanceof tr.model.um.IdleExpectation) {
+ } else if (expectation instanceof tr.model.um.LoadExpectation) {
+ }
+ }
- function sampleMetric(values, model) {
- var n1 = new tr.v.ScalarNumeric(sizeInBytes_smallerIsBetter, 1);
- var n2 = new tr.v.ScalarNumeric(sizeInBytes_smallerIsBetter, 2);
- var n3 = SIZE_NUMERIC_BUILDER.build();
- n3.add(1);
- values.addValue(new tr.v.NumericValue('foo', n1));
- values.addValue(new tr.v.NumericValue('bar', n2));
- values.addValue(new tr.v.NumericValue('baz', n3));
+ var chromeHelper = model.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+
+ tr.b.iterItems(model.processes, function(pid, process) {
+ });
+
+ values.addHistogram(hist);
}
tr.metrics.MetricRegistry.register(sampleMetric);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric.html
index c30d0790d8c..8d3820e77d7 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric.html
@@ -8,14 +8,12 @@ found in the LICENSE file.
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/system_health/utils.html">
<link rel="import" href="/tracing/model/model.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.sh', function() {
-
function syncIsComplete(markers) {
return markers.length === 2;
}
@@ -34,21 +32,23 @@ tr.exportTo('tr.metrics.sh', function() {
var targetDomain = undefined;
if (!syncIsComplete(markers) || !syncInvolvesTelemetry(markers))
continue;
+
for (var marker of markers) {
var domain = marker.domainId;
if (domain === tr.model.ClockDomainId.TELEMETRY)
latency = (marker.endTs - marker.startTs);
else
- targetDomain = domain;
+ targetDomain = domain.toLowerCase();
}
- values.addValue(new tr.v.NumericValue(
- 'clock_sync_latency_' + targetDomain,
- new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- latency),
- { description: 'Clock sync latency for domain ' + targetDomain }));
+
+ var hist = new tr.v.Histogram('clock_sync_latency_' + targetDomain,
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createExponential(1e-3, 1e3, 30));
+ hist.description = 'Clock sync latency for domain ' + targetDomain;
+ hist.addSample(latency);
+ values.addHistogram(hist);
}
- };
+ }
tr.metrics.MetricRegistry.register(clockSyncLatencyMetric);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric_test.html
index fe6a37d4819..bc1dd5103ab 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/clock_sync_latency_metric_test.html
@@ -25,22 +25,27 @@ tr.b.unittest.testSuite(function() {
model.clockSyncManager.addClockSyncMarker(
tr.model.ClockDomainId.WIN_QPC, 'ID02', 5.0);
- var battorName = 'clock_sync_latency_' + tr.model.ClockDomainId.BATTOR;
- var winQpcName = 'clock_sync_latency_' + tr.model.ClockDomainId.WIN_QPC;
+ var battorName = 'clock_sync_latency_' +
+ tr.model.ClockDomainId.BATTOR.toLowerCase();
+ var winQpcName = 'clock_sync_latency_' +
+ tr.model.ClockDomainId.WIN_QPC.toLowerCase();
var valueSet = new tr.v.ValueSet();
tr.metrics.sh.clockSyncLatencyMetric(valueSet, model);
- var battorEntry = tr.b.getOnlyElement(
- valueSet.valueDicts.filter(
- (dict) => dict.name === battorName));
+ var battorValue = undefined;
+ var winQpcValue = undefined;
+ for (var value of valueSet) {
+ if (value.name === battorName)
+ battorValue = value;
+ else if (value.name === winQpcName)
+ winQpcValue = value;
+ }
- var winQpcEntry = tr.b.getOnlyElement(
- valueSet.valueDicts.filter(
- (dict) => dict.name === winQpcName));
-
- assert.equal(battorEntry.numeric.value, 3.0);
- assert.equal(winQpcEntry.numeric.value, 6.0);
+ assert.isDefined(battorValue);
+ assert.isDefined(winQpcValue);
+ assert.closeTo(battorValue.average, 3.0, 1e-5);
+ assert.closeTo(winQpcValue.average, 6.0, 1e-5);
});
test('clockSyncLatencyMetric_noTelemetry', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric.html
new file mode 100644
index 00000000000..3879154231b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/metrics/metric_registry.html">
+<link rel="import" href="/tracing/value/histogram.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.metrics.sh', function() {
+ // Use a lower bound of 0.01 for the metric boundaries (when no CPU time
+ // is consumed) and an upper bound of 50 (fifty cores are all active
+ // for the entire time). We can't use zero exactly for the lower bound with an
+ // exponential histogram.
+ var CPU_TIME_PERCENTAGE_BOUNDARIES =
+ tr.v.HistogramBinBoundaries.createExponential(0.01, 50, 200);
+
+ /**
+ * This metric measures total CPU time for Chrome processes, per second of
+ * clock time.
+ * This metric requires only the 'toplevel' tracing category.
+ *
+ * @param {!tr.v.ValueSet} values
+ * @param {!tr.model.Model} model
+ * @param {!Object=} opt_options
+ */
+ function cpuTimeMetric(values, model, opt_options) {
+ var rangeOfInterest = model.bounds;
+ if (opt_options && opt_options.rangeOfInterest)
+ rangeOfInterest = opt_options.rangeOfInterest;
+ var allProcessCpuTime = 0;
+
+ for (var pid in model.processes) {
+ var process = model.processes[pid];
+ var processCpuTime = 0;
+ for (var tid in process.threads) {
+ var thread = process.threads[tid];
+ var threadCpuTime = 0;
+ thread.sliceGroup.topLevelSlices.forEach(function(slice) {
+ if (slice.duration === 0)
+ return;
+ if (!slice.cpuDuration)
+ return;
+ var sliceRange = tr.b.Range.fromExplicitRange(slice.start, slice.end);
+ var intersection = rangeOfInterest.findIntersection(sliceRange);
+ var fractionOfSliceInsideRangeOfInterest =
+ intersection.duration / slice.duration;
+
+ // We assume that if a slice doesn't lie entirely inside the range of
+ // interest, then the CPU time is evenly distributed inside of the
+ // slice.
+ threadCpuTime +=
+ slice.cpuDuration * fractionOfSliceInsideRangeOfInterest;
+ });
+ processCpuTime += threadCpuTime;
+ }
+ allProcessCpuTime += processCpuTime;
+ }
+
+ // Normalize cpu time by clock time.
+ var normalizedAllProcessCpuTime = 0;
+ if (rangeOfInterest.duration > 0) {
+ normalizedAllProcessCpuTime =
+ allProcessCpuTime / rangeOfInterest.duration;
+ }
+
+ var unit = tr.b.Unit.byName.normalizedPercentage_smallerIsBetter;
+ var cpuTimeHist = new tr.v.Histogram(
+ 'cpu_time_percentage', unit, CPU_TIME_PERCENTAGE_BOUNDARIES);
+ cpuTimeHist.description =
+ 'Percent CPU utilization, normalized against a single core. Can be ' +
+ 'greater than 100% if machine has multiple cores.';
+ cpuTimeHist.addSample(normalizedAllProcessCpuTime);
+ values.addHistogram(cpuTimeHist);
+ }
+
+ tr.metrics.MetricRegistry.register(cpuTimeMetric, {
+ supportsRangeOfInterest: true
+ });
+
+ return {
+ cpuTimeMetric: cpuTimeMetric,
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric_test.html
new file mode 100644
index 00000000000..65616512ea8
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/cpu_time_metric_test.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/metrics/system_health/cpu_time_metric.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ function computeCpuTime(customizeModelCallback, opt_options) {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ customizeModelCallback(model);
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.cpuTimeMetric(values, model, opt_options);
+ return tr.b.getOnlyElement(values).average;
+ }
+
+ // There are two slices, each of length 50. The total bounds is 3000.
+ // This yields total CPU time of 100ms, averaged over 3 seconds is 33ms.
+ test('cpuTimeMetric_oneProcess', function() {
+ var sliceDuration = 50;
+ var totalDuration = 3000;
+ var value = computeCpuTime(function(model) {
+ model.rendererProcess = model.getOrCreateProcess(2);
+ model.rendererMain = model.rendererProcess.getOrCreateThread(3);
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: 0,
+ duration: sliceDuration,
+ cpuStart: 0,
+ cpuDuration: sliceDuration,
+ }));
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: totalDuration - sliceDuration,
+ duration: sliceDuration,
+ cpuStart: totalDuration - sliceDuration,
+ cpuDuration: sliceDuration,
+ }));
+ });
+ assert.closeTo(value, 0.033, 0.001);
+ });
+
+ // Makes sure that rangeOfInterest works correctly.
+ test('cpuTimeMetric_oneProcess_rangeOfInterest', function() {
+ var sliceDuration = 50;
+ var totalDuration = 3000;
+ var rangeOfInterest = new tr.b.Range.fromExplicitRange(-10, 30);
+ var options = {}
+ options.rangeOfInterest = rangeOfInterest
+ var value = computeCpuTime(function(model) {
+ model.rendererProcess = model.getOrCreateProcess(2);
+ model.rendererMain = model.rendererProcess.getOrCreateThread(3);
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: 0,
+ duration: sliceDuration,
+ cpuStart: 0,
+ cpuDuration: sliceDuration,
+ }));
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: totalDuration - sliceDuration,
+ duration: sliceDuration,
+ cpuStart: totalDuration - sliceDuration,
+ cpuDuration: sliceDuration,
+ }));
+ }, options);
+ assert.closeTo(value, 0.75, 0.001);
+ });
+
+ // Process 1: There are two slices, each of length 50. The total bounds is
+ // 3000. Process 2: There is one slice of length 50.
+ // This yields total CPU time of 150ms, averaged over 3 seconds is 50ms.
+ test('cpuTimeMetric_twoProcesses', function() {
+ var sliceDuration = 50;
+ var totalDuration = 3000;
+ var value = computeCpuTime(function(model) {
+ model.rendererProcess = model.getOrCreateProcess(2);
+ model.rendererMain = model.rendererProcess.getOrCreateThread(3);
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: 0,
+ duration: sliceDuration,
+ cpuStart: 0,
+ cpuDuration: sliceDuration,
+ }));
+ model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: totalDuration - sliceDuration,
+ duration: sliceDuration,
+ cpuStart: totalDuration - sliceDuration,
+ cpuDuration: sliceDuration,
+ }));
+
+ var otherProcess = model.getOrCreateProcess(3);
+ var otherThread = otherProcess.getOrCreateThread(4);
+ otherThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ type: tr.model.ThreadSlice,
+ isTopLevel: true,
+ start: 0,
+ duration: sliceDuration,
+ cpuStart: 0,
+ cpuDuration: sliceDuration,
+ }));
+ });
+ assert.closeTo(value, 0.05, 0.001);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric.html
deleted file mode 100644
index 6274def9412..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2015 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/statistics.html">
-<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/metrics/system_health/utils.html">
-<link rel="import" href="/tracing/model/user_model/animation_expectation.html">
-<link rel="import" href="/tracing/model/user_model/idle_expectation.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
-
-<script>
-'use strict';
-
-tr.exportTo('tr.metrics.sh', function() {
- var UNIT = tr.v.Unit.byName.normalizedPercentage_biggerIsBetter;
-
- var DESCRIPTION = 'Normalized CPU budget consumption';
-
- function efficiencyMetric(values, model) {
- var scores = [];
-
- model.userModel.expectations.forEach(function(ue) {
- var options = {};
- options.description = DESCRIPTION;
-
- var score = undefined;
-
- if ((ue.totalCpuMs === undefined) ||
- (ue.totalCpuMs == 0))
- return;
-
- var cpuFractionBudget = tr.b.Range.fromExplicitRange(0.5, 1.5);
-
- if (ue instanceof tr.model.um.IdleExpectation) {
- cpuFractionBudget = tr.b.Range.fromExplicitRange(0.1, 1);
- } else if (ue instanceof tr.model.um.AnimationExpectation) {
- cpuFractionBudget = tr.b.Range.fromExplicitRange(1, 2);
- }
-
- var cpuMsBudget = tr.b.Range.fromExplicitRange(
- ue.duration * cpuFractionBudget.min,
- ue.duration * cpuFractionBudget.max);
- var normalizedCpu = tr.b.normalize(
- ue.totalCpuMs, cpuMsBudget.min, cpuMsBudget.max);
- score = 1 - tr.b.clamp(normalizedCpu, 0, 1);
-
- scores.push(score);
-
- values.addValue(new tr.v.NumericValue(
- 'efficiency', new tr.v.ScalarNumeric(UNIT, score), options));
- });
-
- // Manually reduce scores.
- // https://github.com/catapult-project/catapult/issues/2036
-
- var options = {};
- options.description = DESCRIPTION;
- var overallScore = tr.b.Statistics.weightedMean(
- scores, tr.metrics.sh.perceptualBlend);
- if (overallScore === undefined)
- return;
-
- values.addValue(new tr.v.NumericValue(
- 'efficiency', new tr.v.ScalarNumeric(UNIT, overallScore), options));
- }
-
- tr.metrics.MetricRegistry.register(efficiencyMetric);
-
- return {
- efficiencyMetric: efficiencyMetric
- };
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric_test.html
deleted file mode 100644
index 5fe0f1a4561..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/efficiency_metric_test.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2015 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import"
- href="/tracing/metrics/system_health/efficiency_metric.html">
-<link rel="import" href="/tracing/model/user_model/idle_expectation.html">
-<link rel="import" href="/tracing/value/value_set.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- function createModel() {
- return tr.c.TestUtils.newModel(function(model) {
- model.p1 = model.getOrCreateProcess(1);
- model.t2 = model.p1.getOrCreateThread(2);
-
- var slice = tr.c.TestUtils.newSliceEx({
- title: 'foo',
- start: 0,
- end: 100,
- type: tr.model.ThreadSlice
- });
- slice.isTopLevel = true;
-
- var idle = new tr.model.um.IdleExpectation(model, 0, 100);
- idle.associatedEvents.push(slice);
- model.userModel.expectations.push(idle);
- });
- }
-
- test('optimalEfficiency', function() {
- var model = createModel();
- var exp = model.userModel.expectations[0];
- tr.b.getOnlyElement(exp.associatedEvents).cpuSelfTime = 10;
- var values = new tr.v.ValueSet();
- tr.metrics.sh.efficiencyMetric(values, model);
- assert.equal(1, values.valueDicts[0].numeric.value);
- });
-
- test('pessimalEfficiency', function() {
- var model = createModel();
- var exp = model.userModel.expectations[0];
- tr.b.getOnlyElement(exp.associatedEvents).cpuSelfTime = 100;
- var values = new tr.v.ValueSet();
- tr.metrics.sh.efficiencyMetric(values, model);
- assert.equal(0, values.valueDicts[0].numeric.value);
- });
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric.html
deleted file mode 100644
index bc1aa3828ca..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric.html
+++ /dev/null
@@ -1,423 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2016 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/statistics.html">
-<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/metrics/system_health/utils.html">
-<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
-<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
-
-<script>
-'use strict';
-
-tr.exportTo('tr.metrics.sh', function() {
- var timeDurationInMs_smallerIsBetter =
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;
-
- function findTargetRendererHelper(chromeHelper) {
- var largestPid = -1;
- for (var pid in chromeHelper.rendererHelpers) {
- var rendererHelper = chromeHelper.rendererHelpers[pid];
- if (rendererHelper.isChromeTracingUI)
- continue;
- if (pid > largestPid)
- largestPid = pid;
- }
-
- if (largestPid === -1)
- return undefined;
-
- return chromeHelper.rendererHelpers[largestPid];
- }
-
- /**
- * A utility class for finding navigationStart event for given frame and
- * timestamp.
- * @constructor
- */
- function NavigationStartFinder(rendererHelper) {
- this.navigationStartsForFrameId_ = {};
- for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
- if (ev.category !== 'blink.user_timing' ||
- ev.title !== 'navigationStart')
- continue;
- var frameIdRef = ev.args['frame'];
- var list = this.navigationStartsForFrameId_[frameIdRef];
- if (list === undefined)
- this.navigationStartsForFrameId_[frameIdRef] = list = [];
- list.unshift(ev);
- }
- }
-
- NavigationStartFinder.prototype = {
- findNavigationStartEventForFrameBeforeTimestamp: function(frameIdRef, ts) {
- var list = this.navigationStartsForFrameId_[frameIdRef];
- if (list === undefined) {
- console.warn('No navigationStartEvent found for frame id "' +
- frameIdRef + '"');
- return undefined;
- }
- var eventBeforeTimestamp;
- for (var ev of list) {
- if (ev.start > ts)
- continue;
- if (eventBeforeTimestamp === undefined)
- eventBeforeTimestamp = ev;
- }
- if (eventBeforeTimestamp === undefined) {
- console.warn('Failed to find navigationStartEvent.');
- return undefined;
- }
- return eventBeforeTimestamp;
- }
- };
-
- /**
- * A utility class for finding Paint event for given frame and timestamp.
- * @constructor
- */
- function PaintFinder(rendererHelper) {
- this.paintsForFrameId_ = {};
- for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
- if (ev.category !== 'devtools.timeline' || ev.title !== 'Paint')
- continue;
- var frameIdRef = ev.args['data']['frame'];
- var list = this.paintsForFrameId_[frameIdRef];
- if (list === undefined)
- this.paintsForFrameId_[frameIdRef] = list = [];
- list.push(ev);
- }
- }
-
- PaintFinder.prototype = {
- findPaintEventForFrameAfterTimestamp: function(frameIdRef, ts) {
- var list = this.paintsForFrameId_[frameIdRef];
- if (list === undefined)
- return undefined;
-
- var eventAfterTimestamp;
- for (var ev of list) {
- if (ev.start < ts)
- continue;
- if (eventAfterTimestamp === undefined)
- eventAfterTimestamp = ev;
- }
- return eventAfterTimestamp;
- }
- };
-
- var FIRST_PAINT_NUMERIC_BUILDER =
- new tr.v.NumericBuilder(timeDurationInMs_smallerIsBetter, 0)
- .addLinearBins(1000, 20) // 50ms step to 1s
- .addLinearBins(3000, 20) // 100ms step to 3s
- .addExponentialBins(20000, 20);
- function createHistogram() {
- var histogram = FIRST_PAINT_NUMERIC_BUILDER.build();
- histogram.customizeSummaryOptions({
- avg: true,
- count: false,
- max: true,
- min: true,
- std: true,
- sum: false,
- percentile: [0.90, 0.95, 0.99],
- });
- return histogram;
- }
-
- function findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ts) {
- var snapshot;
-
- var objects = rendererHelper.process.objects;
- var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader'];
- if (frameLoaderInstances === undefined) {
- console.warn('Failed to find FrameLoader for frameId "' + frameIdRef +
- '" at ts ' + ts + ', the trace maybe incomplete or from an old' +
- 'Chrome.');
- return undefined;
- }
-
- var snapshot;
- for (var instance of frameLoaderInstances) {
- if (!instance.isAliveAt(ts))
- continue;
- var maybeSnapshot = instance.getSnapshotAt(ts);
- if (frameIdRef !== maybeSnapshot.args['frame']['id_ref'])
- continue;
- snapshot = maybeSnapshot;
- }
-
- return snapshot;
- }
-
- function findAllUserTimingEvents(rendererHelper, title) {
- var targetEvents = [];
-
- for (var ev of rendererHelper.process.getDescendantEvents()) {
- if (ev.category !== 'blink.user_timing' || ev.title !== title)
- continue;
- targetEvents.push(ev);
- }
-
- return targetEvents;
- }
-
- function findAllLayoutEvents(rendererHelper) {
- var isTelemetryInternalEvent =
- prepareTelemetryInternalEventPredicate(rendererHelper);
- var layoutsForFrameId = {};
- for (var ev of rendererHelper.process.getDescendantEvents()) {
- if (ev.category !==
- 'blink,benchmark,disabled-by-default-blink.debug.layout' ||
- ev.title !== 'FrameView::performLayout')
- continue;
- if (isTelemetryInternalEvent(ev))
- continue;
- if (ev.args.counters === undefined) {
- console.warn('Ignoring FrameView::performLayout event with no ' +
- 'counters arg (END event is missing).');
- continue;
- }
- var frameIdRef = ev.args.counters['frame'];
- if (frameIdRef === undefined)
- continue;
- var list = layoutsForFrameId[frameIdRef];
- if (list === undefined)
- layoutsForFrameId[frameIdRef] = list = [];
- list.push(ev);
- }
- return layoutsForFrameId;
- }
-
- function prepareTelemetryInternalEventPredicate(rendererHelper) {
- var ignoreRegions = [];
-
- var internalRegionStart;
- for (var slice of
- rendererHelper.mainThread.asyncSliceGroup.getDescendantEvents()) {
- if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.start$/))
- internalRegionStart = slice.start;
- if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.end$/)) {
- var timedEvent = new tr.model.TimedEvent(internalRegionStart);
- timedEvent.duration = slice.end - internalRegionStart;
- ignoreRegions.push(timedEvent);
- }
- }
-
- return function isTelemetryInternalEvent(slice) {
- for (var region of ignoreRegions)
- if (region.bounds(slice))
- return true;
- return false;
- }
- }
-
- var URL_BLACKLIST = [
- 'about:blank',
- // Chrome on Android creates main frames with the below URL for plugins.
- 'data:text/html,pluginplaceholderdata'
- ];
- function shouldIgnoreURL(url) {
- return URL_BLACKLIST.indexOf(url) >= 0;
- }
-
- var METRICS = [
- {
- valueName: 'firstContentfulPaint',
- title: 'firstContentfulPaint',
- description: 'time to first contentful paint'
- },
- {
- valueName: 'timeToOnload',
- title: 'loadEventStart',
- description: 'time to onload. ' +
- 'This is temporary metric used for PCv1/v2 sanity checking'
- }];
-
- function firstContentfulPaintMetric(values, model) {
- var chromeHelper = model.getOrCreateHelper(
- tr.model.helpers.ChromeModelHelper);
- var rendererHelper = findTargetRendererHelper(chromeHelper);
- var isTelemetryInternalEvent =
- prepareTelemetryInternalEventPredicate(rendererHelper);
- var navigationStartFinder = new NavigationStartFinder(rendererHelper);
-
- for (var metric of METRICS) {
- var histogram = createHistogram();
- var targetEvents = findAllUserTimingEvents(rendererHelper, metric.title);
- for (var ev of targetEvents) {
- if (isTelemetryInternalEvent(ev))
- continue;
- var frameIdRef = ev.args['frame'];
- var snapshot =
- findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ev.start);
- if (snapshot === undefined || !snapshot.args.isLoadingMainFrame)
- continue;
- var url = snapshot.args.documentLoaderURL;
- if (shouldIgnoreURL(url))
- continue;
- var navigationStartEvent = navigationStartFinder.
- findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
- // Ignore layout w/o preceding navigationStart, as they are not
- // attributed to any time-to-X metric.
- if (navigationStartEvent === undefined)
- continue;
-
- var timeToEvent = ev.start - navigationStartEvent.start;
- histogram.add(timeToEvent, {url: url});
- }
- values.addValue(new tr.v.NumericValue(
- metric.valueName, histogram,
- { description: metric.description }));
- }
- }
-
- /**
- * Compute significance of given layout event.
- *
- * Significance of a layout is the number of layout objects newly added to the
- * layout tree, weighted by page height (before and after the layout).
- */
- function layoutSignificance(event) {
- var newObjects = event.args.counters['LayoutObjectsThatHadNeverHadLayout'];
- var visibleHeight = event.args['counters']['visibleHeight'];
- if (!newObjects || !visibleHeight)
- return 0;
-
- var heightBefore = event.args['contentsHeightBeforeLayout'];
- var heightAfter = event.args['counters']['contentsHeightAfterLayout'];
- var ratioBefore = Math.max(1, heightBefore / visibleHeight);
- var ratioAfter = Math.max(1, heightAfter / visibleHeight);
- return newObjects / ((ratioBefore + ratioAfter) / 2);
- }
-
- /**
- * If there are loading fonts when layout happened, the layout change
- * accounting is postponed until the font is displayed. However, icon fonts
- * shouldn't block first meaningful paint. We use a threshold that only web
- * fonts that laid out more than 200 characters should block first meaningful
- * paint.
- */
- function hasTooManyBlankCharactersToBeMeaningful(event) {
- var BLOCK_FIRST_MEANINGFUL_PAINT_IF_BLANK_CHARACTERS_MORE_THAN = 200;
- return event.args['counters']['approximateBlankCharacterCount'] >
- BLOCK_FIRST_MEANINGFUL_PAINT_IF_BLANK_CHARACTERS_MORE_THAN;
- }
-
- /**
- * Computes Time to first meaningful paint (TTFMP) from |model| and add it to
- * |value|.
- *
- * TTFMP is computed from three types of events: NavigationStart, Layout, and
- * Paint. Each Layout event has associated "significance" value, indicating
- * how the layout was visually significant.
- *
- * TTFMP is the time between NavigationStart and Paint that follows the Layout
- * with biggest significance value.
- *
- * Design doc: https://goo.gl/vpaxv6
- */
- function firstMeaningfulPaintMetric(values, model) {
- var chromeHelper = model.getOrCreateHelper(
- tr.model.helpers.ChromeModelHelper);
- var rendererHelper = findTargetRendererHelper(chromeHelper);
- var navigationStartFinder = new NavigationStartFinder(rendererHelper);
- var paintFinder = new PaintFinder(rendererHelper);
- var firstMeaningfulPaintHistogram = createHistogram();
-
- function addFirstMeaningfulPaintSampleToHistogram(
- frameIdRef, navigationStart, mostSignificantLayout) {
- var snapshot = findFrameLoaderSnapshotAt(
- rendererHelper, frameIdRef, mostSignificantLayout.start);
- if (snapshot === undefined || !snapshot.args.isLoadingMainFrame)
- return;
- var url = snapshot.args.documentLoaderURL;
- if (shouldIgnoreURL(url))
- return;
- var paintEvent = paintFinder.findPaintEventForFrameAfterTimestamp(
- frameIdRef, mostSignificantLayout.start);
- if (paintEvent === undefined) {
- console.warn('Failed to find paint event after the most significant ' +
- 'layout for frameId "' + frameIdRef + '".');
- return;
- }
- var timeToFirstMeaningfulPaint = paintEvent.start - navigationStart.start;
- firstMeaningfulPaintHistogram.add(timeToFirstMeaningfulPaint, {url: url});
- }
-
- var layoutsForFrameId = findAllLayoutEvents(rendererHelper);
-
- for (var frameIdRef in layoutsForFrameId) {
- var navigationStart;
- var mostSignificantLayout;
- var maxSignificanceSoFar = 0;
- var accumulatedSignificanceWhileHavingBlankText = 0;
-
- // Iterate over the layout events, remembering one with largest
- // significance.
- for (var ev of layoutsForFrameId[frameIdRef]) {
- var navigationStartForThisLayout = navigationStartFinder.
- findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
- // Ignore layout w/o preceding navigationStart, as they are not
- // attributed to any TTFMP.
- if (navigationStartForThisLayout === undefined)
- continue;
-
- if (navigationStart !== navigationStartForThisLayout) {
- // New navigation is found. Compute TTFMP for current navigation, and
- // reset the state variables.
- if (navigationStart !== undefined &&
- mostSignificantLayout !== undefined)
- addFirstMeaningfulPaintSampleToHistogram(
- frameIdRef, navigationStart, mostSignificantLayout);
- navigationStart = navigationStartForThisLayout;
- mostSignificantLayout = undefined;
- maxSignificanceSoFar = 0;
- accumulatedSignificanceWhileHavingBlankText = 0;
- }
-
- // Check if |ev| has the largest significance. If the page has many
- // blank characters, the significance value is accumulated until
- // the text become visible.
- var significance = layoutSignificance(ev);
- if (hasTooManyBlankCharactersToBeMeaningful(ev)) {
- accumulatedSignificanceWhileHavingBlankText += significance;
- } else {
- significance += accumulatedSignificanceWhileHavingBlankText;
- accumulatedSignificanceWhileHavingBlankText = 0;
- if (significance > maxSignificanceSoFar) {
- maxSignificanceSoFar = significance;
- mostSignificantLayout = ev;
- }
- }
- }
-
- // Emit TTFMP for the last navigation.
- if (mostSignificantLayout !== undefined)
- addFirstMeaningfulPaintSampleToHistogram(
- frameIdRef, navigationStart, mostSignificantLayout);
- }
-
- values.addValue(new tr.v.NumericValue(
- 'firstMeaningfulPaint', firstMeaningfulPaintHistogram,
- { description: 'time to first meaningful paint' }));
- }
-
- function firstPaintMetric(values, model) {
- firstContentfulPaintMetric(values, model);
- firstMeaningfulPaintMetric(values, model);
- }
-
- tr.metrics.MetricRegistry.register(firstPaintMetric);
-
- return {
- firstPaintMetric: firstPaintMetric
- };
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric_test.html
deleted file mode 100644
index be318aa3600..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/first_paint_metric_test.html
+++ /dev/null
@@ -1,235 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2016 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import"
- href="/tracing/metrics/system_health/first_paint_metric.html">
-<link rel="import" href="/tracing/value/value_set.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- test('firstContentfulPaint', function() {
- var model = tr.c.TestUtils.newModel(function(model) {
- var rendererProcess = model.getOrCreateProcess(1);
- var mainThread = rendererProcess.getOrCreateThread(2);
- mainThread.name = 'CrRendererMain';
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'navigationStart',
- start: 200,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
- {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
- documentLoaderURL: 'http://example.com'});
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'firstContentfulPaint',
- start: 1000,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- });
- var values = new tr.v.ValueSet();
- tr.metrics.sh.firstPaintMetric(values, model);
- var numeric = values.valueDicts[0].numeric;
- assert.equal(1, numeric.running.count);
- assert.equal(800, numeric.running.mean);
- });
-
- test('firstContentfulPaintIgnoringWarmCache', function() {
- var model = tr.c.TestUtils.newModel(function(model) {
- var rendererProcess = model.getOrCreateProcess(1);
- var mainThread = rendererProcess.getOrCreateThread(2);
- mainThread.name = 'CrRendererMain';
-
- // warm cache navigation
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'navigationStart',
- start: 200,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- mainThread.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx({
- cat: 'blink.console',
- title: 'telemetry.internal.warmCache.start',
- start: 250,
- duration: 0.0
- }));
- rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
- {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
- documentLoaderURL: 'http://example.com'});
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'firstContentfulPaint',
- start: 1000,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- mainThread.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx({
- cat: 'blink.console',
- title: 'telemetry.internal.warmCache.end',
- start: 1250,
- duration: 0.0
- }));
-
- // measurement navigation
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'navigationStart',
- start: 2000,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 2100,
- {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
- documentLoaderURL: 'http://example.com'});
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'firstContentfulPaint',
- start: 2400,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- });
- var values = new tr.v.ValueSet();
- tr.metrics.sh.firstPaintMetric(values, model);
- var numeric = values.valueDicts[0].numeric;
- assert.equal(1, numeric.running.count);
- assert.equal(400, numeric.running.mean);
- });
-
- test('firstMeaningfulPaint', function() {
- var model = tr.c.TestUtils.newModel(function(model) {
- var rendererProcess = model.getOrCreateProcess(1);
- var mainThread = rendererProcess.getOrCreateThread(2);
- mainThread.name = 'CrRendererMain';
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'navigationStart',
- start: 200,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
- {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
- documentLoaderURL: 'http://example.com'});
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink,benchmark,disabled-by-default-blink.debug.layout',
- title: 'FrameView::performLayout',
- start: 500,
- duration: 10.0,
- args: {
- counters: {
- frame: '0xdeadbeef',
- LayoutObjectsThatHadNeverHadLayout: 10,
- contentsHeightAfterLayout: 800,
- visibleHeight: 1000,
- },
- contentsHeightBeforeLayout: 0
- }
- }));
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'devtools.timeline',
- title: 'Paint',
- start: 600,
- duration: 1.0,
- args: {data: {frame: '0xdeadbeef'}}
- }));
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink,benchmark,disabled-by-default-blink.debug.layout',
- title: 'FrameView::performLayout',
- start: 800,
- duration: 10.0,
- args: {
- counters: {
- frame: '0xdeadbeef',
- LayoutObjectsThatHadNeverHadLayout: 100,
- contentsHeightAfterLayout: 800,
- visibleHeight: 1000
- },
- contentsHeightBeforeLayout: 800
- }
- }));
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'devtools.timeline',
- title: 'Paint',
- start: 1000,
- duration: 1.0,
- args: {data: {frame: '0xdeadbeef'}}
- }));
- });
- var values = new tr.v.ValueSet();
- tr.metrics.sh.firstPaintMetric(values, model);
- var fmpEntries = values.valueDicts.filter(
- (dict) => dict.name === 'firstMeaningfulPaint');
- var numeric = fmpEntries[0].numeric;
- assert.equal(1, numeric.running.count);
- assert.equal(800, numeric.running.mean);
- });
-
- test('firstMeaningfulPaintWithInvalidLayoutCounters', function() {
- var model = tr.c.TestUtils.newModel(function(model) {
- var rendererProcess = model.getOrCreateProcess(1);
- var mainThread = rendererProcess.getOrCreateThread(2);
- mainThread.name = 'CrRendererMain';
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink.user_timing',
- title: 'navigationStart',
- start: 200,
- duration: 0.0,
- args: {frame: '0xdeadbeef'}
- }));
- rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
- {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
- documentLoaderURL: 'http://example.com'});
-
- // FrameView::performLayout trace event does not have frame ID
- // if blink.debug.layout category is not enabled.
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink,benchmark,disabled-by-default-blink.debug.layout',
- title: 'FrameView::performLayout',
- start: 500,
- duration: 10.0,
- args: {
- counters: {},
- contentsHeightBeforeLayout: 0
- }
- }));
-
- // Incomplete slice: counters argument is missing.
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'blink,benchmark,disabled-by-default-blink.debug.layout',
- title: 'FrameView::performLayout',
- start: 550,
- duration: 10.0,
- args: {
- contentsHeightBeforeLayout: 0
- }
- }));
-
- mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
- cat: 'devtools.timeline',
- title: 'Paint',
- start: 600,
- duration: 1.0,
- args: {data: {frame: '0xdeadbeef'}}
- }));
- });
- var values = new tr.v.ValueSet();
- tr.metrics.sh.firstPaintMetric(values, model);
- var fmpEntries = values.valueDicts.filter(
- (dict) => dict.name === 'firstMeaningfulPaint');
- var numeric = fmpEntries[0].numeric;
- assert.equal(0, numeric.running.count);
- });
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html
index 96961779782..e8b6eeb2ba8 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html
@@ -8,15 +8,11 @@ found in the LICENSE file.
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/system_health/long_tasks_metric.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
<script>
'use strict';
tr.exportTo('tr.metrics.sh', function() {
- var normalizedPercentage_smallerIsBetter =
- tr.v.Unit.byName.normalizedPercentage_smallerIsBetter;
-
// The following math is easier if the units are seconds rather than ms,
// so durations will be converted from ms to s.
var MS_PER_S = 1000;
@@ -127,9 +123,10 @@ tr.exportTo('tr.metrics.sh', function() {
if (overallHazard === undefined)
overallHazard = 0;
- values.addValue(new tr.v.NumericValue(
- 'hazard', new tr.v.ScalarNumeric(
- normalizedPercentage_smallerIsBetter, overallHazard)));
+ var hist = new tr.v.Histogram('hazard',
+ tr.b.Unit.byName.normalizedPercentage_smallerIsBetter);
+ hist.addSample(overallHazard);
+ values.addHistogram(hist);
}
tr.metrics.MetricRegistry.register(hazardMetric);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric_test.html
index 629f608e942..f89d10f4aa1 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric_test.html
@@ -24,9 +24,7 @@ tr.b.unittest.testSuite(function() {
});
var values = new tr.v.ValueSet();
tr.metrics.sh.hazardMetric(values, model);
- var valueDicts = values.valueDicts;
- assert.equal(1, valueDicts.length);
- return valueDicts[0];
+ return tr.b.getOnlyElement(values);
}
test('minimalHazard', function() {
@@ -39,8 +37,8 @@ tr.b.unittest.testSuite(function() {
duration: duration
}));
});
- assert.notEqual(0, value.numeric.value);
- assert.closeTo(value.numeric.value, 0.1611, 1e-5);
+ assert.notEqual(0, value.average);
+ assert.closeTo(value.average, 0.1611, 1e-5);
});
test('maximalHazard', function() {
@@ -52,7 +50,7 @@ tr.b.unittest.testSuite(function() {
duration: 2200
}));
});
- assert.closeTo(value.numeric.value, 1, 1e-5);
+ assert.closeTo(value.average, 1, 1e-5);
});
test('blendedHazards', function() {
@@ -82,7 +80,7 @@ tr.b.unittest.testSuite(function() {
duration: 400
}));
});
- assert.closeTo(0.92144, value.numeric.value, 1e-4);
+ assert.closeTo(0.92144, value.average, 1e-4);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric.html
new file mode 100644
index 00000000000..2a680024dbf
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric.html
@@ -0,0 +1,437 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/category_util.html">
+<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/metrics/metric_registry.html">
+<link rel="import" href="/tracing/metrics/system_health/utils.html">
+<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
+<link rel="import" href="/tracing/model/timed_event.html">
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/numeric.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.metrics.sh', function() {
+ var RESPONSIVENESS_THRESHOLD_MS = 50;
+ var INTERACTIVE_WINDOW_SIZE_MS = 5 * 1000;
+ var timeDurationInMs_smallerIsBetter =
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
+ var RelatedEventSet = tr.v.d.RelatedEventSet;
+
+ // TODO(ksakamoto): This should be a method of tr.model.Event or one of its
+ // subclasses.
+ function hasCategoryAndName(event, category, title) {
+ return event.title === title && event.category &&
+ tr.b.getCategoryParts(event.category).indexOf(category) !== -1;
+ }
+
+ function findTargetRendererHelper(chromeHelper) {
+ var largestPid = -1;
+ for (var pid in chromeHelper.rendererHelpers) {
+ var rendererHelper = chromeHelper.rendererHelpers[pid];
+ if (rendererHelper.isChromeTracingUI)
+ continue;
+ if (pid > largestPid)
+ largestPid = pid;
+ }
+
+ if (largestPid === -1)
+ return undefined;
+
+ return chromeHelper.rendererHelpers[largestPid];
+ }
+
+ function createBreakdownDiagnostic(rendererHelper, start, end) {
+ var breakdownDict = rendererHelper.generateTimeBreakdownTree(
+ start, end);
+
+ var breakdownDiagnostic = new tr.v.d.Breakdown();
+ breakdownDiagnostic.colorScheme =
+ tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER;
+
+ for (var label in breakdownDict) {
+ breakdownDiagnostic.set(label, breakdownDict[label].total);
+ }
+ return breakdownDiagnostic;
+ }
+
+ /**
+ * A utility class for finding navigationStart event for given frame and
+ * timestamp.
+ * @constructor
+ */
+ function NavigationStartFinder(rendererHelper) {
+ this.navigationStartsForFrameId_ = {};
+ for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
+ if (!hasCategoryAndName(ev, 'blink.user_timing', 'navigationStart'))
+ continue;
+ var frameIdRef = ev.args['frame'];
+ var list = this.navigationStartsForFrameId_[frameIdRef];
+ if (list === undefined)
+ this.navigationStartsForFrameId_[frameIdRef] = list = [];
+ list.unshift(ev);
+ }
+ }
+
+ NavigationStartFinder.prototype = {
+ findNavigationStartEventForFrameBeforeTimestamp: function(frameIdRef, ts) {
+ var list = this.navigationStartsForFrameId_[frameIdRef];
+ if (list === undefined) {
+ console.warn('No navigationStartEvent found for frame id "' +
+ frameIdRef + '"');
+ return undefined;
+ }
+ var eventBeforeTimestamp;
+ for (var ev of list) {
+ if (ev.start > ts)
+ continue;
+ if (eventBeforeTimestamp === undefined)
+ eventBeforeTimestamp = ev;
+ }
+ if (eventBeforeTimestamp === undefined) {
+ console.warn('Failed to find navigationStartEvent.');
+ return undefined;
+ }
+ return eventBeforeTimestamp;
+ }
+ };
+
+ var FIRST_PAINT_BOUNDARIES = tr.v.HistogramBinBoundaries
+ .createLinear(0, 1e3, 20) // 50ms step to 1s
+ .addLinearBins(3e3, 20) // 100ms step to 3s
+ .addExponentialBins(20e3, 20);
+
+ function createHistogram(name) {
+ var histogram = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, FIRST_PAINT_BOUNDARIES);
+ histogram.customizeSummaryOptions({
+ avg: true,
+ count: false,
+ max: true,
+ min: true,
+ std: true,
+ sum: false,
+ percentile: [0.90, 0.95, 0.99],
+ });
+ return histogram;
+ }
+
+ function findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ts) {
+ var snapshot;
+
+ var objects = rendererHelper.process.objects;
+ var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader'];
+ if (frameLoaderInstances === undefined) {
+ console.warn('Failed to find FrameLoader for frameId "' + frameIdRef +
+ '" at ts ' + ts + ', the trace maybe incomplete or from an old' +
+ 'Chrome.');
+ return undefined;
+ }
+
+ var snapshot;
+ for (var instance of frameLoaderInstances) {
+ if (!instance.isAliveAt(ts))
+ continue;
+ var maybeSnapshot = instance.getSnapshotAt(ts);
+ if (frameIdRef !== maybeSnapshot.args['frame']['id_ref'])
+ continue;
+ snapshot = maybeSnapshot;
+ }
+
+ return snapshot;
+ }
+
+ function findAllUserTimingEvents(rendererHelper, title) {
+ var targetEvents = [];
+
+ for (var ev of rendererHelper.process.getDescendantEvents()) {
+ if (!hasCategoryAndName(ev, 'blink.user_timing', title))
+ continue;
+ targetEvents.push(ev);
+ }
+
+ return targetEvents;
+ }
+
+ function findFirstMeaningfulPaintCandidates(rendererHelper) {
+ var isTelemetryInternalEvent =
+ prepareTelemetryInternalEventPredicate(rendererHelper);
+ var candidatesForFrameId = {};
+ for (var ev of rendererHelper.process.getDescendantEvents()) {
+ if (!hasCategoryAndName(ev, 'loading', 'firstMeaningfulPaintCandidate'))
+ continue;
+ if (isTelemetryInternalEvent(ev))
+ continue;
+ var frameIdRef = ev.args['frame'];
+ if (frameIdRef === undefined)
+ continue;
+ var list = candidatesForFrameId[frameIdRef];
+ if (list === undefined)
+ candidatesForFrameId[frameIdRef] = list = [];
+ list.push(ev);
+ }
+ return candidatesForFrameId;
+ }
+
+ function prepareTelemetryInternalEventPredicate(rendererHelper) {
+ var ignoreRegions = [];
+
+ var internalRegionStart;
+ for (var slice of
+ rendererHelper.mainThread.asyncSliceGroup.getDescendantEvents()) {
+ if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.start$/))
+ internalRegionStart = slice.start;
+ if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.end$/)) {
+ var timedEvent = new tr.model.TimedEvent(internalRegionStart);
+ timedEvent.duration = slice.end - internalRegionStart;
+ ignoreRegions.push(timedEvent);
+ }
+ }
+
+ return function isTelemetryInternalEvent(slice) {
+ for (var region of ignoreRegions)
+ if (region.bounds(slice))
+ return true;
+ return false;
+ }
+ }
+
+ var URL_BLACKLIST = [
+ 'about:blank',
+ // Chrome on Android creates main frames with the below URL for plugins.
+ 'data:text/html,pluginplaceholderdata'
+ ];
+ function shouldIgnoreURL(url) {
+ return URL_BLACKLIST.indexOf(url) >= 0;
+ }
+
+ var METRICS = [
+ {
+ valueName: 'timeToFirstContentfulPaint',
+ title: 'firstContentfulPaint',
+ description: 'time to first contentful paint'
+ },
+ {
+ valueName: 'timeToOnload',
+ title: 'loadEventStart',
+ description: 'time to onload. ' +
+ 'This is temporary metric used for PCv1/v2 sanity checking'
+ }];
+
+ function timeToFirstContentfulPaintMetric(values, model) {
+ var chromeHelper = model.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+ var rendererHelper = findTargetRendererHelper(chromeHelper);
+ var isTelemetryInternalEvent =
+ prepareTelemetryInternalEventPredicate(rendererHelper);
+ var navigationStartFinder = new NavigationStartFinder(rendererHelper);
+
+ for (var metric of METRICS) {
+ var histogram = createHistogram(metric.valueName);
+ histogram.description = metric.description;
+ var targetEvents = findAllUserTimingEvents(rendererHelper, metric.title);
+ for (var ev of targetEvents) {
+ if (isTelemetryInternalEvent(ev))
+ continue;
+ var frameIdRef = ev.args['frame'];
+ var snapshot =
+ findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ev.start);
+ if (snapshot === undefined || !snapshot.args.isLoadingMainFrame)
+ continue;
+ var url = snapshot.args.documentLoaderURL;
+ if (shouldIgnoreURL(url))
+ continue;
+ var navigationStartEvent = navigationStartFinder.
+ findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
+ // Ignore layout w/o preceding navigationStart, as they are not
+ // attributed to any time-to-X metric.
+ if (navigationStartEvent === undefined)
+ continue;
+
+ var timeToEvent = ev.start - navigationStartEvent.start;
+ histogram.addSample(timeToEvent, {url: new tr.v.d.Generic(url)});
+ }
+ values.addHistogram(histogram);
+ }
+ }
+
+ function addTimeToInteractiveSampleToHistogram(histogram, rendererHelper,
+ navigationStart, firstMeaningfulPaint, url) {
+ if (shouldIgnoreURL(url))
+ return;
+ var navigationStartTime = navigationStart.start;
+ var firstInteractive = Infinity;
+ var firstInteractiveCandidate = firstMeaningfulPaint;
+ var lastLongTaskEvent = undefined;
+ // Find the first interactive point X after firstMeaningfulPaint so that
+ // range [X, X + INTERACTIVE_WINDOW_SIZE_MS] contains no
+ // 'TaskQueueManager::ProcessTaskFromWorkQueues' slice which takes more than
+ // RESPONSIVENESS_THRESHOLD_MS.
+ // For more details on why TaskQueueManager::ProcessTaskFromWorkQueue is
+ // chosen as a proxy for all un-interruptable task on renderer thread, see
+ // https://github.com/GoogleChrome/lighthouse/issues/489
+ // TODO(nedn): replace this with just "var ev of rendererHelper..." once
+ // canary binary is updated.
+ // (https://github.com/catapult-project/catapult/issues/2586)
+ for (var ev of [...rendererHelper.mainThread.sliceGroup.childEvents()]) {
+ if (ev.start < firstInteractiveCandidate)
+ continue;
+ var interactiveDurationSoFar = ev.start - firstInteractiveCandidate;
+ if (interactiveDurationSoFar >= INTERACTIVE_WINDOW_SIZE_MS) {
+ firstInteractive = firstInteractiveCandidate;
+ break;
+ }
+ if (ev.title === 'TaskQueueManager::ProcessTaskFromWorkQueue' &&
+ ev.duration > RESPONSIVENESS_THRESHOLD_MS) {
+ firstInteractiveCandidate = ev.end - 50;
+ lastLongTaskEvent = ev;
+ }
+ }
+ var breakdownDiagnostic = createBreakdownDiagnostic(
+ rendererHelper, navigationStartTime, firstInteractive);
+
+ var timeToFirstInteractive = firstInteractive - navigationStartTime;
+ histogram.addSample(
+ timeToFirstInteractive,
+ {
+ "Start": new RelatedEventSet(navigationStart),
+ "Last long task": new RelatedEventSet(lastLongTaskEvent),
+ "Navigation infos": new tr.v.d.Generic(
+ {url: url, pid: rendererHelper.pid,
+ start: navigationStartTime, interactive: firstInteractive}),
+ "Breakdown of [navStart, Interactive]": breakdownDiagnostic,
+ });
+ }
+
+ /**
+ * Computes Time to first meaningful paint (TTFMP) & time to interactive (TTI)
+ * from |model| and add it to |value|.
+ *
+ * First meaningful paint is the paint following the layout with the highest
+ * "Layout Significance". The Layout Significance is computed inside Blink,
+ * by FirstMeaningfulPaintDetector class. It logs
+ * "firstMeaningfulPaintCandidate" event every time the Layout Significance
+ * marks a record. TTFMP is the time between NavigationStart and the last
+ * firstMeaningfulPaintCandidate event.
+ *
+ * Design doc: https://goo.gl/vpaxv6
+ *
+ * TTI is computed as the starting time of the timed window with size
+ * INTERACTIVE_WINDOW_SIZE_MS that happens after FMP in which there is no
+ * uninterruptable task on the main thread with size more than
+ * RESPONSIVENESS_THRESHOLD_MS.
+ *
+ * Design doc: https://goo.gl/ISWndc
+ */
+ function timeToFirstMeaningfulPaintAndTimeToInteractiveMetrics(
+ values, model) {
+ var chromeHelper = model.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+ var rendererHelper = findTargetRendererHelper(chromeHelper);
+ var navigationStartFinder = new NavigationStartFinder(rendererHelper);
+ var firstMeaningfulPaintHistogram = createHistogram(
+ 'timeToFirstMeaningfulPaint');
+ firstMeaningfulPaintHistogram.description =
+ 'time to first meaningful paint';
+ var firstInteractiveHistogram = createHistogram('timeToFirstInteractive');
+ firstInteractiveHistogram.description = 'time to first interactive';
+
+ function addFirstMeaningfulPaintSampleToHistogram(
+ frameIdRef, navigationStart, fmpMarkerEvent) {
+ var snapshot = findFrameLoaderSnapshotAt(
+ rendererHelper, frameIdRef, fmpMarkerEvent.start);
+ if (snapshot === undefined || !snapshot.args.isLoadingMainFrame)
+ return;
+ var url = snapshot.args.documentLoaderURL;
+ if (shouldIgnoreURL(url))
+ return;
+
+ var timeToFirstMeaningfulPaint =
+ fmpMarkerEvent.start - navigationStart.start;
+ var extraDiagnostic = {
+ url: url,
+ pid: rendererHelper.pid
+ };
+ var breakdownDiagnostic = createBreakdownDiagnostic(
+ rendererHelper, navigationStart.start, fmpMarkerEvent.start);
+ firstMeaningfulPaintHistogram.addSample(timeToFirstMeaningfulPaint,
+ {
+ "Breakdown of [navStart, FMP]": breakdownDiagnostic,
+ "Start": new RelatedEventSet(navigationStart),
+ "End": new RelatedEventSet(fmpMarkerEvent),
+ "Navigation infos": new tr.v.d.Generic(
+ {url: url, pid: rendererHelper.pid,
+ start: navigationStart.start, fmp: fmpMarkerEvent.start}),
+ });
+ return {firstMeaningfulPaint: fmpMarkerEvent.start, url: url};
+ }
+
+ var candidatesForFrameId =
+ findFirstMeaningfulPaintCandidates(rendererHelper);
+
+ for (var frameIdRef in candidatesForFrameId) {
+ var navigationStart;
+ var lastCandidate;
+
+ // Iterate over the FMP candidates, remembering the last one.
+ for (var ev of candidatesForFrameId[frameIdRef]) {
+ var navigationStartForThisCandidate = navigationStartFinder.
+ findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
+ // Ignore candidate w/o preceding navigationStart, as they are not
+ // attributed to any TTFMP.
+ if (navigationStartForThisCandidate === undefined)
+ continue;
+
+ if (navigationStart !== navigationStartForThisCandidate) {
+ // New navigation is found. Compute TTFMP for current navigation, and
+ // reset the state variables.
+ if (navigationStart !== undefined && lastCandidate !== undefined) {
+ data = addFirstMeaningfulPaintSampleToHistogram(
+ frameIdRef, navigationStart, lastCandidate);
+ if (data !== undefined)
+ addTimeToInteractiveSampleToHistogram(
+ firstInteractiveHistogram, rendererHelper,
+ navigationStart,
+ data.firstMeaningfulPaint, data.url);
+ }
+ navigationStart = navigationStartForThisCandidate;
+ }
+ lastCandidate = ev;
+ }
+
+ // Emit TTFMP for the last navigation.
+ if (lastCandidate !== undefined) {
+ var data = addFirstMeaningfulPaintSampleToHistogram(
+ frameIdRef, navigationStart, lastCandidate);
+
+ if (data !== undefined)
+ addTimeToInteractiveSampleToHistogram(
+ firstInteractiveHistogram, rendererHelper, navigationStart,
+ data.firstMeaningfulPaint, data.url);
+ }
+ }
+
+ values.addHistogram(firstMeaningfulPaintHistogram);
+ values.addHistogram(firstInteractiveHistogram);
+ }
+
+ function loadingMetric(values, model) {
+ timeToFirstContentfulPaintMetric(values, model);
+ timeToFirstMeaningfulPaintAndTimeToInteractiveMetrics(values, model);
+ }
+
+ tr.metrics.MetricRegistry.register(loadingMetric);
+
+ return {
+ loadingMetric: loadingMetric,
+ RESPONSIVENESS_THRESHOLD_MS: RESPONSIVENESS_THRESHOLD_MS,
+ INTERACTIVE_WINDOW_SIZE_MS: INTERACTIVE_WINDOW_SIZE_MS
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric_test.html
new file mode 100644
index 00000000000..7e22de36550
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/loading_metric_test.html
@@ -0,0 +1,338 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/metrics/system_health/loading_metric.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('timeToFirstContentfulPaint', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing,rail',
+ title: 'firstContentfulPaint',
+ start: 1000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ 'timeToFirstContentfulPaint'));
+ assert.equal(1, numeric.running.count);
+ assert.equal(800, numeric.running.mean);
+ });
+
+ test('timeToFirstContentfulPaintIgnoringWarmCache', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+
+ // warm cache navigation
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ mainThread.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx({
+ cat: 'blink.console',
+ title: 'telemetry.internal.warmCache.start',
+ start: 250,
+ duration: 0.0
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing,rail',
+ title: 'firstContentfulPaint',
+ start: 1000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ mainThread.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSliceEx({
+ cat: 'blink.console',
+ title: 'telemetry.internal.warmCache.end',
+ start: 1250,
+ duration: 0.0
+ }));
+
+ // measurement navigation
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 2000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 2100,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing,rail',
+ title: 'firstContentfulPaint',
+ start: 2400,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ 'timeToFirstContentfulPaint'));
+ assert.equal(1, numeric.running.count);
+ assert.equal(400, numeric.running.mean);
+ });
+
+ test('timeToFirstMeaningfulPaint', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 600,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 1000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ 'timeToFirstMeaningfulPaint'));
+ assert.equal(1, numeric.running.count);
+ assert.equal(800, numeric.running.mean);
+ });
+
+ test('timeToInteractive', function() {
+ // Our renderer thread would looks like
+ //
+ // * * [ main thread busy ] *
+ // | | |
+ // | | |
+ // v v v
+ // First navigation FMP TTI
+ // 200 9200 15400
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1984);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9180,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 9350,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 11150,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 12550,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 14950,
+ duration: 500,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 22150,
+ duration: 10,
+ }));
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ 'timeToFirstInteractive'));
+ assert.equal(1, numeric.running.count);
+ assert.equal(15200, numeric.running.mean);
+ var binsWithSampleDiagnosticMaps = numeric.allBins.filter(
+ bin => bin.diagnosticMaps.length > 0);
+ var diagnostic = binsWithSampleDiagnosticMaps[0].diagnosticMaps[0].get(
+ 'Navigation infos');
+ assert.equal(diagnostic.value.start, 200);
+ assert.equal(diagnostic.value.interactive, 15400);
+ assert.equal(diagnostic.value.pid, 1984);
+ });
+
+ test('multiTimeToInteractive', function() {
+ // Our renderer thread would looks like
+ //
+ // * * [ main thread busy ] * * *
+ // | | | | |
+ // | | | | |
+ // v v v v v
+ // 1st navigation 1st FMP 2nd nav 1st TTI 2nd FMP & TTI
+ // 200 9200 12000 14500 16000
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1984);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9180,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 9350,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 11150,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 12000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 12550,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 14950,
+ duration: 500,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 16000,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 29150,
+ duration: 10,
+ }));
+ });
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ 'timeToFirstInteractive'));
+ assert.equal(2, numeric.running.count);
+ assert.equal(4000, numeric.running.min);
+ assert.equal(15200, numeric.running.max);
+});
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric.html
index 1e2fea97a19..afbf6f12959 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_driver.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
@@ -20,9 +20,6 @@ tr.exportTo('tr.metrics.sh', function() {
// uninteresting.
var LONGEST_TASK_MS = 1000;
- var timeDurationInMs_smallerIsBetter =
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;
-
/**
* This helper function calls |cb| for each of the top-level tasks on the
* given thread in the given range whose duration is longer than LONG_TASK_MS.
@@ -36,7 +33,7 @@ tr.exportTo('tr.metrics.sh', function() {
thread, opt_range, cb, opt_this) {
thread.sliceGroup.topLevelSlices.forEach(function(slice) {
if (opt_range &&
- !opt_range.intersectsExplicitRangeExclusive(slice.start, slice.end))
+ !opt_range.intersectsExplicitRangeInclusive(slice.start, slice.end))
return;
if (slice.duration < LONG_TASK_MS)
@@ -65,10 +62,6 @@ tr.exportTo('tr.metrics.sh', function() {
});
}
- var LONG_TASK_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- tr.b.Range.fromExplicitRange(LONG_TASK_MS, LONGEST_TASK_MS), 50);
-
/**
* This metric directly measures long tasks on renderer main threads.
* This metric requires only the 'toplevel' tracing category.
@@ -79,16 +72,32 @@ tr.exportTo('tr.metrics.sh', function() {
*/
function longTasksMetric(values, model, opt_options) {
var rangeOfInterest = opt_options ? opt_options.rangeOfInterest : undefined;
- var longTaskNumeric = LONG_TASK_NUMERIC_BUILDER.build();
+ var longTaskHist = new tr.v.Histogram('long tasks',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(
+ LONG_TASK_MS, LONGEST_TASK_MS, 40));
+ longTaskHist.description = 'durations of long tasks';
+ var slices = new tr.model.EventSet();
iterateRendererMainThreads(model, function(thread) {
iterateLongTopLevelTasksOnThreadInRange(
thread, rangeOfInterest, function(task) {
- longTaskNumeric.add(task.duration, task.stableId);
+ longTaskHist.addSample(task.duration,
+ {relatedEvents: new tr.v.d.RelatedEventSet([task])});
+ slices.push(task);
+ slices.addEventSet(task.descendentSlices);
});
});
- var options = {description: 'durations of long tasks'};
- values.addValue(new tr.v.NumericValue(
- 'long tasks', longTaskNumeric, options));
+ values.addHistogram(longTaskHist);
+
+ var sampleForEvent = undefined;
+ var breakdown = tr.v.d.RelatedHistogramBreakdown.buildFromEvents(
+ values, 'long tasks ', slices,
+ e => (model.getUserFriendlyCategoryFromEvent(e) || 'unknown'),
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, sampleForEvent,
+ tr.v.HistogramBinBoundaries.createExponential(1, LONGEST_TASK_MS, 40));
+ breakdown.colorScheme =
+ tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER;
+ longTaskHist.diagnostics.set('category', breakdown);
}
tr.metrics.MetricRegistry.register(longTasksMetric, {
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric_test.html
new file mode 100644
index 00000000000..60872ad5c6f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/long_tasks_metric_test.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_driver.html">
+<link rel="import" href="/tracing/metrics/system_health/long_tasks_metric.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('longTasksMetric', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var proc = model.getOrCreateProcess(1);
+ var thread = proc.getOrCreateThread(2);
+ thread.name = 'CrRendererMain';
+ var longTask = tr.c.TestUtils.newSliceEx({
+ title: 'foo',
+ start: 0,
+ duration: 50,
+ });
+ thread.sliceGroup.pushSlice(longTask);
+
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ title: 'UpdateLayerTree',
+ start: 0,
+ duration: 1,
+ cpuStart: 0,
+ cpuDuration: 1,
+ }));
+
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ title: 'minorGC',
+ start: 1,
+ duration: 1,
+ cpuStart: 1,
+ cpuDuration: 1,
+ }));
+
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ title: 'Decode Image',
+ start: 2,
+ duration: 1,
+ cpuStart: 2,
+ cpuDuration: 1,
+ }));
+
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ title: 'Layout',
+ start: 3,
+ duration: 1,
+ cpuStart: 3,
+ cpuDuration: 1,
+ }));
+
+ model.addUserFriendlyCategoryDriver(
+ tr.e.chrome.ChromeUserFriendlyCategoryDriver);
+ });
+ var valueSet = new tr.v.ValueSet();
+ tr.metrics.sh.longTasksMetric(valueSet, model);
+ var longTaskHist = tr.b.getOnlyElement(
+ valueSet.getValuesNamed('long tasks'));
+ assert.strictEqual(1, longTaskHist.numValues);
+ assert.strictEqual(1, longTaskHist.centralBins[0].count);
+ assert.lengthOf(longTaskHist.centralBins[0].diagnosticMaps, 1);
+ var events =
+ longTaskHist.centralBins[0].diagnosticMaps[0].get('relatedEvents');
+ assert.instanceOf(events, tr.v.d.RelatedEventSet);
+ assert.strictEqual(tr.b.getOnlyElement(events).title,
+ 'foo');
+ var breakdown = longTaskHist.diagnostics.get('category');
+ assert.instanceOf(breakdown, tr.v.d.RelatedHistogramBreakdown);
+ assert.lengthOf(breakdown, 4);
+
+ var hist = breakdown.get('layout');
+ assert.instanceOf(hist, tr.v.Histogram);
+ assert.strictEqual(tr.b.getOnlyElement(valueSet.getValuesNamed(hist.name)),
+ hist);
+ assert.strictEqual(0, hist.name.indexOf(longTaskHist.name));
+ assert.strictEqual(1, hist.numValues);
+ assert.strictEqual(1, hist.centralBins[0].count);
+
+ hist = breakdown.get('gc');
+ assert.instanceOf(hist, tr.v.Histogram);
+ assert.strictEqual(tr.b.getOnlyElement(valueSet.getValuesNamed(hist.name)),
+ hist);
+ assert.strictEqual(0, hist.name.indexOf(longTaskHist.name));
+ assert.strictEqual(1, hist.numValues);
+ assert.strictEqual(1, hist.centralBins[0].count);
+
+ hist = breakdown.get('composite');
+ assert.instanceOf(hist, tr.v.Histogram);
+ assert.strictEqual(tr.b.getOnlyElement(valueSet.getValuesNamed(hist.name)),
+ hist);
+ assert.strictEqual(0, hist.name.indexOf(longTaskHist.name));
+ assert.strictEqual(1, hist.numValues);
+ assert.strictEqual(1, hist.centralBins[0].count);
+
+ hist = breakdown.get('imageDecode');
+ assert.instanceOf(hist, tr.v.Histogram);
+ assert.strictEqual(tr.b.getOnlyElement(valueSet.getValuesNamed(hist.name)),
+ hist);
+ assert.strictEqual(0, hist.name.indexOf(longTaskHist.name));
+ assert.strictEqual(1, hist.numValues);
+ assert.strictEqual(1, hist.centralBins[0].count);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric.html
index 1aa81e05b2b..42dcc01c452 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric.html
@@ -8,48 +8,47 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/multi_dimensional_view.html">
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.sh', function() {
+ var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
- var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
- var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
+ var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter;
var DISPLAYED_SIZE_NUMERIC_NAME =
tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;
var LEVEL_OF_DETAIL_NAMES = new Map();
+ LEVEL_OF_DETAIL_NAMES.set(BACKGROUND, 'background');
LEVEL_OF_DETAIL_NAMES.set(LIGHT, 'light');
LEVEL_OF_DETAIL_NAMES.set(DETAILED, 'detailed');
- var MEMORY_NUMERIC_BUILDER_MAP = new WeakMap();
+ var BOUNDARIES_FOR_UNIT_MAP = new WeakMap();
// For unitless numerics (process counts), we use 20 linearly scaled bins
// from 0 to 20.
- MEMORY_NUMERIC_BUILDER_MAP.set(unitlessNumber_smallerIsBetter,
- tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter,
- tr.b.Range.fromExplicitRange(0, 20), 20));
+ BOUNDARIES_FOR_UNIT_MAP.set(count_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(0, 20, 20));
// For size numerics (subsystem and vm stats), we use 1 bin from 0 B to
// 1 KiB and 4*24 exponentially scaled bins from 1 KiB to 16 GiB (=2^24 KiB).
- MEMORY_NUMERIC_BUILDER_MAP.set(sizeInBytes_smallerIsBetter,
- new tr.v.NumericBuilder(sizeInBytes_smallerIsBetter, 0)
+ BOUNDARIES_FOR_UNIT_MAP.set(sizeInBytes_smallerIsBetter,
+ new tr.v.HistogramBinBoundaries(0)
.addBinBoundary(1024 /* 1 KiB */)
.addExponentialBins(16 * 1024 * 1024 * 1024 /* 16 GiB */, 4 * 24));
- function memoryMetric(values, model) {
- var browserNameToGlobalDumps = splitGlobalDumpsByBrowserName(model);
+ function memoryMetric(values, model, opt_options) {
+ var rangeOfInterest = opt_options ? opt_options.rangeOfInterest : undefined;
+ var browserNameToGlobalDumps =
+ splitGlobalDumpsByBrowserName(model, rangeOfInterest);
addGeneralMemoryDumpValues(browserNameToGlobalDumps, values);
addDetailedMemoryDumpValues(browserNameToGlobalDumps, values);
addMemoryDumpCountValues(browserNameToGlobalDumps, values);
@@ -60,10 +59,12 @@ tr.exportTo('tr.metrics.sh', function() {
*
* @param {!tr.Model} model The trace model from which the global dumps
* should be extracted.
+ * @param {!tr.b.Range=} opt_rangeOfInterest If proided, global memory dumps
+ * that do not inclusively intersect the range will be skipped.
* @return {!Map<string, !Array<!tr.model.GlobalMemoryDump>} A map from
* browser names to the associated global memory dumps.
*/
- function splitGlobalDumpsByBrowserName(model) {
+ function splitGlobalDumpsByBrowserName(model, opt_rangeOfInterest) {
var chromeModelHelper =
model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);
var browserNameToGlobalDumps = new Map();
@@ -77,8 +78,9 @@ tr.exportTo('tr.metrics.sh', function() {
chromeModelHelper.browserHelpers.forEach(function(helper) {
// Retrieve the associated global memory dumps and check that they
// haven't been classified as belonging to another browser process.
- var globalDumps = helper.process.memoryDumps.map(
- d => d.globalMemoryDump);
+ var globalDumps = skipDumpsThatDoNotIntersectRange(
+ helper.process.memoryDumps.map(d => d.globalMemoryDump),
+ opt_rangeOfInterest);
globalDumps.forEach(function(globalDump) {
var existingHelper = globalDumpToBrowserHelper.get(globalDump);
if (existingHelper !== undefined) {
@@ -96,8 +98,9 @@ tr.exportTo('tr.metrics.sh', function() {
// 2. If any global memory dump does not have any associated browser
// process for some reason, associate it with an 'unknown_browser' browser
// so that we don't lose the data.
- var unclassifiedGlobalDumps =
- model.globalMemoryDumps.filter(g => !globalDumpToBrowserHelper.has(g));
+ var unclassifiedGlobalDumps = skipDumpsThatDoNotIntersectRange(
+ model.globalMemoryDumps.filter(g => !globalDumpToBrowserHelper.has(g)),
+ opt_rangeOfInterest);
if (unclassifiedGlobalDumps.length > 0) {
makeKeyUniqueAndSet(
browserNameToGlobalDumps, 'unknown_browser', unclassifiedGlobalDumps);
@@ -106,9 +109,16 @@ tr.exportTo('tr.metrics.sh', function() {
return browserNameToGlobalDumps;
}
+ function skipDumpsThatDoNotIntersectRange(dumps, opt_range) {
+ if (!opt_range)
+ return dumps;
+ return dumps.filter(d => opt_range.intersectsExplicitRangeInclusive(
+ d.start, d.end));
+ }
+
function canonicalizeName(name) {
return name.toLowerCase().replace(' ', '_');
- };
+ }
var USER_FRIENDLY_BROWSER_NAMES = {
'chrome': 'Chrome',
@@ -218,15 +228,15 @@ tr.exportTo('tr.metrics.sh', function() {
* memory:{chrome, webview}:
* {browser_process, renderer_processes, ..., all_processes}:
* process_count
- * type: tr.v.Numeric (histogram over all matching global memory dumps)
- * unit: unitlessNumber_smallerIsBetter
+ * type: tr.v.Histogram (over all matching global memory dumps)
+ * unit: count_smallerIsBetter
*
* * MEMORY USAGE REPORTED BY CHROME
* memory:{chrome, webview}:
* {browser_process, renderer_processes, ..., all_processes}:
* reported_by_chrome[:{v8, malloc, ...}]:
* {effective_size, allocated_objects_size, locked_size}
- * type: tr.v.Numeric (histogram over all matching global memory dumps)
+ * type: tr.v.Histogram (over all matching global memory dumps)
* unit: sizeInBytes_smallerIsBetter
*/
function addGeneralMemoryDumpValues(browserNameToGlobalDumps, values) {
@@ -236,26 +246,58 @@ tr.exportTo('tr.metrics.sh', function() {
// Increment memory:<browser-name>:<process-name>:process_count value.
addProcessScalar({
source: 'process_count',
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
- descriptionPrefixBuilder: buildProcessCountDescriptionPrefix
+ property: PROCESS_COUNT,
+ value: 1
});
+ if (processDump.totals !== undefined) {
+ tr.b.iterItems({
+ 'residentBytes': RESIDENT_SIZE,
+ 'peakResidentBytes': PEAK_RESIDENT_SIZE
+ }, function(totalName, property) {
+ addProcessScalar({
+ source: 'reported_by_os',
+ property: property,
+ component: ['system_memory'],
+ value: processDump.totals[totalName]
+ });
+ });
+ }
+
// Add memory:<browser-name>:<process-name>:reported_by_chrome:...
// values.
if (processDump.memoryAllocatorDumps === undefined)
return;
processDump.memoryAllocatorDumps.forEach(function(rootAllocatorDump) {
- CHROME_VALUE_PROPERTIES.forEach(function(spec) {
+ CHROME_VALUE_PROPERTIES.forEach(function(property) {
addProcessScalar({
source: 'reported_by_chrome',
component: [rootAllocatorDump.name],
- property: spec.propertyName,
- value: rootAllocatorDump.numerics[spec.propertyName],
- descriptionPrefixBuilder: spec.descriptionPrefixBuilder
+ property: property,
+ value: rootAllocatorDump.numerics[property.name]
});
});
+ // Some dump providers add allocated objects size as
+ // "allocated_objects" child dump.
+ if (rootAllocatorDump.numerics['allocated_objects_size'] ===
+ undefined) {
+ var allocatedObjectsDump =
+ rootAllocatorDump.getDescendantDumpByFullName(
+ 'allocated_objects');
+ if (allocatedObjectsDump !== undefined) {
+ addProcessScalar({
+ source: 'reported_by_chrome',
+ component: [rootAllocatorDump.name],
+ property: ALLOCATED_OBJECTS_SIZE,
+ value: allocatedObjectsDump.numerics['size']
+ });
+ }
+ }
});
+
+ // Add memory:<browser-name>:<process-name>:reported_by_chrome:v8:
+ // {heap, allocated_by_malloc}:...
+ addV8MemoryDumpValues(processDump, addProcessScalar);
},
function(componentTree) {
// Subtract memory:<browser-name>:<process-name>:reported_by_chrome:
@@ -270,42 +312,165 @@ tr.exportTo('tr.metrics.sh', function() {
}
/**
- * Build a description prefix for a memory:<browser-name>:<process-name>:
- * process_count value.
+ * Add memory dump values calculated from V8 components excluding
+ * 'heap_spaces/other_spaces'.
*
- * @param {!Array<string>} componentPath The underlying component path (must
- * be empty).
- * @param {string} processName The canonical name of the process.
- * @return {string} Prefix for the value's description (always
- * 'total number of renderer processes').
+ * @param {!tr.model.ProcessMemoryDump} processDump The process memory dump.
+ * @param {!function} addProcessScalar The callback for adding a scalar value.
*/
- function buildProcessCountDescriptionPrefix(componentPath, processName) {
- if (componentPath.length > 0) {
- throw new Error('Unexpected process count non-empty component path: ' +
- componentPath.join(':'));
- }
- return 'total number of ' + convertProcessNameToUserFriendlyName(
- processName, true /* opt_requirePlural */);
+ function addV8MemoryDumpValues(processDump, addProcessScalar) {
+ var v8Dump = processDump.getMemoryAllocatorDumpByFullName('v8');
+ if (v8Dump === undefined)
+ return;
+ v8Dump.children.forEach(function(isolateDump) {
+ // v8:allocated_by_malloc:...
+ var mallocDump = isolateDump.getDescendantDumpByFullName('malloc');
+ if (mallocDump !== undefined) {
+ addV8ComponentValues(mallocDump, ['v8', 'allocated_by_malloc'],
+ addProcessScalar);
+ }
+ // v8:heap:...
+ var heapDump = isolateDump.getDescendantDumpByFullName('heap_spaces');
+ if (heapDump !== undefined) {
+ addV8ComponentValues(heapDump, ['v8', 'heap'], addProcessScalar);
+ heapDump.children.forEach(function(spaceDump) {
+ if (spaceDump.name === 'other_spaces')
+ return;
+ addV8ComponentValues(spaceDump, ['v8', 'heap', spaceDump.name],
+ addProcessScalar);
+ });
+ }
+ });
+
+ // V8 generates bytecode when interpreting and code objects when
+ // compiling the javascript. Total code size includes the size
+ // of code and bytecode objects.
+ addProcessScalar({
+ source: 'reported_by_chrome',
+ component: ['v8'],
+ property: CODE_AND_METADATA_SIZE,
+ value: v8Dump.numerics['code_and_metadata_size']
+ });
+ addProcessScalar({
+ source: 'reported_by_chrome',
+ component: ['v8'],
+ property: CODE_AND_METADATA_SIZE,
+ value: v8Dump.numerics['bytecode_and_metadata_size']
+ });
}
/**
+ * Add memory dump values calculated from the specified V8 component.
+ *
+ * @param {!tr.model.MemoryAllocatorDump} v8Dump The V8 memory dump.
+ * @param {!Array<string>} componentPath The component path for reporting.
+ * @param {!function} addProcessScalar The callback for adding a scalar value.
+ */
+ function addV8ComponentValues(componentDump, componentPath,
+ addProcessScalar) {
+ CHROME_VALUE_PROPERTIES.forEach(function(property) {
+ addProcessScalar({
+ source: 'reported_by_chrome',
+ component: componentPath,
+ property: property,
+ value: componentDump.numerics[property.name]
+ });
+ });
+ }
+
+ var PROCESS_COUNT = {
+ unit: count_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ if (componentPath.length > 0) {
+ throw new Error('Unexpected process count non-empty component path: ' +
+ componentPath.join(':'));
+ }
+ return 'total number of ' + convertProcessNameToUserFriendlyName(
+ processName, true /* opt_requirePlural */);
+ }
+ };
+
+ var EFFECTIVE_SIZE = {
+ name: 'effective_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildChromeValueDescriptionPrefix(componentPath, processName, {
+ userFriendlyPropertyName: 'effective size',
+ componentPreposition: 'of'
+ });
+ }
+ };
+
+ var ALLOCATED_OBJECTS_SIZE = {
+ name: 'allocated_objects_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildChromeValueDescriptionPrefix(componentPath, processName, {
+ userFriendlyPropertyName: 'size of all objects allocated',
+ totalUserFriendlyPropertyName: 'size of all allocated objects',
+ componentPreposition: 'by'
+ });
+ }
+ };
+
+ var LOCKED_SIZE = {
+ name: 'locked_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildChromeValueDescriptionPrefix(componentPath, processName, {
+ userFriendlyPropertyName: 'locked (pinned) size',
+ componentPreposition: 'of'
+ });
+ }
+ };
+
+ var PEAK_SIZE = {
+ name: 'peak_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildChromeValueDescriptionPrefix(componentPath, processName, {
+ userFriendlyPropertyName: 'peak size',
+ componentPreposition: 'of'
+ });
+ }
+ };
+
+ var CODE_AND_METADATA_SIZE = {
+ name: 'code_and_metadata_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildChromeValueDescriptionPrefix(componentPath, processName, {
+ userFriendlyPropertyNamePrefix: 'size of',
+ userFriendlyPropertyName: 'code and metadata'
+ });
+ }
+ };
+
+ var CHROME_VALUE_PROPERTIES = [
+ EFFECTIVE_SIZE,
+ ALLOCATED_OBJECTS_SIZE,
+ LOCKED_SIZE,
+ PEAK_SIZE
+ ];
+
+ /**
* Build a description prefix for a memory:<browser-name>:<process-name>:
* reported_by_chrome:... value.
*
+ * @param {!Array<string>} componentPath The underlying component path (e.g.
+ * ['malloc']).
+ * @param {string} processName The canonical name of the process.
* @param {{
* userFriendlyPropertyName: string,
* userFriendlyPropertyNamePrefix: (string|undefined),
* totalUserFriendlyPropertyName: (string|undefined),
* componentPreposition: (string|undefined) }}
* formatSpec Specification of how the property should be formatted.
- * @param {!Array<string>} componentPath The underlying component path (e.g.
- * ['malloc']).
- * @param {string} processName The canonical name of the process.
* @return {string} Prefix for the value's description (e.g.
* 'effective size of malloc in the browser process').
*/
function buildChromeValueDescriptionPrefix(
- formatSpec, componentPath, processName) {
+ componentPath, processName, formatSpec) {
var nameParts = [];
if (componentPath.length === 0) {
nameParts.push('total');
@@ -332,7 +497,13 @@ tr.exportTo('tr.metrics.sh', function() {
nameParts.push(formatSpec.userFriendlyPropertyNamePrefix);
nameParts.push(formatSpec.userFriendlyPropertyName);
nameParts.push(formatSpec.componentPreposition);
- nameParts.push(componentPath.join(':'));
+ if (componentPath[componentPath.length - 1] === 'allocated_by_malloc') {
+ nameParts.push('objects allocated by malloc for');
+ nameParts.push(
+ componentPath.slice(0, componentPath.length - 1).join(':'));
+ } else {
+ nameParts.push(componentPath.join(':'));
+ }
}
nameParts.push('in');
}
@@ -340,165 +511,39 @@ tr.exportTo('tr.metrics.sh', function() {
return nameParts.join(' ');
}
- // Specifications of properties reported by Chrome.
- var CHROME_VALUE_PROPERTIES = [
- {
- propertyName: 'effective_size',
- descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind(
- undefined, {
- userFriendlyPropertyName: 'effective size',
- componentPreposition: 'of'
- })
- },
- {
- propertyName: 'allocated_objects_size',
- descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind(
- undefined, {
- userFriendlyPropertyName: 'size of all objects allocated',
- totalUserFriendlyPropertyName: 'size of all allocated objects',
- componentPreposition: 'by'
- })
- },
- {
- propertyName: 'locked_size',
- descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind(
- undefined, {
- userFriendlyPropertyName: 'locked (pinned) size',
- componentPreposition: 'of'
- })
+ var RESIDENT_SIZE = {
+ name: 'resident_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildOsValueDescriptionPrefix(componentPath, processName,
+ 'resident set size (RSS)');
}
- ];
-
- /**
- * Add heavy memory dump values calculated from heavy global memory dumps to
- * |values|. In particular, this function adds the following values:
- *
- * * MEMORY USAGE REPORTED BY THE OS
- * memory:{chrome, webview}:
- * {browser_process, renderer_processes, ..., all_processes}:
- * reported_by_os:system_memory:[{ashmem, native_heap, java_heap}:]
- * {proportional_resident_size, private_dirty_size}
- * memory:{chrome, webview}:
- * {browser_process, renderer_processes, ..., all_processes}:
- * reported_by_os:gpu_memory:[{gl, graphics, ...}:]
- * proportional_resident_size
- * type: tr.v.Numeric (histogram over matching heavy global memory dumps)
- * unit: sizeInBytes_smallerIsBetter
- *
- * * MEMORY USAGE REPORTED BY CHROME
- * memory:{chrome, webview}:
- * {browser_process, renderer_processes, ..., all_processes}:
- * reported_by_chrome:v8:code_and_metadata_size
- * type: tr.v.Numeric (histogram over matching heavy global memory dumps)
- * unit: sizeInBytes_smallerIsBetter
- */
- function addDetailedMemoryDumpValues(browserNameToGlobalDumps, values) {
- addMemoryDumpValues(browserNameToGlobalDumps,
- g => g.levelOfDetail === DETAILED,
- function(processDump, addProcessScalar) {
- // Add memory:<browser-name>:<process-name>:reported_by_os:
- // system_memory:... values.
- tr.b.iterItems(
- SYSTEM_VALUE_COMPONENTS,
- function(componentName, componentSpec) {
- tr.b.iterItems(
- SYSTEM_VALUE_PROPERTIES,
- function(propertyName, propertySpec) {
- var node = getDescendantVmRegionClassificationNode(
- processDump.vmRegions,
- componentSpec.classificationPath);
- var componentPath = ['system_memory'];
- if (componentName)
- componentPath.push(componentName);
- addProcessScalar({
- source: 'reported_by_os',
- component: componentPath,
- property: propertyName,
- value: node === undefined ?
- 0 : (node.byteStats[propertySpec.byteStat] || 0),
- unit: sizeInBytes_smallerIsBetter,
- descriptionPrefixBuilder:
- propertySpec.descriptionPrefixBuilder
- });
- });
- });
-
- // Add memory:<browser-name>:<process-name>:reported_by_os:
- // gpu_memory:... values.
- var memtrackDump = processDump.getMemoryAllocatorDumpByFullName(
- 'gpu/android_memtrack');
- if (memtrackDump !== undefined) {
- var descriptionPrefixBuilder = SYSTEM_VALUE_PROPERTIES[
- 'proportional_resident_size'].descriptionPrefixBuilder;
- memtrackDump.children.forEach(function(memtrackChildDump) {
- var childName = memtrackChildDump.name;
- addProcessScalar({
- source: 'reported_by_os',
- component: ['gpu_memory', childName],
- property: 'proportional_resident_size',
- value: memtrackChildDump.numerics['memtrack_pss'],
- descriptionPrefixBuilder: descriptionPrefixBuilder
- });
- });
- }
+ };
- // Add memory:<browser-name>:<process-name>:reported_by_chrome:v8:
- // code_and_metadata_size when available.
- var v8Dump = processDump.getMemoryAllocatorDumpByFullName('v8');
- if (v8Dump !== undefined) {
- // V8 generates bytecode when interpreting and code objects when
- // compiling the javascript. Total code size includes the size
- // of code and bytecode objects.
- addProcessScalar({
- source: 'reported_by_chrome',
- component: ['v8'],
- property: 'code_and_metadata_size',
- value: v8Dump.numerics['code_and_metadata_size'],
- descriptionPrefixBuilder:
- buildCodeAndMetadataSizeValueDescriptionPrefix
- });
- addProcessScalar({
- source: 'reported_by_chrome',
- component: ['v8'],
- property: 'code_and_metadata_size',
- value: v8Dump.numerics['bytecode_and_metadata_size'],
- descriptionPrefixBuilder:
- buildCodeAndMetadataSizeValueDescriptionPrefix
- });
- }
- }, function(componentTree) {}, values);
- }
+ var PEAK_RESIDENT_SIZE = {
+ name: 'peak_resident_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildOsValueDescriptionPrefix(componentPath, processName,
+ 'peak resident set size');
+ }
+ };
- // Specifications of components reported by the system.
- var SYSTEM_VALUE_COMPONENTS = {
- '': {
- classificationPath: [],
- },
- 'java_heap': {
- classificationPath: ['Android', 'Java runtime', 'Spaces'],
- userFriendlyName: 'the Java heap'
- },
- 'ashmem': {
- classificationPath: ['Android', 'Ashmem'],
- userFriendlyName: 'ashmem'
- },
- 'native_heap': {
- classificationPath: ['Native heap'],
- userFriendlyName: 'the native heap'
+ var PROPORTIONAL_RESIDENT_SIZE = {
+ name: 'proportional_resident_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildOsValueDescriptionPrefix(componentPath, processName,
+ 'proportional resident size (PSS)');
}
};
- // Specifications of properties reported by the system.
- var SYSTEM_VALUE_PROPERTIES = {
- 'proportional_resident_size': {
- byteStat: 'proportionalResident',
- descriptionPrefixBuilder: buildOsValueDescriptionPrefix.bind(
- undefined, 'proportional resident size (PSS)')
- },
- 'private_dirty_size': {
- byteStat: 'privateDirtyResident',
- descriptionPrefixBuilder: buildOsValueDescriptionPrefix.bind(
- undefined, 'private dirty size')
+ var PRIVATE_DIRTY_SIZE = {
+ name: 'private_dirty_size',
+ unit: sizeInBytes_smallerIsBetter,
+ buildDescriptionPrefix: function(componentPath, processName) {
+ return buildOsValueDescriptionPrefix(componentPath, processName,
+ 'private dirty size');
}
};
@@ -506,16 +551,16 @@ tr.exportTo('tr.metrics.sh', function() {
* Build a description prefix for a memory:<browser-name>:<process-name>:
* reported_by_os:... value.
*
- * @param {string} userFriendlyPropertyName User-friendly name of the
- * underlying property (e.g. 'private dirty size').
* @param {!Array<string>} componentPath The underlying component path (e.g.
* ['system', 'java_heap']).
* @param {string} processName The canonical name of the process.
+ * @param {string} userFriendlyPropertyName User-friendly name of the
+ * underlying property (e.g. 'private dirty size').
* @return {string} Prefix for the value's description (e.g.
* 'total private dirty size of the Java heal in the GPU process').
*/
function buildOsValueDescriptionPrefix(
- userFriendlyPropertyName, componentPath, processName) {
+ componentPath, processName, userFriendlyPropertyName) {
if (componentPath.length > 2) {
throw new Error('OS value component path for \'' +
userFriendlyPropertyName + '\' too long: ' + componentPath.join(':'));
@@ -567,23 +612,93 @@ tr.exportTo('tr.metrics.sh', function() {
}
/**
- * Build a description prefix for a memory:<browser-name>:<process-name>:
- * reported_by_chrome:...:code_and_metadata_size value.
+ * Add heavy memory dump values calculated from heavy global memory dumps to
+ * |values|. In particular, this function adds the following values:
*
- * @param {!Array<string>} componentPath The underlying component path (e.g.
- * ['v8']).
- * @param {string} processName The canonical name of the process.
- * @return {string} Prefix for the value's description (e.g.
- * 'size of v8 code and metadata in').
+ * * MEMORY USAGE REPORTED BY THE OS
+ * memory:{chrome, webview}:
+ * {browser_process, renderer_processes, ..., all_processes}:
+ * reported_by_os:system_memory:[{ashmem, native_heap, java_heap}:]
+ * {proportional_resident_size, private_dirty_size}
+ * memory:{chrome, webview}:
+ * {browser_process, renderer_processes, ..., all_processes}:
+ * reported_by_os:gpu_memory:[{gl, graphics, ...}:]
+ * proportional_resident_size
+ * type: tr.v.Histogram (over matching heavy global memory dumps)
+ * unit: sizeInBytes_smallerIsBetter
+ *
+ * * MEMORY USAGE REPORTED BY CHROME
+ * memory:{chrome, webview}:
+ * {browser_process, renderer_processes, ..., all_processes}:
+ * reported_by_chrome:v8:code_and_metadata_size
+ * type: tr.v.Histogram (over matching heavy global memory dumps)
+ * unit: sizeInBytes_smallerIsBetter
*/
- function buildCodeAndMetadataSizeValueDescriptionPrefix(
- componentPath, processName) {
- return buildChromeValueDescriptionPrefix({
- userFriendlyPropertyNamePrefix: 'size of',
- userFriendlyPropertyName: 'code and metadata'
- }, componentPath, processName);
+ function addDetailedMemoryDumpValues(browserNameToGlobalDumps, values) {
+ addMemoryDumpValues(browserNameToGlobalDumps,
+ g => g.levelOfDetail === DETAILED,
+ function(processDump, addProcessScalar) {
+ // Add memory:<browser-name>:<process-name>:reported_by_os:
+ // system_memory:... values.
+ tr.b.iterItems(
+ SYSTEM_VALUE_COMPONENTS,
+ function(componentName, componentSpec) {
+ tr.b.iterItems({
+ 'proportionalResident': PROPORTIONAL_RESIDENT_SIZE,
+ 'privateDirtyResident': PRIVATE_DIRTY_SIZE
+ }, function(byteStatName, property) {
+ var node = getDescendantVmRegionClassificationNode(
+ processDump.vmRegions,
+ componentSpec.classificationPath);
+ var componentPath = ['system_memory'];
+ if (componentName)
+ componentPath.push(componentName);
+ addProcessScalar({
+ source: 'reported_by_os',
+ component: componentPath,
+ property: property,
+ value: node === undefined ?
+ 0 : (node.byteStats[byteStatName] || 0)
+ });
+ });
+ });
+
+ // Add memory:<browser-name>:<process-name>:reported_by_os:
+ // gpu_memory:... values.
+ var memtrackDump = processDump.getMemoryAllocatorDumpByFullName(
+ 'gpu/android_memtrack');
+ if (memtrackDump !== undefined) {
+ memtrackDump.children.forEach(function(memtrackChildDump) {
+ addProcessScalar({
+ source: 'reported_by_os',
+ component: ['gpu_memory', memtrackChildDump.name],
+ property: PROPORTIONAL_RESIDENT_SIZE,
+ value: memtrackChildDump.numerics['memtrack_pss']
+ });
+ });
+ }
+ }, function(componentTree) {}, values);
}
+ // Specifications of components reported by the system.
+ var SYSTEM_VALUE_COMPONENTS = {
+ '': {
+ classificationPath: [],
+ },
+ 'java_heap': {
+ classificationPath: ['Android', 'Java runtime', 'Spaces'],
+ userFriendlyName: 'the Java heap'
+ },
+ 'ashmem': {
+ classificationPath: ['Android', 'Ashmem'],
+ userFriendlyName: 'ashmem'
+ },
+ 'native_heap': {
+ classificationPath: ['Native heap'],
+ userFriendlyName: 'the native heap'
+ }
+ };
+
/**
* Get the descendant of a VM region classification |node| specified by the
* given |path| of child node titles. If |node| is undefined or such a
@@ -604,11 +719,11 @@ tr.exportTo('tr.metrics.sh', function() {
*
* * DUMP COUNTS
* memory:{chrome, webview}:all_processes:dump_count[:{light, detailed}]
- * type: tr.v.ScalarNumeric (scalar over the whole trace)
- * unit: unitlessNumber_smallerIsBetter
+ * type: tr.v.Histogram
+ * unit: count_smallerIsBetter
*
* Note that unlike all other values generated by the memory metric, the
- * global memory dump counts are NOT instances of tr.v.Numeric (histogram)
+ * global memory dump counts are NOT instances of tr.v.Histogram
* because it doesn't make sense to aggregate them (they are already counts
* over all global dumps associated with the relevant browser).
*/
@@ -643,7 +758,7 @@ tr.exportTo('tr.metrics.sh', function() {
}
/**
- * Add a tr.v.ScalarNumeric value to |values| reporting that the number of
+ * Add a tr.v.Histogram value to |values| reporting that the number of
* |levelOfDetailName| memory dumps added by |browserName| was
* |levelOfDetailCount|.
*/
@@ -655,22 +770,22 @@ tr.exportTo('tr.metrics.sh', function() {
nameParts.push(levelOfDetailName);
var name = nameParts.join(':');
- // Build the underlying numeric for the memory value.
- var numeric = new ScalarNumeric(
- unitlessNumber_smallerIsBetter, levelOfDetailDumpCount);
+ // Build the underlying histogram for the memory value.
+ var histogram = new tr.v.Histogram(name, count_smallerIsBetter,
+ BOUNDARIES_FOR_UNIT_MAP.get(count_smallerIsBetter));
+ histogram.addSample(levelOfDetailDumpCount);
// Build the options for the memory value.
- var description = [
+ histogram.description = [
'total number of',
levelOfDetailName || 'all',
'memory dumps added by',
convertBrowserNameToUserFriendlyName(browserName),
'to the trace'
].join(' ');
- var options = { description: description };
// Report the memory value.
- values.addValue(new tr.v.NumericValue(name, numeric, options));
+ values.addHistogram(histogram);
}
/**
@@ -706,35 +821,35 @@ tr.exportTo('tr.metrics.sh', function() {
* memory dump, the following values will be reported (for Chrome):
*
* memory:chrome:browser_process:source:X:A:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A in all 'browser' process dumps in global dump 1,
* ...
* sum of X:A in all 'browser' process dumps in global dump N
* ]
*
* memory:chrome:browser_process:source:X:B:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:B in all 'browser' process dumps in global dump 1,
* ...
* sum of X:B in all 'browser' process dumps in global dump N
* ]
*
* memory:chrome:browser_process:source:X:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A+X:B in all 'browser' process dumps in global dump 1,
* ...
* sum of X:A+X:B in all 'browser' process dumps in global dump N
* ]
*
* memory:chrome:browser_process:source:Y:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of Y in all 'browser' process dumps in global dump 1,
* ...
* sum of Y in all 'browser' process dumps in global dump N
* ]
*
* memory:chrome:browser_process:source:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A+X:B+Y in all 'browser' process dumps in global dump 1,
* ...
* sum of X:A+X:B+Y in all 'browser' process dumps in global dump N
@@ -743,35 +858,35 @@ tr.exportTo('tr.metrics.sh', function() {
* ...
*
* memory:chrome:all_processes:source:X:A:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A in all process dumps in global dump 1,
* ...
* sum of X:A in all process dumps in global dump N,
* ]
*
* memory:chrome:all_processes:source:X:B:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:B in all process dumps in global dump 1,
* ...
* sum of X:B in all process dumps in global dump N,
* ]
*
* memory:chrome:all_processes:source:X:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A+X:B in all process dumps in global dump 1,
* ...
* sum of X:A+X:B in all process dumps in global dump N,
* ]
*
* memory:chrome:all_processes:source:Y:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of Y in all process dumps in global dump 1,
* ...
* sum of Y in all process dumps in global dump N
* ]
*
* memory:chrome:all_processes:source:proportional_resident_size :
- * Numeric aggregated over [
+ * Histogram aggregated over [
* sum of X:A+X:B+Y in all process dumps in global dump 1,
* ...
* sum of X:A+X:B+Y in all process dumps in global dump N
@@ -791,10 +906,9 @@ tr.exportTo('tr.metrics.sh', function() {
* !function(!{
* source: string,
* componentPath: (!Array<string>|undefined),
- * propertyName: (string|undefined),
- * value: (!tr.v.ScalarNumeric|number|undefined),
- * unit: (!tr.v.Unit|undefined),
- * descriptionPrefixBuilder: (!function(!Array<string>): string)
+ * property: !{name: string, unit: !tr.b.Unit, buildDescriptionPrefix:
+ * !function(!Array<string>, string): string},
+ * value: (!tr.v.Histogram|number|undefined)
* }))}
* customProcessDumpValueExtractor Callback for extracting values from a
* process memory dump.
@@ -809,9 +923,9 @@ tr.exportTo('tr.metrics.sh', function() {
values) {
browserNameToGlobalDumps.forEach(function(globalDumps, browserName) {
var filteredGlobalDumps = globalDumps.filter(customGlobalDumpFilter);
- var sourceToPropertyToData = extractDataFromGlobalDumps(
+ var sourceToPropertyToBuilder = extractDataFromGlobalDumps(
filteredGlobalDumps, customProcessDumpValueExtractor);
- reportDataAsValues(sourceToPropertyToData, browserName,
+ reportDataAsValues(sourceToPropertyToBuilder, browserName,
customComponentTreeModifier, values);
});
}
@@ -824,33 +938,33 @@ tr.exportTo('tr.metrics.sh', function() {
* This function returns the following nested map structure:
*
* Source name (Map key, e.g. 'reported_by_os')
- * -> Property name (Map key, e.g. 'proportional_resident_size')
- * -> {unit, descriptionPrefixBuilder, processAndComponentTreeBuilder}
+ * -> Property (Map key, e.g. PROPORTIONAL_RESIDENT_SIZE)
+ * -> processAndComponentTreeBuilder
*
* where |processAndComponentTreeBuilder| is a
* tr.b.MultiDimensionalViewBuilder:
*
- * Browser name (0th dimension key, e.g. 'webview') x
- * -> Component path (1st dimension keys, e.g. ['system', 'native_heap'])
- * -> Sum of value over the processes (number).
+ * Process name (0th dimension key, e.g. 'browser_process') x
+ * Component path (1st dimension keys, e.g. ['system', 'native_heap'])
+ * -> Sum of value over the processes (number).
*
* See addMemoryDumpValues for more details.
*/
function extractDataFromGlobalDumps(
globalDumps, customProcessDumpValueExtractor) {
- var sourceToPropertyToData = new Map();
+ var sourceToPropertyToBuilder = new Map();
var dumpCount = globalDumps.length;
globalDumps.forEach(function(globalDump, dumpIndex) {
tr.b.iterItems(globalDump.processMemoryDumps, function(_, processDump) {
extractDataFromProcessDump(
- processDump, sourceToPropertyToData, dumpIndex, dumpCount,
+ processDump, sourceToPropertyToBuilder, dumpIndex, dumpCount,
customProcessDumpValueExtractor);
});
});
- return sourceToPropertyToData;
+ return sourceToPropertyToBuilder;
}
- function extractDataFromProcessDump(processDump, sourceToPropertyToData,
+ function extractDataFromProcessDump(processDump, sourceToPropertyToBuilder,
dumpIndex, dumpCount, customProcessDumpValueExtractor) {
// Process name is typically 'browser', 'renderer', etc.
var rawProcessName = processDump.process.name;
@@ -864,81 +978,61 @@ tr.exportTo('tr.metrics.sh', function() {
var component = spec.component || [];
function createDetailsForErrorMessage() {
- var propertyUserFriendlyName =
- spec.property === undefined ? '(undefined)' : spec.property;
- var componentUserFriendlyName =
- component.length === 0 ? '(empty)' : component.join(':');
return ['source=', spec.source, ', property=',
- propertyUserFriendlyName, ', component=',
- componentUserFriendlyName, ' in ',
- processDump.process.userFriendlyName].join('');
+ spec.property.name || '(undefined)', ', component=',
+ component.length === 0 ? '(empty)' : component.join(':'),
+ ' in ', processDump.process.userFriendlyName].join('');
}
- var value, unit;
- if (spec.value instanceof ScalarNumeric) {
+ var value;
+ if (spec.value instanceof tr.v.ScalarNumeric) {
value = spec.value.value;
- unit = spec.value.unit;
- if (spec.unit !== undefined) {
- throw new Error('ScalarNumeric value for ' +
- createDetailsForErrorMessage() + ' already specifies a unit');
+ if (spec.value.unit !== spec.property.unit) {
+ throw new Error('ScalarNumeric unit for ' +
+ createDetailsForErrorMessage() + ' (' +
+ spec.value.unit.unitName +
+ ') doesn\'t match the unit of the property (' +
+ spec.property.unit.unitName + ')');
}
} else {
value = spec.value;
- unit = spec.unit;
}
- var propertyToData = sourceToPropertyToData.get(spec.source);
- if (propertyToData === undefined) {
- propertyToData = new Map();
- sourceToPropertyToData.set(spec.source, propertyToData);
+ var propertyToBuilder = sourceToPropertyToBuilder.get(spec.source);
+ if (propertyToBuilder === undefined) {
+ propertyToBuilder = new Map();
+ sourceToPropertyToBuilder.set(spec.source, propertyToBuilder);
}
- var data = propertyToData.get(spec.property);
- if (data === undefined) {
- data = {
- processAndComponentTreeBuilder:
- new tr.b.MultiDimensionalViewBuilder(
- 2 /* dimensions (process name and component path) */,
- dumpCount /* valueCount */),
- unit: unit,
- descriptionPrefixBuilder: spec.descriptionPrefixBuilder
- };
- propertyToData.set(spec.property, data);
- } else if (data.unit !== unit) {
- throw new Error('Multiple units provided for ' +
- createDetailsForErrorMessage() + ':' +
- data.unit.unitName + ' and ' + unit.unitName);
- } else if (data.descriptionPrefixBuilder !==
- spec.descriptionPrefixBuilder) {
- throw new Error(
- 'Multiple description prefix builders provided for' +
- createDetailsForErrorMessage());
+ var builder = propertyToBuilder.get(spec.property);
+ if (builder === undefined) {
+ builder = new tr.b.MultiDimensionalViewBuilder(
+ 2 /* dimensions (process name and component path) */,
+ dumpCount /* valueCount */),
+ propertyToBuilder.set(spec.property, builder);
}
var values = new Array(dumpCount);
values[dumpIndex] = value;
- data.processAndComponentTreeBuilder.addPath(
+ builder.addPath(
[processNamePath, component] /* path */, values,
tr.b.MultiDimensionalViewBuilder.ValueKind.TOTAL /* valueKind */);
});
}
- function reportDataAsValues(sourceToPropertyToData, browserName,
+ function reportDataAsValues(sourceToPropertyToBuilder, browserName,
customComponentTreeModifier, values) {
// For each source name (e.g. 'reported_by_os')...
- sourceToPropertyToData.forEach(function(propertyToData, sourceName) {
- // For each property name (e.g. 'effective_size')...
- propertyToData.forEach(function(data, propertyName) {
- var tree = data.processAndComponentTreeBuilder.buildTopDownTreeView();
- var unit = data.unit;
- var descriptionPrefixBuilder = data.descriptionPrefixBuilder;
+ sourceToPropertyToBuilder.forEach(function(propertyToBuilder, sourceName) {
+ // For each property (e.g. EFFECTIVE_SIZE)...
+ propertyToBuilder.forEach(function(builders, property) {
+ var tree = builders.buildTopDownTreeView();
// Total over 'all' processes...
customComponentTreeModifier(tree);
reportComponentDataAsValues(browserName, sourceName,
- propertyName, 'all_processes', [] /* componentPath */, tree,
- unit, descriptionPrefixBuilder, values);
+ property, 'all_processes', [] /* componentPath */, tree, values);
// For each process name (e.g. 'renderer')...
tree.children[0].forEach(function(processTree, processName) {
@@ -951,8 +1045,8 @@ tr.exportTo('tr.metrics.sh', function() {
}
customComponentTreeModifier(processTree);
reportComponentDataAsValues(browserName, sourceName,
- propertyName, processName, [] /* componentPath */, processTree,
- unit, descriptionPrefixBuilder, values);
+ property, processName, [] /* componentPath */, processTree,
+ values);
});
});
});
@@ -960,37 +1054,37 @@ tr.exportTo('tr.metrics.sh', function() {
/**
* For the given |browserName| (e.g. 'chrome'), |processName|
- * (e.g. 'gpu_process'), |propertyName| (e.g. 'effective_size'),
- * |componentPath| (e.g. ['v8']), add a tr.v.Numeric with |unit| aggregating
- * the total values of the associated |componentNode| across all timestamps
+ * (e.g. 'gpu_process'), |property| (e.g. EFFECTIVE_SIZE), |componentPath|
+ * (e.g. ['v8']), add a tr.v.Histogram with |unit| aggregating the total
+ * values of the associated |componentNode| across all timestamps
* (corresponding to global memory dumps associated with the given browser)
* to |values|.
*
* See addMemoryDumpValues for more details.
*/
function reportComponentDataAsValues(
- browserName, sourceName, propertyName, processName, componentPath,
- componentNode, unit, descriptionPrefixBuilder, values) {
+ browserName, sourceName, property, processName, componentPath,
+ componentNode, values) {
// Construct the name of the memory value.
var nameParts = ['memory', browserName, processName, sourceName].concat(
componentPath);
- if (propertyName !== undefined)
- nameParts.push(propertyName);
+ if (property.name !== undefined)
+ nameParts.push(property.name);
var name = nameParts.join(':');
// Build the underlying numeric for the memory value.
- var numeric = buildMemoryNumericFromNode(componentNode, unit);
+ var numeric = buildMemoryNumericFromNode(name, componentNode,
+ property.unit);
// Build the options for the memory value.
- var description = [
- descriptionPrefixBuilder(componentPath, processName),
+ numeric.description = [
+ property.buildDescriptionPrefix(componentPath, processName),
'in',
convertBrowserNameToUserFriendlyName(browserName)
].join(' ');
- var options = { description: description };
// Report the memory value.
- values.addValue(new tr.v.NumericValue(name, numeric, options));
+ values.addHistogram(numeric);
// Recursively report memory values for sub-components.
var depth = componentPath.length;
@@ -998,23 +1092,26 @@ tr.exportTo('tr.metrics.sh', function() {
componentNode.children[1].forEach(function(childNode, childName) {
componentPath[depth] = childName;
reportComponentDataAsValues(
- browserName, sourceName, propertyName, processName, componentPath,
- childNode, unit, descriptionPrefixBuilder, values);
+ browserName, sourceName, property, processName, componentPath,
+ childNode, values);
});
componentPath.pop();
}
/**
- * Create a memory tr.v.Numeric (histogram) with |unit| and add all total
- * values in |node| to it.
+ * Create a memory tr.v.Histogram with |unit| and add all total values in
+ * |node| to it.
*/
- function buildMemoryNumericFromNode(node, unit) {
- var numeric = MEMORY_NUMERIC_BUILDER_MAP.get(unit).build();
- node.values.forEach(v => numeric.add(v.total));
- return numeric;
+ function buildMemoryNumericFromNode(name, node, unit) {
+ var histogram = new tr.v.Histogram(
+ name, unit, BOUNDARIES_FOR_UNIT_MAP.get(unit));
+ node.values.forEach(v => histogram.addSample(v.total));
+ return histogram;
}
- tr.metrics.MetricRegistry.register(memoryMetric);
+ tr.metrics.MetricRegistry.register(memoryMetric, {
+ supportsRangeOfInterest: true
+ });
return {
memoryMetric: memoryMetric
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric_test.html
index 500333d61f9..64cd9a08394 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/memory_metric_test.html
@@ -5,12 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/metrics/system_health/memory_metric.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/memory_dump_test_utils.html">
<link rel="import" href="/tracing/model/vm_region.html">
-<link rel="import" href="/tracing/value/value.html">
<link rel="import" href="/tracing/value/value_set.html">
<script>
@@ -19,6 +20,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var VMRegion = tr.model.VMRegion;
var VMRegionClassificationNode = tr.model.VMRegionClassificationNode;
+ var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
var SIZE_DELTA = tr.model.MemoryDumpTestUtils.SIZE_DELTA;
@@ -27,18 +29,18 @@ tr.b.unittest.testSuite(function() {
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addChildDump = tr.model.MemoryDumpTestUtils.addChildDump;
var addOwnershipLink = tr.model.MemoryDumpTestUtils.addOwnershipLink;
- var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
- function memoryMetricTest(name, modelCallback, expectedNumerics) {
+ function memoryMetricTest(
+ name, modelCallback, opt_options, expectedNumerics) {
test(name, function() {
// Create a model and a fake value list.
var model = tr.c.TestUtils.newModel(modelCallback);
var valueNameToValues = {};
var fakeValueList = {
- addValue: function(value) {
+ addHistogram: function(value) {
var values = valueNameToValues[value.name];
if (values === undefined)
valueNameToValues[value.name] = values = [];
@@ -47,7 +49,7 @@ tr.b.unittest.testSuite(function() {
};
// Run the memory metric on the model.
- tr.metrics.sh.memoryMetric(fakeValueList, model);
+ tr.metrics.sh.memoryMetric(fakeValueList, model, opt_options);
// Check that the names of the added values match expectations.
var actualValueNames = Object.keys(valueNameToValues).sort();
@@ -82,56 +84,45 @@ tr.b.unittest.testSuite(function() {
tr.b.iterItems(valueNameToValues, function(valueName, actualValues) {
assert.lengthOf(actualValues, 1,
'Multiple \'' + valueName + '\' values');
- var actualValue = actualValues[0];
- assert.instanceOf(actualValue, tr.v.NumericValue);
+ var actualHistogram = actualValues[0];
+ assert.instanceOf(actualHistogram, tr.v.Histogram);
- var actualNumeric = actualValue.numeric;
- var expectedNumeric = expectedNumerics[valueName];
- assert.strictEqual(actualNumeric.unit, expectedNumeric.unit,
+ var expectedHistogram = expectedNumerics[valueName];
+ assert.strictEqual(actualHistogram.unit, expectedHistogram.unit,
'Invalid \'' + valueName + '\' unit (expected: ' +
- expectedNumeric.unit.unitName, + ', actual: ' +
- actualNumeric.unit.unitName + ')');
+ expectedHistogram.unit.unitName, + ', actual: ' +
+ actualHistogram.unit.unitName + ')');
- if (typeof expectedNumeric.value === 'number') {
- // Scalar.
- assert.instanceOf(actualNumeric, tr.v.ScalarNumeric,
- 'Invalid \'' + valueName + '\' class');
- assert.closeTo(actualNumeric.value, expectedNumeric.value,
- SIZE_DELTA, 'Invalid \'' + valueName + '\' numeric value');
- } else if (expectedNumeric.value instanceof Array) {
- // Histogram.
- assert.instanceOf(actualNumeric, tr.v.Numeric,
- 'Invalid \'' + valueName + '\' class');
- assert.strictEqual(actualNumeric.numValues,
- expectedNumeric.value.length,
- 'Invalid \'' + valueName + '\' Numeric numValues');
- assert.closeTo(actualNumeric.sum,
- expectedNumeric.value.reduce((a, b) => a + b, 0), SIZE_DELTA,
- 'Invalid \'' + valueName + '\' Numeric sum');
+ if (!(expectedHistogram.value instanceof Array))
+ assert.fail('Test sanity check: expected value must be an array');
- // Check that the bin counts match.
- var binToCount = new Map();
- expectedNumeric.value.forEach(function(value) {
- var bin = actualNumeric.getBinForValue(value);
- binToCount.set(bin, (binToCount.get(bin) || 0) + 1);
- });
- actualNumeric.allBins.forEach(function(bin) {
- binToCount.set(bin, (binToCount.get(bin) || 0) - bin.count);
- });
- binToCount.forEach(function(count, bin) {
- assert.strictEqual(count, 0, 'Invalid \'' + valueName +
- '\' bin count for range ' + bin.min + '-' + bin.max);
- });
- } else {
- assert.fail(
- 'Test sanity check: expected value must be a number or an array');
- }
+ assert.instanceOf(actualHistogram, tr.v.Histogram,
+ 'Invalid \'' + valueName + '\' class');
+ assert.strictEqual(actualHistogram.numValues,
+ expectedHistogram.value.length,
+ 'Invalid \'' + valueName + '\' Histogram numValues');
+ assert.closeTo(actualHistogram.sum,
+ expectedHistogram.value.reduce((a, b) => a + b, 0), SIZE_DELTA,
+ 'Invalid \'' + valueName + '\' Histogram sum');
+
+ // Check that the bin counts match.
+ var binToCount = new Map();
+ expectedHistogram.value.forEach(function(value) {
+ var bin = actualHistogram.getBinForValue(value);
+ binToCount.set(bin, (binToCount.get(bin) || 0) + 1);
+ });
+ actualHistogram.allBins.forEach(function(bin) {
+ binToCount.set(bin, (binToCount.get(bin) || 0) - bin.count);
+ });
+ binToCount.forEach(function(count, bin) {
+ assert.strictEqual(count, 0, 'Invalid \'' + valueName +
+ '\' bin count for range ' + bin.min + '-' + bin.max);
+ });
// Check that the description matches expectations.
- //if (expectedNumeric.description !== '')
- assert.strictEqual(
- actualValue.description, expectedNumeric.description,
- 'Invalid \'' + valueName + '\' description');
+ assert.strictEqual(
+ actualHistogram.description, expectedHistogram.description,
+ 'Invalid \'' + valueName + '\' description');
});
});
}
@@ -158,28 +149,34 @@ tr.b.unittest.testSuite(function() {
memoryMetricTest('noDumps_noBrowser', function(model) {
createProcessWithName(model, 'Non-browser');
- }, {
+ }, undefined /* opt_options */, {
/* no values */
});
memoryMetricTest('noDumps_chrome', function(model) {
createChromeBrowserProcess(model);
- }, {
+ }, undefined /* opt_options */, {
'memory:chrome:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:light': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome to ' +
'the trace'
},
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
'memory:chrome:all_processes:dump_count': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome to the ' +
'trace'
}
@@ -190,83 +187,108 @@ tr.b.unittest.testSuite(function() {
createWebViewProcess(model);
createProcessWithName(model, 'Non-browser');
createChromeBrowserProcess(model);
- }, {
+ }, undefined /* opt_options */, {
'memory:chrome2:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome(2) ' +
'to the trace'
},
'memory:chrome2:all_processes:dump_count:light': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome(2) to ' +
'the trace'
},
+ 'memory:chrome2:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by ' +
+ 'Chrome(2) to the trace'
+ },
'memory:chrome2:all_processes:dump_count': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome(2) to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:light': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome to ' +
'the trace'
},
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
'memory:chrome:all_processes:dump_count': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome to the ' +
'trace'
},
'memory:webview:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by WebView ' +
'to the trace'
},
'memory:webview:all_processes:dump_count:light': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by WebView to ' +
'the trace'
},
+ 'memory:webview:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by WebView ' +
+ 'to the trace'
+ },
'memory:webview:all_processes:dump_count': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by WebView to the ' +
'trace'
}
});
memoryMetricTest('dumpCountsOnly_unknownBrowser', function(model) {
- addGlobalMemoryDump(model, 45, DETAILED);
- addGlobalMemoryDump(model, 68, LIGHT);
- addGlobalMemoryDump(model, 89, DETAILED);
- }, {
+ addGlobalMemoryDump(model, {ts: 45, levelOfDetail: DETAILED});
+ addGlobalMemoryDump(model, {ts: 65, levelOfDetail: BACKGROUND});
+ addGlobalMemoryDump(model, {ts: 68, levelOfDetail: LIGHT});
+ addGlobalMemoryDump(model, {ts: 89, levelOfDetail: DETAILED});
+ }, undefined /* opt_options */, {
'memory:unknown_browser:all_processes:dump_count:detailed': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by an ' +
'unknown browser to the trace'
},
'memory:unknown_browser:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by an unknown ' +
'browser to the trace'
},
+ 'memory:unknown_browser:all_processes:dump_count:background': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by an ' +
+ 'unknown browser to the trace'
+ },
'memory:unknown_browser:all_processes:dump_count': {
- value: 3,
- unit: unitlessNumber_smallerIsBetter,
+ value: [4],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by an unknown ' +
'browser to the trace'
}
@@ -274,35 +296,43 @@ tr.b.unittest.testSuite(function() {
memoryMetricTest('dumpCountsOnly_webview', function(model) {
var p = createWebViewProcess(model);
- addProcessMemoryDump(addGlobalMemoryDump(model, 45, LIGHT), p, 45);
- addProcessMemoryDump(addGlobalMemoryDump(model, 68, LIGHT), p, 68);
- }, {
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 45, levelOfDetail: LIGHT}), p, {ts: 45});
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 68, levelOfDetail: LIGHT}), p, {ts: 68});
+ }, undefined /* opt_options */, {
'memory:webview:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by WebView ' +
'to the trace'
},
'memory:webview:all_processes:dump_count:light': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by WebView to ' +
'the trace'
},
+ 'memory:webview:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by WebView ' +
+ 'to the trace'
+ },
'memory:webview:all_processes:dump_count': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by WebView to the ' +
'trace'
},
'memory:webview:all_processes:process_count': {
value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of all processes in WebView'
},
'memory:webview:browser_process:process_count': {
value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in WebView'
}
});
@@ -315,126 +345,224 @@ tr.b.unittest.testSuite(function() {
var pUnknown = createProcessWithName(model, undefined);
// Timestamp 1.
- var gmd1 = addGlobalMemoryDump(model, 20);
- var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, 19);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 20});
+ var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, {ts: 19});
pmdBrowser1.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser1, 'malloc', {
- 'size': 8,
- 'allocated_objects_size': 4
- })
+ newAllocatorDump(pmdBrowser1, 'malloc', {numerics: {
+ size: 8,
+ allocated_objects_size: 4
+ }})
];
- var pmdRendererA1 = addProcessMemoryDump(gmd1, pRendererA, 20);
+ pmdBrowser1.totals = {
+ residentBytes: 200,
+ peakResidentBytes: 230
+ };
+ var pmdRendererA1 = addProcessMemoryDump(gmd1, pRendererA, {ts: 20});
pmdRendererA1.memoryAllocatorDumps = (function() {
var mallocDump =
- newAllocatorDump(pmdRendererA1, 'malloc', { 'size': 16 });
+ newAllocatorDump(pmdRendererA1, 'malloc', {numerics: {size: 16}});
var partitionAllocDump =
newAllocatorDump(pmdRendererA1, 'partition_alloc');
+ var v8Dump = newAllocatorDump(pmdRendererA1, 'v8',
+ {numerics: {code_and_metadata_size: 16}});
addOwnershipLink(
- addChildDump(partitionAllocDump, 'allocated_objects', { 'size': 32 }),
- addChildDump(partitionAllocDump, 'partitions', { 'size': 24 }));
- return [mallocDump, partitionAllocDump];
+ addChildDump(partitionAllocDump, 'allocated_objects',
+ {numerics: {size: 32}}),
+ addChildDump(partitionAllocDump, 'partitions',
+ {numerics: {size: 24}}));
+ return [mallocDump, partitionAllocDump, v8Dump];
})();
- var pmdGpu1 = addProcessMemoryDump(gmd1, pPpapi, 21);
+ var pmdGpu1 = addProcessMemoryDump(gmd1, pPpapi, {ts: 21});
pmdGpu1.memoryAllocatorDumps = [
- newAllocatorDump(pmdGpu1, 'gpu', {
- 'size': 30,
- 'allocated_objects_size': 25
- })
+ newAllocatorDump(pmdGpu1, 'gpu', {numerics: {
+ size: 30,
+ allocated_objects_size: 25
+ }})
];
// Timestamp 2.
- var gmd2 = addGlobalMemoryDump(model, 40);
- var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, 41);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 40});
+ var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, {ts: 41});
pmdBrowser2.memoryAllocatorDumps = (function() {
- var mallocDump = newAllocatorDump(pmdBrowser2, 'malloc', { 'size': 120 });
+ var mallocDump = newAllocatorDump(pmdBrowser2, 'malloc',
+ {numerics: {size: 120}});
var tracingDump =
- newAllocatorDump(pmdBrowser2, 'tracing', { 'size': 40 });
+ newAllocatorDump(pmdBrowser2, 'tracing', {numerics: {size: 40}});
return [mallocDump, tracingDump];
})();
- var pmdRendererA2 = addProcessMemoryDump(gmd2, pRendererA, 39);
+ var pmdRendererA2 = addProcessMemoryDump(gmd2, pRendererA, {ts: 39});
pmdRendererA2.memoryAllocatorDumps = (function() {
var partitionAllocDump =
newAllocatorDump(pmdRendererA2, 'partition_alloc');
addOwnershipLink(
addChildDump(partitionAllocDump, 'allocated_objects',
- { 'size': 320 }),
- addChildDump(partitionAllocDump, 'partitions', { 'size': 240 }));
- var v8Dump = newAllocatorDump(pmdRendererA2, 'v8', { 'size': 650 });
+ {numerics: {size: 320}}),
+ addChildDump(partitionAllocDump, 'partitions',
+ {numerics: {size: 240}}));
+ var v8Dump = newAllocatorDump(pmdRendererA2, 'v8',
+ {numerics: {size: 650}});
+ var isolateDumpA = addChildDump(v8Dump, 'isolate_A');
+ addChildDump(isolateDumpA, 'malloc', {numerics: {
+ size: 1,
+ peak_size: 2
+ }});
+ var heapDumpA = addChildDump(isolateDumpA, 'heap_spaces', {numerics: {
+ size: 42,
+ allocated_objects_size: 36
+ }});
+ addChildDump(heapDumpA, 'code_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ addChildDump(heapDumpA, 'large_object_space', {numerics: {
+ allocated_objects_size: 3,
+ size: 4
+ }});
+ addChildDump(heapDumpA, 'map_space', {numerics: {
+ allocated_objects_size: 5,
+ size: 6,
+ }});
+ addChildDump(heapDumpA, 'new_space', {numerics: {
+ allocated_objects_size: 7,
+ size: 8
+ }});
+ addChildDump(heapDumpA, 'old_space', {numerics: {
+ allocated_objects_size: 9,
+ size: 10
+ }});
+ addChildDump(heapDumpA, 'other_spaces', {numerics: {
+ allocated_objects_size: 11,
+ size: 12
+ }});
+ var isolateDumpB = addChildDump(v8Dump, 'isolate_B');
+ addChildDump(isolateDumpB, 'malloc', {numerics: {
+ size: 10,
+ peak_size: 20
+ }});
+ var heapDumpB = addChildDump(isolateDumpB, 'heap_spaces', {numerics: {
+ size: 12,
+ allocated_objects_size: 6
+ }});
+ addChildDump(heapDumpB, 'code_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ addChildDump(heapDumpB, 'large_object_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ addChildDump(heapDumpB, 'map_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2,
+ }});
+ addChildDump(heapDumpB, 'new_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ addChildDump(heapDumpB, 'old_space', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ addChildDump(heapDumpB, 'other_spaces', {numerics: {
+ allocated_objects_size: 1,
+ size: 2
+ }});
+ var isolateDumpC = addChildDump(v8Dump, 'isolate_C');
+ addChildDump(isolateDumpC, 'malloc', {numerics: {
+ size: 100,
+ }});
+ addChildDump(isolateDumpC, 'heap_spaces', {numerics: {
+ size: 2,
+ allocated_objects_size: 1
+ }});
+ var isolateDumpD = addChildDump(v8Dump, 'isolate_D');
+ addChildDump(isolateDumpD, 'malloc', {numerics: {
+ peak_size: 200,
+ }});
return [partitionAllocDump, v8Dump];
})();
- var pmdRendererB2 = addProcessMemoryDump(gmd2, pRendererB, 40);
+ var pmdRendererB2 = addProcessMemoryDump(gmd2, pRendererB, {ts: 40});
pmdRendererB2.memoryAllocatorDumps = [
- newAllocatorDump(pmdRendererB2, 'v8', {
- 'size': 970,
- 'allocated_objects_size': 860
- }),
- newAllocatorDump(pmdRendererB2, 'malloc', {
- 'allocated_objects_size': 750
- })
+ newAllocatorDump(pmdRendererB2, 'v8', {numerics: {
+ size: 970,
+ allocated_objects_size: 860,
+ bytecode_and_metadata_size: 678
+ }}),
+ newAllocatorDump(pmdRendererB2, 'malloc',
+ {numerics: {allocated_objects_size: 750}})
];
- var pmdUnknown = addProcessMemoryDump(gmd2, pUnknown, 42);
+ var pmdUnknown = addProcessMemoryDump(gmd2, pUnknown, {ts: 42});
pmdUnknown.memoryAllocatorDumps = [
- newAllocatorDump(pmdRendererB2, 'v8', {
- 'size': 111
- })
+ newAllocatorDump(pmdRendererB2, 'v8', {numerics: {size: 111}})
];
// Timestamp 3.
- var gmd3 = addGlobalMemoryDump(model, 60);
- var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, 60);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 60});
+ var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, {ts: 60});
pmdBrowser3.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser3, 'malloc', {
- 'size': 8000,
- 'allocated_objects_size': 4000
- })
+ newAllocatorDump(pmdBrowser3, 'malloc', {numerics: {
+ size: 8000,
+ allocated_objects_size: 4000
+ }})
];
- var pmdRendererB3 = addProcessMemoryDump(gmd3, pRendererB, 61);
+ var pmdRendererB3 = addProcessMemoryDump(gmd3, pRendererB, {ts: 61});
// Intentionally pmdRendererB3.memoryAllocatorDumps undefined.
- var pmdGpu3 = addProcessMemoryDump(gmd3, pPpapi, 59);
+ var pmdGpu3 = addProcessMemoryDump(gmd3, pPpapi, {ts: 59});
pmdGpu3.memoryAllocatorDumps = [
- newAllocatorDump(pmdGpu3, 'gpu', { 'size': 300 })
+ newAllocatorDump(pmdGpu3, 'gpu', {numerics: {size: 300}})
];
// Timestamp 4.
- var gmd4 = addGlobalMemoryDump(model, 80);
- var pmdBrowser4 = addProcessMemoryDump(gmd4, pBrowser, 81);
+ var gmd4 = addGlobalMemoryDump(model, {ts: 80});
+ var pmdBrowser4 = addProcessMemoryDump(gmd4, pBrowser, {ts: 81});
pmdBrowser4.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser4, 'malloc', { 'size': 80000 })
+ newAllocatorDump(pmdBrowser4, 'malloc', {numerics: {size: 80000}})
];
- var pmdRendererB4 = addProcessMemoryDump(gmd4, pRendererB, 79);
+ var pmdRendererB4 = addProcessMemoryDump(gmd4, pRendererB, {ts: 79});
pmdRendererB4.memoryAllocatorDumps = (function() {
- var v8Dump = newAllocatorDump(pmdRendererB4, 'v8', { 'size': 9e5 });
+ var v8Dump = newAllocatorDump(pmdRendererB4, 'v8', {numerics: {
+ code_and_metadata_size: 21,
+ bytecode_and_metadata_size: 35,
+ size: 9e5
+ }});
var partitionAllocDump = newAllocatorDump(pmdRendererB4,
- 'partition_alloc', { 'size': 5e5 });
+ 'partition_alloc', {numerics: {size: 5e5}});
addOwnershipLink(partitionAllocDump, v8Dump);
return [v8Dump, partitionAllocDump];
})();
- var pmdGpu4 = addProcessMemoryDump(gmd4, pPpapi, 80);
+ var pmdGpu4 = addProcessMemoryDump(gmd4, pPpapi, {ts: 80});
pmdGpu4.memoryAllocatorDumps = [
- newAllocatorDump(pmdGpu4, 'gpu', { 'memtrack_pss': 666 /* ignored */ })
+ newAllocatorDump(pmdGpu4, 'gpu',
+ {numerics: {memtrack_pss: 666 /* ignored */}})
];
- }, {
+ }, undefined /* opt_options */, {
'memory:chrome:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:light': {
- value: 4,
- unit: unitlessNumber_smallerIsBetter,
+ value: [4],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome to ' +
'the trace'
},
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
'memory:chrome:all_processes:dump_count': {
- value: 4,
- unit: unitlessNumber_smallerIsBetter,
+ value: [4],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome to the ' +
'trace'
},
'memory:chrome:all_processes:process_count': {
value: [3, 4, 3, 3],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of all processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:effective_size': {
@@ -445,11 +573,43 @@ tr.b.unittest.testSuite(function() {
'processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:allocated_objects_size': {
- value: [25 + 4, 750 + 860, 4000, 0],
+ value: [25 + 4 + 32, (36 + 6 + 1) + 750 + 860 + 320 + 40, 4000, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of all allocated objects reported by Chrome ' +
'for all processes in Chrome'
},
+ 'memory:chrome:all_processes:reported_by_chrome:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak size reported by Chrome for all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_os:resident_size': {
+ value: [200, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total resident set size (RSS) reported by the OS for all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_os:peak_resident_size': {
+ value: [230, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak resident set size reported by the OS for all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_os:system_memory:resident_size': {
+ value: [200, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total resident set size (RSS) of system memory (RAM) ' +
+ 'used by all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_os:system_memory:peak_resident_size':
+ {
+ value: [230, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak resident set size of system memory (RAM) ' +
+ 'used by all processes in Chrome'
+ },
'memory:chrome:all_processes:reported_by_chrome:gpu:effective_size': {
value: [30, 0, 300, 0],
unit: sizeInBytes_smallerIsBetter,
@@ -469,11 +629,18 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:all_processes:reported_by_chrome:malloc:allocated_objects_size':
{
- value: [4, 750, 4000, 0],
+ value: [4, 40 + 750, 4000, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by malloc in all ' +
'processes in Chrome'
},
+ 'memory:chrome:all_processes:reported_by_chrome:partition_alloc:allocated_objects_size':
+ {
+ value: [32, 320, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by partition_alloc in ' +
+ 'all processes in Chrome'
+ },
'memory:chrome:all_processes:reported_by_chrome:partition_alloc:effective_size':
{
value: [32, 320, 0, 5e5],
@@ -486,6 +653,115 @@ tr.b.unittest.testSuite(function() {
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of tracing in all processes in Chrome'
},
+ 'memory:chrome:all_processes:reported_by_chrome:v8:allocated_by_malloc:effective_size':
+ {
+ value: [0, 1 + 10 + 100, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of objects allocated by malloc for v8 ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:allocated_by_malloc:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of objects allocated by malloc for v8 ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:code_and_metadata_size':
+ {
+ value: [16, 678, 0, 21 + 35],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total size of code and metadata reported by Chrome ' +
+ 'for all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:code_and_metadata_size':
+ {
+ value: [16, 678, 0, 21 + 35],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of v8 code and metadata in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:allocated_objects_size':
+ {
+ value: [0, 36 + 6 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap in all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:effective_size': {
+ value: [0, 42 + 12 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:code_space:allocated_objects_size':
+ {
+ value: [0, 1 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:code_space ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:code_space:effective_size':
+ {
+ value: [0, 2 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:code_space in all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:large_object_space:allocated_objects_size':
+ {
+ value: [0, 3 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by ' +
+ 'v8:heap:large_object_space in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:large_object_space:effective_size':
+ {
+ value: [0, 4 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:large_object_space in all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:map_space:allocated_objects_size':
+ {
+ value: [0, 5 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:map_space ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:map_space:effective_size':
+ {
+ value: [0, 6 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:map_space in all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:new_space:allocated_objects_size':
+ {
+ value: [0, 7 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:new_space ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:new_space:effective_size':
+ {
+ value: [0, 8 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:new_space in all ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:old_space:allocated_objects_size':
+ {
+ value: [0, 9 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:old_space ' +
+ 'in all processes in Chrome'
+ },
+ 'memory:chrome:all_processes:reported_by_chrome:v8:heap:old_space:effective_size':
+ {
+ value: [0, 10 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:old_space in all ' +
+ 'processes in Chrome'
+ },
'memory:chrome:all_processes:reported_by_chrome:v8:effective_size': {
value: [0, 650 + 970 + 111, 0, 4e5],
unit: sizeInBytes_smallerIsBetter,
@@ -493,14 +769,46 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:all_processes:reported_by_chrome:v8:allocated_objects_size':
{
- value: [0, 860, 0, 0],
+ value: [0, (36 + 6 + 1) + 860, 0, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by v8 in all processes ' +
'in Chrome'
},
+ 'memory:chrome:all_processes:reported_by_chrome:v8:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of v8 in all processes in Chrome'
+ },
+ 'memory:chrome:browser_process:reported_by_os:peak_resident_size': {
+ value: [230, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak resident set size reported by the OS for the ' +
+ 'browser process in Chrome'
+ },
+ 'memory:chrome:browser_process:reported_by_os:system_memory:peak_resident_size':
+ {
+ value: [230, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak resident set size of system memory (RAM) ' +
+ 'used by the browser process in Chrome'
+ },
+ 'memory:chrome:browser_process:reported_by_os:resident_size': {
+ value: [200, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total resident set size (RSS) reported by the OS for the ' +
+ 'browser process in Chrome'
+ },
+ 'memory:chrome:browser_process:reported_by_os:system_memory:resident_size':
+ {
+ value: [200, 0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total resident set size (RSS) of system memory (RAM) ' +
+ 'used by the browser process in Chrome'
+ },
'memory:chrome:browser_process:process_count': {
value: [1, 1, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:effective_size': {
@@ -510,7 +818,7 @@ tr.b.unittest.testSuite(function() {
'process in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:allocated_objects_size': {
- value: [4, 0, 4000, 0],
+ value: [4 + 40, 0, 4000, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of all allocated objects reported by Chrome ' +
'for the browser process in Chrome'
@@ -522,7 +830,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:browser_process:reported_by_chrome:malloc:allocated_objects_size':
{
- value: [4, 0, 4000, 0],
+ value: [4 + 40, 0, 4000, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by malloc in the ' +
'browser process in Chrome'
@@ -534,7 +842,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:ppapi_process:process_count': {
value: [1, 0, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of PPAPI processes in Chrome'
},
'memory:chrome:ppapi_process:reported_by_chrome:effective_size': {
@@ -563,7 +871,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:renderer_processes:process_count': {
value: [1, 2, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of renderer processes in Chrome'
},
'memory:chrome:renderer_processes:reported_by_chrome:effective_size': {
@@ -574,11 +882,18 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:renderer_processes:reported_by_chrome:allocated_objects_size':
{
- value: [0, 750 + 860, 0, 0],
+ value: [32, (36 + 6 + 1) + 750 + 860 + 320, 0, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of all allocated objects reported by ' +
'Chrome for renderer processes in Chrome'
},
+ 'memory:chrome:renderer_processes:reported_by_chrome:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak size reported by Chrome ' +
+ 'for renderer processes in Chrome'
+ },
'memory:chrome:renderer_processes:reported_by_chrome:malloc:effective_size':
{
value: [16, 0, 0, 0],
@@ -593,6 +908,13 @@ tr.b.unittest.testSuite(function() {
description: 'size of all objects allocated by malloc in renderer ' +
'processes in Chrome'
},
+ 'memory:chrome:renderer_processes:reported_by_chrome:partition_alloc:allocated_objects_size':
+ {
+ value: [32, 320, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by partition_alloc in ' +
+ 'renderer processes in Chrome'
+ },
'memory:chrome:renderer_processes:reported_by_chrome:partition_alloc:effective_size':
{
value: [32, 320, 0, 5e5],
@@ -600,6 +922,118 @@ tr.b.unittest.testSuite(function() {
description: 'effective size of partition_alloc in renderer ' +
'processes in Chrome'
},
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:allocated_by_malloc:effective_size':
+ {
+ value: [0, 1 + 10 + 100, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of objects allocated by malloc for v8 ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:allocated_by_malloc:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of objects allocated by malloc for v8 ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:allocated_objects_size':
+ {
+ value: [0, 36 + 6 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap in renderer ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:code_and_metadata_size':
+ {
+ value: [16, 678, 0, 21 + 35],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total size of code and metadata reported by Chrome ' +
+ 'for renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:code_and_metadata_size':
+ {
+ value: [16, 678, 0, 21 + 35],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of v8 code and metadata in renderer processes ' +
+ 'in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:effective_size':
+ {
+ value: [0, 42 + 12 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap in renderer processes ' +
+ 'in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:code_space:allocated_objects_size':
+ {
+ value: [0, 1 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:code_space ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:code_space:effective_size':
+ {
+ value: [0, 2 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:code_space in renderer ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:large_object_space:allocated_objects_size':
+ {
+ value: [0, 3 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by ' +
+ 'v8:heap:large_object_space in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:large_object_space:effective_size':
+ {
+ value: [0, 4 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:large_object_space in ' +
+ 'renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:map_space:allocated_objects_size':
+ {
+ value: [0, 5 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:map_space ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:map_space:effective_size':
+ {
+ value: [0, 6 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:map_space in renderer ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:new_space:allocated_objects_size':
+ {
+ value: [0, 7 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:new_space ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:new_space:effective_size':
+ {
+ value: [0, 8 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:new_space in renderer ' +
+ 'processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:old_space:allocated_objects_size':
+ {
+ value: [0, 9 + 1, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'size of all objects allocated by v8:heap:old_space ' +
+ 'in renderer processes in Chrome'
+ },
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:heap:old_space:effective_size':
+ {
+ value: [0, 10 + 2, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of v8:heap:old_space in renderer ' +
+ 'processes in Chrome'
+ },
'memory:chrome:renderer_processes:reported_by_chrome:v8:effective_size': {
value: [0, 650 + 970, 0, 4e5],
unit: sizeInBytes_smallerIsBetter,
@@ -607,14 +1041,20 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:renderer_processes:reported_by_chrome:v8:allocated_objects_size':
{
- value: [0, 860, 0, 0],
+ value: [0, (36 + 6 + 1) + 860, 0, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by v8 in renderer ' +
'processes in Chrome'
},
+ 'memory:chrome:renderer_processes:reported_by_chrome:v8:peak_size':
+ {
+ value: [0, 2 + 20 + 200, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of v8 in renderer processes in Chrome'
+ },
'memory:chrome:unknown_processes:process_count': {
value: [0, 1, 0, 0],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of unknown processes in Chrome'
},
'memory:chrome:unknown_processes:reported_by_chrome:effective_size': {
@@ -638,138 +1078,113 @@ tr.b.unittest.testSuite(function() {
var pGpu = createProcessWithName(model, 'GPU Process');
// Timestamp 1.
- var gmd1 = addGlobalMemoryDump(model, 10, DETAILED);
- var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, 9);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 10, levelOfDetail: DETAILED});
+ var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, {ts: 9});
pmdBrowser1.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 128, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 8 })
+ {privateDirtyResident: 8})
]);
- var pmdRendererA1 = addProcessMemoryDump(gmd1, pRendererA, 10);
+ var pmdRendererA1 = addProcessMemoryDump(gmd1, pRendererA, {ts: 10});
pmdRendererA1.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xEF01, 256, 0, '[anon:libc_malloc]',
- { 'privateDirtyResident': 17 })
+ {privateDirtyResident: 17})
]);
- var pmdRendererB1 = addProcessMemoryDump(gmd1, pRendererB, 11);
+ var pmdRendererB1 = addProcessMemoryDump(gmd1, pRendererB, {ts: 11});
pmdRendererB1.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0x2345, 512, 0, '[heap]',
- { 'proportionalResident': 67, 'privateDirtyResident': 34 })
+ {proportionalResident: 67, privateDirtyResident: 34})
]);
- pmdRendererB1.memoryAllocatorDumps = [
- newAllocatorDump(pmdRendererA4, 'v8', { 'code_and_metadata_size': 16 })
- ];
- var pmdGpu1 = addProcessMemoryDump(gmd1, pGpu, 10);
+ var pmdGpu1 = addProcessMemoryDump(gmd1, pGpu, {ts: 10});
pmdGpu1.memoryAllocatorDumps = (function() {
var gpuDump = newAllocatorDump(pmdGpu1, 'gpu');
var memtrackDump = addChildDump(gpuDump, 'android_memtrack');
- addChildDump(memtrackDump, 'gl', { 'memtrack_pss': 100 });
- addChildDump(memtrackDump, 'graphics', { 'memtrack_pss': 200 });
+ addChildDump(memtrackDump, 'gl', {numerics: {memtrack_pss: 100}});
+ addChildDump(memtrackDump, 'graphics', {numerics: {memtrack_pss: 200}});
return [gpuDump];
})();
// Timestamp 2 (light global memory dump, so it should be skipped for
// mmaps_* values).
- var gmd2 = addGlobalMemoryDump(model, 20, LIGHT);
- var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, 18);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 20, levelOfDetail: LIGHT});
+ var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, {ts: 18});
pmdBrowser2.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0x999, 999, 999, '/dev/ashmem/dalvik-main space',
- { 'proportionalResident': 999 })
+ {proportionalResident: 999})
]);
- var pmdRendererA2 = addProcessMemoryDump(gmd2, pRendererA, 19);
- pmdRendererA2.memoryAllocatorDumps = [
- newAllocatorDump(pmdRendererA4, 'v8', {
- 'bytecode_and_metadata_size': 678
- })
- ];
- var pmdRendererB2 = addProcessMemoryDump(gmd2, pRendererB, 21);
- var pmdRendererC2 = addProcessMemoryDump(gmd2, pRendererC, 22);
- var pmdGpu2 = addProcessMemoryDump(gmd2, pGpu, 20);
+ var pmdRendererB2 = addProcessMemoryDump(gmd2, pRendererB, {ts: 21});
+ var pmdRendererC2 = addProcessMemoryDump(gmd2, pRendererC, {ts: 22});
+ var pmdGpu2 = addProcessMemoryDump(gmd2, pGpu, {ts: 20});
pmdGpu2.memoryAllocatorDumps = (function() {
var gpuDump = newAllocatorDump(pmdGpu2, 'gpu');
var memtrackDump = addChildDump(gpuDump, 'android_memtrack');
- addChildDump(memtrackDump, 'gl', { 'memtrack_pss': 12345 });
+ addChildDump(memtrackDump, 'gl', {numerics: {memtrack_pss: 12345}});
return [gpuDump];
})();
// Timestamp 3.
- var gmd3 = addGlobalMemoryDump(model, 30, DETAILED);
- var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, 30);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 30, levelOfDetail: DETAILED});
+ var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, {ts: 30});
pmdBrowser3.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 1024, 0, '/dev/ashmem/dalvik-non moving space',
- { 'proportionalResident': 3, 'privateDirtyResident': 80 })
+ {proportionalResident: 3, privateDirtyResident: 80})
]);
- var pmdRendererA3 = addProcessMemoryDump(gmd3, pRendererA, 29);
+ var pmdRendererA3 = addProcessMemoryDump(gmd3, pRendererA, {ts: 29});
// Intentionally pmdRendererA3.vmRegions undefined.
- var pmdRendererC3 = addProcessMemoryDump(gmd3, pRendererC, 31);
+ var pmdRendererC3 = addProcessMemoryDump(gmd3, pRendererC, {ts: 31});
pmdRendererC3.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0x2345, 2048, 0, '/no/matching/category',
- { 'proportionalResident': 200 }),
- new VMRegion(0x2345, 2048, 0, '/dev/ashmem',
- { 'proportionalResident': 500 }),
+ {proportionalResident: 200}),
+ new VMRegion(0x2345, 2048, 0, '/dev/ashmem', {proportionalResident: 500}),
]);
- var pmdGpu3 = addProcessMemoryDump(gmd3, pGpu, 30);
+ var pmdGpu3 = addProcessMemoryDump(gmd3, pGpu, {ts: 30});
pmdGpu3.memoryAllocatorDumps = (function() {
var gpuDump = newAllocatorDump(pmdGpu3, 'gpu',
- { 'memtrack_pss': 6000 /* ignored */ });
+ {numerics: {memtrack_pss: 6000 /* ignored */}});
var memtrackDump = addChildDump(gpuDump, 'android_memtrack',
- { 'memtrack_pss': 5000 /* ignored */ });
- addChildDump(memtrackDump, 'gl', { 'memtrack_pss': 3000 });
- addChildDump(memtrackDump, 'graphics', { 'ignored': 2000 });
- addChildDump(memtrackDump, 'gfx', { 'memtrack_pss': 1000 });
+ {numerics: {memtrack_pss: 5000 /* ignored */}});
+ addChildDump(memtrackDump, 'gl', {numerics: {memtrack_pss: 3000}});
+ addChildDump(memtrackDump, 'graphics', {numerics: {ignored: 2000}});
+ addChildDump(memtrackDump, 'gfx', {numerics: {memtrack_pss: 1000}});
return [gpuDump];
})();
pmdGpu3.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xCDCD, 4096, 0, '/dev/ashmem/dalvik-zygote space',
- { 'proportionalResident': 150, 'privateDirtyResident': 90 })
+ {proportionalResident: 150, privateDirtyResident: 90})
]);
// Timestamp 4.
- var gmd4 = addGlobalMemoryDump(model, 40, DETAILED);
- var pmdBrowser4 = addProcessMemoryDump(gmd4, pBrowser, 40);
- var pmdRendererA4 = addProcessMemoryDump(gmd4, pRendererA, 40);
- pmdRendererA4.memoryAllocatorDumps = [
- newAllocatorDump(pmdRendererA4, 'v8', {
- 'code_and_metadata_size': 21,
- 'bytecode_and_metadata_size': 35
- })
- ];
- }, {
+ var gmd4 = addGlobalMemoryDump(model, {ts: 40, levelOfDetail: DETAILED});
+ var pmdBrowser4 = addProcessMemoryDump(gmd4, pBrowser, {ts: 40});
+ }, undefined /* opt_options */, {
'memory:unknown_browser:all_processes:dump_count:detailed': {
- value: 3,
- unit: unitlessNumber_smallerIsBetter,
+ value: [3],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by an ' +
'unknown browser to the trace'
},
'memory:unknown_browser:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by an unknown ' +
'browser to the trace'
},
+ 'memory:unknown_browser:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by an ' +
+ 'unknown browser to the trace'
+ },
'memory:unknown_browser:all_processes:dump_count': {
- value: 4,
- unit: unitlessNumber_smallerIsBetter,
+ value: [4],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by an unknown ' +
'browser to the trace'
},
'memory:unknown_browser:all_processes:process_count': {
- value: [4, 5, 4, 2],
- unit: unitlessNumber_smallerIsBetter,
+ value: [4, 4, 4, 1],
+ unit: count_smallerIsBetter,
description: 'total number of all processes in an unknown browser'
},
- 'memory:unknown_browser:all_processes:reported_by_chrome:code_and_metadata_size':
- {
- value: [16, 0, 21 + 35],
- unit: sizeInBytes_smallerIsBetter,
- description: 'total size of code and metadata reported by Chrome ' +
- 'for all processes in an unknown browser'
- },
- 'memory:unknown_browser:all_processes:reported_by_chrome:v8:code_and_metadata_size':
- {
- value: [16, 0, 21 + 35],
- unit: sizeInBytes_smallerIsBetter,
- description: 'size of v8 code and metadata in all processes in an ' +
- 'unknown browser'
- },
'memory:unknown_browser:all_processes:reported_by_os:gpu_memory:proportional_resident_size':
{
value: [100 + 200, 3000 + 1000, 0],
@@ -870,7 +1285,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:unknown_browser:browser_process:process_count': {
value: [1, 1, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in an unknown browser'
},
'memory:unknown_browser:browser_process:reported_by_os:private_dirty_size':
@@ -945,7 +1360,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:unknown_browser:gpu_process:process_count': {
value: [1, 1, 1, 0],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of GPU processes in an unknown browser'
},
'memory:unknown_browser:gpu_process:reported_by_os:proportional_resident_size':
@@ -1047,24 +1462,10 @@ tr.b.unittest.testSuite(function() {
'in the GPU process in an unknown browser'
},
'memory:unknown_browser:renderer_processes:process_count': {
- value: [2, 3, 2, 1],
- unit: unitlessNumber_smallerIsBetter,
+ value: [2, 2, 2, 0],
+ unit: count_smallerIsBetter,
description: 'total number of renderer processes in an unknown browser'
},
- 'memory:unknown_browser:renderer_processes:reported_by_chrome:code_and_metadata_size':
- {
- value: [16, 0, 21 + 35],
- unit: sizeInBytes_smallerIsBetter,
- description: 'total size of code and metadata reported by Chrome ' +
- 'for renderer processes in an unknown browser'
- },
- 'memory:unknown_browser:renderer_processes:reported_by_chrome:v8:code_and_metadata_size':
- {
- value: [16, 0, 21 + 35],
- unit: sizeInBytes_smallerIsBetter,
- description: 'size of v8 code and metadata in renderer processes ' +
- 'in an unknown browser'
- },
'memory:unknown_browser:renderer_processes:reported_by_os:private_dirty_size':
{
value: [17 + 34, 0, 0],
@@ -1141,53 +1542,59 @@ tr.b.unittest.testSuite(function() {
var pBrowser = createChromeBrowserProcess(model);
// Timestamp 1.
- var gmd1 = addGlobalMemoryDump(model, 10, DETAILED);
- var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, 10);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 10, levelOfDetail: DETAILED});
+ var pmdBrowser1 = addProcessMemoryDump(gmd1, pBrowser, {ts: 10});
pmdBrowser1.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 128, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 100 })
+ {privateDirtyResident: 100})
]);
// Timestamp 2 (light global memory dump, so it should be skipped for
// mmaps_* values).
- var gmd2 = addGlobalMemoryDump(model, 20, LIGHT);
- var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, 20);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 20, levelOfDetail: LIGHT});
+ var pmdBrowser2 = addProcessMemoryDump(gmd2, pBrowser, {ts: 20});
pmdBrowser2.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser2, 'malloc', { size: 32 })
+ newAllocatorDump(pmdBrowser2, 'malloc', {numerics: {size: 32}})
];
// Timestamp 3.
- var gmd3 = addGlobalMemoryDump(model, 30, DETAILED);
- var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, 30);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 30, levelOfDetail: DETAILED});
+ var pmdBrowser3 = addProcessMemoryDump(gmd3, pBrowser, {ts: 30});
pmdBrowser3.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser3, 'malloc', { size: 48 })
+ newAllocatorDump(pmdBrowser3, 'malloc', {numerics: {size: 48}})
];
pmdBrowser3.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 1024, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 150 })
+ {privateDirtyResident: 150})
]);
- }, {
+ }, {} /* opt_options */, {
'memory:chrome:all_processes:dump_count:detailed': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome to ' +
'the trace'
},
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
'memory:chrome:all_processes:dump_count': {
- value: 3,
- unit: unitlessNumber_smallerIsBetter,
+ value: [3],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome to the ' +
'trace'
},
'memory:chrome:all_processes:process_count': {
value: [1, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of all processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:effective_size': {
@@ -1270,7 +1677,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome:browser_process:process_count': {
value: [1, 1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:effective_size': {
@@ -1364,168 +1771,230 @@ tr.b.unittest.testSuite(function() {
var pRenderer2 = createProcessWithName(model, 'Renderer');
// Timestamp 1 (WebView).
- var gmd1 = addGlobalMemoryDump(model, 0, LIGHT);
- var pmdBrowser1 = addProcessMemoryDump(gmd1, pWebView, 0);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 0, levelOfDetail: LIGHT});
+ var pmdBrowser1 = addProcessMemoryDump(gmd1, pWebView, {ts: 0});
pmdBrowser1.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser1, 'malloc', { size: 2 }),
- newAllocatorDump(pmdBrowser1, 'v8', { size: 4 })
+ newAllocatorDump(pmdBrowser1, 'malloc', {numerics: {size: 2}}),
+ newAllocatorDump(pmdBrowser1, 'v8', {numerics: {size: 4}})
];
// Timestamp 2 (Chrome 1 + Renderer + GPU Process).
- var gmd2 = addGlobalMemoryDump(model, 10, DETAILED);
- var pmdBrowser2 = addProcessMemoryDump(gmd2, pChrome1, 12);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 10, levelOfDetail: DETAILED});
+ var pmdBrowser2 = addProcessMemoryDump(gmd2, pChrome1, {ts: 12});
pmdBrowser2.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 9999, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 8 })
+ {privateDirtyResident: 8})
]);
- var pmdGpu2 = addProcessMemoryDump(gmd2, pGpu1, 8);
+ var pmdGpu2 = addProcessMemoryDump(gmd2, pGpu1, {ts: 8});
pmdGpu2.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 9999, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 16 })
+ {privateDirtyResident: 16})
]);
- var pmdRenderer2 = addProcessMemoryDump(gmd2, pRenderer1, 8);
+ var pmdRenderer2 = addProcessMemoryDump(gmd2, pRenderer1, {ts: 8});
pmdRenderer2.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser2, 'malloc', { size: 32 })
+ newAllocatorDump(pmdBrowser2, 'malloc', {numerics: {size: 32}})
];
// Timestamp 3 (Chrome 2).
- var gmd3 = addGlobalMemoryDump(model, 20, DETAILED);
- var pmdBrowser3 = addProcessMemoryDump(gmd3, pChrome2, 20);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 20, levelOfDetail: DETAILED});
+ var pmdBrowser3 = addProcessMemoryDump(gmd3, pChrome2, {ts: 20});
pmdBrowser3.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser3, 'malloc', { size: 64 }),
- newAllocatorDump(pmdBrowser3, 'sqlite', { size: 128 }),
- newAllocatorDump(pmdBrowser3, 'discardable', {
+ newAllocatorDump(pmdBrowser3, 'malloc', {numerics: {size: 64}}),
+ newAllocatorDump(pmdBrowser3, 'sqlite', {numerics: {size: 128}}),
+ newAllocatorDump(pmdBrowser3, 'discardable', {numerics: {
size: 8388608,
locked_size: 4194304
- })
+ }})
];
pmdBrowser3.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 99, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 256 })
+ {privateDirtyResident: 256})
]);
// Timestamp 4 (Chrome 2 + Renderer).
- var gmd4 = addGlobalMemoryDump(model, 30, LIGHT);
- var pmdBrowser4 = addProcessMemoryDump(gmd4, pChrome2, 28);
+ var gmd4 = addGlobalMemoryDump(model, {ts: 30, levelOfDetail: LIGHT});
+ var pmdBrowser4 = addProcessMemoryDump(gmd4, pChrome2, {ts: 28});
pmdBrowser4.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser4, 'malloc', { size: 512 }),
- newAllocatorDump(pmdBrowser3, 'discardable', { size: 16777216 })
+ newAllocatorDump(pmdBrowser4, 'malloc', {numerics: {size: 512}}),
+ newAllocatorDump(pmdBrowser3, 'discardable', {numerics: {size: 16777216}})
];
- var pmdRenderer4 = addProcessMemoryDump(gmd4, pRenderer2, 32);
+ var pmdRenderer4 = addProcessMemoryDump(gmd4, pRenderer2, {ts: 32});
pmdRenderer4.memoryAllocatorDumps = [
- newAllocatorDump(pmdRenderer4, 'malloc', { size: 1024 }),
- newAllocatorDump(pmdRenderer4, 'v8', { size: 2048 })
+ newAllocatorDump(pmdRenderer4, 'malloc', {numerics: {size: 1024}}),
+ newAllocatorDump(pmdRenderer4, 'v8', {numerics: {size: 2048}})
];
// Timestamp 5 (Unknown browser).
- var gmd5 = addGlobalMemoryDump(model, 40, LIGHT);
- var pmdBrowser5 = addProcessMemoryDump(gmd5, pUnknownBrowser, 40);
+ var gmd5 = addGlobalMemoryDump(model, {ts: 40, levelOfDetail: LIGHT});
+ var pmdBrowser5 = addProcessMemoryDump(gmd5, pUnknownBrowser, {ts: 40});
pmdBrowser5.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser5, 'malloc', { size: 4096 }),
- newAllocatorDump(pmdBrowser5, 'sqlite', { size: 8192 }),
+ newAllocatorDump(pmdBrowser5, 'malloc', {numerics: {size: 4096}}),
+ newAllocatorDump(pmdBrowser5, 'sqlite', {numerics: {size: 8192}}),
];
// Timestamp 6 (WebView).
- var gmd6 = addGlobalMemoryDump(model, 50, DETAILED);
- var pmdBrowser6 = addProcessMemoryDump(gmd6, pWebView, 50);
- pmdBrowser6.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser6, 'malloc', { size: 16384 }),
- newAllocatorDump(pmdBrowser6, 'v8', {
- 'allocated_objects_size': 32768,
- 'code_and_metadata_size': 33554432,
- 'size': 67108864
- })
- ];
+ var gmd6 = addGlobalMemoryDump(model, {ts: 50, levelOfDetail: DETAILED});
+ var pmdBrowser6 = addProcessMemoryDump(gmd6, pWebView, {ts: 50});
+ pmdBrowser6.memoryAllocatorDumps = (function() {
+ var mallocDump = newAllocatorDump(pmdBrowser6, 'malloc',
+ {numerics: {size: 16384}});
+ var v8Dump = newAllocatorDump(pmdBrowser6, 'v8', {numerics: {
+ allocated_objects_size: 32768,
+ code_and_metadata_size: 33554432,
+ size: 67108864
+ }});
+ var isolateDump = addChildDump(v8Dump, 'isolate');
+ addChildDump(isolateDump, 'malloc', {numerics: {
+ size: 1,
+ peak_size: 2
+ }});
+ return [mallocDump, v8Dump];
+ })();
pmdBrowser6.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 99999, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 65536 })
+ {privateDirtyResident: 65536})
]);
// Timestamp 7 (Chrome 1 + GPU Process).
- var gmd7 = addGlobalMemoryDump(model, 60, DETAILED);
- var pmdBrowser7 = addProcessMemoryDump(gmd7, pChrome1, 63);
+ var gmd7 = addGlobalMemoryDump(model, {ts: 60, levelOfDetail: DETAILED});
+ var pmdBrowser7 = addProcessMemoryDump(gmd7, pChrome1, {ts: 63});
pmdBrowser7.memoryAllocatorDumps = [
- newAllocatorDump(pmdBrowser4, 'malloc', { size: 131072 }),
- newAllocatorDump(pmdBrowser4, 'sqlite', { size: 262144 })
+ newAllocatorDump(pmdBrowser4, 'malloc', {numerics: {size: 131072}}),
+ newAllocatorDump(pmdBrowser4, 'sqlite', {numerics: {size: 262144}})
];
pmdBrowser7.vmRegions = VMRegionClassificationNode.fromRegions([
new VMRegion(0xABCD, 999999, 0, '/dev/ashmem/dalvik-non moving space',
- { 'privateDirtyResident': 524288 })
+ {privateDirtyResident: 524288})
]);
- var pmdGpu7 = addProcessMemoryDump(gmd7, pGpu1, 57);
+ var pmdGpu7 = addProcessMemoryDump(gmd7, pGpu1, {ts: 57});
pmdGpu7.memoryAllocatorDumps = (function() {
- var gpuDump = newAllocatorDump(pmdGpu7, 'gpu', { 'size': 1048576 });
+ var gpuDump = newAllocatorDump(pmdGpu7, 'gpu',
+ {numerics: {size: 1048576}});
var memtrackDump = addChildDump(gpuDump, 'android_memtrack');
- addChildDump(memtrackDump, 'gl', { 'memtrack_pss': 2097152 });
+ addChildDump(memtrackDump, 'gl', {numerics: {memtrack_pss: 2097152}});
return [gpuDump];
})();
- }, {
+
+ // Timestamp 8 (Chrome 1).
+ var gmd8 = addGlobalMemoryDump(model, {ts: 76, levelOfDetail: BACKGROUND});
+ var pmdBrowser8 = addProcessMemoryDump(gmd8, pChrome1, {ts: 80});
+ pmdBrowser8.memoryAllocatorDumps = [
+ newAllocatorDump(pmdBrowser5, 'malloc', {numerics: {size: 1024}}),
+ newAllocatorDump(pmdBrowser5, 'sqlite', {numerics: {size: 2048}}),
+ ];
+
+ // Timestamp 9 (WebView).
+ var gmd9 = addGlobalMemoryDump(model, {ts: 90, levelOfDetail: BACKGROUND});
+ var pmdBrowser9 = addProcessMemoryDump(gmd9, pWebView, {ts: 90});
+ pmdBrowser9.memoryAllocatorDumps = [
+ newAllocatorDump(pmdBrowser5, 'v8', {numerics: {size: 4096}}),
+ newAllocatorDump(pmdBrowser5, 'sqlite', {numerics: {size: 2048}}),
+ ];
+ }, undefined /* opt_options */, {
// WebView (GMD1, GMD6).
'memory:webview:all_processes:dump_count:detailed': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by WebView ' +
'to the trace'
},
'memory:webview:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by WebView to ' +
'the trace'
},
+ 'memory:webview:all_processes:dump_count:background': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by WebView ' +
+ 'to the trace'
+ },
'memory:webview:all_processes:dump_count': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [3],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by WebView to the ' +
'trace'
},
'memory:webview:all_processes:process_count': {
- value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ value: [1, 1, 1],
+ unit: count_smallerIsBetter,
description: 'total number of all processes in WebView'
},
'memory:webview:all_processes:reported_by_chrome:effective_size': {
- value: [4 + 2, 16384 + 67108864],
+ value: [4 + 2, 16384 + 67108864, 4096 + 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for all ' +
'processes in WebView'
},
'memory:webview:all_processes:reported_by_chrome:code_and_metadata_size': {
- value: [33554432],
+ value: [0, 33554432, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of code and metadata reported by Chrome for ' +
'all processes in WebView'
},
'memory:webview:all_processes:reported_by_chrome:allocated_objects_size': {
- value: [0, 32768],
+ value: [0, 32768, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of all allocated objects reported by Chrome ' +
'for all processes in WebView'
},
+ 'memory:webview:all_processes:reported_by_chrome:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak size reported by Chrome for all ' +
+ 'processes in WebView'
+ },
'memory:webview:all_processes:reported_by_chrome:malloc:effective_size': {
- value: [2, 16384],
+ value: [2, 16384, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of malloc in all processes in WebView'
},
+ 'memory:webview:all_processes:reported_by_chrome:sqlite:effective_size': {
+ value: [0, 2048, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of sqlite in all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_chrome:v8:allocated_by_malloc:effective_size':
+ {
+ value: [0, 1, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of objects allocated by malloc for v8 ' +
+ 'in all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_chrome:v8:allocated_by_malloc:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of objects allocated by malloc for v8 ' +
+ 'in all processes in WebView'
+ },
'memory:webview:all_processes:reported_by_chrome:v8:effective_size': {
- value: [4, 67108864],
+ value: [4, 67108864, 4096],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of v8 in all processes in WebView'
},
'memory:webview:all_processes:reported_by_chrome:v8:code_and_metadata_size':
{
- value: [33554432],
+ value: [0, 33554432, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of v8 code and metadata in all processes in ' +
'WebView'
},
'memory:webview:all_processes:reported_by_chrome:v8:allocated_objects_size':
{
- value: [0, 32768],
+ value: [0, 32768, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by v8 in all processes ' +
'in WebView'
},
+ 'memory:webview:all_processes:reported_by_chrome:v8:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of v8 in all processes in WebView'
+ },
'memory:webview:all_processes:reported_by_os:private_dirty_size': {
value: [65536],
unit: sizeInBytes_smallerIsBetter,
@@ -1595,54 +2064,86 @@ tr.b.unittest.testSuite(function() {
'memory (RAM) used by all processes in WebView'
},
'memory:webview:browser_process:process_count': {
- value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ value: [1, 1, 1],
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in WebView'
},
'memory:webview:browser_process:reported_by_chrome:effective_size': {
- value: [4 + 2, 16384 + 67108864],
+ value: [4 + 2, 16384 + 67108864, 4096 + 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for the browser ' +
'process in WebView'
},
'memory:webview:browser_process:reported_by_chrome:allocated_objects_size':
{
- value: [0, 32768],
+ value: [0, 32768, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of all allocated objects reported by ' +
'Chrome for the browser process in WebView'
},
'memory:webview:browser_process:reported_by_chrome:code_and_metadata_size':
{
- value: [33554432],
+ value: [0, 33554432, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total size of code and metadata reported by Chrome ' +
'for the browser process in WebView'
},
+ 'memory:webview:browser_process:reported_by_chrome:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total peak size reported by Chrome ' +
+ 'for the browser process in WebView'
+ },
'memory:webview:browser_process:reported_by_chrome:malloc:effective_size': {
- value: [2, 16384],
+ value: [2, 16384, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of malloc in the browser process in WebView'
},
+ 'memory:webview:browser_process:reported_by_chrome:v8:allocated_by_malloc:effective_size':
+ {
+ value: [0, 1, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of objects allocated by malloc for v8 ' +
+ 'in the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_chrome:v8:allocated_by_malloc:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of objects allocated by malloc for v8 ' +
+ 'in the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_chrome:sqlite:effective_size': {
+ value: [0, 0, 2048],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'effective size of sqlite in the browser process in WebView'
+ },
'memory:webview:browser_process:reported_by_chrome:v8:effective_size': {
- value: [4, 67108864],
+ value: [4, 67108864, 4096],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of v8 in the browser process in WebView'
},
'memory:webview:browser_process:reported_by_chrome:v8:allocated_objects_size':
{
- value: [0, 32768],
+ value: [0, 32768, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of all objects allocated by v8 in the browser ' +
'process in WebView'
},
'memory:webview:browser_process:reported_by_chrome:v8:code_and_metadata_size':
{
- value: [33554432],
+ value: [0, 33554432, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'size of v8 code and metadata in the browser process ' +
'in WebView'
},
+ 'memory:webview:browser_process:reported_by_chrome:v8:peak_size':
+ {
+ value: [0, 2, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'peak size of v8 in the browser process in WebView'
+ },
'memory:webview:browser_process:reported_by_os:private_dirty_size': {
value: [65536],
unit: sizeInBytes_smallerIsBetter,
@@ -1722,46 +2223,52 @@ tr.b.unittest.testSuite(function() {
'memtrack component in all processes in Chrome'
},
'memory:chrome:all_processes:dump_count:detailed': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome to ' +
'the trace'
},
'memory:chrome:all_processes:dump_count:light': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome to ' +
'the trace'
},
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
'memory:chrome:all_processes:dump_count': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [3],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome to the ' +
'trace'
},
'memory:chrome:all_processes:process_count': {
- value: [3, 2],
- unit: unitlessNumber_smallerIsBetter,
+ value: [3, 2, 1],
+ unit: count_smallerIsBetter,
description: 'total number of all processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:effective_size': {
- value: [32, 1048576 + 131072 + 262144],
+ value: [32, 1048576 + 131072 + 262144, 1024 + 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for all ' +
'processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:gpu:effective_size': {
- value: [0, 1048576],
+ value: [0, 1048576, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of gpu in all processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:malloc:effective_size': {
- value: [32, 131072],
+ value: [32, 131072, 1024],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of malloc in all processes in Chrome'
},
'memory:chrome:all_processes:reported_by_chrome:sqlite:effective_size': {
- value: [0, 262144],
+ value: [0, 262144, 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of sqlite in all processes in Chrome'
},
@@ -1840,23 +2347,23 @@ tr.b.unittest.testSuite(function() {
'memory (RAM) used by all processes in Chrome'
},
'memory:chrome:browser_process:process_count': {
- value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ value: [1, 1, 1],
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:effective_size': {
- value: [0, 131072 + 262144],
+ value: [0, 131072 + 262144, 1024 + 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for the browser ' +
'process in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:malloc:effective_size': {
- value: [0, 131072],
+ value: [0, 131072, 1024],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of malloc in the browser process in Chrome'
},
'memory:chrome:browser_process:reported_by_chrome:sqlite:effective_size': {
- value: [0, 262144],
+ value: [0, 262144, 2048],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of sqlite in the browser process in Chrome'
},
@@ -1929,7 +2436,7 @@ tr.b.unittest.testSuite(function() {
'memory (RAM) used by the browser process in Chrome'
},
'memory:chrome:gpu_process:reported_by_chrome:effective_size': {
- value: [0, 1048576],
+ value: [0, 1048576, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for the GPU ' +
'process in Chrome'
@@ -1949,12 +2456,12 @@ tr.b.unittest.testSuite(function() {
'memtrack component in the GPU process in Chrome'
},
'memory:chrome:gpu_process:process_count': {
- value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ value: [1, 1, 0],
+ unit: count_smallerIsBetter,
description: 'total number of GPU processes in Chrome'
},
'memory:chrome:gpu_process:reported_by_chrome:gpu:effective_size': {
- value: [0, 1048576],
+ value: [0, 1048576, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of gpu in the GPU process in Chrome'
},
@@ -2027,19 +2534,19 @@ tr.b.unittest.testSuite(function() {
'memory (RAM) used by the GPU process in Chrome'
},
'memory:chrome:renderer_processes:process_count': {
- value: [1, 0],
- unit: unitlessNumber_smallerIsBetter,
+ value: [1, 0, 0],
+ unit: count_smallerIsBetter,
description: 'total number of renderer processes in Chrome'
},
'memory:chrome:renderer_processes:reported_by_chrome:effective_size': {
- value: [32, 0],
+ value: [32, 0, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'total effective size reported by Chrome for renderer ' +
'processes in Chrome'
},
'memory:chrome:renderer_processes:reported_by_chrome:malloc:effective_size':
{
- value: [32, 0],
+ value: [32, 0, 0],
unit: sizeInBytes_smallerIsBetter,
description: 'effective size of malloc in renderer processes in ' +
'Chrome'
@@ -2116,26 +2623,32 @@ tr.b.unittest.testSuite(function() {
// Chrome 2 (GMD2, GMD7).
'memory:chrome2:all_processes:dump_count:detailed': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by Chrome(2) ' +
'to the trace'
},
'memory:chrome2:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by Chrome(2) to ' +
'the trace'
},
+ 'memory:chrome2:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by ' +
+ 'Chrome(2) to the trace'
+ },
'memory:chrome2:all_processes:dump_count': {
- value: 2,
- unit: unitlessNumber_smallerIsBetter,
+ value: [2],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by Chrome(2) to ' +
'the trace'
},
'memory:chrome2:all_processes:process_count': {
value: [1, 2],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of all processes in Chrome(2)'
},
'memory:chrome2:all_processes:reported_by_chrome:discardable:effective_size':
@@ -2248,7 +2761,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome2:browser_process:process_count': {
value: [1, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in Chrome(2)'
},
'memory:chrome2:browser_process:reported_by_chrome:effective_size': {
@@ -2360,7 +2873,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:chrome2:renderer_processes:process_count': {
value: [0, 1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of renderer processes in Chrome(2)'
},
'memory:chrome2:renderer_processes:reported_by_chrome:effective_size': {
@@ -2384,26 +2897,32 @@ tr.b.unittest.testSuite(function() {
// Unknown browser (GMD5).
'memory:unknown_browser:all_processes:dump_count:detailed': {
- value: 0,
- unit: unitlessNumber_smallerIsBetter,
+ value: [0],
+ unit: count_smallerIsBetter,
description: 'total number of detailed memory dumps added by an ' +
'unknown browser to the trace'
},
'memory:unknown_browser:all_processes:dump_count:light': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of light memory dumps added by an unknown ' +
'browser to the trace'
},
+ 'memory:unknown_browser:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by an ' +
+ 'unknown browser to the trace'
+ },
'memory:unknown_browser:all_processes:dump_count': {
- value: 1,
- unit: unitlessNumber_smallerIsBetter,
+ value: [1],
+ unit: count_smallerIsBetter,
description: 'total number of all memory dumps added by an unknown ' +
'browser to the trace'
},
'memory:unknown_browser:all_processes:process_count': {
value: [1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of all processes in an unknown browser'
},
'memory:unknown_browser:all_processes:reported_by_chrome:effective_size': {
@@ -2428,7 +2947,7 @@ tr.b.unittest.testSuite(function() {
},
'memory:unknown_browser:browser_process:process_count': {
value: [1],
- unit: unitlessNumber_smallerIsBetter,
+ unit: count_smallerIsBetter,
description: 'total number of browser processes in an unknown browser'
},
'memory:unknown_browser:browser_process:reported_by_chrome:effective_size':
@@ -2454,14 +2973,283 @@ tr.b.unittest.testSuite(function() {
}
});
+ memoryMetricTest('rangeOfInterest', function(model) {
+ var pChrome = createChromeBrowserProcess(model);
+ var pWebView = createWebViewProcess(model);
+
+ // Chrome: only the LIGHT dumps should be kept.
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 5, duration: 4, levelOfDetail: DETAILED}), pChrome);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 10, duration: 2, levelOfDetail: LIGHT}), pChrome);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 13, duration: 3, levelOfDetail: LIGHT}), pChrome);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 20, duration: 1, levelOfDetail: BACKGROUND}), pChrome);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 22, duration: 5, levelOfDetail: DETAILED}), pChrome);
+
+ // WebView: only the DETAILED dumps should be kept.
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 4, duration: 1, levelOfDetail: LIGHT}), pWebView);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 5, duration: 5, levelOfDetail: DETAILED}), pWebView);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 10, duration: 0, levelOfDetail: DETAILED}), pWebView);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 11, duration: 7, levelOfDetail: BACKGROUND}), pWebView);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 19, duration: 2, levelOfDetail: DETAILED}), pWebView);
+ addProcessMemoryDump(addGlobalMemoryDump(
+ model, {ts: 21, duration: 5, levelOfDetail: LIGHT}), pWebView);
+
+ // Unknown browser: only the LIGHT dump should be kept.
+ addGlobalMemoryDump(model, {ts: 5, duration: 3, levelOfDetail: DETAILED});
+ addGlobalMemoryDump(model, {ts: 9, duration: 12, levelOfDetail: LIGHT});
+ addGlobalMemoryDump(model, {ts: 22, duration: 3, levelOfDetail: DETAILED});
+ }, { /* opt_options */
+ rangeOfInterest: tr.b.Range.fromExplicitRange(10, 20)
+ }, {
+ 'memory:chrome:all_processes:dump_count': {
+ value: [3],
+ unit: count_smallerIsBetter,
+ description: 'total number of all memory dumps added by Chrome to the ' +
+ 'trace'
+ },
+ 'memory:chrome:all_processes:dump_count:detailed': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of detailed memory dumps added by Chrome to ' +
+ 'the trace'
+ },
+ 'memory:chrome:all_processes:dump_count:light': {
+ value: [2],
+ unit: count_smallerIsBetter,
+ description: 'total number of light memory dumps added by Chrome to ' +
+ 'the trace'
+ },
+ 'memory:chrome:all_processes:dump_count:background': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by Chrome ' +
+ 'to the trace'
+ },
+ 'memory:chrome:all_processes:process_count': {
+ value: [1, 1, 1],
+ unit: count_smallerIsBetter,
+ description: 'total number of all processes in Chrome'
+ },
+ 'memory:chrome:browser_process:process_count': {
+ value: [1, 1, 1],
+ unit: count_smallerIsBetter,
+ description: 'total number of browser processes in Chrome'
+ },
+
+ 'memory:webview:all_processes:dump_count': {
+ value: [4],
+ unit: count_smallerIsBetter,
+ description: 'total number of all memory dumps added by WebView to the ' +
+ 'trace'
+ },
+ 'memory:webview:all_processes:dump_count:detailed': {
+ value: [3],
+ unit: count_smallerIsBetter,
+ description: 'total number of detailed memory dumps added by WebView ' +
+ 'to the trace'
+ },
+ 'memory:webview:all_processes:dump_count:light': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of light memory dumps added by WebView to ' +
+ 'the trace'
+ },
+ 'memory:webview:all_processes:dump_count:background': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by WebView ' +
+ 'to the trace'
+ },
+ 'memory:webview:all_processes:process_count': {
+ value: [1, 1, 1, 1],
+ unit: count_smallerIsBetter,
+ description: 'total number of all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:private_dirty_size': {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total private dirty size reported by the OS for all ' +
+ 'processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:proportional_resident_size': {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total proportional resident size (PSS) reported by the ' +
+ 'OS for all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:ashmem:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of ashmem in all processes in ' +
+ 'WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:ashmem:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of ashmem in all ' +
+ 'processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:java_heap:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of the Java heap in all processes ' +
+ 'in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:java_heap:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of the Java heap in ' +
+ 'all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:native_heap:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of the native heap in all ' +
+ 'processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:native_heap:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of the native heap ' +
+ 'in all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total private dirty size of system memory (RAM) used ' +
+ 'by all processes in WebView'
+ },
+ 'memory:webview:all_processes:reported_by_os:system_memory:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total proportional resident size (PSS) of system ' +
+ 'memory (RAM) used by all processes in WebView'
+ },
+ 'memory:webview:browser_process:process_count': {
+ value: [1, 1, 1, 1],
+ unit: count_smallerIsBetter,
+ description: 'total number of browser processes in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:private_dirty_size': {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total private dirty size reported by the OS for the ' +
+ 'browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total proportional resident size (PSS) reported by ' +
+ 'the OS for the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:ashmem:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of ashmem in the browser process ' +
+ 'in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:ashmem:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of ashmem in the ' +
+ 'browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:java_heap:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of the Java heap in the browser ' +
+ 'process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:java_heap:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of the Java heap in ' +
+ 'the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:native_heap:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'private dirty size of the native heap in the browser ' +
+ 'process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:native_heap:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'proportional resident size (PSS) of the native heap ' +
+ 'in the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:private_dirty_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total private dirty size of system memory (RAM) used ' +
+ 'by the browser process in WebView'
+ },
+ 'memory:webview:browser_process:reported_by_os:system_memory:proportional_resident_size':
+ {
+ value: [0, 0, 0],
+ unit: sizeInBytes_smallerIsBetter,
+ description: 'total proportional resident size (PSS) of system ' +
+ 'memory (RAM) used by the browser process in WebView'
+ },
+ 'memory:unknown_browser:all_processes:dump_count': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of all memory dumps added by an unknown ' +
+ 'browser to the trace'
+ },
+ 'memory:unknown_browser:all_processes:dump_count:detailed': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of detailed memory dumps added by an ' +
+ 'unknown browser to the trace'
+ },
+ 'memory:unknown_browser:all_processes:dump_count:light': {
+ value: [1],
+ unit: count_smallerIsBetter,
+ description: 'total number of light memory dumps added by an unknown ' +
+ 'browser to the trace'
+ },
+ 'memory:unknown_browser:all_processes:dump_count:background': {
+ value: [0],
+ unit: count_smallerIsBetter,
+ description: 'total number of background memory dumps added by an ' +
+ 'unknown browser to the trace'
+ }
+ });
+
test('dumpIdBrowserClashThrows', function() {
var model = tr.c.TestUtils.newModel(function(model) {
var pWebView = createWebViewProcess(model);
var pChrome = createChromeBrowserProcess(model);
- var gmd = addGlobalMemoryDump(model, 10);
- addProcessMemoryDump(gmd, pWebView, 9);
- addProcessMemoryDump(gmd, pChrome, 11);
+ var gmd = addGlobalMemoryDump(model, {ts: 10});
+ addProcessMemoryDump(gmd, pWebView, {ts: 9});
+ addProcessMemoryDump(gmd, pChrome, {ts: 11});
});
var values = new tr.v.ValueSet();
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric.html
index eec9635a5a5..e61a491f30c 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric.html
@@ -6,46 +6,282 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/importer/find_input_expectations.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/metrics/system_health/clock_sync_latency_metric.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/metrics/system_health/loading_metric.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.sh', function() {
- var IDEAL_FRAME_RATE = 60;
- var IDEAL_FRAME_DURATION = 1000 / IDEAL_FRAME_RATE;
-
- function energyConsumedPerFrame(valueList, model) {
- var frameEnergyConsumed = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.energyInJoules_smallerIsBetter,
- tr.b.Range.fromExplicitRange(0, .5), 20).build();
- var frameStartTs = parseFloat(model.device.powerSeries.samples[0].start);
- while (model.device.powerSeries.getSamplesWithinRange(
- frameStartTs, frameStartTs + IDEAL_FRAME_DURATION).length) {
- var currentFrameEnergy = model.device.powerSeries.getEnergyConsumed(
- frameStartTs, frameStartTs + IDEAL_FRAME_DURATION);
- frameStartTs += IDEAL_FRAME_DURATION;
- frameEnergyConsumed.add(currentFrameEnergy);
+ // TODO(alexandermont): Per-frame power metric will be deprecated once
+ // newer metrics come online.
+ // Frame rate, used to divide power sample interval into frames
+ // for purposes of per-frame power metric.
+ var FRAMES_PER_SEC = 60;
+ var FRAME_MS = tr.b.convertUnit(1.0 / FRAMES_PER_SEC,
+ tr.b.UnitScale.Metric.NONE, tr.b.UnitScale.Metric.MILLI);
+
+ /**
+ * Returns power data for the specified interval in the form:
+ * {
+ * duration: durationInMs,
+ * energy: energyInJ,
+ * power: powerInW
+ * }
+ */
+ function getPowerData_(model, start, end) {
+ var durationInMs = end - start;
+ var durationInS = tr.b.convertUnit(durationInMs,
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
+ var energyInJ = model.device.powerSeries.getEnergyConsumedInJ(start, end);
+ var powerInW = energyInJ / durationInS;
+ return {duration: durationInMs, energy: energyInJ, power: powerInW};
+ }
+
+ // TODO(alexandermont): When LoadExpectation v1.0 is released,
+ // update this function to use the new LoadExpectation rather
+ // than calling loading_metric.html. If we set the end of the loading
+ // RAIL stage to be the TTI, then we may not even need to treat the loading
+ // events separately; we can just treat them like any other RAIL stage
+ // (and the RAIL stage boundaries will be the intervals that we want.)
+ /**
+ * Returns the intervals of time between navigation event and time to
+ * interactive.
+ */
+ function getNavigationTTIIntervals_(model) {
+ var values = new tr.v.ValueSet();
+ tr.metrics.sh.loadingMetric(values, model);
+ var ttiValues = values.getValuesNamed('timeToFirstInteractive');
+ var intervals = [];
+ for (var bin of tr.b.getOnlyElement(ttiValues).allBins) {
+ for (var diagnostics of bin.diagnosticMaps) {
+ var breakdown = diagnostics.get('Navigation infos');
+ intervals.push(tr.b.Range.fromExplicitRange(
+ breakdown.value.start, breakdown.value.interactive));
+ }
+ }
+ return intervals.sort((x, y) => x.min - y.min);
+ }
+
+ /**
+ * Creates a histogram suitable for time data.
+ */
+ function makeTimeHistogram_(values, title, description) {
+ var hist = new tr.v.Histogram(title + ':time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter);
+ hist.customizeSummaryOptions({
+ avg: false,
+ count: false,
+ max: true,
+ min: true,
+ std: false,
+ sum: true,
+ });
+ hist.description = 'Time spent in ' + description;
+ values.addHistogram(hist);
+ return hist;
+ }
+
+ /**
+ * Creates a histogram suitable for energy data.
+ */
+ function makeEnergyHistogram_(values, title, description) {
+ var hist = new tr.v.Histogram(title + ':energy',
+ tr.b.Unit.byName.energyInJoules_smallerIsBetter);
+ hist.customizeSummaryOptions({
+ avg: false,
+ count: false,
+ max: true,
+ min: true,
+ std: false,
+ sum: true,
+ });
+ hist.description = 'Energy consumed in ' + description;
+ values.addHistogram(hist);
+ return hist;
+ }
+
+ /**
+ * Creates a histogram suitable for power data.
+ */
+ function makePowerHistogram_(values, title, description) {
+ var hist = new tr.v.Histogram(title + ':power',
+ tr.b.Unit.byName.powerInWatts_smallerIsBetter);
+ hist.customizeSummaryOptions({
+ avg: true,
+ count: false,
+ max: true,
+ min: true,
+ std: false,
+ sum: false,
+ });
+ hist.description = 'Energy consumption rate in ' + description;
+ values.addHistogram(hist);
+ return hist;
+ }
+
+ /**
+ * Stores the power data in data into the given histograms for time, energy,
+ * and power. If a histogram is undefined then the corresponding type of
+ * data is not stored.
+ *
+ * @param {!Object} data - Power data (obtained from getPowerData_)
+ * @param {tr.v.Histogram} timeHist - Histogram to store time data.
+ * @param {tr.v.Histogram} energyHist - Histogram to store energy data.
+ * @param {tr.v.Histogram} powerHist - Histogram to store power data.
+ */
+ function storePowerData_(data, timeHist, energyHist, powerHist) {
+ if (timeHist !== undefined)
+ timeHist.addSample(data.duration);
+ if (energyHist !== undefined)
+ energyHist.addSample(data.energy);
+ if (powerHist !== undefined)
+ powerHist.addSample(data.power);
+ }
+
+ function createHistograms_(model, values) {
+ var hists = {};
+
+ // "Generic" RAIL stage metrics. These give time, energy, and power
+ // for each RAIL stage, indexed by name. For instance, "Tap Animation"
+ // is different from "Tap, Touch Animation". There is one histogram
+ // for each RAIL stage name; if there are multiple RAIL stages with
+ // the same name, these are different samples in the histogram.
+ hists.railStageToTimeHist = new Map();
+ hists.railStageToEnergyHist = new Map();
+ hists.railStageToPowerHist = new Map();
+
+ // Metrics for scrolling. A scroll stage is any stage with the
+ // string "Scroll" in its name. For instance, "Scroll Response",
+ // "Scroll Animation", and "Scroll, Touch Animation" are all
+ // scroll stages. Histograms for scroll metrics contain one
+ // sample for each scroll stage.
+ hists.scrollTimeHist = makeTimeHistogram_(values, 'scroll','scrolling');
+ hists.scrollEnergyHist = makeEnergyHistogram_(values, 'scroll','scrolling');
+ hists.scrollPowerHist = makePowerHistogram_(values, 'scroll','scrolling');
+
+ // Metrics for loading. Loading intervals are defined by the intervals
+ // between navigation and TTI (time-to-interactive) given by
+ // getNavigationTTIIntervals_. We also have a metric for the energy
+ // consumed after load.
+ hists.loadTimeHist = makeTimeHistogram_(values, 'load', 'page loads');
+ hists.loadEnergyHist = makeEnergyHistogram_(values, 'load', 'page loads');
+ hists.afterLoadTimeHist = makeTimeHistogram_(values, 'after_load',
+ 'period after load');
+ hists.afterLoadPowerHist = makePowerHistogram_(values, 'after_load',
+ 'period after load');
+
+ // Metrics for video. A video stage is any stage with the string "Video"
+ // in its name. Histograms for video metrics contain one sample for each
+ // video stage. Only power metrics are available for video stages.
+ hists.videoPowerHist = makePowerHistogram_(values, 'video',
+ 'video playback')
+
+ // Frame based power metric.
+ hists.frameEnergyHist = makeEnergyHistogram_(values, 'per_frame',
+ 'each frame');
+
+ for (var exp of model.userModel.expectations) {
+ var currTitle = exp.title.toLowerCase().replace(' ', '_');
+ // If we haven't seen a RAIL stage with this title before,
+ // we have to create a new set of histograms for the "generic"
+ // RAIL stage metrics.
+ if (!hists.railStageToTimeHist.has(currTitle)) {
+ var timeHist = makeTimeHistogram_(values, currTitle,
+ 'RAIL stage ' + currTitle);
+
+ var energyHist = makeEnergyHistogram_(values, currTitle,
+ 'RAIL stage ' + currTitle);
+
+ var powerHist = makePowerHistogram_(values, currTitle,
+ 'RAIL stage ' + currTitle);
+
+ hists.railStageToTimeHist.set(currTitle, timeHist);
+ hists.railStageToEnergyHist.set(currTitle, energyHist);
+ hists.railStageToPowerHist.set(currTitle, powerHist);
+ }
+ }
+ return hists;
+ }
+
+ /**
+ * Process a single interaction record (RAIL stage) for power metric
+ * purposes. This function only keeps track of metrics that are based
+ * on the start and end time of the RAIL stages.
+ */
+ function processInteractionRecord_(exp, model, hists) {
+ var currTitle = exp.title.toLowerCase().replace(' ', '_');
+ var data = getPowerData_(model, exp.start, exp.end);
+
+ // Add the samples for the "generic" RAIL stage metrics.
+ storePowerData_(data, hists.railStageToTimeHist.get(currTitle),
+ hists.railStageToEnergyHist.get(currTitle),
+ hists.railStageToPowerHist.get(currTitle));
+
+ // If this is a scroll stage, add the sample for the scroll metrics.
+ // TODO(alexandermont): Treat scroll responses different from
+ // scroll animations?
+ if (exp.initiatorType === tr.importer.INITIATOR_TYPE.SCROLL) {
+ storePowerData_(data, hists.scrollTimeHist,
+ hists.scrollEnergyHist, hists.scrollPowerHist);
}
- valueList.addValue(new tr.v.NumericValue(
- 'energy_consumed_per_frame', frameEnergyConsumed,
- {description: 'Energy consumption per frame in joules'}));
+ // If this is a video stage, add the sample for the video metrics.
+ if (exp.initiatorType === tr.importer.INITIATOR_TYPE.VIDEO)
+ storePowerData_(data, undefined, undefined, hists.videoPowerHist)
}
- function powerMetric(valueList, model) {
- // TODO(alexandermont): Once it's possible to specify multiple metrics
- // in a Telemetry benchmark, separate out this metric from the power
- // metric and have the benchmark use both.
- // (See: https://github.com/catapult-project/catapult/issues/2430.)
- tr.metrics.sh.clockSyncLatencyMetric(valueList, model);
+ /**
+ * Compute the loading power metric from the model and put the results
+ * in |hists|. Note that this is not in processInteractionRecord_ because
+ * the loading metric intervals don't correspond exactly to the RAIL stages.
+ */
+ function computeLoadingMetric_(model, hists) {
+ var intervals = getNavigationTTIIntervals_(model);
+ var lastLoadTime = undefined;
+ for (var interval of intervals) {
+ var loadData = getPowerData_(model, interval.min, interval.max);
+ storePowerData_(loadData, hists.loadTimeHist, hists.loadEnergyHist,
+ undefined);
+ lastLoadTime = (lastLoadTime === undefined ? interval.max :
+ Math.max(lastLoadTime, interval.max));
+ }
+ if (lastLoadTime !== undefined) {
+ var afterLoadData = getPowerData_(model, lastLoadTime, model.bounds.max);
+ storePowerData_(afterLoadData, hists.afterLoadTimeHist,
+ undefined, hists.afterLoadPowerHist);
+ }
+ }
+
+ /**
+ * Compute the per-frame power metrics and put the results in |hists|.
+ */
+ function computeFrameBasedPowerMetric_(model, hists) {
+ model.device.powerSeries.updateBounds();
+ var currentTime = model.device.powerSeries.bounds.min;
+ while (currentTime < model.device.powerSeries.bounds.max) {
+ var frameData = getPowerData_(model, currentTime, currentTime + FRAME_MS);
+ hists.frameEnergyHist.addSample(frameData.energy);
+ currentTime += FRAME_MS;
+ }
+ }
+
+
+ function powerMetric(values, model) {
if (!model.device.powerSeries)
return;
- energyConsumedPerFrame(valueList, model);
+
+ var hists = createHistograms_(model, values);
+ for (var exp of model.userModel.expectations)
+ processInteractionRecord_(exp, model, hists);
+
+ // The following two metrics aren't based directly on the IR intervals,
+ // and so need to be computed outside the processInteractionRecord_ loop.
+ computeLoadingMetric_(model, hists);
+ computeFrameBasedPowerMetric_(model, hists);
}
tr.metrics.MetricRegistry.register(powerMetric);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric_test.html
index bdc034e63a7..d89937a3bd7 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/power_metric_test.html
@@ -6,16 +6,323 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/importer/find_input_expectations.html">
<link rel="import" href="/tracing/metrics/system_health/power_metric.html">
+<link rel="import" href="/tracing/model/user_model/idle_expectation.html">
+<link rel="import" href="/tracing/model/user_model/load_expectation.html">
<link rel="import" href="/tracing/value/value_set.html">
<script>
'use strict';
+function getMetricValueCount(values, name) {
+ for (var value of values)
+ if (value.name === name)
+ return value.numValues;
+}
+
+function getMetricValueSum(values, name) {
+ for (var value of values)
+ if (value.name === name)
+ return value.sum;
+}
+
+function getMetricValueAvg(values, name) {
+ for (var value of values)
+ if (value.name === name)
+ return value.average;
+}
+
tr.b.unittest.testSuite(function() {
- test('powerMetric_multipleFrames', function() {
+ test('powerMetric_noPowerSeries', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ tr.metrics.sh.powerMetric(valueSet, model);
+ assert.lengthOf(valueSet, 0);
+ });
+
+ test('powerMetric_generic_oneStageEachType', function() {
var model = new tr.Model();
var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.LoadExpectation(
+ model, tr.model.um.LOAD_SUBTYPE_NAMES.SUCCESSFUL, 0, 500));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 500, 500));
+ tr.metrics.sh.powerMetric(valueSet, model);
+
+ assert.equal(getMetricValueSum(valueSet,
+ 'successful_load:time'), 500);
+ assert.equal(getMetricValueSum(valueSet,
+ 'idle:time'), 500);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'successful_load:energy'), 125, 0.5);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'idle:energy'), 375, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'successful_load:power'), 250, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'idle:power'), 750, 0.5);
+ });
+
+ test('powerMetric_generic_multipleStagesEachType', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.LoadExpectation(
+ model, tr.model.um.LOAD_SUBTYPE_NAMES.SUCCESSFUL, 0, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 200, 300));
+ model.userModel.expectations.push(new tr.model.um.LoadExpectation(
+ model, tr.model.um.LOAD_SUBTYPE_NAMES.SUCCESSFUL, 500, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 700, 300));
+ tr.metrics.sh.powerMetric(valueSet, model);
+
+ assert.equal(getMetricValueSum(valueSet,
+ 'successful_load:time'), 400);
+ assert.equal(getMetricValueSum(valueSet,
+ 'idle:time'), 600);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'successful_load:energy'), 140, 0.5);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'idle:energy'), 360, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'successful_load:power'), 350, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'idle:power'), 600, 0.5);
+ });
+
+ test('powerMetric_loading_oneInterval', function() {
+ // Interval of load is [200, 15400].
+ // Trace goes until 22150.
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1984);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9180,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: 9200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 9350,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 11150,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 12550,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 14950,
+ duration: 500,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 22150,
+ duration: 10,
+ }));
+
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 15400; i++)
+ model.device.powerSeries.addPowerSample(i.toString(), '20');
+ for (var i = 15401; i <= 22160; i++)
+ model.device.powerSeries.addPowerSample(i.toString(), '10');
+ });
+
+ var valueSet = new tr.v.ValueSet();
+ tr.metrics.sh.powerMetric(valueSet, model);
+ // Energy for first load is 20 W * 15.2 s
+ // (interval from 0.2 s to 15.4 s)
+ assert.closeTo(
+ getMetricValueAvg(valueSet, 'load:energy'), 304, 0.1);
+ assert.closeTo(
+ getMetricValueAvg(valueSet, 'load:time'), 15200, 0.1);
+ assert.closeTo(
+ getMetricValueAvg(valueSet, 'after_load:power'), 10, 0.01);
+ assert.closeTo(
+ getMetricValueAvg(valueSet, 'after_load:time'), 6760, 0.1);
+ });
+
+ test('powerMetric_loading_noMeaningfulPaint', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1984);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: 200,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+ rendererProcess.objects.addSnapshot('ptr', 'loading', 'FrameLoader', 300,
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ documentLoaderURL: 'http://example.com'});
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 9350,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 11150,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 12550,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 14950,
+ duration: 500,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: 22150,
+ duration: 10,
+ }));
+
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 15400; i++)
+ model.device.powerSeries.addPowerSample(i.toString(), '20');
+ for (var i = 15401; i <= 22160; i++)
+ model.device.powerSeries.addPowerSample(i.toString(), '10');
+ });
+
+ var valueSet = new tr.v.ValueSet();
+ tr.metrics.sh.powerMetric(valueSet, model);
+ // Energy for first load is 20 W * 15.2 s
+ // (interval from 0.2 s to 15.4 s)
+ assert.equal(getMetricValueCount(valueSet, 'after_load:power'), 0);
+ });
+
+ test('powerMetric_scroll_oneStageEachType', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, tr.importer.INITIATOR_TYPE.SCROLL, 0, 500));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 500, 500));
+ tr.metrics.sh.powerMetric(valueSet, model);
+
+ assert.equal(getMetricValueSum(valueSet,
+ 'scroll:time'), 500);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'scroll:energy'), 125, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'scroll:power'), 250, 0.5);
+ });
+
+ test('powerMetric_scroll_multipleStagesEachType', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, tr.importer.INITIATOR_TYPE.SCROLL, 0, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 200, 300));
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, tr.importer.INITIATOR_TYPE.SCROLL, 500, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 700, 300));
+ tr.metrics.sh.powerMetric(valueSet, model);
+
+ assert.equal(getMetricValueSum(valueSet,
+ 'scroll:time'), 400);
+ assert.closeTo(getMetricValueSum(valueSet,
+ 'scroll:energy'), 140, 0.5);
+ assert.closeTo(getMetricValueAvg(valueSet,
+ 'scroll:power'), 350, 0.5);
+ });
+
+ test('powerMetric_frameBased_multipleFrames', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, "Video", 1, 70));
model.device.powerSeries = new tr.model.PowerSeries(model.device);
// We want values in different frames, so they must go up by more than 16.66
// milliseconds.
@@ -26,16 +333,20 @@ tr.b.unittest.testSuite(function() {
model.device.powerSeries.addPowerSample('53', '.4');
model.device.powerSeries.addPowerSample('70', '.5');
tr.metrics.sh.powerMetric(valueSet, model);
- var powerEntries = valueSet.valueDicts.filter(
- (dict) => dict.name === 'energy_consumed_per_frame');
- var powerEntry = tr.b.getOnlyElement(powerEntries);
- assert.equal(powerEntry.numeric.centralBins[0].count, 5);
- assert.closeTo(powerEntry.numeric.running.sum, 0.0172, 1e-4);
+ assert.closeTo(getMetricValueAvg(valueSet, 'per_frame:energy'),
+ 0.00344, 1e-4)
+ assert.closeTo(getMetricValueSum(valueSet, 'per_frame:energy'),
+ 0.0172, 1e-4)
});
- test('powerMetric_oneFrame', function() {
+ test('powerMetric_frameBased_oneFrame', function() {
var model = new tr.Model();
var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, "Video", 1, 6));
model.device.powerSeries = new tr.model.PowerSeries(model.device);
// We want values in the same frame, so they must go up by less than 16.66
// milliseconds.
@@ -46,20 +357,54 @@ tr.b.unittest.testSuite(function() {
model.device.powerSeries.addPowerSample('5', '.4');
model.device.powerSeries.addPowerSample('6', '.5');
tr.metrics.sh.powerMetric(valueSet, model);
- var powerEntries = valueSet.valueDicts.filter(
- (dict) => dict.name === 'energy_consumed_per_frame');
- var powerEntry = tr.b.getOnlyElement(powerEntries);
- assert.equal(powerEntry.numeric.centralBins[0].count, 1);
- assert.closeTo(powerEntry.numeric.running.sum, 0.0011, 1e-4);
+ assert.closeTo(getMetricValueAvg(valueSet, 'per_frame:energy'),
+ 0.0011, 1e-4)
+ assert.closeTo(getMetricValueSum(valueSet, 'per_frame:energy'),
+ 0.0011, 1e-4)
});
- test('powerMetric_noPowerSeries', function() {
+ test('powerMetric_video_oneStageEachType', function() {
var model = new tr.Model();
var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain';
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, "Video", 0, 500));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 500, 500));
tr.metrics.sh.powerMetric(valueSet, model);
- var powerEntries = valueSet.valueDicts.filter(
- (dict) => dict.name === 'energy_consumed_per_frame');
- assert.lengthOf(powerEntries, 0);
+
+ assert.closeTo(getMetricValueAvg(valueSet, 'video:power'), 250, 0.5);
});
+
+ test('powerMetric_video_multipleStagesEachType', function() {
+ var model = new tr.Model();
+ var valueSet = new tr.v.ValueSet();
+ var rendererProcess = model.getOrCreateProcess(1234);
+ var mainThread = rendererProcess.getOrCreateThread(1);
+ mainThread.name = 'CrRendererMain'
+ model.device.powerSeries = new tr.model.PowerSeries(model.device);
+ for (var i = 0; i <= 1000; i++) {
+ model.device.powerSeries.addPowerSample(i.toString(), i.toString());
+ }
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, tr.importer.INITIATOR_TYPE.VIDEO, 0, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 200, 300));
+ model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
+ model, tr.importer.INITIATOR_TYPE.VIDEO, 500, 200));
+ model.userModel.expectations.push(new tr.model.um.IdleExpectation(
+ model, 700, 300));
+ tr.metrics.sh.powerMetric(valueSet, model);
+
+ assert.closeTo(getMetricValueAvg(valueSet, 'video:power'), 350, 0.5);
+ });
+
+
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric.html
index 5098c535277..a8d08820aff 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric.html
@@ -11,8 +11,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/user_model/animation_expectation.html">
<link rel="import" href="/tracing/model/user_model/load_expectation.html">
<link rel="import" href="/tracing/model/user_model/response_expectation.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
@@ -34,8 +33,9 @@ tr.exportTo('tr.metrics.sh', function() {
throw new Error('Animation missing frameEvents ' +
animationExpectation.stableId);
- var durationSeconds = animationExpectation.duration / 1000;
- return animationExpectation.frameEvents.length / durationSeconds;
+ var durationInS = tr.b.convertUnit(animationExpectation.duration,
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
+ return animationExpectation.frameEvents.length / durationInS;
}
function computeAnimationframeTimeDiscrepancy(animationExpectation) {
@@ -49,75 +49,75 @@ tr.exportTo('tr.metrics.sh', function() {
return event.start;
});
- var absolute = false;
+ var absolute = true;
return tr.b.Statistics.timestampsDiscrepancy(frameTimestamps, absolute);
}
- var RESPONSE_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- tr.b.Range.fromExplicitRange(100, 1000), 90);
-
- var THROUGHPUT_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.unitlessNumber_biggerIsBetter,
- tr.b.Range.fromExplicitRange(10, 60), 10);
-
- var DISCREPANCY_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter,
- tr.b.Range.fromExplicitRange(0, 1), 50);
-
- var LATENCY_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- tr.b.Range.fromExplicitRange(0, 300), 60);
-
/**
* @param {!tr.v.ValueSet} values
* @param {!tr.model.Model} model
* @param {!Object=} opt_options
*/
function responsivenessMetric(values, model, opt_options) {
- // TODO(benjhayden): Add categories to benchmark to support:
- // tr.metrics.sh.firstPaintMetric(values, model);
-
- var responseNumeric = RESPONSE_NUMERIC_BUILDER.build();
- var throughputNumeric = THROUGHPUT_NUMERIC_BUILDER.build();
- var frameTimeDiscrepancyNumeric = DISCREPANCY_NUMERIC_BUILDER.build();
- var latencyNumeric = LATENCY_NUMERIC_BUILDER.build();
+ var responseNumeric = new tr.v.Histogram('response latency',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(100, 1e3, 50));
+ var throughputNumeric = new tr.v.Histogram('animation throughput',
+ tr.b.Unit.byName.unitlessNumber_biggerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(10, 60, 10));
+ var frameTimeDiscrepancyNumeric = new tr.v.Histogram(
+ 'animation frameTimeDiscrepancy',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(0, 1e3, 50).
+ addExponentialBins(1e4, 10));
+ var latencyNumeric = new tr.v.Histogram('animation latency',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createLinear(0, 300, 60));
model.userModel.expectations.forEach(function(ue) {
if (opt_options && opt_options.rangeOfInterest &&
- !opt_options.rangeOfInterest.intersectsExplicitRangeExclusive(
+ !opt_options.rangeOfInterest.intersectsExplicitRangeInclusive(
ue.start, ue.end))
return;
- var sourceInfo = {userExpectationId: ue.stableId};
+ var sampleDiagnosticMap = tr.v.d.DiagnosticMap.fromObject(
+ {relatedEvents: new tr.v.d.RelatedEventSet([ue])});
- // Responsiveness is not defined for Idle.
+ // Responsiveness is not defined for Idle or Startup expectations.
if (ue instanceof tr.model.um.IdleExpectation) {
return;
+ } else if (ue instanceof tr.model.um.StartupExpectation) {
+ return;
} else if (ue instanceof tr.model.um.LoadExpectation) {
- // This is already covered by firstPaintMetric.
+ // This is already covered by loadingMetric.
} else if (ue instanceof tr.model.um.ResponseExpectation) {
- responseNumeric.add(ue.duration, sourceInfo);
+ responseNumeric.addSample(ue.duration, sampleDiagnosticMap);
} else if (ue instanceof tr.model.um.AnimationExpectation) {
+ if (ue.frameEvents === undefined || ue.frameEvents.length === 0) {
+ // Ignore animation stages that do not have associated frames:
+ // https://github.com/catapult-project/catapult/issues/2446
+ return;
+ }
var throughput = computeAnimationThroughput(ue);
if (throughput === undefined)
throw new Error('Missing throughput for ' +
ue.stableId);
- throughputNumeric.add(throughput, sourceInfo);
+ throughputNumeric.addSample(throughput, sampleDiagnosticMap);
var frameTimeDiscrepancy = computeAnimationframeTimeDiscrepancy(ue);
if (frameTimeDiscrepancy === undefined)
throw new Error('Missing frameTimeDiscrepancy for ' +
ue.stableId);
- frameTimeDiscrepancyNumeric.add(frameTimeDiscrepancy, sourceInfo);
+ frameTimeDiscrepancyNumeric.addSample(
+ frameTimeDiscrepancy, sampleDiagnosticMap);
ue.associatedEvents.forEach(function(event) {
if (!(event instanceof tr.e.cc.InputLatencyAsyncSlice))
return;
- latencyNumeric.add(event.duration, sourceInfo);
+ latencyNumeric.addSample(event.duration, sampleDiagnosticMap);
});
} else {
throw new Error('Unrecognized stage for ' + ue.stableId);
@@ -136,15 +136,10 @@ tr.exportTo('tr.metrics.sh', function() {
});
});
- values.addValue(new tr.v.NumericValue(
- 'response latency', responseNumeric));
- values.addValue(new tr.v.NumericValue(
- 'animation throughput', throughputNumeric));
- values.addValue(new tr.v.NumericValue(
- 'animation frameTimeDiscrepancy',
- frameTimeDiscrepancyNumeric));
- values.addValue(new tr.v.NumericValue(
- 'animation latency', latencyNumeric));
+ values.addHistogram(responseNumeric);
+ values.addHistogram(throughputNumeric);
+ values.addHistogram(frameTimeDiscrepancyNumeric);
+ values.addHistogram(latencyNumeric);
}
tr.metrics.MetricRegistry.register(responsivenessMetric, {
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric_test.html
new file mode 100644
index 00000000000..ed2d3341805
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/responsiveness_metric_test.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
+<link rel="import" href="/tracing/metrics/system_health/responsiveness_metric.html">
+<link rel="import" href="/tracing/model/slice_group.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ function createModel(collectionOfFrameTimestamps) {
+ var opts = {
+ customizeModelCallback: function(model) {
+ var thread = tr.c.TestUtils.newFakeThread();
+ collectionOfFrameTimestamps.forEach(function(frameTimestamps) {
+ frameTimestamps.sort((a, b) => a - b);
+ var ue = new tr.model.um.AnimationExpectation(
+ model, 'test', frameTimestamps[0],
+ frameTimestamps[frameTimestamps.length - 1]);
+ var group = new tr.model.SliceGroup(thread);
+ frameTimestamps.forEach(function(time) {
+ group.pushSlice(tr.c.TestUtils.newSliceEx({
+ title: tr.model.helpers.IMPL_RENDERING_STATS,
+ start: time,
+ end: time,
+ cpuStart: time,
+ cpuEnd: time
+ }));
+ });
+ group.createSubSlices();
+ group.slices.forEach(function(slice) {
+ ue.associatedEvents.push(slice);
+ });
+ model.userModel.expectations.push(ue);
+ model.userModel.expectations.push(
+ new tr.model.um.StartupExpectation(model, 0, 1));
+ model.userModel.expectations.push(
+ new tr.model.um.ResponseExpectation(model, 'test', 1, 1));
+ });
+ }
+ };
+ return tr.c.TestUtils.newModelWithEvents([], opts);
+ }
+
+ test('animationThroughputNoFrames', function() {
+ var model = createModel([[]]);
+ var valueList = new tr.v.ValueSet();
+ tr.metrics.sh.responsivenessMetric(valueList, model);
+ var value = tr.b.getOnlyElement(valueList.getValuesNamed(
+ 'animation throughput'));
+ assert.strictEqual(value.numValues, 0);
+ });
+
+ test('animationThroughputFramesAndNoFrames', function() {
+ var model = createModel([[0, 100], []]);
+ var valueList = new tr.v.ValueSet();
+ tr.metrics.sh.responsivenessMetric(valueList, model);
+ var value = tr.b.getOnlyElement(valueList.getValuesNamed(
+ 'animation throughput'));
+ assert.strictEqual(value.average, 20);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/system_health_metrics.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/system_health_metrics.html
index 723e526b554..dfc2364a457 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/system_health_metrics.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/system_health_metrics.html
@@ -5,7 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/metrics/system_health/efficiency_metric.html">
+<link rel="import" href="/tracing/metrics/system_health/cpu_time_metric.html">
<link rel="import" href="/tracing/metrics/system_health/hazard_metric.html">
<link rel="import" href="/tracing/metrics/system_health/long_tasks_metric.html">
<link rel="import" href="/tracing/metrics/system_health/power_metric.html"
@@ -18,10 +18,10 @@ found in the LICENSE file.
tr.exportTo('tr.metrics.sh', function() {
function systemHealthMetrics(values, model) {
tr.metrics.sh.responsivenessMetric(values, model);
- tr.metrics.sh.efficiencyMetric(values, model);
tr.metrics.sh.longTasksMetric(values, model);
tr.metrics.sh.hazardMetric(values, model);
tr.metrics.sh.powerMetric(values, model);
+ tr.metrics.sh.cpuTimeMetric(values, model);
}
tr.metrics.MetricRegistry.register(systemHealthMetrics);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/utils.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/utils.html
index 9e0d09bd32f..64c8b8b4f49 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/utils.html
@@ -29,7 +29,7 @@ tr.exportTo('tr.metrics.sh', function() {
return;
if (!opt_range ||
- opt_range.intersectsExplicitRangeExclusive(ir.start, ir.end))
+ opt_range.intersectsExplicitRangeInclusive(ir.start, ir.end))
filteredExpectations.push(ir);
});
return filteredExpectations;
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric.html
index 10e873b97f5..7d47baf0d9c 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric.html
@@ -7,53 +7,54 @@ found in the LICENSE file.
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/system_health/utils.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.sh', function() {
function webviewStartupMetric(values, model) {
+ var startupWallHist = new tr.v.Histogram('webview_startup_wall_time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter);
+ startupWallHist.description = 'WebView startup wall time';
+ var startupCPUHist = new tr.v.Histogram('webview_startup_cpu_time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter);
+ startupCPUHist.description = 'WebView startup CPU time';
+ var loadWallHist = new tr.v.Histogram('webview_url_load_wall_time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter);
+ loadWallHist.description = 'WebView blank URL load wall time';
+ var loadCPUHist = new tr.v.Histogram('webview_url_load_cpu_time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter);
+ loadCPUHist.description = 'WebView blank URL load CPU time';
+
+ // TODO(alexandermont): Only iterate over the processes and threads that
+ // could contain these events.
for (var slice of model.getDescendantEvents()) {
+ if (!(slice instanceof tr.model.ThreadSlice))
+ continue;
+
// WebViewStartupInterval is the title of the section of code that is
// entered (via android.os.Trace.beginSection) when WebView is started
// up. This value is defined in TelemetryActivity.java.
- if (!(slice instanceof tr.model.Slice))
- return;
if (slice.title === 'WebViewStartupInterval') {
- values.addValue(new tr.v.NumericValue(
- 'webview_startup_wall_time',
- new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- slice.duration),
- { description: 'WebView startup wall time' }));
- values.addValue(new tr.v.NumericValue(
- 'webview_startup_cpu_time',
- new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- slice.cpuDuration),
- { description: 'WebView startup CPU time' }));
+ startupWallHist.addSample(slice.duration);
+ startupCPUHist.addSample(slice.cpuDuration);
}
+
// WebViewBlankUrlLoadInterval is the title of the section of code
// that is entered (via android.os.Trace.beginSection) when WebView
// is started up. This value is defined in TelemetryActivity.java.
if (slice.title === 'WebViewBlankUrlLoadInterval') {
- values.addValue(new tr.v.NumericValue(
- 'webview_url_load_wall_time',
- new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- slice.duration),
- { description: 'WebView blank URL load wall time' }));
- values.addValue(new tr.v.NumericValue(
- 'webview_url_load_cpu_time',
- new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- slice.cpuDuration),
- { description: 'WebView blank URL load CPU time' }));
+ loadWallHist.addSample(slice.duration);
+ loadCPUHist.addSample(slice.cpuDuration);
}
}
- };
+
+ values.addHistogram(startupWallHist);
+ values.addHistogram(startupCPUHist);
+ values.addHistogram(loadWallHist);
+ values.addHistogram(loadCPUHist);
+ }
tr.metrics.MetricRegistry.register(webviewStartupMetric);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric_test.html
index fa4da093afc..ace1b317e03 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/system_health/webview_startup_metric_test.html
@@ -35,34 +35,17 @@ function makeTestModel() {
}
tr.b.unittest.testSuite(function() {
- test('webviewStartupMetric_allIntervals', function() {
+ test('webviewStartupMetric', function() {
var values = new tr.v.ValueSet();
tr.metrics.sh.webviewStartupMetric(values, makeTestModel());
- assert.lengthOf(values.valueDicts, 4);
- });
-
- test('webviewStartupMetric_startupWallInterval', function() {
- var values = new tr.v.ValueSet();
- tr.metrics.sh.webviewStartupMetric(values, makeTestModel());
- assert.equal(values.valueDicts[0].numeric.value, 42);
- });
-
- test('webviewStartupMetric_startupCpuInterval', function() {
- var values = new tr.v.ValueSet();
- tr.metrics.sh.webviewStartupMetric(values, makeTestModel());
- assert.equal(values.valueDicts[1].numeric.value, 32);
- });
-
- test('webviewStartupMetric_urlLoadWallInterval', function() {
- var values = new tr.v.ValueSet();
- tr.metrics.sh.webviewStartupMetric(values, makeTestModel());
- assert.equal(values.valueDicts[2].numeric.value, 27);
- });
-
- test('webviewStartupMetric_urlLoadCpuInterval', function() {
- var values = new tr.v.ValueSet();
- tr.metrics.sh.webviewStartupMetric(values, makeTestModel());
- assert.equal(values.valueDicts[3].numeric.value, 17);
+ assert.closeTo(42, values.getValuesNamed(
+ 'webview_startup_wall_time')[0].average, 1e-2);
+ assert.closeTo(32, values.getValuesNamed(
+ 'webview_startup_cpu_time')[0].average, 1e-2);
+ assert.closeTo(27, values.getValuesNamed(
+ 'webview_url_load_wall_time')[0].average, 1e-2);
+ assert.closeTo(17, values.getValuesNamed(
+ 'webview_url_load_cpu_time')[0].average, 1e-2);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric.html
index f47020e25b7..c028524b339 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric.html
@@ -7,8 +7,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
@@ -16,11 +16,20 @@ found in the LICENSE file.
tr.exportTo('tr.metrics', function() {
var MEMORY_INFRA_TRACING_CATEGORY = 'disabled-by-default-memory-infra';
+ var TIME_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
+ 1e-3, 1e5, 30);
+
+ var BYTE_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
+ 1, 1e9, 30);
+
+ var COUNT_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
+ 1, 1e5, 30);
+
function addTimeDurationValue(valueName, duration, allValues) {
- var scalarNumericValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, duration);
- var numericValue = new tr.v.NumericValue(valueName, scalarNumericValue);
- allValues.addValue(numericValue);
+ var hist = new tr.v.Histogram(valueName,
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TIME_BOUNDARIES);
+ hist.addSample(duration);
+ allValues.addHistogram(hist);
}
// Adds values specific to memory-infra dumps.
@@ -34,7 +43,7 @@ tr.exportTo('tr.metrics', function() {
var overheadByProvider = {};
tr.b.iterItems(model.processes, function(pid, process) {
tr.b.iterItems(process.threads, function(tid, thread) {
- tr.b.iterItems(thread.sliceGroup.slices, function(slice_id, slice) {
+ tr.b.iterItems(thread.sliceGroup.slices, (unusedSliceId, slice) => {
if (slice.category !== MEMORY_INFRA_TRACING_CATEGORY)
return;
totalOverhead += slice.duration;
@@ -42,8 +51,13 @@ tr.exportTo('tr.metrics', function() {
nonMemoryInfraThreadOverhead += slice.duration;
if (slice.args && slice.args['dump_provider.name']) {
var providerName = slice.args['dump_provider.name'];
- overheadByProvider[providerName] =
- (overheadByProvider[providerName] || 0) + slice.duration;
+ var durationAndCount = overheadByProvider[providerName];
+ if (durationAndCount === undefined) {
+ overheadByProvider[providerName] = durationAndCount =
+ {duration: 0, count: 0};
+ }
+ durationAndCount.duration += slice.duration;
+ durationAndCount.count++;
}
});
});
@@ -58,24 +72,23 @@ tr.exportTo('tr.metrics', function() {
nonMemoryInfraThreadOverhead / memoryDumpCount, values);
tr.b.iterItems(overheadByProvider, function(providerName, overhead) {
addTimeDurationValue(
- 'Average CPU overhead of ' + providerName + ' per memory-infra dump',
- overhead / memoryDumpCount, values);
+ 'Average CPU overhead of ' + providerName + ' per OnMemoryDump call',
+ overhead.duration / overhead.count, values);
});
var memoryInfraEventsSize =
categoryNamesToTotalEventSizes.get(MEMORY_INFRA_TRACING_CATEGORY);
- var memoryInfraTraceBytesValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, memoryInfraEventsSize);
- values.addValue(new tr.v.NumericValue(
+ var memoryInfraTraceBytesValue = new tr.v.Histogram(
'Total trace size of memory-infra dumps in bytes',
- memoryInfraTraceBytesValue));
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
+ memoryInfraTraceBytesValue.addSample(memoryInfraEventsSize);
+ values.addHistogram(memoryInfraTraceBytesValue);
- var traceBytesPerDumpValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter,
- memoryInfraEventsSize / memoryDumpCount);
- values.addValue(new tr.v.NumericValue(
+ var traceBytesPerDumpValue = new tr.v.Histogram(
'Average trace size of memory-infra dumps in bytes',
- traceBytesPerDumpValue));
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
+ traceBytesPerDumpValue.addSample(memoryInfraEventsSize / memoryDumpCount);
+ values.addHistogram(traceBytesPerDumpValue);
}
function tracingMetric(values, model) {
@@ -145,35 +158,36 @@ tr.exportTo('tr.metrics', function() {
var maxEventBytesPerCategory = maxCatNameAndBytes[1];
var categoryWithMaxEventBytes = maxCatNameAndBytes[0];
- var maxEventCountPerSecValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, maxEventCountPerSec);
- var maxEventBytesPerSecValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, maxEventBytesPerSec);
- var totalTraceBytesValue = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, totalTraceBytes);
+ var maxEventCountPerSecValue = new tr.v.Histogram(
+ 'Max number of events per second',
+ tr.b.Unit.byName.count_smallerIsBetter, COUNT_BOUNDARIES);
+ maxEventCountPerSecValue.addSample(maxEventCountPerSec);
+
+ var maxEventBytesPerSecValue = new tr.v.Histogram(
+ 'Max event size in bytes per second',
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
+ maxEventBytesPerSecValue.addSample(maxEventBytesPerSec);
+
+ var totalTraceBytesValue = new tr.v.Histogram('Total trace size in bytes',
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
+ totalTraceBytesValue.addSample(totalTraceBytes);
var biggestCategory = {
name: categoryWithMaxEventBytes,
size_in_bytes: maxEventBytesPerCategory
};
- var totalBytes = new tr.v.NumericValue(
- 'Total trace size in bytes', totalTraceBytesValue);
- totalBytes.diagnostics.add(
+ totalTraceBytesValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
- values.addValue(totalBytes);
+ values.addHistogram(totalTraceBytesValue);
- var peakEvents = new tr.v.NumericValue(
- 'Max number of events per second', maxEventCountPerSecValue);
- peakEvents.diagnostics.add(
+ maxEventCountPerSecValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
- values.addValue(peakEvents);
+ values.addHistogram(maxEventCountPerSecValue);
- var peakBytes = new tr.v.NumericValue(
- 'Max event size in bytes per second', maxEventBytesPerSecValue);
- peakBytes.diagnostics.add(
+ maxEventBytesPerSecValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
- values.addValue(peakBytes);
+ values.addHistogram(maxEventBytesPerSecValue);
addMemoryInfraValues(values, model, categoryNamesToTotalEventSizes);
}
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric_test.html
index 97a158f384a..2f123162dab 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/tracing_metric_test.html
@@ -29,9 +29,8 @@ tr.b.unittest.testSuite(function() {
}
function checkDurationValue(allValues, metricName, expected) {
- var values = allValues.getValuesWithName(metricName);
- assert.lengthOf(values, 1);
- assert.closeTo(1000 * values[0].numeric.value, expected, 0.1);
+ var value = tr.b.getOnlyElement(allValues.getValuesNamed(metricName));
+ assert.closeTo(1000 * value.average, expected, 0.1);
}
test('hasEventSizesInBytes', function() {
@@ -62,9 +61,9 @@ tr.b.unittest.testSuite(function() {
tr.metrics.tracingMetric(allValues, model);
var eventStringSize = getEventStringSize(events, [0, 1]);
- var values = allValues.getValuesWithName('Total trace size in bytes');
- assert.strictEqual(values.length, 1);
- assert.strictEqual(values[0].numeric.value, eventStringSize);
+ var value = tr.b.getOnlyElement(allValues.getValuesNamed(
+ 'Total trace size in bytes'));
+ assert.strictEqual(value.average, eventStringSize);
});
test('maxValuePerSec', function() {
@@ -82,15 +81,14 @@ tr.b.unittest.testSuite(function() {
tr.metrics.tracingMetric(allValues, model);
var maxEventCountPerSec = 3;
- var values = allValues.getValuesWithName('Max number of events per second');
- assert.strictEqual(values.length, 1);
- assert.strictEqual(values[0].numeric.value, maxEventCountPerSec);
+ var value = tr.b.getOnlyElement(allValues.getValuesNamed(
+ 'Max number of events per second'));
+ assert.strictEqual(value.average, maxEventCountPerSec);
var maxEventBytesPerSec = getEventStringSize(events, [2, 3, 5]);
- var values = allValues.getValuesWithName(
- 'Max event size in bytes per second');
- assert.strictEqual(values.length, 1);
- assert.strictEqual(values[0].numeric.value, maxEventBytesPerSec);
+ value = tr.b.getOnlyElement(allValues.getValuesNamed(
+ 'Max event size in bytes per second'));
+ assert.strictEqual(value.average, maxEventBytesPerSec);
});
test('diagnostics', function() {
@@ -105,13 +103,11 @@ tr.b.unittest.testSuite(function() {
var model = makeModel(JSON.stringify(events), true);
tr.metrics.tracingMetric(allValues, model);
- for (var i = 0; i < allValues.length; i++) {
- assert.strictEqual(
- values[i].diagnostics.category_with_max_event_size.name,
- 'foo');
- assert.strictEqual(
- values[i].diagnostics.category_with_max_event_size.size_in_bytes,
- getEventStringSize(events, [0, 1, 3]));
+ for (var value of allValues) {
+ var d = value.diagnostics.get('category_with_max_event_size').value;
+ assert.strictEqual(d.name, 'foo');
+ assert.strictEqual(d.size_in_bytes, getEventStringSize(
+ events, [0, 1, 3]));
}
});
@@ -137,29 +133,27 @@ tr.b.unittest.testSuite(function() {
];
var model = makeModel(JSON.stringify(events), true);
- tr.model.MemoryDumpTestUtils.addGlobalMemoryDump(model, 550);
+ tr.model.MemoryDumpTestUtils.addGlobalMemoryDump(model, {ts: 550});
tr.metrics.tracingMetric(allValues, model);
var memoryCategorySize = events.filter(
slice => slice['cat'] === MEMORY_INFRA_TRACING_CATEGORY).reduce(
(acc, slice) => acc + JSON.stringify(slice).length, 0);
- var totalSizeValue = allValues.getValuesWithName(
- 'Total trace size of memory-infra dumps in bytes');
- assert.lengthOf(totalSizeValue, 1);
- assert.strictEqual(totalSizeValue[0].numeric.value, memoryCategorySize);
- var sizePerDumpValue = allValues.getValuesWithName(
- 'Average trace size of memory-infra dumps in bytes');
- assert.lengthOf(sizePerDumpValue, 1);
- assert.strictEqual(sizePerDumpValue[0].numeric.value, memoryCategorySize);
+ var totalSizeValue = tr.b.getOnlyElement(allValues.getValuesNamed(
+ 'Total trace size of memory-infra dumps in bytes'));
+ assert.strictEqual(totalSizeValue.average, memoryCategorySize);
+ var sizePerDumpValue = tr.b.getOnlyElement(allValues.getValuesNamed(
+ 'Average trace size of memory-infra dumps in bytes'));
+ assert.strictEqual(sizePerDumpValue.average, memoryCategorySize);
checkDurationValue(allValues,
- 'Average CPU overhead of mdp1 per memory-infra dump', 13);
+ 'Average CPU overhead of mdp1 per OnMemoryDump call', 6.5);
checkDurationValue(allValues,
- 'Average CPU overhead of mdp2 per memory-infra dump', 32);
+ 'Average CPU overhead of mdp2 per OnMemoryDump call', 16);
checkDurationValue(allValues,
- 'Average CPU overhead of mdp3 per memory-infra dump', 12);
+ 'Average CPU overhead of mdp3 per OnMemoryDump call', 6);
checkDurationValue(allValues,
- 'Average CPU overhead of mdp4 per memory-infra dump', 8);
+ 'Average CPU overhead of mdp4 per OnMemoryDump call', 8);
checkDurationValue(allValues,
'Average CPU overhead on non-memory-infra threads per memory-infra ' +
'dump',
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric.html
index 3c5565b9c46..37a0f2f8f99 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric.html
@@ -4,200 +4,207 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.v8', function() {
- var DURATION_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
- tr.b.Range.fromExplicitRange(4, 200), 100);
+ var CUSTOM_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(4, 200, 100);
function computeExecuteMetrics(values, model) {
- var cpuTotalExecution = DURATION_NUMERIC_BUILDER.build();
- var wallTotalExecution = DURATION_NUMERIC_BUILDER.build();
- var cpuSelfExecution = DURATION_NUMERIC_BUILDER.build();
- var wallSelfExecution = DURATION_NUMERIC_BUILDER.build();
+ var cpuTotalExecution = new tr.v.Histogram('v8_execution_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalExecution.description = 'cpu total time spent in script execution';
+ var wallTotalExecution = new tr.v.Histogram('v8_execution_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalExecution.description =
+ 'wall total time spent in script execution';
+ var cpuSelfExecution = new tr.v.Histogram('v8_execution_cpu_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuSelfExecution.description = 'cpu self time spent in script execution';
+ var wallSelfExecution = new tr.v.Histogram('v8_execution_wall_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallSelfExecution.description = 'wall self time spent in script execution';
for (var e of model.findTopmostSlicesNamed('V8.Execute')) {
- cpuTotalExecution.add(e.cpuDuration);
- wallTotalExecution.add(e.duration);
- cpuSelfExecution.add(e.cpuSelfTime);
- wallSelfExecution.add(e.selfTime);
+ cpuTotalExecution.addSample(e.cpuDuration);
+ wallTotalExecution.addSample(e.duration);
+ cpuSelfExecution.addSample(e.cpuSelfTime);
+ wallSelfExecution.addSample(e.selfTime);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_execution_cpu_total', cpuTotalExecution,
- { description: 'cpu total time spent in script execution' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_execution_wall_total', wallTotalExecution,
- { description: 'wall total time spent in script execution' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_execution_cpu_self', cpuSelfExecution,
- { description: 'cpu self time spent in script execution' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_execution_wall_self', wallSelfExecution,
- { description: 'wall self time spent in script execution' }));
+ values.addHistogram(cpuTotalExecution);
+ values.addHistogram(wallTotalExecution);
+ values.addHistogram(cpuSelfExecution);
+ values.addHistogram(wallSelfExecution);
}
function computeParseLazyMetrics(values, model) {
- var cpuSelfParseLazy = DURATION_NUMERIC_BUILDER.build();
- var wallSelfParseLazy = DURATION_NUMERIC_BUILDER.build();
+ var cpuSelfParseLazy = new tr.v.Histogram('v8_parse_lazy_cpu_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuSelfParseLazy.description =
+ 'cpu self time spent performing lazy parsing';
+ var wallSelfParseLazy = new tr.v.Histogram('v8_parse_lazy_wall_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallSelfParseLazy.description =
+ 'wall self time spent performing lazy parsing';
for (var e of model.findTopmostSlicesNamed('V8.ParseLazyMicroSeconds')) {
- cpuSelfParseLazy.add(e.cpuSelfTime);
- wallSelfParseLazy.add(e.selfTime);
+ cpuSelfParseLazy.addSample(e.cpuSelfTime);
+ wallSelfParseLazy.addSample(e.selfTime);
}
for (var e of model.findTopmostSlicesNamed('V8.ParseLazy')) {
- cpuSelfParseLazy.add(e.cpuSelfTime);
- wallSelfParseLazy.add(e.selfTime);
+ cpuSelfParseLazy.addSample(e.cpuSelfTime);
+ wallSelfParseLazy.addSample(e.selfTime);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_parse_lazy_cpu_self', cpuSelfParseLazy,
- { description: 'cpu self time spent performing lazy parsing' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_parse_lazy_wall_self', wallSelfParseLazy,
- { description: 'wall self time spent performing lazy parsing' }));
+ values.addHistogram(cpuSelfParseLazy);
+ values.addHistogram(wallSelfParseLazy);
}
function computeCompileFullCodeMetrics(values, model) {
- var cpuSelfCompileFullCode = DURATION_NUMERIC_BUILDER.build();
- var wallSelfCompileFullCode = DURATION_NUMERIC_BUILDER.build();
+ var cpuSelfCompileFullCode = new tr.v.Histogram(
+ 'v8_compile_full_code_cpu_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuSelfCompileFullCode.description =
+ 'cpu self time spent performing compiling full code';
+ var wallSelfCompileFullCode = new tr.v.Histogram(
+ 'v8_compile_full_code_wall_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallSelfCompileFullCode.description =
+ 'wall self time spent performing compiling full code';
for (var e of model.findTopmostSlicesNamed('V8.CompileFullCode')) {
- cpuSelfCompileFullCode.add(e.cpuSelfTime);
- wallSelfCompileFullCode.add(e.selfTime);
+ cpuSelfCompileFullCode.addSample(e.cpuSelfTime);
+ wallSelfCompileFullCode.addSample(e.selfTime);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_compile_full_code_cpu_self',
- cpuSelfCompileFullCode,
- { description: 'cpu self time spent performing compiling full code' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_compile_full_code_wall_self',
- wallSelfCompileFullCode, {
- description: 'wall self time spent performing compiling full code'
- }));
+ values.addHistogram(cpuSelfCompileFullCode);
+ values.addHistogram(wallSelfCompileFullCode);
}
function computeCompileIgnitionMetrics(values, model) {
- var cpuSelfCompileIgnition = DURATION_NUMERIC_BUILDER.build();
- var wallSelfCompileIgnition = DURATION_NUMERIC_BUILDER.build();
+ var cpuSelfCompileIgnition = new tr.v.Histogram(
+ 'v8_compile_ignition_cpu_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuSelfCompileIgnition.description =
+ 'cpu self time spent in compile ignition';
+ var wallSelfCompileIgnition = new tr.v.Histogram(
+ 'v8_compile_ignition_wall_self',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallSelfCompileIgnition.description =
+ 'wall self time spent in compile ignition';
for (var e of model.findTopmostSlicesNamed('V8.CompileIgnition')) {
- cpuSelfCompileIgnition.add(e.cpuSelfTime);
- wallSelfCompileIgnition.add(e.selfTime);
+ cpuSelfCompileIgnition.addSample(e.cpuSelfTime);
+ wallSelfCompileIgnition.addSample(e.selfTime);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_compile_ignition_cpu_self',
- cpuSelfCompileIgnition,
- { description: 'cpu self time spent in compile ignition' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_compile_ignition_wall_self',
- wallSelfCompileIgnition, {
- description: 'wall self time spent in compile ignition'
- }));
+ values.addHistogram(cpuSelfCompileIgnition);
+ values.addHistogram(wallSelfCompileIgnition);
}
function computeRecompileMetrics(values, model) {
- var cpuTotalRecompileSynchronous = DURATION_NUMERIC_BUILDER.build();
- var wallTotalRecompileSynchronous = DURATION_NUMERIC_BUILDER.build();
- var cpuTotalRecompileConcurrent = DURATION_NUMERIC_BUILDER.build();
- var wallTotalRecompileConcurrent = DURATION_NUMERIC_BUILDER.build();
+ var cpuTotalRecompileSynchronous = new tr.v.Histogram(
+ 'v8_recompile_synchronous_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalRecompileSynchronous.description =
+ 'cpu total time spent in synchronous recompilation';
+ var wallTotalRecompileSynchronous = new tr.v.Histogram(
+ 'v8_recompile_synchronous_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalRecompileSynchronous.description =
+ 'wall total time spent in synchronous recompilation';
+ var cpuTotalRecompileConcurrent = new tr.v.Histogram(
+ 'v8_recompile_concurrent_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalRecompileConcurrent.description =
+ 'cpu total time spent in concurrent recompilation';
+ var wallTotalRecompileConcurrent = new tr.v.Histogram(
+ 'v8_recompile_concurrent_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalRecompileConcurrent.description =
+ 'wall total time spent in concurrent recompilation';
// TODO(eakuefner): Stop computing overall values once dash v2 is ready.
// https://github.com/catapult-project/catapult/issues/2180
- var cpuTotalRecompileOverall = DURATION_NUMERIC_BUILDER.build();
- var wallTotalRecompileOverall = DURATION_NUMERIC_BUILDER.build();
+ var cpuTotalRecompileOverall = new tr.v.Histogram(
+ 'v8_recompile_overall_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalRecompileOverall.description =
+ 'cpu total time spent in synchronous or concurrent recompilation';
+ var wallTotalRecompileOverall = new tr.v.Histogram(
+ 'v8_recompile_overall_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalRecompileOverall.description =
+ 'wall total time spent in synchronous or concurrent recompilation';
for (var e of model.findTopmostSlicesNamed('V8.RecompileSynchronous')) {
- cpuTotalRecompileSynchronous.add(e.cpuDuration);
- wallTotalRecompileSynchronous.add(e.duration);
- cpuTotalRecompileOverall.add(e.cpuDuration);
- wallTotalRecompileOverall.add(e.duration);
+ cpuTotalRecompileSynchronous.addSample(e.cpuDuration);
+ wallTotalRecompileSynchronous.addSample(e.duration);
+ cpuTotalRecompileOverall.addSample(e.cpuDuration);
+ wallTotalRecompileOverall.addSample(e.duration);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_synchronous_cpu_total',
- cpuTotalRecompileSynchronous,
- { description: 'cpu total time spent in synchronous recompilation' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_synchronous_wall_total',
- wallTotalRecompileSynchronous,
- { description: 'wall total time spent in synchronous recompilation' }));
-
+ values.addHistogram(cpuTotalRecompileSynchronous);
+ values.addHistogram(wallTotalRecompileSynchronous);
for (var e of model.findTopmostSlicesNamed('V8.RecompileConcurrent')) {
- cpuTotalRecompileConcurrent.add(e.cpuDuration);
- wallTotalRecompileConcurrent.add(e.duration);
- cpuTotalRecompileOverall.add(e.cpuDuration);
- wallTotalRecompileOverall.add(e.duration);
+ cpuTotalRecompileConcurrent.addSample(e.cpuDuration);
+ wallTotalRecompileConcurrent.addSample(e.duration);
+ cpuTotalRecompileOverall.addSample(e.cpuDuration);
+ wallTotalRecompileOverall.addSample(e.duration);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_concurrent_cpu_total',
- cpuTotalRecompileConcurrent,
- { description: 'cpu total time spent in concurrent recompilation' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_concurrent_wall_total',
- wallTotalRecompileConcurrent,
- { description: 'wall total time spent in concurrent recompilation' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_overall_cpu_total',
- cpuTotalRecompileOverall, {
- description:
- 'cpu total time spent in synchronous or concurrent recompilation'
- }));
- values.addValue(new tr.v.NumericValue(
- 'v8_recompile_overall_wall_total',
- wallTotalRecompileOverall, {
- description:
- 'wall total time spent in synchronous or concurrent recompilation'
- }));
+ values.addHistogram(cpuTotalRecompileConcurrent);
+ values.addHistogram(wallTotalRecompileConcurrent);
+ values.addHistogram(cpuTotalRecompileOverall);
+ values.addHistogram(wallTotalRecompileOverall);
}
function computeOptimizeCodeMetrics(values, model) {
- var cpuTotalOptimizeCode = DURATION_NUMERIC_BUILDER.build();
- var wallTotalOptimizeCode = DURATION_NUMERIC_BUILDER.build();
+ var cpuTotalOptimizeCode = new tr.v.Histogram('v8_optimize_code_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalOptimizeCode.description =
+ 'cpu total time spent in code optimization';
+ var wallTotalOptimizeCode = new tr.v.Histogram(
+ 'v8_optimize_code_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalOptimizeCode.description =
+ 'wall total time spent in code optimization';
for (var e of model.findTopmostSlicesNamed('V8.OptimizeCode')) {
- cpuTotalOptimizeCode.add(e.cpuDuration);
- wallTotalOptimizeCode.add(e.duration);
+ cpuTotalOptimizeCode.addSample(e.cpuDuration);
+ wallTotalOptimizeCode.addSample(e.duration);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_optimize_code_cpu_total',
- cpuTotalOptimizeCode,
- { description: 'cpu total time spent in code optimization' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_optimize_code_wall_total',
- wallTotalOptimizeCode,
- { description: 'wall total time spent in code optimization' }));
+ values.addHistogram(cpuTotalOptimizeCode);
+ values.addHistogram(wallTotalOptimizeCode);
}
function computeDeoptimizeCodeMetrics(values, model) {
- var cpuTotalDeoptimizeCode = DURATION_NUMERIC_BUILDER.build();
- var wallTotalDeoptimizeCode = DURATION_NUMERIC_BUILDER.build();
+ var cpuTotalDeoptimizeCode = new tr.v.Histogram(
+ 'v8_deoptimize_code_cpu_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ cpuTotalDeoptimizeCode.description =
+ 'cpu total time spent in code deoptimization';
+ var wallTotalDeoptimizeCode = new tr.v.Histogram(
+ 'v8_deoptimize_code_wall_total',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
+ wallTotalDeoptimizeCode.description =
+ 'wall total time spent in code deoptimization';
for (var e of model.findTopmostSlicesNamed('V8.DeoptimizeCode')) {
- cpuTotalDeoptimizeCode.add(e.cpuDuration);
- wallTotalDeoptimizeCode.add(e.duration);
+ cpuTotalDeoptimizeCode.addSample(e.cpuDuration);
+ wallTotalDeoptimizeCode.addSample(e.duration);
}
- values.addValue(new tr.v.NumericValue(
- 'v8_deoptimize_code_cpu_total',
- cpuTotalDeoptimizeCode,
- { description: 'cpu total time spent in code deoptimization' }));
- values.addValue(new tr.v.NumericValue(
- 'v8_deoptimize_code_wall_total',
- wallTotalDeoptimizeCode,
- { description: 'wall total time spent in code deoptimization' }));
+ values.addHistogram(cpuTotalDeoptimizeCode);
+ values.addHistogram(wallTotalDeoptimizeCode);
}
function executionMetric(values, model) {
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric_test.html
index 9cb7099796c..d582e5da3a3 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/execution_metric_test.html
@@ -42,7 +42,7 @@ tr.b.unittest.testSuite(function() {
'v8_deoptimize_code_cpu_total',
'v8_deoptimize_code_wall_total',
].forEach(function(name) {
- assert.isAbove(values.getValuesWithName(name).length, 0);
+ assert.strictEqual(values.getValuesNamed(name).length, 1);
});
});
@@ -62,12 +62,10 @@ tr.b.unittest.testSuite(function() {
shiftWorldToZero: false
});
var values = new tr.v.ValueSet();
-
tr.metrics.v8.executionMetric(values, model);
- var value = values.getValuesWithName('v8_execution_wall_total_sum')[0];
-
- assert.closeTo(value.numeric.value, 0.1, 1e-5);
+ var value = values.getValuesNamed('v8_execution_wall_total')[0];
+ assert.closeTo(value.running.sum, 0.1, 1e-5);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html
index d842445ab16..7a0c88f18cd 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html
@@ -4,12 +4,12 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/v8/utils.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
@@ -27,25 +27,28 @@ tr.exportTo('tr.metrics.v8', function() {
addDurationOfSubEvents(values, model);
addIdleTimesOfTopEvents(values, model);
addTotalIdleTimesOfTopEvents(values, model);
+ addPercentageInV8ExecuteOfTopEvents(values, model);
+ addTotalPercentageInV8Execute(values, model);
addV8ExecuteMutatorUtilization(values, model);
}
tr.metrics.MetricRegistry.register(gcMetric);
var timeDurationInMs_smallerIsBetter =
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
var percentage_biggerIsBetter =
- tr.v.Unit.byName.normalizedPercentage_biggerIsBetter;
+ tr.b.Unit.byName.normalizedPercentage_biggerIsBetter;
+ var percentage_smallerIsBetter =
+ tr.b.Unit.byName.normalizedPercentage_smallerIsBetter;
- var numericBuilder = new tr.v.NumericBuilder(
- timeDurationInMs_smallerIsBetter, 0);
// 0.1 steps from 0 to 20 since it is the most common range.
- numericBuilder.addLinearBins(20, 200);
// Exponentially increasing steps from 20 to 200.
- numericBuilder.addExponentialBins(200, 100);
+ var CUSTOM_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 20, 200)
+ .addExponentialBins(200, 100);
- function createNumericForTopEventTime() {
- var n = numericBuilder.build();
+ function createNumericForTopEventTime(name) {
+ var n = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
n.customizeSummaryOptions({
avg: true,
count: true,
@@ -57,8 +60,9 @@ tr.exportTo('tr.metrics.v8', function() {
return n;
}
- function createNumericForSubEventTime() {
- var n = numericBuilder.build();
+ function createNumericForSubEventTime(name) {
+ var n = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
n.customizeSummaryOptions({
avg: true,
count: false,
@@ -71,8 +75,9 @@ tr.exportTo('tr.metrics.v8', function() {
return n;
}
- function createNumericForIdleTime() {
- var n = numericBuilder.build();
+ function createNumericForIdleTime(name) {
+ var n = new tr.v.Histogram(name,
+ timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
n.customizeSummaryOptions({
avg: true,
count: false,
@@ -85,105 +90,130 @@ tr.exportTo('tr.metrics.v8', function() {
return n;
}
- function createPercentage(numerator, denominator) {
- var percentage = denominator === 0 ? 0 : numerator / denominator * 100;
- return new tr.v.ScalarNumeric(percentage_biggerIsBetter, percentage);
+ function createPercentage(name, numerator, denominator, unit) {
+ var hist = new tr.v.Histogram(name, unit);
+ if (denominator === 0)
+ hist.addSample(0);
+ else
+ hist.addSample(numerator / denominator);
+ hist.customizeSummaryOptions({
+ avg: true,
+ count: false,
+ max: false,
+ min: false,
+ std: false,
+ sum: false,
+ percentile: []
+ });
+ return hist;
+ }
+
+ function isNotForcedTopGarbageCollectionEvent(event) {
+ // We exclude garbage collection events forced by benchmark runner,
+ // because they cannot happen in real world.
+ return tr.metrics.v8.utils.isTopGarbageCollectionEvent(event) &&
+ !tr.metrics.v8.utils.isForcedGarbageCollectionEvent(event);
+ }
+
+ function isNotForcedSubGarbageCollectionEvent(event) {
+ // We exclude garbage collection events forced by benchmark runner,
+ // because they cannot happen in real world.
+ return tr.metrics.v8.utils.isSubGarbageCollectionEvent(event) &&
+ !tr.metrics.v8.utils.isForcedGarbageCollectionEvent(event);
}
/**
* Example output:
- * - Animation-v8_gc_full_mark_compactor.
+ * - v8-gc-full-mark-compactor.
*/
function addDurationOfTopEvents(values, model) {
- groupAndProcessEvents(model,
- tr.metrics.v8.utils.isTopGarbageCollectionEvent,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
tr.metrics.v8.utils.topGarbageCollectionEventName,
- function(stageTitle, name, events) {
- var cpuDuration = createNumericForTopEventTime();
+ function(name, events) {
+ var cpuDuration = createNumericForTopEventTime(name);
events.forEach(function(event) {
- cpuDuration.add(event.cpuDuration);
+ cpuDuration.addSample(event.cpuDuration);
});
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name, cpuDuration));
+ values.addHistogram(cpuDuration);
}
);
}
/**
* Example output:
- * - Animation:v8_gc_total
+ * - v8-gc-total
*/
function addTotalDurationOfTopEvents(values, model) {
- groupAndProcessEvents(model,
- tr.metrics.v8.utils.isTopGarbageCollectionEvent,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
event => 'v8-gc-total',
- function(stageTitle, name, events) {
- var cpuDuration = createNumericForTopEventTime();
+ function(name, events) {
+ var cpuDuration = createNumericForTopEventTime(name);
events.forEach(function(event) {
- cpuDuration.add(event.cpuDuration);
+ cpuDuration.addSample(event.cpuDuration);
});
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name, cpuDuration));
+ values.addHistogram(cpuDuration);
}
);
}
/**
* Example output:
- * - Animation-v8-gc-full-mark-compactor-evacuate.
+ * - v8-gc-full-mark-compactor-evacuate.
*/
function addDurationOfSubEvents(values, model) {
- groupAndProcessEvents(model,
- tr.metrics.v8.utils.isSubGarbageCollectionEvent,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedSubGarbageCollectionEvent,
tr.metrics.v8.utils.subGarbageCollectionEventName,
- function(stageTitle, name, events) {
- var cpuDuration = createNumericForSubEventTime();
+ function(name, events) {
+ var cpuDuration = createNumericForSubEventTime(name);
events.forEach(function(event) {
- cpuDuration.add(event.cpuDuration);
+ cpuDuration.addSample(event.cpuDuration);
});
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name, cpuDuration));
+ values.addHistogram(cpuDuration);
}
);
}
/**
* Example output:
- * - Animation-v8-gc-full-mark-compactor_idle_deadline_overrun,
- * - Animation-v8-gc-full-mark-compactor_outside_idle,
- * - Animation-v8-gc-full-mark-compactor_percentage_idle.
+ * - v8-gc-full-mark-compactor_idle_deadline_overrun,
+ * - v8-gc-full-mark-compactor_outside_idle,
+ * - v8-gc-full-mark-compactor_percentage_idle.
*/
function addIdleTimesOfTopEvents(values, model) {
- groupAndProcessEvents(model,
- tr.metrics.v8.utils.isTopGarbageCollectionEvent,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
tr.metrics.v8.utils.topGarbageCollectionEventName,
- function(stageTitle, name, events) {
- addIdleTimes(values, model, stageTitle, name, events);
+ function(name, events) {
+ addIdleTimes(values, model, name, events);
}
);
}
/**
* Example output:
- * - Animation-v8-gc-total_idle_deadline_overrun,
- * - Animation-v8-gc-total_outside_idle,
- * - Animation-v8-gc-total_percentage_idle.
+ * - v8-gc-total_idle_deadline_overrun,
+ * - v8-gc-total_outside_idle,
+ * - v8-gc-total_percentage_idle.
*/
function addTotalIdleTimesOfTopEvents(values, model) {
- groupAndProcessEvents(model,
- tr.metrics.v8.utils.isTopGarbageCollectionEvent,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
event => 'v8-gc-total',
- function(stageTitle, name, events) {
- addIdleTimes(values, model, stageTitle, name, events);
+ function(name, events) {
+ addIdleTimes(values, model, name, events);
}
);
}
- function addIdleTimes(values, model, stageTitle, name, events) {
+ function addIdleTimes(values, model, name, events) {
var cpuDuration = createNumericForIdleTime();
var insideIdle = createNumericForIdleTime();
- var outsideIdle = createNumericForIdleTime();
- var idleDeadlineOverrun = createNumericForIdleTime();
+ var outsideIdle = createNumericForIdleTime(name + '_outside_idle');
+ var idleDeadlineOverrun = createNumericForIdleTime(
+ name + '_idle_deadline_overrun');
events.forEach(function(event) {
var idleTask = tr.metrics.v8.utils.findParent(
event, tr.metrics.v8.utils.isIdleTask);
@@ -203,94 +233,103 @@ tr.exportTo('tr.metrics.v8', function() {
inside = event.cpuDuration;
}
}
- cpuDuration.add(event.cpuDuration);
- insideIdle.add(inside);
- outsideIdle.add(event.cpuDuration - inside);
- idleDeadlineOverrun.add(overrun);
+ cpuDuration.addSample(event.cpuDuration);
+ insideIdle.addSample(inside);
+ outsideIdle.addSample(event.cpuDuration - inside);
+ idleDeadlineOverrun.addSample(overrun);
+ });
+ values.addHistogram(idleDeadlineOverrun);
+ values.addHistogram(outsideIdle);
+ var percentage = createPercentage(name + '_percentage_idle', insideIdle.sum,
+ cpuDuration.sum,
+ percentage_biggerIsBetter);
+ values.addHistogram(percentage);
+ }
+
+
+ /**
+ * Example output:
+ * - v8-gc-full-mark-compactor_percentage_in_v8_execute.
+ */
+ function addPercentageInV8ExecuteOfTopEvents(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
+ tr.metrics.v8.utils.topGarbageCollectionEventName,
+ function(name, events) {
+ addPercentageInV8Execute(values, model, name, events);
+ }
+ );
+ }
+
+ /**
+ * Example output:
+ * - v8-gc-total_percentage_in_v8_execute.
+ */
+ function addTotalPercentageInV8Execute(values, model) {
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
+ isNotForcedTopGarbageCollectionEvent,
+ event => 'v8-gc-total',
+ function(name, events) {
+ addPercentageInV8Execute(values, model, name, events);
+ }
+ );
+ }
+
+ function addPercentageInV8Execute(values, model, name, events) {
+ var cpuDurationInV8Execute = 0;
+ var cpuDurationTotal = 0;
+ events.forEach(function(event) {
+ var v8Execute = tr.metrics.v8.utils.findParent(
+ event, tr.metrics.v8.utils.isV8ExecuteEvent);
+ if (v8Execute) {
+ cpuDurationInV8Execute += event.cpuDuration;
+ }
+ cpuDurationTotal += event.cpuDuration;
});
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name + '_idle_deadline_overrun',
- idleDeadlineOverrun));
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name + '_outside_idle', outsideIdle));
- var percentage = createPercentage(insideIdle.sum,
- cpuDuration.sum);
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-' + name + '_percentage_idle', percentage));
+ var percentage = createPercentage(
+ name + '_percentage_in_v8_execute', cpuDurationInV8Execute,
+ cpuDurationTotal, percentage_smallerIsBetter);
+ values.addHistogram(percentage);
}
function addV8ExecuteMutatorUtilization(values, model) {
- groupAndProcessEvents(model,
+ tr.metrics.v8.utils.groupAndProcessEvents(model,
tr.metrics.v8.utils.isTopV8ExecuteEvent,
event => 'v8-execute',
- function(stageTitle, name, events) {
+ function(name, events) {
events.sort((a, b) => a.start - b.start);
var time = 0;
var pauses = [];
// Glue together the v8.execute events and adjust the GC pause
// times accordingly.
- events.forEach(function(topEvent) {
- topEvent.iterateAllDescendents(function(e) {
- if (tr.metrics.v8.utils.isTopGarbageCollectionEvent(e)) {
+ for (var topEvent of events) {
+ for (var e of topEvent.enumerateAllDescendents()) {
+ if (isNotForcedTopGarbageCollectionEvent(e)) {
pauses.push({ start: e.start - topEvent.start + time,
end: e.end - topEvent.start + time });
}
- });
+ }
time += topEvent.duration;
- });
+ }
// Now we have one big v8.execute interval from 0 to |time| and
// a list of GC pauses.
var mutatorUtilization = tr.metrics.v8.utils.mutatorUtilization(
0, time, WINDOW_SIZE_MS, pauses);
[0.90, 0.95, 0.99].forEach(function(percent) {
- var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter,
- mutatorUtilization.percentile(1.0 - percent) * 100);
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-v8-execute-mutator-utilization_pct_0' +
- percent * 100,
- value));
+ var hist = new tr.v.Histogram(
+ 'v8-execute-mutator-utilization_pct_0' + percent * 100,
+ percentage_biggerIsBetter);
+ hist.addSample(mutatorUtilization.percentile(1.0 - percent));
+ values.addHistogram(hist);
});
- var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter,
- mutatorUtilization.min);
- values.addValue(new tr.v.NumericValue(
- stageTitle + '-v8-execute-mutator-utilization_min', value));
+ var hist = new tr.v.Histogram(
+ 'v8-execute-mutator-utilization_min', percentage_biggerIsBetter);
+ hist.addSample(mutatorUtilization.min);
+ values.addHistogram(hist);
}
);
}
- /**
- * Filters events using the |filterCallback|, then groups events by the user
- * expectation stage title and the name computed using the |nameCallback|,
- * and then invokes the |processCallback| with the grouped events.
- * @param {Function} filterCallback Takes an event and returns a boolean.
- * @param {Function} nameCallback Takes event and returns a string.
- * @param {Function} processCallback Takes a stage title, a name, and
- * an array of events.
- */
- function groupAndProcessEvents(model, filterCallback,
- nameCallback, processCallback) {
- // Two level map: stageTitle -> name -> [events].
- var stageTitleToNameToEvents = {};
- model.userModel.expectations.forEach(function(ue) {
- stageTitleToNameToEvents[ue.stageTitle] =
- stageTitleToNameToEvents[ue.stageTitle] || {};
- var nameToEvents = stageTitleToNameToEvents[ue.stageTitle];
- ue.associatedEvents.forEach(function(event) {
- if (!filterCallback(event)) return;
- var name = nameCallback(event);
- nameToEvents[name] = nameToEvents[name] || [];
- nameToEvents[name].push(event);
- });
- });
- tr.b.iterItems(stageTitleToNameToEvents,
- function(stageTitle, nameToEvents) {
- tr.b.iterItems(nameToEvents, function(name, events) {
- processCallback(stageTitle, name, events);
- });
- }
- );
- }
-
return {
gcMetric: gcMetric,
WINDOW_SIZE_MS: WINDOW_SIZE_MS // For testing purposes only.
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html
index a0e32cfdbb5..1ae15e021fe 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html
@@ -19,17 +19,13 @@ tr.b.unittest.testSuite(function() {
function createModel(start, end, slices) {
var opts = {
customizeModelCallback: function(model) {
- var group = new tr.model.SliceGroup(tr.c.TestUtils.newFakeThread());
- var ue = new tr.model.um.AnimationExpectation(
- model, 'test', start, end);
+ var process = model.getOrCreateProcess(1);
+ var thread = process.getOrCreateThread(2);
+ var group = thread.sliceGroup;
slices.forEach(function(slice) {
group.pushSlice(tr.c.TestUtils.newSliceEx(slice));
});
group.createSubSlices();
- group.slices.forEach(function(slice) {
- ue.associatedEvents.push(slice);
- });
- model.userModel.expectations.push(ue);
}
};
var model = tr.c.TestUtils.newModelWithEvents([], opts);
@@ -37,7 +33,7 @@ tr.b.unittest.testSuite(function() {
}
function constructName(name, suffix) {
- return 'Animation-' + name + '_' + suffix;
+ return name + '_' + suffix;
}
function run(slices) {
@@ -46,11 +42,7 @@ tr.b.unittest.testSuite(function() {
var endTime = slices.reduce((acc, slice) => (Math.max(acc, slice.end)));
var model = createModel(startTime - 1, endTime + 1, slices);
tr.metrics.v8.gcMetric(values, model);
- var result = {};
- values.valueDicts.forEach(function(value) {
- result[value.name] = value.numeric.value;
- });
- return result;
+ return values;
}
test('topEvents', function() {
@@ -72,24 +64,30 @@ tr.b.unittest.testSuite(function() {
}
];
var actual = run(slices);
- var expected = {
- sum: 100,
- count: 1,
- avg: 100,
- max: 100,
- idle_deadline_overrun_sum: 0,
- idle_deadline_overrun_avg: 0,
- idle_deadline_overrun_max: 0,
- outside_idle_sum: 100,
- outside_idle_avg: 100,
- outside_idle_max: 100,
- percentage_idle: 0
- };
- tr.b.iterItems(expected, function(key, value) {
- var name = constructName(telemetryName, key);
- assert.equal(name + ':' + actual[name], name + ':' + value);
- });
- assert.closeTo(actual[constructName(telemetryName, 'pct_090')], 100, 1);
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(telemetryName));
+ assert.strictEqual(value.running.sum, 100);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 100);
+ assert.strictEqual(value.running.max, 100);
+ assert.closeTo(value.getApproximatePercentile(0.90), 100, 1);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_outside_idle'));
+ assert.strictEqual(value.running.sum, 100);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ telemetryName + '_percentage_idle'));
+ assert.strictEqual(value.average, 0);
});
});
@@ -107,23 +105,29 @@ tr.b.unittest.testSuite(function() {
}
];
var actual = run(slices);
- var expected = {
- sum: 80,
- count: 1,
- avg: 80,
- max: 80,
- idle_deadline_overrun_sum: 0,
- idle_deadline_overrun_avg: 0,
- idle_deadline_overrun_max: 0,
- outside_idle_sum: 0,
- outside_idle_avg: 0,
- outside_idle_max: 0,
- percentage_idle: 100
- };
- tr.b.iterItems(expected, function(key, value) {
- var name = constructName('v8-gc-latency-mark-compactor', key);
- assert.equal(name + ':' + actual[name], name + ':' + value);
- });
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor'));
+ assert.strictEqual(value.running.sum, 80);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 80);
+ assert.strictEqual(value.running.max, 80);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_outside_idle'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_percentage_idle'));
+ assert.strictEqual(value.average, 1);
});
test('idleTimeOverrun', function() {
@@ -140,23 +144,29 @@ tr.b.unittest.testSuite(function() {
}
];
var actual = run(slices);
- var expected = {
- sum: 80,
- count: 1,
- avg: 80,
- max: 80,
- idle_deadline_overrun_sum: 70,
- idle_deadline_overrun_avg: 70,
- idle_deadline_overrun_max: 70,
- outside_idle_sum: 70,
- outside_idle_avg: 70,
- outside_idle_max: 70,
- percentage_idle: 100 / 8
- };
- tr.b.iterItems(expected, function(key, value) {
- var name = constructName('v8-gc-latency-mark-compactor', key);
- assert.equal(name + ':' + actual[name], name + ':' + value);
- });
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor'));
+ assert.strictEqual(value.running.sum, 80);
+ assert.strictEqual(value.numValues, 1);
+ assert.strictEqual(value.average, 80);
+ assert.strictEqual(value.running.max, 80);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 70);
+ assert.strictEqual(value.average, 70);
+ assert.strictEqual(value.running.max, 70);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_outside_idle'));
+ assert.strictEqual(value.running.sum, 70);
+ assert.strictEqual(value.average, 70);
+ assert.strictEqual(value.running.max, 70);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_percentage_idle'));
+ assert.closeTo(value.average, 1 / 8, 1e-6);
});
test('subEvents', function() {
@@ -172,16 +182,11 @@ tr.b.unittest.testSuite(function() {
},
];
var actual = run(slices);
- var expected = {
- avg: 80,
- max: 80,
- };
var telemetryName = 'v8-gc-latency-mark-compactor-mark';
- tr.b.iterItems(expected, function(key, value) {
- var name = constructName(telemetryName, key);
- assert.equal(name + ':' + actual[name], name + ':' + value);
- });
- assert.closeTo(actual[constructName(telemetryName, 'pct_090')], 80, 1);
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(telemetryName));
+ assert.strictEqual(value.average, 80);
+ assert.strictEqual(value.running.max, 80);
+ assert.closeTo(value.getApproximatePercentile(0.90), 80, 1);
});
test('total', function() {
@@ -197,23 +202,52 @@ tr.b.unittest.testSuite(function() {
}
];
var actual = run(slices);
- var expected = {
- sum: 180,
- count: 2,
- avg: 90,
- max: 100,
- idle_deadline_overrun_sum: 0,
- idle_deadline_overrun_avg: 0,
- idle_deadline_overrun_max: 0,
- outside_idle_sum: 180,
- outside_idle_avg: 90,
- outside_idle_max: 100,
- percentage_idle: 0
- };
- tr.b.iterItems(expected, function(key, value) {
- var name = constructName('v8-gc-total', key);
- assert.equal(name + ':' + actual[name], name + ':' + value);
- });
+
+ var value = tr.b.getOnlyElement(actual.getValuesNamed('v8-gc-total'));
+ assert.strictEqual(value.running.sum, 180);
+ assert.strictEqual(value.numValues, 2);
+ assert.strictEqual(value.average, 90);
+ assert.strictEqual(value.running.max, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-total_idle_deadline_overrun'));
+ assert.strictEqual(value.running.sum, 0);
+ assert.strictEqual(value.average, 0);
+ assert.strictEqual(value.running.max, 0);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-total_outside_idle'));
+ assert.strictEqual(value.running.sum, 180);
+ assert.strictEqual(value.average, 90);
+ assert.strictEqual(value.running.max, 100);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-total_percentage_idle'));
+ assert.strictEqual(value.average, 0);
+ });
+
+ test('percentageInV8Execute', function() {
+ var values = new tr.v.ValueSet();
+ var slices = [
+ {
+ title: 'V8.Execute',
+ args: {}, start: 100, end: 200,
+ cpuStart: 100, cpuEnd: 200
+ },
+ {
+ title: 'V8.GCFinalizeMC', args: {}, start: 110, end: 190,
+ cpuStart: 110, cpuEnd: 190
+ },
+ {
+ title: 'V8.GCFinalizeMC', args: {}, start: 210, end: 220,
+ cpuStart: 210, cpuEnd: 220
+ }
+ ];
+ var actual = run(slices);
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-gc-latency-mark-compactor_percentage_in_v8_execute'));
+ assert.strictEqual(value.average,
+ (190 - 110) / ((190 - 110) + (220 - 210)));
});
test('mutatorUtilization', function() {
@@ -240,13 +274,16 @@ tr.b.unittest.testSuite(function() {
0, 300, tr.metrics.v8.WINDOW_SIZE_MS,
[{start: 50, end: 60}, {start: 110, end: 120}]);
var actual = run(slices);
- assert.strictEqual(
- actual['Animation-v8-execute-mutator-utilization_pct_095'],
- mutatorUtilization.percentile(1 - 0.95) * 100);
- assert.strictEqual(
- actual['Animation-v8-execute-mutator-utilization_pct_099'],
- mutatorUtilization.percentile(1 - 0.99) * 100);
- });
+ var value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-execute-mutator-utilization_pct_095'));
+ assert.closeTo(value.average,
+ mutatorUtilization.percentile(1 - 0.95), 1e-2);
+
+ value = tr.b.getOnlyElement(actual.getValuesNamed(
+ 'v8-execute-mutator-utilization_pct_099'));
+ assert.closeTo(value.average,
+ mutatorUtilization.percentile(1 - 0.99), 1e-2);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html
index 1d561d0811f..36e2b70152a 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html
@@ -4,13 +4,13 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/piecewise_linear_function.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/range_utils.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
@@ -30,6 +30,9 @@ tr.exportTo('tr.metrics.v8.utils', function() {
var LOW_MEMORY_EVENT = 'V8.GCLowMemoryNotification';
+ var MAJOR_GC_EVENT = 'MajorGC';
+ var MINOR_GC_EVENT = 'MinorGC';
+
// Maps the top-level GC events in timeline to telemetry friendly names.
var TOP_GC_EVENTS = {
'V8.GCCompactor': 'v8-gc-full-mark-compactor',
@@ -38,11 +41,12 @@ tr.exportTo('tr.metrics.v8.utils', function() {
'V8.GCIncrementalMarking': 'v8-gc-incremental-step',
'V8.GCIncrementalMarkingFinalize': 'v8-gc-incremental-finalize',
'V8.GCIncrementalMarkingStart': 'v8-gc-incremental-start',
- 'V8.GCLowMemoryNotification': 'v8-gc-low-memory-mark-compactor',
'V8.GCPhantomHandleProcessingCallback' : 'v8-gc-phantom-handle-callback',
'V8.GCScavenger': 'v8-gc-scavenger'
};
+ var LOW_MEMORY_MARK_COMPACTOR = 'v8-gc-low-memory-mark-compactor';
+
/**
* Finds the first parent of the |event| for which the |predicate| holds.
*/
@@ -77,16 +81,26 @@ tr.exportTo('tr.metrics.v8.utils', function() {
// Low memory notification is handled specially because it contains
// several full mark compact events.
return event.title && event.title.startsWith(GC_EVENT_PREFIX) &&
- event.title != LOW_MEMORY_EVENT;
+ event.title !== LOW_MEMORY_EVENT;
}
function isTopGarbageCollectionEvent(event) {
return event.title in TOP_GC_EVENTS;
}
+ function isForcedGarbageCollectionEvent(event) {
+ return findParent(event, isLowMemoryEvent) !== null;
+ }
+
function isSubGarbageCollectionEvent(event) {
+ // To reduce number of results, we return only the first level of GC
+ // subevents. Some subevents are nested in MajorGC or MinorGC events, so
+ // we have to check for it explicitly.
return isGarbageCollectionEvent(event) &&
- !isTopGarbageCollectionEvent(event);
+ event.parentSlice &&
+ (isTopGarbageCollectionEvent(event.parentSlice) ||
+ event.parentSlice.title === MAJOR_GC_EVENT ||
+ event.parentSlice.title === MINOR_GC_EVENT);
}
function topGarbageCollectionEventName(event) {
@@ -94,7 +108,7 @@ tr.exportTo('tr.metrics.v8.utils', function() {
// Full mark compact events inside a low memory notification
// are counted as low memory mark compacts.
if (findParent(event, isLowMemoryEvent)) {
- return TOP_GC_EVENTS[LOW_MEMORY_EVENT];
+ return LOW_MEMORY_MARK_COMPACTOR;
}
}
return TOP_GC_EVENTS[event.title];
@@ -112,6 +126,29 @@ tr.exportTo('tr.metrics.v8.utils', function() {
}
/**
+ * Filters events using the |filterCallback|, then groups events by the user
+ * the name computed using the |nameCallback|, and then invokes
+ * the |processCallback| with the grouped events.
+ * @param {Function} filterCallback Takes an event and returns a boolean.
+ * @param {Function} nameCallback Takes event and returns a string.
+ * @param {Function} processCallback Takes a name, and an array of events.
+ */
+ function groupAndProcessEvents(model, filterCallback,
+ nameCallback, processCallback) {
+ // Map: name -> [events].
+ var nameToEvents = {};
+ for (var event of model.getDescendantEvents()) {
+ if (!filterCallback(event)) continue;
+ var name = nameCallback(event);
+ nameToEvents[name] = nameToEvents[name] || [];
+ nameToEvents[name].push(event);
+ }
+ tr.b.iterItems(nameToEvents, function(name, events) {
+ processCallback(name, events);
+ });
+ }
+
+ /**
* Given a list of intervals, returns a new list with all overalapping
* intervals merged into a single interval.
*/
@@ -238,19 +275,39 @@ tr.exportTo('tr.metrics.v8.utils', function() {
return mu;
}
+ function hasV8Stats(globalMemoryDump) {
+ var v8stats = undefined;
+ globalMemoryDump.iterateContainerDumps(function(dump) {
+ v8stats = v8stats || dump.getMemoryAllocatorDumpByFullName('v8');
+ });
+ return !!v8stats;
+ }
+
+ function rangeForMemoryDumps(model) {
+ var startOfFirstDumpWithV8 =
+ model.globalMemoryDumps.filter(hasV8Stats).reduce(
+ (start, dump) => Math.min(start, dump.start), Infinity);
+ if (startOfFirstDumpWithV8 === Infinity)
+ return new tr.b.Range(); // Empty range.
+ return tr.b.Range.fromExplicitRange(startOfFirstDumpWithV8, Infinity);
+ }
+
return {
findParent: findParent,
+ groupAndProcessEvents: groupAndProcessEvents,
+ isForcedGarbageCollectionEvent: isForcedGarbageCollectionEvent,
+ isGarbageCollectionEvent: isGarbageCollectionEvent,
isIdleTask: isIdleTask,
isLowMemoryEvent: isLowMemoryEvent,
- isV8ExecuteEvent: isV8ExecuteEvent,
- isTopV8ExecuteEvent: isTopV8ExecuteEvent,
- isGarbageCollectionEvent: isGarbageCollectionEvent,
- isTopGarbageCollectionEvent: isTopGarbageCollectionEvent,
isSubGarbageCollectionEvent: isSubGarbageCollectionEvent,
- topGarbageCollectionEventName: topGarbageCollectionEventName,
+ isTopGarbageCollectionEvent: isTopGarbageCollectionEvent,
+ isTopV8ExecuteEvent: isTopV8ExecuteEvent,
+ isV8ExecuteEvent: isV8ExecuteEvent,
+ mutatorUtilization: mutatorUtilization,
subGarbageCollectionEventName: subGarbageCollectionEventName,
- unionOfIntervals: unionOfIntervals,
- mutatorUtilization: mutatorUtilization
+ topGarbageCollectionEventName: topGarbageCollectionEventName,
+ rangeForMemoryDumps: rangeForMemoryDumps,
+ unionOfIntervals: unionOfIntervals
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils_test.html
index d5068a16c52..775de11e702 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils_test.html
@@ -5,7 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/metrics/v8/utils.html">
+<link rel="import" href="/tracing/model/memory_dump_test_utils.html">
<script>
'use strict';
@@ -141,5 +143,34 @@ tr.b.unittest.testSuite(function() {
assert.closeTo(expected.percentile(0.9), actual.percentile(0.9), 1e-3);
});
+ function addDumpWithAllocator(model, process, allocator, start) {
+ var gmd = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump(
+ model, {ts: start});
+ var pmd = tr.model.MemoryDumpTestUtils.addProcessMemoryDump(gmd, process);
+ pmd.memoryAllocatorDumps =
+ [tr.model.MemoryDumpTestUtils.newAllocatorDump(pmd, allocator)];
+ }
+
+ test('rangeForMemoryDumps', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var process = model.getOrCreateProcess(1);
+ addDumpWithAllocator(model, process, 'dummy', 10);
+ addDumpWithAllocator(model, process, 'v8', 20);
+ });
+ var range = tr.metrics.v8.utils.rangeForMemoryDumps(model);
+ assert.isFalse(range.isEmpty);
+ assert.strictEqual(range.min, 20);
+ assert.strictEqual(range.max, Infinity);
+ });
+
+ test('rangeForMemoryDumpsEmpty', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var process = model.getOrCreateProcess(1);
+ addDumpWithAllocator(model, process, 'dummy', 10);
+ addDumpWithAllocator(model, process, 'dummy', 20);
+ });
+ var range = tr.metrics.v8.utils.rangeForMemoryDumps(model);
+ assert.isTrue(range.isEmpty);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/v8_metrics.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/v8_metrics.html
index 1fa69344494..59e4c49dd7f 100644
--- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/v8_metrics.html
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/v8_metrics.html
@@ -17,7 +17,8 @@ tr.exportTo('tr.metrics.v8', function() {
function v8AndMemoryMetrics(values, model) {
tr.metrics.v8.executionMetric(values, model);
tr.metrics.v8.gcMetric(values, model);
- tr.metrics.sh.memoryMetric(values, model);
+ tr.metrics.sh.memoryMetric(values, model,
+ {rangeOfInterest: tr.metrics.v8.utils.rangeForMemoryDumps(model)});
}
tr.metrics.MetricRegistry.register(v8AndMemoryMetrics);
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/valueset_output_for_compare_samples_test.json b/chromium/third_party/catapult/tracing/tracing/metrics/valueset_output_for_compare_samples_test.json
new file mode 100644
index 00000000000..85ec04033fe
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/metrics/valueset_output_for_compare_samples_test.json
@@ -0,0 +1 @@
+[{"sampleValues":[70.38199999928474],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":70.38199999928474,"max":70.38199999928474,"sum":70.38199999928474,"meanlogs":4.253937548643484,"variance":0,"mean":70.38199999928474},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b33442c5-4666-46b1-aa73-b726ff995caf","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[339.4839999973774],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":339.4839999973774,"max":339.4839999973774,"sum":339.4839999973774,"meanlogs":5.827426817750858,"variance":0,"mean":339.4839999973774},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"97c09fee-7599-4ba6-bffd-d82c7d38a8de","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[251.50699999928474],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":251.50699999928474,"max":251.50699999928474,"sum":251.50699999928474,"meanlogs":5.527470822151607,"variance":0,"mean":251.50699999928474},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1368.7138160020113,"stableId":"12281.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1620.220816001296,"stableId":"12281.1295.SliceGroup.1134","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":10.090408136743806,"other":241.41659186254103,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1368.7138160020113,"pid":12281,"fmp":1620.220816001296}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"fb9a13e6-01e8-4ffa-8a49-58d3d554175e","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[359.9989999961258],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":359.9989999961258,"max":359.9989999961258,"sum":359.9989999961258,"meanlogs":5.886101253657758,"variance":0,"mean":359.9989999961258},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1368.7138160020113,"stableId":"12281.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":68.534,"start":1710.178815998137,"stableId":"12281.1295.SliceGroup.1565","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1368.7138160020113,"pid":12281,"interactive":1728.712815998137}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.300027209535319,"other":348.69897278659045,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"bc6f6373-1243-4ee4-bf41-4ad4c2cc3a3b","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[71.0029999986291,32.31400000303984],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":32.31400000303984,"max":71.0029999986291,"sum":103.31700000166893,"meanlogs":3.869111351299595,"variance":748.4193603293527,"mean":51.658500000834465},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5a1f5cdd-8f05-4b8e-914e-b25ed8ed3446","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[89.73600000143051,412.53999999910593,28.776000000536442,168.152000002563],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":4,"min":28.776000000536442,"max":412.53999999910593,"sum":699.2040000036359,"meanlogs":4.750903808953008,"variance":85123.39617114076,"mean":174.80100000090897},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"f46ae39d-3321-4ac7-8917-8c5d02ceaa98","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[169.51699999719858,124.88199999928474],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":124.88199999928474,"max":169.51699999719858,"sum":294.3989999964833,"meanlogs":4.980161254103994,"variance":996.1416124068842,"mean":147.19949999824166},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4115.824345007539,"stableId":"12298.1295.SliceGroup.2104","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":4240.7063450068235,"stableId":"12298.1295.SliceGroup.2481","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":12.713352381822483,"other":112.16864761746226,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":4115.824345007539,"pid":12298,"fmp":4240.7063450068235}}}]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1083.3763450086117,"stableId":"12298.1295.SliceGroup.43","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1252.8933450058103,"stableId":"12298.1295.SliceGroup.939","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":23.184204388645075,"other":146.33279560855354,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1083.3763450086117,"pid":12298,"fmp":1252.8933450058103}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"e151c66a-db91-4b8e-8a72-ed553961e7ed","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[3270.468000001848,238.02000000292082],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":238.02000000292082,"max":3270.468000001848,"sum":3508.4880000047688,"meanlogs":6.78252153834195,"variance":4597870.4363487465,"mean":1754.2440000023844},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4115.824345007539,"stableId":"12298.1295.SliceGroup.2104","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":118.309,"start":4285.535345010459,"stableId":"12298.1295.SliceGroup.2896","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":4115.824345007539,"pid":12298,"interactive":4353.84434501046}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":13.61272462908967,"other":224.40727537383125,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1083.3763450086117,"stableId":"12298.1295.SliceGroup.43","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":118.309,"start":4285.535345010459,"stableId":"12298.1295.SliceGroup.2896","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1083.3763450086117,"pid":12298,"interactive":4353.84434501046}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2407.6157246280027,"other":862.8522753738349,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"927f25d6-eb94-4838-9deb-514a8c8310e1","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[143.6650000065565],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":143.6650000065565,"max":143.6650000065565,"sum":143.6650000065565,"meanlogs":4.96748420048591,"variance":0,"mean":143.6650000065565},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"db5c1ae8-a3e1-4331-a298-021dd6921207","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[358.4480000063777],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":358.4480000063777,"max":358.4480000063777,"sum":358.4480000063777,"meanlogs":5.8817836007223665,"variance":0,"mean":358.4480000063777},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"56147d2a-21c4-43eb-9a7b-8f96d4f9460d","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[143.6740000024438],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":143.6740000024438,"max":143.6740000024438,"sum":143.6740000024438,"meanlogs":4.967546844233469,"variance":0,"mean":143.6740000024438},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1470.4746529981494,"stableId":"12328.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1614.1486530005932,"stableId":"12328.1295.SliceGroup.503","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":8.732362295842842,"other":134.94163770660091,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1470.4746529981494,"pid":12328,"fmp":1614.1486530005932}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"7e2001b7-7590-452b-9449-b37d497ef289","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[202.7290000022649],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":202.7290000022649,"max":202.7290000022649,"sum":202.7290000022649,"meanlogs":5.311870111810042,"variance":0,"mean":202.7290000022649},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1470.4746529981494,"stableId":"12328.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":54.897,"start":1668.3066530004144,"stableId":"12328.1295.SliceGroup.1339","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1470.4746529981494,"pid":12328,"interactive":1673.2036530004143}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":10.697713706017549,"other":192.03128629624717,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"18d559c1-f50a-482d-baf1-5e03a6aea4d5","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[162.48300000280142,50.48199999332428],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":50.48199999332428,"max":162.48300000280142,"sum":212.9649999961257,"meanlogs":4.5060951089485375,"variance":6272.112001561449,"mean":106.48249999806285},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"2be0298e-f59e-4b56-9a3a-10cd134b74ba","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[440.8449999988079,136.38299999386072],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":136.38299999386072,"max":440.8449999988079,"sum":577.2279999926686,"meanlogs":5.502080221952837,"variance":46348.55472350623,"mean":288.6139999963343},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"95a83409-8b7f-4869-946b-8d9320f7a714","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[162.50100000202656,50.4919999986887],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":50.4919999986887,"max":162.50100000202656,"sum":212.99300000071526,"meanlogs":4.506249531737064,"variance":6273.00804087387,"mean":106.49650000035763},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3776.59332100302,"stableId":"12344.1295.SliceGroup.2516","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3827.0853210017085,"stableId":"12344.1295.SliceGroup.2602","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.262581339684662,"other":43.22941865900404,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3776.59332100302,"pid":12344,"fmp":3827.0853210017085}}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1062.3743209987879,"stableId":"12344.1295.SliceGroup.43","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1224.8753210008144,"stableId":"12344.1295.SliceGroup.486","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":22.093557667398244,"other":140.40744233462846,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1062.3743209987879,"pid":12344,"fmp":1224.8753210008144}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5811d8d6-3ac1-4376-be5c-7746fc6add13","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[287.0319999976159,50.4919999986887],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":50.4919999986887,"max":287.0319999976159,"sum":337.5239999963046,"meanlogs":4.790704307829166,"variance":27975.585799746244,"mean":168.7619999981523},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3776.59332100302,"stableId":"12344.1295.SliceGroup.2516","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3776.59332100302,"pid":12344,"interactive":3827.0853210017085}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.262581339684662,"other":43.22941865900404,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1062.3743209987879,"stableId":"12344.1295.SliceGroup.43","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":64.592,"start":1334.8143209964037,"stableId":"12344.1295.SliceGroup.1314","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1062.3743209987879,"pid":12344,"interactive":1349.4063209964038}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":25.59417996654234,"other":261.437820031074,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"41f9d752-c102-4713-b3fe-b9d143078850","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[144.19200000166893],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":144.19200000166893,"max":144.19200000166893,"sum":144.19200000166893,"meanlogs":4.971145744821354,"variance":0,"mean":144.19200000166893},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ab7bac8a-6641-4891-95e6-c9f2700691c9","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[180.46000000089407],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":180.46000000089407,"max":180.46000000089407,"sum":180.46000000089407,"meanlogs":5.195509146571309,"variance":0,"mean":180.46000000089407},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a2060906-d772-4dce-855a-194b8750d68d","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[144.20500000566244],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":144.20500000566244,"max":144.20500000566244,"sum":144.20500000566244,"meanlogs":4.971235898352784,"variance":0,"mean":144.20500000566244},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1499.2115845009685,"stableId":"12371.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1643.416584506631,"stableId":"12371.1295.SliceGroup.491","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":12.871453827442304,"other":131.33354617822008,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1499.2115845009685,"pid":12371,"fmp":1643.416584506631}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3a38ff66-f077-4d69-9e62-460a4edd95e0","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[263.6500000003575],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":263.6500000003575,"max":263.6500000003575,"sum":263.6500000003575,"meanlogs":5.574622465977835,"variance":0,"mean":263.6500000003575},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1499.2115845009685,"stableId":"12371.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":132.216,"start":1680.645584501326,"stableId":"12371.1295.SliceGroup.688","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1499.2115845009685,"pid":12371,"interactive":1762.861584501326}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":19.351323453828954,"other":244.29867654652858,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"19f77af9-cdc6-49fa-909f-e92268cebb9f","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[157.93800000101328,53.311000004410744],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":53.311000004410744,"max":157.93800000101328,"sum":211.24900000542402,"meanlogs":4.519172619953633,"variance":5473.404564144534,"mean":105.62450000271201},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1346938c-1bbd-49c1-9f50-48e27d782d33","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[205.67899999767542,14.987999998033047,97.43600000441074],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":3,"min":14.987999998033047,"max":205.67899999767542,"sum":318.1030000001192,"meanlogs":4.2042541113581375,"variance":18292.42574448572,"mean":106.03433333337307},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"0644db69-4a92-41bb-8c50-0bcbd84795b1","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[157.94799999892712,53.32000000029802],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":53.32000000029802,"max":157.94799999892712,"sum":211.26799999922514,"meanlogs":4.519288680121174,"variance":5473.509191856565,"mean":105.63399999961257},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3800.4072019979358,"stableId":"12477.1295.SliceGroup.1089","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3853.727201998234,"stableId":"12477.1295.SliceGroup.1275","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.907739235120454,"other":41.41226076517755,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3800.4072019979358,"pid":12477,"fmp":3853.727201998234}}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1161.119202002883,"stableId":"12477.1295.SliceGroup.46","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1319.06720200181,"stableId":"12477.1295.SliceGroup.512","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":27.018283272946938,"other":130.92971672598026,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1161.119202002883,"pid":12477,"fmp":1319.06720200181}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"16472fe4-fbab-4fb6-8b7d-574addd88187","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[2761.1069999980928,121.81900000303995],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":121.81900000303995,"max":2761.1069999980928,"sum":2882.9260000011327,"meanlogs":6.362961650910026,"variance":3482920.573458943,"mean":1441.4630000005664},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3800.4072019979358,"stableId":"12477.1295.SliceGroup.1089","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":73.88,"start":3898.3462020009756,"stableId":"12477.1295.SliceGroup.1476","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3800.4072019979358,"pid":12477,"interactive":3922.2262020009757}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":13.748215326475623,"other":108.07078467656432,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1161.119202002883,"stableId":"12477.1295.SliceGroup.46","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":73.88,"start":3898.3462020009756,"stableId":"12477.1295.SliceGroup.1476","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1161.119202002883,"pid":12477,"interactive":3922.2262020009757}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2288.166215321516,"other":472.94078467656647,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"95811b85-f445-4462-9f7d-e12643d3966c","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[167.67499999701977],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":167.67499999701977,"max":167.67499999701977,"sum":167.67499999701977,"meanlogs":5.122027581968027,"variance":0,"mean":167.67499999701977},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"4252312b-dc07-49d0-8838-1a87f8c015eb","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[535.7069999948144],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":535.7069999948144,"max":535.7069999948144,"sum":535.7069999948144,"meanlogs":6.283587369806982,"variance":0,"mean":535.7069999948144},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"0a79bc9c-7fd4-4c51-8fa1-a1f50adf06b0","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[522.1279999986291],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":522.1279999986291,"max":522.1279999986291,"sum":522.1279999986291,"meanlogs":6.257912768548746,"variance":0,"mean":522.1279999986291},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1390.9719379991293,"stableId":"12502.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1913.0999379977584,"stableId":"12502.1295.SliceGroup.335","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":20.887765319936285,"other":501.2402346786927,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1390.9719379991293,"pid":12502,"fmp":1913.0999379977584}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ffcd41bb-8b86-4acc-a473-49146fa60f2d","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[865.292999997258],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":865.292999997258,"max":865.292999997258,"sum":865.292999997258,"meanlogs":6.763068177896923,"variance":0,"mean":865.292999997258},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1390.9719379991293,"stableId":"12502.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":220.912,"start":2085.3529379963875,"stableId":"12502.1295.SliceGroup.991","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1390.9719379991293,"pid":12502,"interactive":2256.2649379963873}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":25.97740895418478,"other":839.315591043073,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"63cc14d3-74d8-4260-a90c-ff90e2d13acc","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[187.2119999974966,60.483999997377396],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":60.483999997377396,"max":187.2119999974966,"sum":247.695999994874,"meanlogs":4.667310265873402,"variance":8029.992992015107,"mean":123.847999997437},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"90a57eed-c170-4f64-bdf6-d863d0394e45","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[576.9139999970794,133.43899999558926],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":133.43899999558926,"max":576.9139999970794,"sum":710.3529999926686,"meanlogs":5.6256688265726025,"variance":98335.03781316083,"mean":355.1764999963343},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c84d9c82-ee49-40a8-8765-fcd2fc79c9fb","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[562.7139999940991,125.57199999690056],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":125.57199999690056,"max":562.7139999940991,"sum":688.2859999909997,"meanlogs":5.582825402691217,"variance":95546.56408077538,"mean":344.14299999549985},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4288.899080000818,"stableId":"12520.1295.SliceGroup.1821","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":4414.471079997718,"stableId":"12520.1295.SliceGroup.1970","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":32.31220147690038,"other":93.25979852000016,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":4288.899080000818,"pid":12520,"fmp":4414.471079997718}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1097.6900800019503,"stableId":"12520.1295.SliceGroup.42","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1660.4040799960494,"stableId":"12520.1295.SliceGroup.313","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":37.99864568807277,"other":524.7153543060263,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1097.6900800019503,"pid":12520,"fmp":1660.4040799960494}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"fa002527-5197-4488-9e94-fda46ed0a646","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[3566.1129999982713,374.9039999994038],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":374.9039999994038,"max":3566.1129999982713,"sum":3941.016999997675,"meanlogs":7.05295073964089,"variance":5091907.440836886,"mean":1970.5084999988376},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4288.899080000818,"stableId":"12520.1295.SliceGroup.1821","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":201.669,"start":4512.134080000222,"stableId":"12520.1295.SliceGroup.2220","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":4288.899080000818,"pid":12520,"interactive":4663.803080000222}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":52.78322305895129,"other":322.1207769404524,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1097.6900800019503,"stableId":"12520.1295.SliceGroup.42","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":201.669,"start":4512.134080000222,"stableId":"12520.1295.SliceGroup.2220","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1097.6900800019503,"pid":12520,"interactive":4663.803080000222}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2056.4012230578105,"other":1509.711776940458,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"35acf845-0ecd-43dd-9267-1e7feb018435","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[66.96399999409914],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":66.96399999409914,"max":66.96399999409914,"sum":66.96399999409914,"meanlogs":4.204155161465419,"variance":0,"mean":66.96399999409914},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ed9d9083-38e6-4ad2-85bf-411a1bd02f82","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[435.9099999964237],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":435.9099999964237,"max":435.9099999964237,"sum":435.9099999964237,"meanlogs":6.077435800014524,"variance":0,"mean":435.9099999964237},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"7735255f-4026-4db0-ae2f-994ba1c4ba38","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[158.4670000001788],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":158.4670000001788,"max":158.4670000001788,"sum":158.4670000001788,"meanlogs":5.065546369748696,"variance":0,"mean":158.4670000001788},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1460.03830049932,"stableId":"12548.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1618.5053004994988,"stableId":"12548.1295.SliceGroup.963","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":10.373592102044341,"other":148.0934078981346,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1460.03830049932,"pid":12548,"fmp":1618.5053004994988}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5a09e58b-1705-4bb8-92a8-685242de0ca6","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[384.72199999558916],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":384.72199999558916,"max":384.72199999558916,"sum":384.72199999558916,"meanlogs":5.952520995530414,"variance":0,"mean":384.72199999558916},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1460.03830049932,"stableId":"12548.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":97.908,"start":1796.8523004949093,"stableId":"12548.1295.SliceGroup.1457","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1460.03830049932,"pid":12548,"interactive":1844.7603004949092}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.979302491655005,"other":372.74269750393506,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a830d58f-e1a2-4598-9ca0-60fcf1e7fc7c","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[102.21299999952316,35.48499999940395],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":35.48499999940395,"max":102.21299999952316,"sum":137.69799999892712,"meanlogs":4.098084471600606,"variance":2226.3129920079546,"mean":68.84899999946356},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"d11771e4-d078-4129-a33d-5e451d999b92","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[186.46599999815226,430.2440000027418,14.380999997258186,183.84699999541044],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":4,"min":14.380999997258186,"max":430.2440000027418,"sum":814.9379999935627,"meanlogs":4.793153296774236,"variance":87855.01530352679,"mean":203.73449999839067},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":2,"diagnosticMaps":[{"url":{"type":"Generic","value":""}},{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a0c0bce4-4d12-49c9-87dc-a193d7d48876","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[102.24100000411272,127.07699999958277],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":102.24100000411272,"max":127.07699999958277,"sum":229.3180000036955,"meanlogs":4.736062986736041,"variance":308.4134478874941,"mean":114.65900000184774},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":2,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1114.3332275003195,"stableId":"12564.1295.SliceGroup.40","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1216.5742275044322,"stableId":"12564.1295.SliceGroup.287","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":23.83599263305738,"other":78.40500737105526,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1114.3332275003195,"pid":12564,"fmp":1216.5742275044322}}},{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3942.1702275052667,"stableId":"12564.1295.SliceGroup.2051","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":4069.2472275048494,"stableId":"12564.1295.SliceGroup.2433","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":16.567506653228094,"other":110.50949334635466,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":3942.1702275052667,"pid":12564,"fmp":4069.2472275048494}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"d9ef5cec-c73e-45dd-b946-fc1f09d521bf","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[3049.9940000008937,222.15699999594653],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":222.15699999594653,"max":3049.9940000008937,"sum":3272.1509999968403,"meanlogs":6.713139620747382,"variance":3998331.04929849,"mean":1636.0754999984201},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3942.1702275052667,"stableId":"12564.1295.SliceGroup.2051","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":84.284,"start":4130.043227501214,"stableId":"12564.1295.SliceGroup.2814","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":3942.1702275052667,"pid":12564,"interactive":4164.327227501213}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":17.668825556659385,"other":204.48817443928695,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1114.3332275003195,"stableId":"12564.1295.SliceGroup.40","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":84.284,"start":4130.043227501214,"stableId":"12564.1295.SliceGroup.2814","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1114.3332275003195,"pid":12564,"interactive":4164.327227501213}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2254.5018255615896,"other":795.4921744392863,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3e4ae7c8-297d-41b8-88a2-cf0d1277c589","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[147.98200000077486],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":147.98200000077486,"max":147.98200000077486,"sum":147.98200000077486,"meanlogs":4.9970906447512204,"variance":0,"mean":147.98200000077486},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b52d9aed-3009-4335-99fb-cf593b66fe60","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[372.515999995172],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":372.515999995172,"max":372.515999995172,"sum":372.515999995172,"meanlogs":5.9202799899043335,"variance":0,"mean":372.515999995172},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"fcc41b33-ecb2-4d44-a729-12b33701dbe5","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[147.99099999666214],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":147.99099999666214,"max":147.99099999666214,"sum":147.99099999666214,"meanlogs":4.997151461081698,"variance":0,"mean":147.99099999666214},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1409.3311719968915,"stableId":"12591.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1557.3221719935536,"stableId":"12591.1295.SliceGroup.506","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":5.055772693341009,"other":142.93522730332108,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1409.3311719968915,"pid":12591,"fmp":1557.3221719935536}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"37ba9924-a9f2-449e-94af-730a35a765d4","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[215.67199999994045],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":215.67199999994045,"max":215.67199999994045,"sum":215.67199999994045,"meanlogs":5.373758735047611,"variance":0,"mean":215.67199999994045},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1409.3311719968915,"stableId":"12591.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":60.661,"start":1614.342171996832,"stableId":"12591.1295.SliceGroup.1339","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1409.3311719968915,"pid":12591,"interactive":1625.003171996832}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.151194885936373,"other":208.5208051140042,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"14acbb42-0527-47a8-8433-c0963175ed4a","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[151.07400000095367,48.9919999986887],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":48.9919999986887,"max":151.07400000095367,"sum":200.06599999964237,"meanlogs":4.454713401225837,"variance":5210.3673622312135,"mean":100.03299999982119},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3b3e9967-2d14-4a47-8e06-b9bc72dc6c6a","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[390.7719999998808,136.31400000303984],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":136.31400000303984,"max":390.7719999998808,"sum":527.0860000029206,"meanlogs":5.441542658874949,"variance":32374.436881196154,"mean":263.5430000014603},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a6efcebd-0b8a-4c0c-8e5b-ac177a3cc7c4","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[151.08600000292063,49],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":49,"max":151.08600000292063,"sum":200.08600000292063,"meanlogs":4.454834754622204,"variance":5210.7756982981555,"mean":100.04300000146031},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3781.6618789955974,"stableId":"12607.1295.SliceGroup.2473","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3830.6618789955974,"stableId":"12607.1295.SliceGroup.2563","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.278638092245469,"other":41.72136190775453,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3781.6618789955974,"pid":12607,"fmp":3830.6618789955974}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1097.2128789946437,"stableId":"12607.1295.SliceGroup.43","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1248.2988789975643,"stableId":"12607.1295.SliceGroup.478","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":17.042867101963246,"other":134.04313290095735,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1097.2128789946437,"pid":12607,"fmp":1248.2988789975643}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"f481b5b5-8b41-45f2-b204-f7477499ddf5","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[236.0690000053644,49],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":49,"max":236.0690000053644,"sum":285.0690000053644,"meanlogs":4.677972216653847,"variance":17497.40538150351,"mean":142.5345000026822},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3781.6618789955974,"stableId":"12607.1295.SliceGroup.2473","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3781.6618789955974,"pid":12607,"interactive":3830.6618789955974}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.278638092245469,"other":41.72136190775453,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1097.2128789946437,"stableId":"12607.1295.SliceGroup.43","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":64.309,"start":1318.972879000008,"stableId":"12607.1295.SliceGroup.1306","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1097.2128789946437,"pid":12607,"interactive":1333.281879000008}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":19.511697958034695,"other":216.55730204732936,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"764c1dba-ed02-4c82-8696-eac7a4fd13b1","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[144.32500000298023],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":144.32500000298023,"max":144.32500000298023,"sum":144.32500000298023,"meanlogs":4.972067700967647,"variance":0,"mean":144.32500000298023},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"78d3990c-65e5-4e6a-92fc-0e89b55b4d67","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[177.8180000036955],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":177.8180000036955,"max":177.8180000036955,"sum":177.8180000036955,"meanlogs":5.180760555321764,"variance":0,"mean":177.8180000036955},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c644d128-3393-4b01-b5e5-dfdff6c6599f","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[144.33500000089407],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":144.33500000089407,"max":144.33500000089407,"sum":144.33500000089407,"meanlogs":4.972136986618016,"variance":0,"mean":144.33500000089407},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1367.4031845033169,"stableId":"12634.1295.SliceGroup.30","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1511.738184504211,"stableId":"12634.1295.SliceGroup.480","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":13.636061310015075,"other":130.69893869087898,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1367.4031845033169,"pid":12634,"fmp":1511.738184504211}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"bbe92495-f924-49c4-8a41-d03e6c17ce27","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[258.3210000013114],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":258.3210000013114,"max":258.3210000013114,"sum":258.3210000013114,"meanlogs":5.554202997615148,"variance":0,"mean":258.3210000013114},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1367.4031845033169,"stableId":"12634.1295.SliceGroup.30","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":129.56300000000002,"start":1546.1611845046282,"stableId":"12634.1295.SliceGroup.677","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1367.4031845033169,"pid":12634,"interactive":1625.7241845046283}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":18.99433502986912,"other":239.3266649714422,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a4c6416c-cad4-4d5a-90b3-a6417e4e2164","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[172.46599999815226],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":172.46599999815226,"max":172.46599999815226,"sum":172.46599999815226,"meanlogs":5.150200115584382,"variance":0,"mean":172.46599999815226},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"977dc7ab-0759-42d5-bc39-ed93062f10f3","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[277.9209999963641,13.547000005841255,106.92300000041723],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":3,"min":13.547000005841255,"max":277.9209999963641,"sum":398.3910000026226,"meanlogs":4.301870323634383,"variance":35951.00174952996,"mean":132.7970000008742},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"9bc8e8f3-af09-4833-bc4a-faeef448a984","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[172.4780000001192],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":172.4780000001192,"max":172.4780000001192,"sum":172.4780000001192,"meanlogs":5.150269692106785,"variance":0,"mean":172.4780000001192},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1116.2510975077748,"stableId":"12650.1295.SliceGroup.43","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1288.729097507894,"stableId":"12650.1295.SliceGroup.513","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":39.16003215055435,"other":133.31796784956478,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1116.2510975077748,"pid":12650,"fmp":1288.729097507894}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"10e0fa26-2342-4c8f-bc84-ea6508b7e7b2","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[315.9119999968409],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":315.9119999968409,"max":315.9119999968409,"sum":315.9119999968409,"meanlogs":5.755463693781216,"variance":0,"mean":315.9119999968409},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1116.2510975077748,"stableId":"12650.1295.SliceGroup.43","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":86.20400000000001,"start":1395.9590975046158,"stableId":"12650.1295.SliceGroup.687","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1116.2510975077748,"pid":12650,"interactive":1432.1630975046157}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":104.45840612475396,"other":211.45359387208708,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5fc5661e-2e79-48af-8ccc-0a47e67b5d80","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[166.82799999415874],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":166.82799999415874,"max":166.82799999415874,"sum":166.82799999415874,"meanlogs":5.116963341509195,"variance":0,"mean":166.82799999415874},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"762a95c9-39d6-4258-92dc-d7c066ddaaa1","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[569.8699999973178],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":569.8699999973178,"max":569.8699999973178,"sum":569.8699999973178,"meanlogs":6.345408264636493,"variance":0,"mean":569.8699999973178},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"0322c0e4-a9f5-4b74-8908-679f3bdfc3d3","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[555.8559999987483],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":555.8559999987483,"max":555.8559999987483,"sum":555.8559999987483,"meanlogs":6.320509267898147,"variance":0,"mean":555.8559999987483},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1543.4436865001917,"stableId":"12676.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":2099.29968649894,"stableId":"12676.1295.SliceGroup.335","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":22.44348577871363,"other":533.4125142200343,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1543.4436865001917,"pid":12676,"fmp":2099.29968649894}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"e929a0a1-dfda-4370-bc44-1f0f2612a043","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[891.0729999937416],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":891.0729999937416,"max":891.0729999937416,"sum":891.0729999937416,"meanlogs":6.792426354522936,"variance":0,"mean":891.0729999937416},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1543.4436865001917,"stableId":"12676.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":215.418,"start":2269.098686493933,"stableId":"12676.1295.SliceGroup.1006","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1543.4436865001917,"pid":12676,"interactive":2434.5166864939333}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":34.29134416841775,"other":856.781655825323,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"24a1fc5a-bfe4-4765-8223-3caeb8bb41ed","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[578.1700000017881,60.00400000065565],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":60.00400000065565,"max":578.1700000017881,"sum":638.1740000024438,"meanlogs":5.2271395848779925,"variance":134248.00177858683,"mean":319.0870000012219},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"462e99a4-50a0-4962-b898-4879961c4ad2","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[593.2459999993443,133.67899999767542],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":133.67899999767542,"max":593.2459999993443,"sum":726.9249999970198,"meanlogs":5.64052527823161,"variance":105600.91374526698,"mean":363.4624999985099},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"823f398b-0073-4c64-bc84-3273a62cbfa7","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[578.1810000017285,128.55300000309944],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":128.55300000309944,"max":578.1810000017285,"sum":706.734000004828,"meanlogs":5.608114119565008,"variance":101082.6691913836,"mean":353.367000002414},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4583.532423004508,"stableId":"12696.1295.SliceGroup.1861","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":4712.0854230076075,"stableId":"12696.1295.SliceGroup.2040","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":30.183027153543236,"other":98.36997284955618,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":4583.532423004508,"pid":12696,"fmp":4712.0854230076075}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1157.5914230048656,"stableId":"12696.1295.SliceGroup.43","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1735.7724230065942,"stableId":"12696.1295.SliceGroup.312","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":34.2369362395147,"other":543.9440637622141,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1157.5914230048656,"pid":12696,"fmp":1735.7724230065942}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5ea12131-0417-4098-a074-3c4d02aa6c92","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[3799.4540000008938,373.5130000012514],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":373.5130000012514,"max":3799.4540000008938,"sum":4172.967000002145,"meanlogs":7.08278273052068,"variance":5868535.867739275,"mean":2086.4835000010726},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474525015958,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":1}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":4583.532423004508,"stableId":"12696.1295.SliceGroup.1861","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":202.369,"start":4804.67642300576,"stableId":"12696.1295.SliceGroup.2261","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":4583.532423004508,"pid":12696,"interactive":4957.045423005759}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":50.593088758463324,"other":322.91991124278815,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1157.5914230048656,"stableId":"12696.1295.SliceGroup.43","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":202.369,"start":4804.67642300576,"stableId":"12696.1295.SliceGroup.2261","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1157.5914230048656,"pid":12696,"interactive":4957.045423005759}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"resource_loading":0,"layout":0,"script_execute":0,"overhead":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2220.7960887580884,"other":1578.6579112428017,"gc":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ad6bcb41-68d6-40ca-acd2-cd7ee2db25fb","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[77.68599999696016],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":77.68599999696016,"max":77.68599999696016,"sum":77.68599999696016,"meanlogs":4.352675060919893,"variance":0,"mean":77.68599999696016},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"eedec467-e681-4371-b5f3-b91bb7442e43","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[465.0599999949336],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":465.0599999949336,"max":465.0599999949336,"sum":465.0599999949336,"meanlogs":6.142166429510581,"variance":0,"mean":465.0599999949336},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5cc69b27-e42f-46ca-9d65-6562dd3c67d4","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[187.1330000013113],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":187.1330000013113,"max":187.1330000013113,"sum":187.1330000013113,"meanlogs":5.2318195940039605,"variance":0,"mean":187.1330000013113},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1384.3658135160804,"stableId":"11801.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1571.4988135173917,"stableId":"11801.1295.SliceGroup.960","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":11.064142278283585,"other":176.06885772302763,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1384.3658135160804,"pid":11801,"fmp":1571.4988135173917}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"e58794bd-b491-4b70-9289-13bba25a6733","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[412.0879999979138],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":412.0879999979138,"max":412.0879999979138,"sum":412.0879999979138,"meanlogs":6.0212369187699,"variance":0,"mean":412.0879999979138},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1384.3658135160804,"stableId":"11801.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":106.703,"start":1739.7508135139942,"stableId":"11801.1295.SliceGroup.1463","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1384.3658135160804,"pid":11801,"interactive":1796.4538135139942}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":12.517328835374002,"other":399.5706711625395,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"7f42ce4b-95ed-4952-b859-122e8d85c6b0","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[100.5650000050664],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":100.5650000050664,"max":100.5650000050664,"sum":100.5650000050664,"meanlogs":4.610804284655564,"variance":0,"mean":100.5650000050664},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a3a02993-40a3-444f-be42-59f2f718fc54","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[169.01500000059605,419.5100000053644,19.10700000077486,165.83500000089407],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":4,"min":19.10700000077486,"max":419.5100000053644,"sum":773.4670000076294,"meanlogs":4.8075307275392785,"variance":82858.23497882795,"mean":193.36675000190735},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":2,"diagnosticMaps":[{"url":{"type":"Generic","value":""}},{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"35b6e4ba-1947-4e05-9e34-38c2093c725a","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[100.58900000154972],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":100.58900000154972,"max":100.58900000154972,"sum":100.58900000154972,"meanlogs":4.61104290776618,"variance":0,"mean":100.58900000154972},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1081.7041284888983,"stableId":"11818.1295.SliceGroup.44","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1182.293128490448,"stableId":"11818.1295.SliceGroup.288","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":21.356874769994135,"other":79.23212523155553,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1081.7041284888983,"pid":11818,"fmp":1182.293128490448}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"50dc4178-7d80-4bc0-8ccb-7e4330899006","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[2810.164000005782],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":2810.164000005782,"max":2810.164000005782,"sum":2810.164000005782,"meanlogs":7.94099812361612,"variance":0,"mean":2810.164000005782},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1081.7041284888983,"stableId":"11818.1295.SliceGroup.44","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":84.10600000000001,"start":3857.76212849468,"stableId":"11818.1295.SliceGroup.2255","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1081.7041284888983,"pid":11818,"interactive":3891.86812849468}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":2152.668743051542,"other":657.4952569542232,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"8c7fa4c7-11de-4047-b6c8-39c3c4414875","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[174.91499999910593],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":174.91499999910593,"max":174.91499999910593,"sum":174.91499999910593,"meanlogs":5.1643001416352945,"variance":0,"mean":174.91499999910593},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"30e7f300-20e2-474a-9ffd-55e7902b8d59","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[369.07200000435114],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":369.07200000435114,"max":369.07200000435114,"sum":369.07200000435114,"meanlogs":5.910991746969724,"variance":0,"mean":369.07200000435114},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b7a529e0-eed8-433d-8b39-6c70f26dad80","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[174.92500000447035],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":174.92500000447035,"max":174.92500000447035,"sum":174.92500000447035,"meanlogs":5.1643573106575165,"variance":0,"mean":174.92500000447035},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1627.5407289937139,"stableId":"11846.1295.SliceGroup.30","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1802.4657289981842,"stableId":"11846.1295.SliceGroup.517","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":35.66346513730498,"other":139.26153486716524,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1627.5407289937139,"pid":11846,"fmp":1802.4657289981842}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"14589394-eaee-443e-bfbb-fd065bd57472","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[240.3490000032782],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":240.3490000032782,"max":240.3490000032782,"sum":240.3490000032782,"meanlogs":5.482092033745827,"variance":0,"mean":240.3490000032782},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1627.5407289937139,"stableId":"11846.1295.SliceGroup.30","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":60.954,"start":1856.935728996992,"stableId":"11846.1295.SliceGroup.1363","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1627.5407289937139,"pid":11846,"interactive":1867.889728996992}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":37.658354569158234,"other":202.69064543412003,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"bdcb89ec-39f9-4b7a-b064-aafe20915fac","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[206.68400000035763],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":206.68400000035763,"max":206.68400000035763,"sum":206.68400000035763,"meanlogs":5.331191056823527,"variance":0,"mean":206.68400000035763},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"8bc232fa-f494-4f74-a4f2-f5e562c5e49e","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[438.89000000059605,126.21899999678135],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":2,"min":126.21899999678135,"max":438.89000000059605,"sum":565.1089999973774,"meanlogs":5.461133652813592,"variance":48881.577121692746,"mean":282.5544999986887},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c6591338-dcf5-472e-aef3-806599b463f2","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[206.7009999975562],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":206.7009999975562,"max":206.7009999975562,"sum":206.7009999975562,"meanlogs":5.331273304593563,"variance":0,"mean":206.7009999975562},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1121.4953815042973,"stableId":"11862.1295.SliceGroup.42","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1328.1963815018535,"stableId":"11862.1295.SliceGroup.512","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":16.210068882347453,"other":190.49093111520864,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1121.4953815042973,"pid":11862,"fmp":1328.1963815018535}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"4c23bf1b-51e9-4f32-8702-494e179ab17c","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[255.1739999962449],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":255.1739999962449,"max":255.1739999962449,"sum":255.1739999962449,"meanlogs":5.541945665387967,"variance":0,"mean":255.1739999962449},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1121.4953815042973,"stableId":"11862.1295.SliceGroup.42","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":51.731,"start":1374.9383815005422,"stableId":"11862.1295.SliceGroup.1301","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1121.4953815042973,"pid":11862,"interactive":1376.6693815005422}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":18.37495827799217,"other":236.79904171825237,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c4cc047b-71f8-4cb4-921b-e0d00cc358b1","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[122.69900000095367],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":122.69900000095367,"max":122.69900000095367,"sum":122.69900000095367,"meanlogs":4.809734201732177,"variance":0,"mean":122.69900000095367},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"51a96368-437c-4505-ac94-285ead995fe1","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[199.9919999986887],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":199.9919999986887,"max":199.9919999986887,"sum":199.9919999986887,"meanlogs":5.298277365741458,"variance":0,"mean":199.9919999986887},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ab585ae6-1adc-4fa3-9444-2af3eb77f372","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[122.70799999684095],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":122.70799999684095,"max":122.70799999684095,"sum":122.70799999684095,"meanlogs":4.809807549239717,"variance":0,"mean":122.70799999684095},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1649.0234330073,"stableId":"11889.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1771.7314330041409,"stableId":"11889.1295.SliceGroup.413","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":15.774498660011979,"other":106.93350133682905,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1649.0234330073,"pid":11889,"fmp":1771.7314330041409}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"56e26be1-7034-4cc4-98f3-44c2e8e5343b","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[283.91300000286105],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":283.91300000286105,"max":283.91300000286105,"sum":283.91300000286105,"meanlogs":5.648667853212036,"variance":0,"mean":283.91300000286105},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1649.0234330073,"stableId":"11889.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":132.941,"start":1849.995433010161,"stableId":"11889.1295.SliceGroup.678","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1649.0234330073,"pid":11889,"interactive":1932.936433010161}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":27.37620882922174,"other":256.5367911736394,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c594fad5-a8b0-4fba-a1ab-7aa3302663e1","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[114.8129999935627,53.56400000303984],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":2,"min":53.56400000303984,"max":114.8129999935627,"sum":168.37699999660254,"meanlogs":4.362090959263188,"variance":1875.7199999195348,"mean":84.18849999830127},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1951659e-e599-460b-b791-77fc30cf2d2e","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[287.23200000077486,11.098999999463558,97.79399999976158],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":3,"min":11.098999999463558,"max":287.23200000077486,"sum":396.125,"meanlogs":4.216669497055796,"variance":39884.07085305326,"mean":132.04166666666666},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"e263a41d-0934-4f61-82cc-f4f6161b92c4","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[114.82999999821186,53.574000000953674],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":2,"min":53.574000000953674,"max":114.82999999821186,"sum":168.40399999916553,"meanlogs":4.362258324776731,"variance":1876.1487678320475,"mean":84.20199999958277},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3890.440709002316,"stableId":"11959.1295.SliceGroup.1184","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3944.0147090032697,"stableId":"11959.1295.SliceGroup.1373","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":11.239109167335922,"other":42.33489083361774,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3890.440709002316,"pid":11959,"fmp":3944.0147090032697}}}]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1117.5747090056539,"stableId":"11959.1295.SliceGroup.46","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1232.4047090038657,"stableId":"11959.1295.SliceGroup.405","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":29.156049964359713,"other":85.67395003385212,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1117.5747090056539,"pid":11959,"fmp":1232.4047090038657}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3db245ed-cd1f-41b1-9e13-b029d2dc5c11","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[366.2449999960661,53.574000000953674],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":2,"min":53.574000000953674,"max":366.2449999960661,"sum":419.8189999970198,"meanlogs":4.942183192065576,"variance":48881.5771189718,"mean":209.9094999985099},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3890.440709002316,"stableId":"11959.1295.SliceGroup.1184","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3890.440709002316,"pid":11959,"interactive":3944.0147090032697}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":11.239109167335922,"other":42.33489083361774,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1117.5747090056539,"stableId":"11959.1295.SliceGroup.46","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":128.019,"start":1405.80070900172,"stableId":"11959.1295.SliceGroup.696","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1117.5747090056539,"pid":11959,"interactive":1483.81970900172}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":125.301376659194,"other":240.94362333687243,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"43aadd24-f8c4-4b52-b202-dbc996fa54ca","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[168.3559999987483],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":168.3559999987483,"max":168.3559999987483,"sum":168.3559999987483,"meanlogs":5.126080785000198,"variance":0,"mean":168.3559999987483},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"f05b17f5-18e9-46fd-b98d-66ccbf2e1129","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[544.262000001967],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":544.262000001967,"max":544.262000001967,"sum":544.262000001967,"meanlogs":6.299430748566061,"variance":0,"mean":544.262000001967},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3442daea-e8d3-4747-8de5-726416b9e5ac","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[529.4430000036955],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":529.4430000036955,"max":529.4430000036955,"sum":529.4430000036955,"meanlogs":6.271825510528688,"variance":0,"mean":529.4430000036955},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1419.8980244919658,"stableId":"12034.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1949.3410244956613,"stableId":"12034.1295.SliceGroup.334","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":22.4746849734956,"other":506.96831503019973,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1419.8980244919658,"pid":12034,"fmp":1949.3410244956613}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"4bba85f2-5f6b-4da0-9503-5063b746a772","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[894.5890000020863],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":894.5890000020863,"max":894.5890000020863,"sum":894.5890000020863,"meanlogs":6.796364394927272,"variance":0,"mean":894.5890000020863},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1419.8980244919658,"stableId":"12034.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":243.97400000000002,"start":2120.513024494052,"stableId":"12034.1295.SliceGroup.1006","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1419.8980244919658,"pid":12034,"interactive":2314.487024494052}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":32.65236415117956,"other":861.9366358509064,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"679e1cbe-100a-4a96-9b35-71c1bc9db77d","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[222.60000000149012],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":222.60000000149012,"max":222.60000000149012,"sum":222.60000000149012,"meanlogs":5.405376438848139,"variance":0,"mean":222.60000000149012},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5f278d34-4c75-43d6-9537-f12e25025040","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[628.777999997139,120.972999997437],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":2,"min":120.972999997437,"max":628.777999997139,"sum":749.750999994576,"meanlogs":5.619672816700583,"variance":128932.95901234866,"mean":374.875499997288},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1ec7888f-6846-4027-8141-b9a65bedad53","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[614.2700000032783],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":614.2700000032783,"max":614.2700000032783,"sum":614.2700000032783,"meanlogs":6.420434570909119,"variance":0,"mean":614.2700000032783},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1121.9041349887848,"stableId":"12050.1295.SliceGroup.58","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1736.174134992063,"stableId":"12050.1295.SliceGroup.328","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":35.0266396116469,"other":579.243360391631,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1121.9041349887848,"pid":12050,"fmp":1736.174134992063}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"fc72d305-2d9a-4508-83e4-4b943e0f2721","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[3669.2989999979136],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":0}},"running":{"count":1,"min":3669.2989999979136,"max":3669.2989999979136,"sum":3669.2989999979136,"meanlogs":8.207755914629276,"variance":0,"mean":3669.2989999979136},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1121.9041349887848,"stableId":"12050.1295.SliceGroup.58","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":242.78900000000002,"start":4598.414134986699,"stableId":"12050.1295.SliceGroup.2002","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1121.9041349887848,"pid":12050,"interactive":4791.203134986698}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":2166.647966922908,"other":1502.6510330749925,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"824e13f0-f90c-4a15-8a6c-57b34c1d44e7","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[69.78699999302626],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":69.78699999302626,"max":69.78699999302626,"sum":69.78699999302626,"meanlogs":4.245447745904042,"variance":0,"mean":69.78699999302626},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"271d4c2c-4109-408a-97d4-2f5c30cac487","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[415.89599999785423],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":415.89599999785423,"max":415.89599999785423,"sum":415.89599999785423,"meanlogs":6.0304352290008945,"variance":0,"mean":415.89599999785423},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1521e9c3-d8e2-4e06-aeb8-c46f7a7f2d1b","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[159.195999994874],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":159.195999994874,"max":159.195999994874,"sum":159.195999994874,"meanlogs":5.0701361474342885,"variance":0,"mean":159.195999994874},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1389.7550839930773,"stableId":"12075.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1548.9510839879513,"stableId":"12075.1295.SliceGroup.964","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":11.0330303962687,"other":148.16296959860546,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1389.7550839930773,"pid":12075,"fmp":1548.9510839879513}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b7ecc4a1-5bf0-4dcc-8b93-020a011b108d","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[364.4669999930263],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":364.4669999930263,"max":364.4669999930263,"sum":364.4669999930263,"meanlogs":5.898436012351617,"variance":0,"mean":364.4669999930263},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1389.7550839930773,"stableId":"12075.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":79.805,"start":1724.4170839861035,"stableId":"12075.1295.SliceGroup.1456","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1389.7550839930773,"pid":12075,"interactive":1754.2220839861036}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":12.509548351717363,"other":351.95745164130926,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b2773bef-4a16-4f64-9bf7-910c94383ef7","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"6d5ab1cb-2c80-4b22-8b6c-c65aaa4fe632","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[454.93900000303984],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":454.93900000303984,"max":454.93900000303984,"sum":454.93900000303984,"meanlogs":6.120163344035926,"variance":0,"mean":454.93900000303984},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"https://www.google.com/webhp?sourceid=chrome-instant&amp;ion=1&amp;espv=2&amp;ie=UTF-8"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5d1296a8-2aec-4e82-b42a-50bca3771857","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"694e0579-ccdc-493b-a1e2-1c066ea6523c","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"8de2f691-d191-4280-b17d-bd16aa25d51e","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[40.51300000399351],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":40.51300000399351,"max":40.51300000399351,"sum":40.51300000399351,"meanlogs":3.7016229103598723,"variance":0,"mean":40.51300000399351},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://does.not.exist/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c5f54f51-57ee-4a9a-b6b1-a8fd5028ff2e","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[23.75400000065565],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":23.75400000065565,"max":23.75400000065565,"sum":23.75400000065565,"meanlogs":3.16775093737965,"variance":0,"mean":23.75400000065565},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://does.not.exist/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"08e777d3-2c2f-4451-810e-b7286af27d10","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[40.51799999922514],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":40.51799999922514,"max":40.51799999922514,"sum":40.51799999922514,"meanlogs":3.701746319801636,"variance":0,"mean":40.51799999922514},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1169.6918735131621,"stableId":"12117.1295.SliceGroup.46","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1210.2098735123873,"stableId":"12117.1295.SliceGroup.106","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":15.933244660225771,"other":24.584755338999354,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://does.not.exist/","start":1169.6918735131621,"pid":12117,"fmp":1210.2098735123873}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"886977b1-35b3-420b-8548-8ee69e3e88d7","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[40.51799999922514],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":40.51799999922514,"max":40.51799999922514,"sum":40.51799999922514,"meanlogs":3.701746319801636,"variance":0,"mean":40.51799999922514},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1169.6918735131621,"stableId":"12117.1295.SliceGroup.46","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://does.not.exist/","start":1169.6918735131621,"pid":12117,"interactive":1210.2098735123873}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":15.933244660225771,"other":24.584755338999354,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"0f020488-607e-43e4-98fa-84cca1d27c78","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[298.8019999936223],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":298.8019999936223,"max":298.8019999936223,"sum":298.8019999936223,"meanlogs":5.699781146655345,"variance":0,"mean":298.8019999936223},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"52c10ad3-e609-46b2-a80a-6159d1713e2d","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[426.29800000041723,121.63100000470877],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":2,"min":121.63100000470877,"max":426.29800000041723,"sum":547.929000005126,"meanlogs":5.428065251760227,"variance":46410.99044319251,"mean":273.964500002563},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"65780f35-4ab5-4ef1-8cd9-dee88998e1a2","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[298.8119999989867],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":298.8119999989867,"max":298.8119999989867,"sum":298.8119999989867,"meanlogs":5.699814613091425,"variance":0,"mean":298.8119999989867},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1040.574086010456,"stableId":"12152.1295.SliceGroup.24","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1339.3860860094428,"stableId":"12152.1295.SliceGroup.1307","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":29.087569628639777,"other":269.72443037034697,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1040.574086010456,"pid":12152,"fmp":1339.3860860094428}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ea042da5-93b9-4ff2-bace-46e242a45229","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[298.8119999989867],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":298.8119999989867,"max":298.8119999989867,"sum":298.8119999989867,"meanlogs":5.699814613091425,"variance":0,"mean":298.8119999989867},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1040.574086010456,"stableId":"12152.1295.SliceGroup.24","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1040.574086010456,"pid":12152,"interactive":1339.3860860094428}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":29.087569628639777,"other":269.72443037034697,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"47b98085-eb79-4730-b3ee-f4399fa3093c","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[142.36299999803305],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":142.36299999803305,"max":142.36299999803305,"sum":142.36299999803305,"meanlogs":4.9583801337413425,"variance":0,"mean":142.36299999803305},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"0379dd81-e130-4ee1-8eb5-719bdf87213e","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[176.20499999821186],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":176.20499999821186,"max":176.20499999821186,"sum":176.20499999821186,"meanlogs":5.171648089933811,"variance":0,"mean":176.20499999821186},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b5e12f4a-5eda-4739-917e-855d222485ec","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[142.37299999594688],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":142.37299999594688,"max":142.37299999594688,"sum":142.37299999594688,"meanlogs":4.958450374230203,"variance":0,"mean":142.37299999594688},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1370.2897255048156,"stableId":"12179.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1512.6627255007625,"stableId":"12179.1295.SliceGroup.490","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":12.760391732384594,"other":129.61260826356238,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1370.2897255048156,"pid":12179,"fmp":1512.6627255007625}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"8c3a4afa-17d9-4908-bfdf-bbf704b33e04","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[261.44899999535073],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":261.44899999535073,"max":261.44899999535073,"sum":261.44899999535073,"meanlogs":5.5662392357859405,"variance":0,"mean":261.44899999535073},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1370.2897255048156,"stableId":"12179.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":134.091,"start":1547.6477255001664,"stableId":"12179.1295.SliceGroup.681","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1370.2897255048156,"pid":12179,"interactive":1631.7387255001663}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":19.44125065067645,"other":242.00774934467435,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"b8222f1c-f7c3-4a74-b650-3b42fbd7835b","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[181.58899999409914],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":181.58899999409914,"max":181.58899999409914,"sum":181.58899999409914,"meanlogs":5.201745891612873,"variance":0,"mean":181.58899999409914},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"93993d5f-8ba2-4ff8-9490-efef750bc4cb","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[237.9599999934435,13.302000001072884,93.10499999672174],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":3,"min":13.302000001072884,"max":237.9599999934435,"sum":344.3669999912381,"meanlogs":4.197914960244518,"variance":25940.90226430926,"mean":114.78899999707937},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"88b1d72e-730b-452a-9a02-f4c34086f56a","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[181.59999999403954],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":181.59999999403954,"max":181.59999999403954,"sum":181.59999999403954,"meanlogs":5.201806466134371,"variance":0,"mean":181.59999999403954},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1217.8226570189,"stableId":"12198.1295.SliceGroup.48","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1399.4226570129395,"stableId":"12198.1295.SliceGroup.501","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":23.386027997793608,"other":158.213971996246,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1217.8226570189,"pid":12198,"fmp":1399.4226570129395}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"88106d68-7701-41e1-ba5f-b76361adf148","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[341.4429999974966],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":341.4429999974966,"max":341.4429999974966,"sum":341.4429999974966,"meanlogs":5.833180754384233,"variance":0,"mean":341.4429999974966},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1217.8226570189,"stableId":"12198.1295.SliceGroup.48","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":152.106,"start":1457.1596570163965,"stableId":"12198.1295.SliceGroup.649","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1217.8226570189,"pid":12198,"interactive":1559.2656570163965}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":47.75107649629095,"other":293.69192350120557,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"25d84e46-88b8-4b60-99f0-5841777d0ef7","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[163.277000002563],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":163.277000002563,"max":163.277000002563,"sum":163.277000002563,"meanlogs":5.095448145002096,"variance":0,"mean":163.277000002563},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5a669333-f1ce-4b36-b22c-cea0bddfe712","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[544.1000000014901],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":544.1000000014901,"max":544.1000000014901,"sum":544.1000000014901,"meanlogs":6.299133053494618,"variance":0,"mean":544.1000000014901},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"5216b844-0d25-4a1c-931a-dea13dab73de","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[529.8669999986887],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":529.8669999986887,"max":529.8669999986887,"sum":529.8669999986887,"meanlogs":6.2726260316559035,"variance":0,"mean":529.8669999986887},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1348.7140690088272,"stableId":"12224.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1878.581069007516,"stableId":"12224.1295.SliceGroup.335","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":20.208694228752883,"other":509.65830576993596,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1348.7140690088272,"pid":12224,"fmp":1878.581069007516}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"30da3456-16db-4aff-bc7e-06d3fbd8a553","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[869.5389999971985],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":869.5389999971985,"max":869.5389999971985,"sum":869.5389999971985,"meanlogs":6.767963186149236,"variance":0,"mean":869.5389999971985},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1348.7140690088272,"stableId":"12224.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":221.897,"start":2046.3560690060258,"stableId":"12224.1295.SliceGroup.999","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","start":1348.7140690088272,"pid":12224,"interactive":2218.2530690060257}},"Breakdown of [navStart, Interactive]":{"type":"Breakdown","values":{"raster":0,"style":0,"layout":0,"resource_loading":0,"composite":0,"renderer_misc":0,"startup":0,"gpu":0,"parseHTML":0,"script_parse_and_compile":0,"record":0,"idle":28.608967267261757,"other":840.9300327299372,"overhead":0,"imageDecode":0,"input":0,"gc":0,"net":0,"iframe_creation":0,"v8_runtime":0,"script_execute":0},"colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3bf635b7-9e6c-4e7b-9bba-4a39b4f77538","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[],"name":"timeToFirstContentfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3dc3efec-e910-4af6-8ae2-3038e4e4bab1","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[71.23400000482798],"name":"timeToOnload","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":1,"min":71.23400000482798,"max":71.23400000482798,"sum":71.23400000482798,"meanlogs":4.26597023259534,"variance":0,"mean":71.23400000482798},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"https://www.google.com/webhp?sourceid=chrome-instant&amp;ion=1&amp;espv=2&amp;ie=UTF-8"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"eca6cc37-2018-45ec-8a40-efd155c9b872","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[],"name":"timeToFirstMeaningfulPaint","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"58e10848-0ce3-451e-82d4-6d394961c579","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[],"name":"timeToFirstInteractive","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"underflowBin":{"count":0,"diagnosticMaps":[]},"diagnostics":{"iteration":{"storyDisplayName":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","type":"IterationInfo","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524648636,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://news.google.co.in/nwshp?tab=in&amp;hl=hi","os-version":"10.11.6","storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"storyRepeatCounter":0,"storysetRepeatCounter":1}},"running":{"count":0,"min":null,"max":null,"sum":0,"meanlogs":0,"variance":0},"nanDiagnosticMaps":[],"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"numNans":0,"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"87e6abcf-e778-43fe-a3cf-354bd0d8965a","maxNumSampleValues":620,"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[91.76999999582767],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":91.76999999582767,"max":91.76999999582767,"sum":91.76999999582767,"meanlogs":4.519285446785457,"variance":0,"mean":91.76999999582767},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"f55f293c-c129-4116-9338-6fbf46f8778a","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[393.8420000001788],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":393.8420000001788,"max":393.8420000001788,"sum":393.8420000001788,"meanlogs":5.9759498136418525,"variance":0,"mean":393.8420000001788},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"36414695-8336-404d-9957-15876f65107b","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[302.79800000041723],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":302.79800000041723,"max":302.79800000041723,"sum":302.79800000041723,"meanlogs":5.7130659165230435,"variance":0,"mean":302.79800000041723},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1399.2109434902668,"stableId":"11524.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1702.008943490684,"stableId":"11524.1295.SliceGroup.1065","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":10.000295067814552,"other":292.7977049326023,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1399.2109434902668,"pid":11524,"fmp":1702.008943490684}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"9349a7d0-2b9b-4a0e-ae74-5a9269f66052","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[450.0000000002385],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":450.0000000002385,"max":450.0000000002385,"sum":450.0000000002385,"meanlogs":6.109247582764896,"variance":0,"mean":450.0000000002385},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1399.2109434902668,"stableId":"11524.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":101.419,"start":1797.7919434905052,"stableId":"11524.1295.SliceGroup.1570","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1399.2109434902668,"pid":11524,"interactive":1849.2109434905053}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.984595887104554,"other":438.01540411313397,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3d99e6cf-e3a1-4e01-b389-70ac422997fd","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[74.5190000012517,30.71400000154972],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":30.71400000154972,"max":74.5190000012517,"sum":105.23300000280142,"meanlogs":3.867886351598893,"variance":959.4390124869451,"mean":52.61650000140071},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"82f292bf-c943-49dd-88ed-40327a5bfd8f","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[192.18899999558926,438.2550000026822,20.133000001311302,183.03100000321865],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":4,"min":20.133000001311302,"max":438.2550000026822,"sum":833.6080000028014,"meanlogs":4.888323998227515,"variance":89184.16698071898,"mean":208.40200000070035},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":2,"diagnosticMaps":[{"url":{"type":"Generic","value":""}},{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://www.rambler.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"a68015f9-43e0-4952-b768-42113e7f4675","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[346.3640000000596,125.46599999815226],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":125.46599999815226,"max":346.3640000000596,"sum":471.82999999821186,"meanlogs":5.339762525354377,"variance":24397.963202421328,"mean":235.91499999910593},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3836.9993580058217,"stableId":"11543.1295.SliceGroup.2043","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3962.465358003974,"stableId":"11543.1295.SliceGroup.2430","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":12.847765894453762,"other":112.61823410369858,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":3836.9993580058217,"pid":11543,"fmp":3962.465358003974}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1068.3513580039144,"stableId":"11543.1295.SliceGroup.44","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1414.715358003974,"stableId":"11543.1295.SliceGroup.1053","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":22.816260139662713,"other":323.5477398603962,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1068.3513580039144,"pid":11543,"fmp":1414.715358003974}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ff027f53-5b4f-40a6-a072-cfbb0af7c703","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[2985.265000003159,216.61700000125165],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":216.61700000125165,"max":2985.265000003159,"sum":3201.8820000044107,"meanlogs":6.68978730814373,"variance":3832705.873957281,"mean":1600.9410000022053},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://www.rambler.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://www.rambler.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3836.9993580058217,"stableId":"11543.1295.SliceGroup.2043","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":80.098,"start":4023.5183580070734,"stableId":"11543.1295.SliceGroup.2801","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":3836.9993580058217,"pid":11543,"interactive":4053.6163580070734}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":13.945964882021752,"other":202.67103511922988,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1068.3513580039144,"stableId":"11543.1295.SliceGroup.44","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":80.098,"start":4023.5183580070734,"stableId":"11543.1295.SliceGroup.2801","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://www.rambler.ru/","start":1068.3513580039144,"pid":11543,"interactive":4053.6163580070734}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":2198.677964883916,"other":786.5870351192285,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"7fe01972-287f-49cd-a271-e0b5669ed4c8","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[143.5839999988675],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":143.5839999988675,"max":143.5839999988675,"sum":143.5839999988675,"meanlogs":4.966920229785686,"variance":0,"mean":143.5839999988675},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3c51c7f7-3ad8-46b3-a1b1-287fe27f0f28","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[366.18100000172853],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":366.18100000172853,"max":366.18100000172853,"sum":366.18100000172853,"meanlogs":5.903127746682823,"variance":0,"mean":366.18100000172853},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"e251e203-763e-4c53-b607-7b89aec26b04","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[143.59300000220537],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":143.59300000220537,"max":143.59300000220537,"sum":143.59300000220537,"meanlogs":4.966982908923226,"variance":0,"mean":143.59300000220537},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1377.9881389960647,"stableId":"11570.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1521.58113899827,"stableId":"11570.1295.SliceGroup.506","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":5.0385919601041245,"other":138.55440804210127,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1377.9881389960647,"pid":11570,"fmp":1521.58113899827}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"adf13e4d-17e6-498f-9c44-ee663ef8d7dc","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[203.03299999994033],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":203.03299999994033,"max":203.03299999994033,"sum":203.03299999994033,"meanlogs":5.313368527406147,"variance":0,"mean":203.03299999994033},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1377.9881389960647,"stableId":"11570.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":57.522,"start":1573.499138996005,"stableId":"11570.1295.SliceGroup.1336","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1377.9881389960647,"pid":11570,"interactive":1581.021138996005}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":6.9609152478100595,"other":196.07208475213042,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1a0bf9b4-53ae-4439-a85b-0b3d6e907372","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[160.35500000417233,49.66799999773502],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":49.66799999773502,"max":160.35500000417233,"sum":210.02300000190735,"meanlogs":4.491375484988935,"variance":6125.805985212525,"mean":105.01150000095367},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"6987aa7b-0bbc-413e-980c-e8081f55784c","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[418.5,140.77799999713898],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":140.77799999713898,"max":418.5,"sum":559.277999997139,"meanlogs":5.491930535712423,"variance":38564.75464279457,"mean":279.6389999985695},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://apeha.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"3bd8066b-59aa-44dd-8301-e375b6e032a7","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[160.37399999797344,49.677000001072884],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":49.677000001072884,"max":160.37399999797344,"sum":210.05099999904633,"meanlogs":4.491525318433982,"variance":6126.912904156901,"mean":105.02549999952316},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3754.2288999930024,"stableId":"11594.1295.SliceGroup.2485","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3803.9058999940753,"stableId":"11594.1295.SliceGroup.2573","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.273713895046988,"other":42.40328610602589,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3754.2288999930024,"pid":11594,"fmp":3803.9058999940753}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1083.3048999905586,"stableId":"11594.1295.SliceGroup.44","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1243.678899988532,"stableId":"11594.1295.SliceGroup.485","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":23.603434336051507,"other":136.77056566192178,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1083.3048999905586,"pid":11594,"fmp":1243.678899988532}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"2f1d27ce-6656-4acd-b611-0e2e4560abdf","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[251.40000000381474,49.677000001072884],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":49.677000001072884,"max":251.40000000381474,"sum":301.0770000048876,"meanlogs":4.7162936727606874,"variance":20346.084365053095,"mean":150.5385000024438},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://apeha.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://apeha.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3754.2288999930024,"stableId":"11594.1295.SliceGroup.2485","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":3754.2288999930024,"pid":11594,"interactive":3803.9058999940753}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":7.273713895046988,"other":42.40328610602589,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1083.3048999905586,"stableId":"11594.1295.SliceGroup.44","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":68.729,"start":1315.9758999943733,"stableId":"11594.1295.SliceGroup.1319","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://apeha.ru/","start":1083.3048999905586,"pid":11594,"interactive":1334.7048999943734}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":26.261816736083382,"other":225.13818326773122,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"ce22ee68-69f6-413b-b912-d454cca2527d","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[120.01399999856949],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":120.01399999856949,"max":120.01399999856949,"sum":120.01399999856949,"meanlogs":4.787608402631767,"variance":0,"mean":120.01399999856949},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"f0b0220f-0b23-44ae-a298-87913643634f","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[189.93800000101328],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":189.93800000101328,"max":189.93800000101328,"sum":189.93800000101328,"meanlogs":5.246697703123765,"variance":0,"mean":189.93800000101328},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"1134d02b-3f7a-4c30-8897-371b8854cfcf","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[120.027000002563],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":120.027000002563,"max":120.027000002563,"sum":120.027000002563,"meanlogs":4.787716717494696,"variance":0,"mean":120.027000002563},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1368.4696565046906,"stableId":"11709.1295.SliceGroup.29","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1488.4966565072536,"stableId":"11709.1295.SliceGroup.422","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":16.75176154054231,"other":103.27523846202068,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1368.4696565046906,"pid":11709,"fmp":1488.4966565072536}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"c817f5c1-ed3b-4d33-aa06-8cb471548215","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[274.29599999749666],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":1,"min":274.29599999749666,"max":274.29599999749666,"sum":274.29599999749666,"meanlogs":5.6142078152542805,"variance":0,"mean":274.29599999749666},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-cold"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1368.4696565046906,"stableId":"11709.1295.SliceGroup.29","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":133.334,"start":1559.4316565021873,"stableId":"11709.1295.SliceGroup.681","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1368.4696565046906,"pid":11709,"interactive":1642.7656565021873}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":25.363932376368666,"other":248.93206762112794,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"532ab408-0adf-4438-9c84-ca0b87a98656","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"},{"sampleValues":[114.11800000071526,51.260999999940395],"name":"timeToFirstContentfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":51.260999999940395,"max":114.11800000071526,"sum":165.37900000065565,"meanlogs":4.337081614959615,"variance":1975.5012245487053,"mean":82.68950000032783},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"45371f21-459d-4239-b9c4-53cba703d900","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first contentful paint"},{"sampleValues":[322.7669999971986,10.686999998986721,95.79699999839067],"name":"timeToOnload","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":3,"min":10.686999998986721,"max":322.7669999971986,"sum":429.250999994576,"meanlogs":4.2360633731184985,"variance":52051.006466080435,"mean":143.08366666485867},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":""}}]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"url":{"type":"Generic","value":"http://narod.yandex.ru/"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"8b058e8c-9b9e-4580-aa5a-506bb0efb8df","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to onload. This is temporary metric used for PCv1/v2 sanity checking"},{"sampleValues":[114.1359999999404,51.270000003278255],"name":"timeToFirstMeaningfulPaint","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":51.270000003278255,"max":114.1359999999404,"sum":165.40600000321865,"meanlogs":4.337248252835771,"variance":1976.0669777901621,"mean":82.70300000160933},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3847.1875955089927,"stableId":"11725.1295.SliceGroup.1137","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":3898.457595512271,"stableId":"11725.1295.SliceGroup.1323","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.035189883442381,"other":40.23481011983586,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3847.1875955089927,"pid":11725,"fmp":3898.457595512271}}}]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1096.4645955115557,"stableId":"11725.1295.SliceGroup.42","title":"navigationStart"}]},"End":{"type":"RelatedEventSet","events":[{"duration":0,"start":1210.600595511496,"stableId":"11725.1295.SliceGroup.382","title":"firstMeaningfulPaintCandidate"}]},"Breakdown of [navStart, FMP]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":30.155908505765325,"other":83.98009149417503,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1096.4645955115557,"pid":11725,"fmp":1210.600595511496}}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"79e75b8b-e4c4-477e-91a9-504c98d4ba2c","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first meaningful paint"},{"sampleValues":[376.03599999529115,51.270000003278255],"name":"timeToFirstInteractive","underflowBin":{"count":0,"diagnosticMaps":[]},"maxNumSampleValues":620,"nanDiagnosticMaps":[],"numNans":0,"running":{"count":2,"min":51.270000003278255,"max":376.03599999529115,"sum":427.3059999985694,"meanlogs":4.933395334667272,"variance":52736.47737540606,"mean":213.6529999992847},"binBoundaries":[0,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3298.5015444623446,3626.704146273491,3987.5630759303654,4384.327654865776,4820.570513667911,5300.2197615077475,5827.594356441047,6407.442995073611,7044.9868717682475,7745.966692414835,8516.694366094736,9364.109840092413,10295.843590019953,11320.285327741181,12446.65954576957,13685.108578372636,15046.783927299006,16543.94667446232,18190.077885738872,20000],"diagnostics":{"iteration":{"storyDisplayName":"http://narod.yandex.ru/","benchmarkName":"page_cycler_v2.intl_hi_ru","benchmarkStartMs":1474524317911,"label":"","product-version":"Chrome/54.0.2840.34","storyUrl":"http://narod.yandex.ru/","os-version":"10.11.6","storyRepeatCounter":0,"storyGroupingKeys":{"cache_temperature":"pcv1-warm"},"type":"IterationInfo","storysetRepeatCounter":0}},"centralBins":[{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":3847.1875955089927,"stableId":"11725.1295.SliceGroup.1137","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":3847.1875955089927,"pid":11725,"interactive":3898.457595512271}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":11.035189883442381,"other":40.23481011983586,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":1,"diagnosticMaps":[{"Start":{"type":"RelatedEventSet","events":[{"duration":0,"start":1096.4645955115557,"stableId":"11725.1295.SliceGroup.42","title":"navigationStart"}]},"Last long task":{"type":"RelatedEventSet","events":[{"duration":102.042,"start":1420.458595506847,"stableId":"11725.1295.SliceGroup.689","title":"TaskQueueManager::ProcessTaskFromWorkQueue"}]},"Navigation infos":{"type":"Generic","value":{"url":"http://narod.yandex.ru/","start":1096.4645955115557,"pid":11725,"interactive":1472.5005955068468}},"Breakdown of [navStart, Interactive]":{"values":{"raster":0,"style":0,"layout":0,"script_execute":0,"resource_loading":0,"composite":0,"startup":0,"v8_runtime":0,"script_parse_and_compile":0,"record":0,"idle":138.6426490469707,"other":237.3933509483208,"overhead":0,"imageDecode":0,"input":0,"gpu":0,"net":0,"iframe_creation":0,"renderer_misc":0,"gc":0,"parseHTML":0},"type":"Breakdown","colorScheme":"ChromeUserFriendlyCategory"}}]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]},{"count":0,"diagnosticMaps":[]}],"guid":"212d4bea-88d7-47ce-a695-5e1fb4c7460f","summaryOptions":{"std":true,"count":false,"min":true,"max":true,"sum":false,"percentile":[0.9,0.95,0.99],"nans":false,"avg":true,"geometricMean":false},"overflowBin":{"count":0,"diagnosticMaps":[]},"unit":"ms_smallerIsBetter","description":"time to first interactive"}]
diff --git a/chromium/third_party/catapult/tracing/tracing/model/alert.html b/chromium/third_party/catapult/tracing/tracing/model/alert.html
index 53a2fa74217..9fd5147806c 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/alert.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/alert.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_info.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -38,7 +38,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Alert ' + this.title + ' at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
}
};
@@ -46,9 +46,7 @@ tr.exportTo('tr.model', function() {
Alert,
{
name: 'alert',
- pluralName: 'alerts',
- singleViewElementName: 'tr-ui-a-alert-sub-view',
- multiViewElementName: 'tr-ui-a-alert-sub-view'
+ pluralName: 'alerts'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/async_slice.html b/chromium/third_party/catapult/tracing/tracing/model/async_slice.html
index 325ef09d0a8..2eb6c57184c 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/async_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/async_slice.html
@@ -5,9 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/extension_registry.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -66,7 +65,7 @@ tr.exportTo('tr.model', function() {
if (opt_argsStripped !== undefined)
this.argsStripped = opt_argsStripped;
- };
+ }
AsyncSlice.prototype = {
__proto__: tr.model.TimedEvent.prototype,
@@ -94,7 +93,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Async slice ' + this.title + ' at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
},
get stableId() {
@@ -117,7 +116,7 @@ tr.exportTo('tr.model', function() {
return undefined;
for (var i = 0; i < this.subSlices.length; i++) {
- if (this.subSlices[i].title == targetTitle)
+ if (this.subSlices[i].title === targetTitle)
return this.subSlices[i];
var slice = this.subSlices[i].findDescendentSlice(targetTitle);
if (slice) return slice;
@@ -125,11 +124,11 @@ tr.exportTo('tr.model', function() {
return undefined;
},
- iterateAllDescendents: function(callback, opt_this) {
- this.subSlices.forEach(callback, opt_this);
- this.subSlices.forEach(function(subSlice) {
- subSlice.iterateAllDescendents(callback, opt_this);
- }, opt_this);
+ enumerateAllDescendents: function*() {
+ for (var slice of this.subSlices)
+ yield slice;
+ for (var slice of this.subSlices)
+ yield * slice.enumerateAllDescendents();
},
compareTo: function(that) {
@@ -141,18 +140,10 @@ tr.exportTo('tr.model', function() {
AsyncSlice,
{
name: 'asyncSlice',
- pluralName: 'asyncSlices',
- singleViewElementName: 'tr-ui-a-single-async-slice-sub-view',
- multiViewElementName: 'tr-ui-a-multi-async-slice-sub-view'
+ pluralName: 'asyncSlices'
});
- var options = new tr.b.ExtensionRegistryOptions(
- tr.b.TYPE_BASED_REGISTRY_MODE);
- options.mandatoryBaseClass = AsyncSlice;
- options.defaultConstructor = AsyncSlice;
- tr.b.decorateExtensionRegistry(AsyncSlice, options);
-
return {
AsyncSlice: AsyncSlice
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager.html b/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager.html
index 37e10a2cff9..82531ce46a3 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager.html
@@ -52,52 +52,6 @@ tr.exportTo('tr.model', function() {
var BATTOR_FAST_SYNC_THRESHOLD_MS = 3;
/**
- * Returns a function that, given a timestamp in |fromMarker|'s domain,
- * returns a timestamp in |toMarker|'s domain.
- */
- function createTransformer(fromMarker, toMarker) {
- var fromTs = fromMarker.ts, toTs = toMarker.ts;
-
- // TODO(charliea): Usually, we estimate that the clock sync marker is
- // issued by the agent exactly in the middle of the controller's start and
- // end timestamps. However, there's currently a bug in the Chrome serial
- // code that's making the clock sync ack for BattOr take much longer to
- // read than it should (by about 8ms). This is causing the above estimate
- // of the controller's sync timestamp to be off by a substantial enough
- // amount that it makes traces hard to read. For now, make an exception
- // for BattOr and just use the controller's start timestamp as the sync
- // time. In the medium term, we should fix the Chrome serial code in order
- // to remove this special logic and get an even more accurate estimate.
- if (fromMarker.domainId === ClockDomainId.BATTOR &&
- toMarker.duration > BATTOR_FAST_SYNC_THRESHOLD_MS) {
- toTs = toMarker.startTs;
- } else if (toMarker.domainId === ClockDomainId.BATTOR &&
- fromMarker.duration > BATTOR_FAST_SYNC_THRESHOLD_MS) {
- fromTs = fromMarker.startTs;
- }
-
- var tsShift = toTs - fromTs;
- return function(ts) { return ts + tsShift; };
- }
-
- /**
- * Given two transformers, creates a third that's a composition of the two.
- *
- * @param {function(Number): Number} aToB A function capable of converting a
- * timestamp from domain A to domain B.
- * @param {function(Number): Number} bToC A function capable of converting a
- * timestamp from domain B to domain C.
- *
- * @return {function(Number): Number} A function capable of converting a
- * timestamp from domain A to domain C.
- */
- function composeTransformers(aToB, bToC) {
- return function(ts) {
- return bToC(aToB(ts));
- };
- }
-
- /**
* A ClockSyncManager holds clock sync markers and uses them to shift
* timestamps from agents' clock domains onto the model's clock domain.
*
@@ -167,26 +121,21 @@ tr.exportTo('tr.model', function() {
if (markers[0].domainId === domainId)
throw new Error('A clock domain cannot sync with itself.');
- // TODO(charliea): Allow multiple paths between clock domains by selecting
- // the path with the least potential error.
- if (this.getTransformerBetween_(markers[0].domainId, domainId)) {
- throw new Error('The current code cannot handle multiple paths ' +
- 'between the same clock domains. However, this is a valid ' +
- 'operation.');
- }
-
markers.push(marker);
-
- this.getOrCreateTransformerMap_(markers[0].domainId)[domainId] =
- createTransformer(markers[0], marker);
- this.getOrCreateTransformerMap_(domainId)[markers[0].domainId] =
- createTransformer(marker, markers[0]);
+ this.onSyncCompleted_(markers[0], marker);
},
+ // TODO(charliea): Remove this once the clockSyncMetric is no longer using
+ // it.
get markersBySyncId() {
return this.markersBySyncId_;
},
+ /** @return {Set<String>} The string IDs of the domains seen so far. */
+ get domainsSeen() {
+ return this.domainsSeen_;
+ },
+
/**
* Returns a function that, given a timestamp in the domain with |domainId|,
* returns a timestamp in the model's clock domain.
@@ -199,6 +148,18 @@ tr.exportTo('tr.model', function() {
* the first alphabetically is selected.
*/
getModelTimeTransformer: function(domainId) {
+ return this.getModelTimeTransformerRaw_(domainId).fn;
+ },
+
+ /**
+ * Returns the error associated with the transformation given by
+ * |getModelTimeTransformer(domainId)|.
+ */
+ getModelTimeTransformerError: function(domainId) {
+ return this.getModelTimeTransformerRaw_(domainId).error;
+ },
+
+ getModelTimeTransformerRaw_: function(domainId) {
this.onDomainSeen_(domainId);
if (!this.modelDomainId_)
@@ -224,10 +185,18 @@ tr.exportTo('tr.model', function() {
// "to" domain.
var visitedDomainIds = new Set();
// Keep a queue of nodes to visit, starting with the "from" domain.
- var queue = [];
- queue.push({ domainId: fromDomainId, transformer: tr.b.identity });
+ var queue = [{
+ domainId: fromDomainId,
+ transformer: Transformer.IDENTITY
+ }];
while (queue.length > 0) {
+ // NOTE: Using a priority queue here would theoretically be much more
+ // efficient, but the actual performance difference is negligible given
+ // how few clock domains we have in a trace.
+ queue.sort((domain1, domain2) =>
+ domain1.transformer.error - domain2.transformer.error);
+
var current = queue.shift();
if (current.domainId === toDomainId)
@@ -254,7 +223,7 @@ tr.exportTo('tr.model', function() {
queue.push({
domainId: outgoingDomainId,
- transformer: composeTransformers(
+ transformer: Transformer.compose(
toNextDomainTransformer, toCurrentDomainTransformer)
});
}
@@ -335,10 +304,30 @@ tr.exportTo('tr.model', function() {
this.domainsSeen_.add(domainId);
},
+ /**
+ * Observer called when a complete sync is made involving |marker1| and
+ * |marker2|.
+ */
+ onSyncCompleted_: function(marker1, marker2) {
+ var forwardTransformer = Transformer.fromMarkers(marker1, marker2);
+ var backwardTransformer = Transformer.fromMarkers(marker2, marker1);
+
+ var existingTransformer =
+ this.getOrCreateTransformerMap_(marker1.domainId)[marker2.domainId];
+ if (!existingTransformer ||
+ forwardTransformer.error < existingTransformer.error) {
+ this.getOrCreateTransformerMap_(marker1.domainId)[marker2.domainId] =
+ forwardTransformer;
+ this.getOrCreateTransformerMap_(marker2.domainId)[marker1.domainId] =
+ backwardTransformer;
+ }
+ },
+
/** Makes timestamps in the two clock domains interchangeable. */
collapseDomains_: function(domain1Id, domain2Id) {
this.getOrCreateTransformerMap_(domain1Id)[domain2Id] =
- this.getOrCreateTransformerMap_(domain2Id)[domain1Id] = tr.b.identity;
+ this.getOrCreateTransformerMap_(domain2Id)[domain1Id] =
+ Transformer.IDENTITY;
},
/**
@@ -372,6 +361,64 @@ tr.exportTo('tr.model', function() {
get ts() { return this.startTs + this.duration / 2; }
};
+ /**
+ * A Transformer encapsulates information about how to turn timestamps in one
+ * clock domain into timestamps in another. It also stores additional data
+ * about the maximum error involved in doing so.
+ */
+ function Transformer(fn, error) {
+ this.fn = fn;
+ this.error = error;
+ }
+
+ Transformer.IDENTITY = new Transformer(tr.b.identity, 0);
+
+ /**
+ * Given two transformers, creates a third that's a composition of the two.
+ *
+ * @param {function(Number): Number} aToB A function capable of converting a
+ * timestamp from domain A to domain B.
+ * @param {function(Number): Number} bToC A function capable of converting a
+ * timestamp from domain B to domain C.
+ *
+ * @return {function(Number): Number} A function capable of converting a
+ * timestamp from domain A to domain C.
+ */
+ Transformer.compose = function(aToB, bToC) {
+ return new Transformer(
+ (ts) => bToC.fn(aToB.fn(ts)), aToB.error + bToC.error);
+ };
+
+ /**
+ * Returns a function that, given a timestamp in |fromMarker|'s domain,
+ * returns a timestamp in |toMarker|'s domain.
+ */
+ Transformer.fromMarkers = function(fromMarker, toMarker) {
+ var fromTs = fromMarker.ts, toTs = toMarker.ts;
+
+ // TODO(charliea): Usually, we estimate that the clock sync marker is
+ // issued by the agent exactly in the middle of the controller's start and
+ // end timestamps. However, there's currently a bug in the Chrome serial
+ // code that's making the clock sync ack for BattOr take much longer to
+ // read than it should (by about 8ms). This is causing the above estimate
+ // of the controller's sync timestamp to be off by a substantial enough
+ // amount that it makes traces hard to read. For now, make an exception
+ // for BattOr and just use the controller's start timestamp as the sync
+ // time. In the medium term, we should fix the Chrome serial code in order
+ // to remove this special logic and get an even more accurate estimate.
+ if (fromMarker.domainId === ClockDomainId.BATTOR &&
+ toMarker.duration > BATTOR_FAST_SYNC_THRESHOLD_MS) {
+ toTs = toMarker.startTs;
+ } else if (toMarker.domainId === ClockDomainId.BATTOR &&
+ fromMarker.duration > BATTOR_FAST_SYNC_THRESHOLD_MS) {
+ fromTs = fromMarker.startTs;
+ }
+
+ var tsShift = toTs - fromTs;
+ return new Transformer(
+ (ts) => ts + tsShift, fromMarker.duration + toMarker.duration);
+ };
+
return {
ClockDomainId: ClockDomainId,
ClockSyncManager: ClockSyncManager
diff --git a/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager_test.html b/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager_test.html
index 6caad9b7d46..f8826420517 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/clock_sync_manager_test.html
@@ -63,19 +63,6 @@ tr.b.unittest.testSuite(function() {
'clock sync marker to it.');
}, testOptions);
- test('addClockSyncMarker_throwsWhenAddingDuplicatePaths', function() {
- var mgr = new ClockSyncManager();
- mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync1', 100);
- mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync1', 100);
-
- mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync2', 100);
-
- assert.throws(function() {
- mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync2', 100);
- }, 'The current code cannot handle multiple paths between the same clock ' +
- 'domains. However, this is a valid operation.');
- }, testOptions);
-
test('addClockSyncMarker_throwsAfterGetModelTimeTransformer', function() {
var mgr = new ClockSyncManager();
mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync1', 100);
@@ -223,6 +210,36 @@ tr.b.unittest.testSuite(function() {
mgr.getModelTimeTransformer(ClockDomainId.DOMAIN_3)(300), 100);
}, testOptions);
+ test('getModelTimeTransformer_usesPathWithLeastError', function() {
+ var mgr = new ClockSyncManager();
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync2', 100, 150);
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync2', 100);
+
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync1', 100, 200);
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync1', 100);
+
+ assert.strictEqual(
+ mgr.getModelTimeTransformer(ClockDomainId.DOMAIN_1)(125), 125);
+ assert.strictEqual(
+ mgr.getModelTimeTransformer(ClockDomainId.DOMAIN_2)(100), 125);
+ }, testOptions);
+
+ // NOTE: This is the same test as the above, but reversed to ensure that
+ // the result didn't stem from some ordering coincidence.
+ test('getModelTimeTransformer_usesPathWithLeastErrorReverse', function() {
+ var mgr = new ClockSyncManager();
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync1', 100);
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync1', 100, 150);
+
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_2, 'sync2', 100);
+ mgr.addClockSyncMarker(ClockDomainId.DOMAIN_1, 'sync2', 100, 200);
+
+ assert.strictEqual(
+ mgr.getModelTimeTransformer(ClockDomainId.DOMAIN_1)(125), 125);
+ assert.strictEqual(
+ mgr.getModelTimeTransformer(ClockDomainId.DOMAIN_2)(100), 125);
+ }, testOptions);
+
test('getModelTimeTransformer_battorSyncUsesNormalTimestampWhenFast',
function() {
var mgr = new ClockSyncManager();
diff --git a/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump.html b/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump.html
index 3abda063566..355deb4bb5e 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump.html
@@ -34,8 +34,9 @@ tr.exportTo('tr.model', function() {
* @enum
*/
ContainerMemoryDump.LevelOfDetail = {
- LIGHT: 0,
- DETAILED: 1
+ BACKGROUND: 0,
+ LIGHT: 1,
+ DETAILED: 2
};
ContainerMemoryDump.prototype = {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump_test.html b/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump_test.html
index 6c8bc649bf1..ff3585c41eb 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/container_memory_dump_test.html
@@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/model/memory_dump_test_utils.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -19,7 +19,7 @@ tr.b.unittest.testSuite(function() {
var MemoryAllocatorDump = tr.model.MemoryAllocatorDump;
var ScalarNumeric = tr.v.ScalarNumeric;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addChildDump = tr.model.MemoryDumpTestUtils.addChildDump;
diff --git a/chromium/third_party/catapult/tracing/tracing/model/counter.html b/chromium/third_party/catapult/tracing/tracing/model/counter.html
index 74c0991c91f..116afa05cc6 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/counter.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/counter.html
@@ -179,11 +179,11 @@ tr.exportTo('tr.model', function() {
* Comparison between counters that orders by parent.compareTo, then name.
*/
Counter.compare = function(x, y) {
- var tmp = x.parent.compareTo(y);
- if (tmp != 0)
+ var tmp = x.parent.compareTo(y.parent);
+ if (tmp !== 0)
return tmp;
var tmp = x.name.localeCompare(y.name);
- if (tmp == 0)
+ if (tmp === 0)
return x.tid - y.tid;
return tmp;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/counter_sample.html b/chromium/third_party/catapult/tracing/tracing/model/counter_sample.html
index f188afcc845..db3882e84c4 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/counter_sample.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/counter_sample.html
@@ -7,9 +7,9 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event.html">
<link rel="import" href="/tracing/model/event_registry.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -84,7 +84,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Counter sample from ' + this.series_.title + ' at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.timestamp);
+ tr.b.Unit.byName.timeStampInMs.format(this.timestamp);
}
};
@@ -93,9 +93,7 @@ tr.exportTo('tr.model', function() {
CounterSample,
{
name: 'counterSample',
- pluralName: 'counterSamples',
- singleViewElementName: 'tr-ui-a-counter-sample-sub-view',
- multiViewElementName: 'tr-ui-a-counter-sample-sub-view'
+ pluralName: 'counterSamples'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/counter_sample_test.html b/chromium/third_party/catapult/tracing/tracing/model/counter_sample_test.html
index 09322c2d8ea..2697a552554 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/counter_sample_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/counter_sample_test.html
@@ -17,31 +17,30 @@ tr.b.unittest.testSuite(function() {
test('groupByTimestamp', function() {
var counter = new Counter();
- var s0 = counter.addSeries(new CounterSeries('x', 0));
- var s1 = counter.addSeries(new CounterSeries('y', 1));
+ var slice0 = counter.addSeries(new CounterSeries('x', 0));
+ var slice1 = counter.addSeries(new CounterSeries('y', 1));
- var s0_0 = s0.addCounterSample(0, 100);
- var s0_1 = s1.addCounterSample(0, 200);
- var s1_0 = s0.addCounterSample(1, 100);
- var s1_1 = s1.addCounterSample(1, 200);
+ var slice0Sample0 = slice0.addCounterSample(0, 100);
+ var slice0Sample1 = slice1.addCounterSample(0, 200);
+ var slice1Sample0 = slice0.addCounterSample(1, 100);
+ var slice1Sample1 = slice1.addCounterSample(1, 200);
- var groups = CounterSample.groupByTimestamp([s0_1, s0_0,
- s1_1, s1_0]);
+ var groups = CounterSample.groupByTimestamp([slice0Sample1, slice0Sample0,
+ slice1Sample1, slice1Sample0]);
assert.equal(groups.length, 2);
- assert.deepEqual(groups[0], [s0_0, s0_1]);
- assert.deepEqual(groups[1], [s1_0, s1_1]);
+ assert.deepEqual(groups[0], [slice0Sample0, slice0Sample1]);
+ assert.deepEqual(groups[1], [slice1Sample0, slice1Sample1]);
});
test('getSampleIndex', function() {
var ctr = new Counter(null, 0, '', 'myCounter');
- var s0 = new CounterSeries('a', 0);
- ctr.addSeries(s0);
+ var slice0 = new CounterSeries('a', 0);
+ ctr.addSeries(slice0);
- var s0_0 = s0.addCounterSample(0, 0);
- var s0_1 = s0.addCounterSample(1, 100);
- assert.equal(s0_0.getSampleIndex(), 0);
- assert.equal(s0_1.getSampleIndex(), 1);
+ var slice0Sample0 = slice0.addCounterSample(0, 0);
+ var slice0Sample1 = slice0.addCounterSample(1, 100);
+ assert.equal(slice0Sample0.getSampleIndex(), 0);
+ assert.equal(slice0Sample1.getSampleIndex(), 1);
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/model/counter_series.html b/chromium/third_party/catapult/tracing/tracing/model/counter_series.html
index ac1463c381a..80ad2e167dc 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/counter_series.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/counter_series.html
@@ -122,4 +122,3 @@ tr.exportTo('tr.model', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/model/counter_test.html b/chromium/third_party/catapult/tracing/tracing/model/counter_test.html
index fef6fa76efe..e5ff4f56b32 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/counter_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/counter_test.html
@@ -8,6 +8,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/counter.html">
<link rel="import" href="/tracing/model/counter_series.html">
+<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/model/process.html">
<script>
'use strict';
@@ -104,6 +106,19 @@ tr.b.unittest.testSuite(function() {
assert.equal(ret[1].start, 10);
assert.equal(ret[1].end, 16);
});
+
+ test('testCounterSortRemainInOrder', function() {
+ var model = new tr.Model();
+ var process = new tr.model.Process(model, 4);
+ var ctr1 = new Counter(process, 0, '', 'a');
+ var ctr2 = new Counter(process, 0, '', 'b');
+
+ var array = [ ctr1, ctr2 ];
+ array.sort(tr.model.Counter.compare);
+
+ assert.equal(array[0], ctr1);
+ assert.equal(array[1], ctr2);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/model/cpu.html b/chromium/third_party/catapult/tracing/tracing/model/cpu.html
index 2194e462185..61f4d40d54a 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/cpu.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/cpu.html
@@ -22,7 +22,6 @@ tr.exportTo('tr.model', function() {
var ColorScheme = tr.b.ColorScheme;
var Counter = tr.model.Counter;
var CpuSlice = tr.model.CpuSlice;
- var Slice = tr.model.Slice;
/**
* The Cpu represents a Cpu from the kernel's point of view.
@@ -48,7 +47,7 @@ tr.exportTo('tr.model', function() {
// Name and arguments of the last active thread.
this.lastActiveName_ = undefined;
this.lastActiveArgs_ = undefined;
- };
+ }
Cpu.prototype = {
__proto__: tr.model.EventContainer.prototype,
@@ -63,7 +62,7 @@ tr.exportTo('tr.model', function() {
findTopmostSlicesInThisContainer: function*(eventPredicate, opt_this) {
// All CpuSlices are toplevel since CpuSlices do not nest.
- for (var s of slices) {
+ for (var s of this.slices) {
yield * s.findTopmostSlicesRelativeToThisSlice(
eventPredicate, opt_this);
}
@@ -135,7 +134,7 @@ tr.exportTo('tr.model', function() {
createSubSlices: function() {
this.samples_ = this.kernel.model.samples.filter(function(sample) {
- return sample.cpu == this;
+ return sample.cpu === this;
}, this);
},
@@ -164,16 +163,16 @@ tr.exportTo('tr.model', function() {
},
/**
- * Closes the thread running on the CPU. |end_timestamp| is the timestamp
+ * Closes the thread running on the CPU. |endTimestamp| is the timestamp
* at which the thread was unscheduled. |args| is merged with the arguments
* specified when the thread was initially scheduled.
*/
- closeActiveThread: function(end_timestamp, args) {
+ closeActiveThread: function(endTimestamp, args) {
// Don't generate a slice if the last active thread is the idle task.
- if (this.lastActiveThread_ == undefined || this.lastActiveThread_ == 0)
+ if (this.lastActiveThread_ === undefined || this.lastActiveThread_ === 0)
return;
- if (end_timestamp < this.lastActiveTimestamp_) {
+ if (endTimestamp < this.lastActiveTimestamp_) {
throw new Error('The end timestamp of a thread running on CPU ' +
this.cpuNumber + ' is before its start timestamp.');
}
@@ -184,7 +183,7 @@ tr.exportTo('tr.model', function() {
this.lastActiveArgs_[key] = args[key];
}
- var duration = end_timestamp - this.lastActiveTimestamp_;
+ var duration = endTimestamp - this.lastActiveTimestamp_;
var slice = new tr.model.CpuSlice(
'', this.lastActiveName_,
ColorScheme.getColorIdForGeneralPurposeString(this.lastActiveName_),
@@ -201,16 +200,16 @@ tr.exportTo('tr.model', function() {
this.lastActiveArgs_ = undefined;
},
- switchActiveThread: function(timestamp, old_thread_args, new_thread_id,
- new_thread_name, new_thread_args) {
+ switchActiveThread: function(timestamp, oldThreadArgs, newThreadId,
+ newThreadName, newThreadArgs) {
// Close the previous active thread and generate a slice.
- this.closeActiveThread(timestamp, old_thread_args);
+ this.closeActiveThread(timestamp, oldThreadArgs);
// Keep track of the new thread.
this.lastActiveTimestamp_ = timestamp;
- this.lastActiveThread_ = new_thread_id;
- this.lastActiveName_ = new_thread_name;
- this.lastActiveArgs_ = new_thread_args;
+ this.lastActiveThread_ = newThreadId;
+ this.lastActiveName_ = newThreadName;
+ this.lastActiveArgs_ = newThreadArgs;
},
/**
diff --git a/chromium/third_party/catapult/tracing/tracing/model/cpu_slice.html b/chromium/third_party/catapult/tracing/tracing/model/cpu_slice.html
index b646a3db0f9..c999e00bc56 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/cpu_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/cpu_slice.html
@@ -56,9 +56,7 @@ tr.exportTo('tr.model', function() {
CpuSlice,
{
name: 'cpuSlice',
- pluralName: 'cpuSlices',
- singleViewElementName: 'tr-ui-a-single-cpu-slice-sub-view',
- multiViewElementName: 'tr-ui-a-multi-cpu-slice-sub-view'
+ pluralName: 'cpuSlices'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/cpu_test.html b/chromium/third_party/catapult/tracing/tracing/model/cpu_test.html
index 2ac7338e089..74c8e135fbe 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/cpu_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/cpu_test.html
@@ -45,7 +45,7 @@ tr.b.unittest.testSuite(function() {
cpu.slices.push(tr.c.TestUtils.newSliceEx({start: 1, duration: 3}));
var shiftCount = 0;
ctr.shiftTimestampsForward = function(ts) {
- if (ts == 0.32)
+ if (ts === 0.32)
shiftCount++;
};
cpu.slices.push(tr.c.TestUtils.newSliceEx({start: 1, duration: 3}));
diff --git a/chromium/third_party/catapult/tracing/tracing/model/event.html b/chromium/third_party/catapult/tracing/tracing/model/event.html
index 10ab2f3c22b..9695c8207ed 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/event.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/event.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/guid.html">
+<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/selectable_item.html">
<link rel="import" href="/tracing/model/selection_state.html">
@@ -46,6 +47,12 @@ tr.exportTo('tr.model', function() {
return undefined;
},
+ get range() {
+ var range = new tr.b.Range();
+ this.addBoundsToRange(range);
+ return range;
+ },
+
// Empty by default. Lazily initialized on an instance in
// addAssociatedAlert(). See #1930.
associatedAlerts: IMMUTABLE_EMPTY_SET,
@@ -56,10 +63,10 @@ tr.exportTo('tr.model', function() {
this.associatedAlerts.push(alert);
},
- /** Adds the range of timestamps for this event to the specified range. */
- addBoundsToRange: function(range) {
- throw new Error('Not implemented');
- }
+ // Adds the range of timestamps for this event to the specified range.
+ // If this is not overridden in subclass, it means that type of event
+ // doesn't have timestamps.
+ addBoundsToRange: function(range) {}
};
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/event_registry.html b/chromium/third_party/catapult/tracing/tracing/model/event_registry.html
index ec2c1ebe3a8..ae5ec61dc33 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/event_registry.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/event_registry.html
@@ -24,25 +24,26 @@ tr.exportTo('tr.model', function() {
// Enforce all options objects have the right fields.
EventRegistry.addEventListener('will-register', function(e) {
var metadata = e.typeInfo.metadata;
-
if (metadata.name === undefined)
throw new Error('Registered events must provide name metadata');
- var i = tr.b.findFirstInArray(
- EventRegistry.getAllRegisteredTypeInfos(),
- function(x) { return x.metadata.name === metadata.name; });
- if (i !== undefined)
- throw new Error('Event type with that name already registered');
-
if (metadata.pluralName === undefined)
throw new Error('Registered events must provide pluralName metadata');
- if (metadata.singleViewElementName === undefined) {
- throw new Error('Registered events must provide ' +
- 'singleViewElementName metadata');
- }
- if (metadata.multiViewElementName === undefined) {
- throw new Error('Registered events must provide ' +
- 'multiViewElementName metadata');
+
+ // Add a subtype registry to every event so that all events can be
+ // extended
+ if (metadata.subTypes === undefined) {
+ metadata.subTypes = {};
+ var options = new tr.b.ExtensionRegistryOptions(
+ tr.b.TYPE_BASED_REGISTRY_MODE);
+ options.mandatoryBaseClass = e.typeInfo.constructor;
+ options.defaultConstructor = e.typeInfo.constructor;
+ tr.b.decorateExtensionRegistry(metadata.subTypes, options);
+ } else {
+ if (!metadata.subTypes.register)
+ throw new Error('metadata.subTypes must be an extension registry.');
}
+
+ e.typeInfo.constructor.subTypes = metadata.subTypes;
});
// Helper: lookup Events indexed by type name.
@@ -55,7 +56,7 @@ tr.exportTo('tr.model', function() {
});
}
return eventsByTypeName[typeName];
- }
+ };
// Ensure eventsByTypeName stays current.
EventRegistry.addEventListener('registry-changed', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/event_set.html b/chromium/third_party/catapult/tracing/tracing/model/event_set.html
index c79ddc85302..344f524fa02 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/event_set.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/event_set.html
@@ -26,16 +26,13 @@ tr.exportTo('tr.model', function() {
* @constructor
*/
function EventSet(opt_events) {
- this.bounds_dirty_ = true;
this.bounds_ = new tr.b.Range();
- this.length_ = 0;
- this.guid_ = tr.b.GUID.allocateSimple();
- this.pushed_guids_ = {};
+ this.events_ = new Set();
if (opt_events) {
if (opt_events instanceof Array) {
- for (var i = 0; i < opt_events.length; i++)
- this.push(opt_events[i]);
+ for (var event of opt_events)
+ this.push(event);
} else if (opt_events instanceof EventSet) {
this.addEventSet(opt_events);
} else {
@@ -43,12 +40,11 @@ tr.exportTo('tr.model', function() {
}
}
}
+
EventSet.prototype = {
__proto__: Object.prototype,
get bounds() {
- if (this.bounds_dirty_)
- this.resolveBounds_();
return this.bounds_;
},
@@ -59,7 +55,7 @@ tr.exportTo('tr.model', function() {
},
get length() {
- return this.length_;
+ return this.events_.size;
},
get guid() {
@@ -67,85 +63,64 @@ tr.exportTo('tr.model', function() {
},
*[Symbol.iterator]() {
- for (var i = 0; i < this.length_; ++i)
- yield this[i];
+ for (var event of this.events_)
+ yield event;
},
clear: function() {
- for (var i = 0; i < this.length_; ++i)
- delete this[i];
- this.length_ = 0;
- this.bounds_dirty_ = true;
- },
-
- resolveBounds_: function() {
- this.bounds_.reset();
- for (var i = 0; i < this.length_; i++)
- this[i].addBoundsToRange(this.bounds_);
- this.bounds_dirty_ = false;
+ this.bounds_ = new tr.b.Range();
+ this.events_.clear();
},
// push pushes only unique events.
// If an event has been already pushed, do nothing.
push: function(event) {
- if (event.guid == undefined)
+ if (event.guid === undefined)
throw new Error('Event must have a GUID');
- if (this.contains(event))
- return event;
+ if (!this.events_.has(event)) {
+ this.events_.add(event);
+ // Some uses of eventSet, particularly in tests, have Events as objects
+ // that don't have addBoundsToRange as a function. Thus we need to
+ // handle this case.
+ if (event.addBoundsToRange)
+ if (this.bounds_ !== undefined)
+ event.addBoundsToRange(this.bounds_);
+ }
- this.pushed_guids_[event.guid] = true;
- this[this.length_++] = event;
- this.bounds_dirty_ = true;
return event;
},
contains: function(event) {
- return this.pushed_guids_[event.guid];
- },
-
- indexOf: function(event) {
- for (var i = 0; i < this.length; i++) {
- if (this[i].guid === event.guid)
- return i;
- }
- return -1;
+ if (this.events_.has(event))
+ return event;
+ else
+ return undefined;
},
addEventSet: function(eventSet) {
- for (var i = 0; i < eventSet.length; i++)
- this.push(eventSet[i]);
- },
-
- subEventSet: function(index, count) {
- count = count || 1;
-
- var eventSet = new EventSet();
- eventSet.bounds_dirty_ = true;
- if (index < 0 || index + count > this.length_)
- throw new Error('Index out of bounds');
-
- for (var i = index; i < index + count; i++)
- eventSet.push(this[i]);
-
- return eventSet;
+ for (var event of eventSet)
+ this.push(event);
},
intersectionIsEmpty: function(otherEventSet) {
- return !this.some(function(event) {
- return otherEventSet.contains(event);
- });
+ return !this.some(event => otherEventSet.contains(event));
},
equals: function(that) {
if (this.length !== that.length)
return false;
- for (var i = 0; i < this.length; i++) {
- var event = this[i];
- if (that.pushed_guids_[event.guid] === undefined)
- return false;
- }
- return true;
+ return this.every(event => that.contains(event));
+ },
+
+ sortEvents: function(compare) {
+ // Convert to array, then sort, then convert back
+ var ary = this.toArray();
+ ary.sort(compare);
+
+ this.clear();
+ for (var event of ary)
+ this.push(event);
},
getEventsOrganizedByBaseType: function(opt_pruneEmpty) {
@@ -164,7 +139,7 @@ tr.exportTo('tr.model', function() {
}
});
- if (maxEventIndex == -1) {
+ if (maxEventIndex === -1) {
console.log(event);
throw new Error('Unrecognized event type');
}
@@ -190,27 +165,20 @@ tr.exportTo('tr.model', function() {
});
},
- getEventsOrganizedByCallback: function(cb) {
- var eventsByCallback = {};
- for (var i = 0; i < this.length; i++) {
- var event = this[i];
- var key = cb(event);
-
- if (key === undefined)
- throw new Error('An event could not be organized');
-
- if (eventsByCallback[key] === undefined)
- eventsByCallback[key] = new EventSet();
-
- eventsByCallback[key].push(event);
- }
- return eventsByCallback;
+ /**
+ * @param {!function(!tr.model.Event):string} cb
+ * @param {*=} opt_this
+ * @return {!Object}
+ */
+ getEventsOrganizedByCallback: function(cb, opt_this) {
+ var groupedEvents = tr.b.group(this, cb, opt_this || this);
+ return tr.b.mapItems(groupedEvents, (_, events) => new EventSet(events));
},
enumEventsOfType: function(type, func) {
- for (var i = 0; i < this.length_; i++)
- if (this[i] instanceof type)
- func(this[i]);
+ for (var event of this)
+ if (event instanceof type)
+ func(event);
},
get userFriendlyName() {
@@ -223,7 +191,7 @@ tr.exportTo('tr.model', function() {
if (this.length === 1) {
var tmp = EventRegistry.getUserFriendlySingularName(eventTypeName);
- return this[0].userFriendlyName;
+ return tr.b.getOnlyElement(this.events_).userFriendlyName;
}
var numEventTypes = tr.b.dictionaryLength(eventsByBaseType);
@@ -237,60 +205,60 @@ tr.exportTo('tr.model', function() {
filter: function(fn, opt_this) {
var res = new EventSet();
-
- this.forEach(function(slice) {
- if (fn.call(this, slice))
- res.push(slice);
- }, opt_this);
+ for (var event of this)
+ if (fn.call(opt_this, event))
+ res.push(event);
return res;
},
toArray: function() {
var ary = [];
- for (var i = 0; i < this.length; i++)
- ary.push(this[i]);
+ for (var event of this)
+ ary.push(event);
return ary;
},
forEach: function(fn, opt_this) {
- for (var i = 0; i < this.length; i++)
- fn.call(opt_this, this[i], i);
+ for (var event of this)
+ fn.call(opt_this, event);
},
map: function(fn, opt_this) {
var res = [];
- for (var i = 0; i < this.length; i++)
- res.push(fn.call(opt_this, this[i], i));
+ for (var event of this)
+ res.push(fn.call(opt_this, event));
return res;
},
every: function(fn, opt_this) {
- for (var i = 0; i < this.length; i++)
- if (!fn.call(opt_this, this[i], i))
+ for (var event of this)
+ if (!fn.call(opt_this, event))
return false;
return true;
},
some: function(fn, opt_this) {
- for (var i = 0; i < this.length; i++)
- if (fn.call(opt_this, this[i], i))
+ for (var event of this)
+ if (fn.call(opt_this, event))
return true;
return false;
},
asDict: function() {
- var stable_ids = [];
- this.forEach(function(event) {
- stable_ids.push(event.stableId);
- });
- return {'events': stable_ids};
+ var stableIds = [];
+ for (var event of this)
+ stableIds.push(event.stableId);
+ return {'events': stableIds};
+ },
+
+ asSet: function() {
+ return this.events_;
}
};
EventSet.IMMUTABLE_EMPTY_SET = (function() {
var s = new EventSet();
- s.resolveBounds_();
s.push = function() {
throw new Error('Cannot push to an immutable event set');
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/event_set_test.html b/chromium/third_party/catapult/tracing/tracing/model/event_set_test.html
index 9fbfd995059..b584c23cf33 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/event_set_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/event_set_test.html
@@ -31,12 +31,14 @@ tr.b.unittest.testSuite(function() {
assert.equal(eventSet.bounds.min, 1);
assert.equal(eventSet.bounds.max, 4);
- assert.equal(eventSet[0], t1.sliceGroup.slices[0]);
+ assert.deepEqual(eventSet, new tr.model.EventSet(
+ t1.sliceGroup.slices[0]));
eventSet.push(t1.sliceGroup.slices[1]);
assert.equal(eventSet.bounds.min, 1);
assert.equal(eventSet.bounds.max, 6);
- assert.equal(eventSet[1], t1.sliceGroup.slices[1]);
+ assert.deepEqual(eventSet, new tr.model.EventSet(
+ [t1.sliceGroup.slices[0], t1.sliceGroup.slices[1]]));
eventSet.clear();
assert.equal(eventSet.length, 0);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/flow_event.html b/chromium/third_party/catapult/tracing/tracing/model/flow_event.html
index bffb8661a7d..f54c94fdc61 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/flow_event.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/flow_event.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -47,7 +47,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Flow event named ' + this.title + ' at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.timestamp);
+ tr.b.Unit.byName.timeStampInMs.format(this.timestamp);
}
};
@@ -55,9 +55,7 @@ tr.exportTo('tr.model', function() {
FlowEvent,
{
name: 'flowEvent',
- pluralName: 'flowEvents',
- singleViewElementName: 'tr-ui-a-single-flow-event-sub-view',
- multiViewElementName: 'tr-ui-a-multi-flow-event-sub-view'
+ pluralName: 'flowEvents'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/frame.html b/chromium/third_party/catapult/tracing/tracing/model/frame.html
index d6bc6195bf2..99b3124727e 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/frame.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/frame.html
@@ -85,9 +85,7 @@ tr.exportTo('tr.model', function() {
Frame,
{
name: 'frame',
- pluralName: 'frames',
- singleViewElementName: 'tr-ui-a-single-frame-sub-view',
- multiViewElementName: 'tr-ui-a-multi-frame-sub-view'
+ pluralName: 'frames'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump.html b/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump.html
index 80bb03ff361..6b8c618f0f8 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump.html
@@ -6,11 +6,11 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/event_registry.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -80,7 +80,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Global memory dump at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
},
get containerName() {
@@ -223,7 +223,7 @@ tr.exportTo('tr.model', function() {
if (sizeNumeric !== undefined) {
size = sizeNumeric.value;
shouldDefineSize = true;
- if (sizeNumeric.unit !== tr.v.Unit.byName.sizeInBytes_smallerIsBetter) {
+ if (sizeNumeric.unit !== tr.b.Unit.byName.sizeInBytes_smallerIsBetter) {
this.model.importWarning({
type: 'memory_dump_parse_error',
message: 'Invalid unit of \'size\' numeric of memory allocator ' +
@@ -239,9 +239,9 @@ tr.exportTo('tr.model', function() {
type: 'memory_dump_parse_error',
message: 'Size provided by memory allocator dump \'' +
dump.fullName + '\'' +
- tr.v.Unit.byName.sizeInBytes.format(size) +
+ tr.b.Unit.byName.sizeInBytes.format(size) +
') is less than ' + dependencyName + ' (' +
- tr.v.Unit.byName.sizeInBytes.format(dependencySize) + ').'
+ tr.b.Unit.byName.sizeInBytes.format(dependencySize) + ').'
});
dump.infos.push({
type: dependencyInfoType,
@@ -330,7 +330,7 @@ tr.exportTo('tr.model', function() {
size = Math.max(size, aggregatedChildrenSize, largestOwnerSize);
dump.numerics[SIZE_NUMERIC_NAME] = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, size);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, size);
// Add a virtual child to make up for extra size of the dump with
// respect to its children (if applicable).
@@ -341,7 +341,7 @@ tr.exportTo('tr.model', function() {
virtualChild.parent = dump;
dump.children.unshift(virtualChild);
virtualChild.numerics[SIZE_NUMERIC_NAME] = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter,
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter,
size - aggregatedChildrenSize);
}
},
@@ -702,7 +702,7 @@ tr.exportTo('tr.model', function() {
});
}
dump.numerics[EFFECTIVE_SIZE_NUMERIC_NAME] = new tr.v.ScalarNumeric(
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, effectiveSize);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, effectiveSize);
},
aggregateNumerics: function() {
@@ -858,9 +858,7 @@ tr.exportTo('tr.model', function() {
GlobalMemoryDump,
{
name: 'globalMemoryDump',
- pluralName: 'globalMemoryDumps',
- singleViewElementName: 'tr-ui-a-container-memory-dump-sub-view',
- multiViewElementName: 'tr-ui-a-container-memory-dump-sub-view'
+ pluralName: 'globalMemoryDumps'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump_test.html b/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump_test.html
index dbc472209d9..edab7779513 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/global_memory_dump_test.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/importer/import.html">
<link rel="import" href="/tracing/model/global_memory_dump.html">
@@ -14,7 +15,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/model/process_memory_dump.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -27,7 +27,7 @@ tr.b.unittest.testSuite(function() {
var MemoryAllocatorDumpLink = tr.model.MemoryAllocatorDumpLink;
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addChildDump = tr.model.MemoryDumpTestUtils.addChildDump;
var addOwnershipLink = tr.model.MemoryDumpTestUtils.addOwnershipLink;
@@ -671,8 +671,8 @@ tr.b.unittest.testSuite(function() {
var containerDumps = createContainerDumps(1);
var gmd = containerDumps[0];
var pmd = containerDumps[1];
- var rootDump = newAllocatorDump(pmd, 'root', { size: 100 });
- addChildDump(rootDump, 'parent', { size: 49 });
+ var rootDump = newAllocatorDump(pmd, 'root', {numerics: {size: 100}});
+ addChildDump(rootDump, 'parent', {numerics: {size: 49}});
pmd.memoryAllocatorDumps = [rootDump];
assert.throws(function() {
@@ -698,8 +698,9 @@ tr.b.unittest.testSuite(function() {
var containerDumps = createContainerDumps(1);
var gmd = containerDumps[0];
var pmd = containerDumps[1];
- var rootDump = newAllocatorDump(pmd, 'root', { effective_size: 99 });
- addChildDump(rootDump, 'parent', { effective_size: 50 });
+ var rootDump = newAllocatorDump(pmd, 'root',
+ {numerics: {effective_size: 99}});
+ addChildDump(rootDump, 'parent', {numerics: {effective_size: 50}});
pmd.memoryAllocatorDumps = [rootDump];
assert.throws(function() {
@@ -725,9 +726,7 @@ tr.b.unittest.testSuite(function() {
var containerDumps = createContainerDumps(0);
var gmd = containerDumps[0];
gmd.memoryAllocatorDumps = [
- newAllocatorDump(gmd, 'v8', {
- size: 50
- })
+ newAllocatorDump(gmd, 'v8', {numerics: {size: 50}})
];
assert.throws(function() {
@@ -752,7 +751,7 @@ tr.b.unittest.testSuite(function() {
test('testSanityCheck_checkDumpTrees_invalidInfo', function() {
var containerDumps = createContainerDumps(0);
var gmd = containerDumps[0];
- var v8Dump = newAllocatorDump(gmd, 'v8', { size: 50 });
+ var v8Dump = newAllocatorDump(gmd, 'v8', {numerics: {size: 50}});
v8Dump.infos.push({
type: PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN,
providedSize: 40,
@@ -784,7 +783,7 @@ tr.b.unittest.testSuite(function() {
var containerDumps = createContainerDumps(0);
var gmd = containerDumps[0];
var v8Dump = new MemoryAllocatorDump(gmd, 'v8');
- addChildDump(v8Dump, 'child1', {}, 42 /* guid */);
+ addChildDump(v8Dump, 'child1', {guid: 42});
addChildDump(v8Dump, 'child2');
gmd.memoryAllocatorDumps = [v8Dump];
@@ -3432,7 +3431,7 @@ tr.b.unittest.testSuite(function() {
var ownedChildDump = pmd.getMemoryAllocatorDumpByFullName(
'root/owned_child');
assertDumpSizes(ownedChildDump, 20, 13, [] /* expectedInfos */,
- { owner_child: 7 } /* expectedOwnedBySiblingSizes */);
+ {'owner_child': 7} /* expectedOwnedBySiblingSizes */);
});
// Check that numeric and diagnostics propagation and aggregation are
@@ -3511,39 +3510,39 @@ tr.b.unittest.testSuite(function() {
checkDumpNumericsAndDiagnostics(
pmd.getMemoryAllocatorDumpByFullName('direct_owner'),
{
- 'size': 10,
- 'effective_size': 3.3333,
- 'summed': 27
+ size: 10,
+ effective_size: 3.3333,
+ summed: 27
},
{
- 'url': 'file://not_overriden.html'
+ url: 'file://not_overriden.html'
});
checkDumpNumericsAndDiagnostics(
pmd.getMemoryAllocatorDumpByFullName('parent_owner/child_owner'),
{
- 'size': 10,
- 'effective_size': 3.3333,
- 'summed': 27
+ size: 10,
+ effective_size: 3.3333,
+ summed: 27
},
{
- 'url': 'https://hello.world.com:42'
+ url: 'https://hello.world.com:42'
});
checkDumpNumericsAndDiagnostics(
pmd.getMemoryAllocatorDumpByFullName('parent_owner'),
{
- 'size': 15,
- 'effective_size': 8.3333,
- 'summed': 40
+ size: 15,
+ effective_size: 8.3333,
+ summed: 40
}, {});
checkDumpNumericsAndDiagnostics(
pmd.getMemoryAllocatorDumpByFullName('precedent_owner'),
{
- 'size': 10,
- 'effective_size': 3.3333,
- 'summed': 0
+ size: 10,
+ effective_size: 3.3333,
+ summed: 0
},
{
- 'url': 'https://hello.world.com:42'
+ url: 'https://hello.world.com:42'
});
checkDumpNumericsAndDiagnostics(
pmd.getMemoryAllocatorDumpByFullName('indirect_owner'), {}, {});
@@ -3610,8 +3609,8 @@ tr.b.unittest.testSuite(function() {
gmd = new GlobalMemoryDump(model, 10);
model.globalMemoryDumps.push(gmd);
- rootDump = newAllocatorDump(gmd, 'root', { size: 64 });
- childDump = addChildDump(rootDump, 'child', { size: 48 });
+ rootDump = newAllocatorDump(gmd, 'root', {numerics: {size: 64}});
+ childDump = addChildDump(rootDump, 'child', {numerics: {size: 48}});
gmd.memoryAllocatorDumps = [rootDump];
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_app.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_app.html
index 8504a34c98e..fcd545bfbd5 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_app.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_app.html
@@ -33,6 +33,8 @@ tr.exportTo('tr.model.helpers', function() {
var RENDER_THREAD_DRAW_NAME = 'DrawFrame';
var RENDER_THREAD_INDEP_DRAW_NAME = 'doFrame';
+ var RENDER_THREAD_QUEUE_NAME = 'queueBuffer';
+ var RENDER_THREAD_SWAP_NAME = 'eglSwapBuffers';
var THREAD_SYNC_NAME = 'syncFrameState';
function getSlicesForThreadTimeRanges(threadTimeRanges) {
@@ -60,20 +62,32 @@ tr.exportTo('tr.model.helpers', function() {
return new Frame(events, threadTimeRanges, args);
}
- function findOverlappingDrawFrame(renderThread, time) {
+ function findOverlappingDrawFrame(renderThread, uiDrawSlice) {
if (!renderThread)
return undefined;
- var slices = renderThread.sliceGroup.slices;
- for (var i = 0; i < slices.length; i++) {
- var slice = slices[i];
- if (slice.title == RENDER_THREAD_DRAW_NAME &&
- slice.start <= time &&
- time <= slice.end) {
- return slice;
- }
- }
- return undefined;
+ // of all top level renderthread slices, find the one that has a 'sync'
+ // within the uiDrawSlice
+ var overlappingDrawFrame;
+ var slices = tr.b.iterateOverIntersectingIntervals(
+ renderThread.sliceGroup.slices,
+ function(range) { return range.start },
+ function(range) { return range.end },
+ uiDrawSlice.start,
+ uiDrawSlice.end,
+ function(rtDrawSlice) {
+ if (rtDrawSlice.title === RENDER_THREAD_DRAW_NAME) {
+ var rtSyncSlice = rtDrawSlice.findDescendentSlice(THREAD_SYNC_NAME);
+ if (rtSyncSlice &&
+ rtSyncSlice.start >= uiDrawSlice.start &&
+ rtSyncSlice.end <= uiDrawSlice.end) {
+ // sync observed which overlaps ui draw. This means the RT draw
+ // corresponds to the UI draw
+ overlappingDrawFrame = rtDrawSlice;
+ }
+ }
+ });
+ return overlappingDrawFrame;
}
/**
@@ -89,14 +103,14 @@ tr.exportTo('tr.model.helpers', function() {
// gather all frame work that occurs outside of performTraversals
var preFrameEvents = [];
uiThread.sliceGroup.slices.forEach(function(slice) {
- if (slice.title == 'obtainView' ||
- slice.title == 'setupListItem' ||
- slice.title == 'deliverInputEvent' ||
- slice.title == 'RV Scroll')
+ if (slice.title === 'obtainView' ||
+ slice.title === 'setupListItem' ||
+ slice.title === 'deliverInputEvent' ||
+ slice.title === 'RV Scroll')
preFrameEvents.push(slice);
});
uiThread.asyncSliceGroup.slices.forEach(function(slice) {
- if (slice.title == 'deliverInputEvent')
+ if (slice.title === 'deliverInputEvent')
preFrameEvents.push(slice);
});
@@ -124,12 +138,28 @@ tr.exportTo('tr.model.helpers', function() {
return traversalStart;
}
+ function getRtFrameEndTime(rtDrawSlice) {
+ // First try and get time that frame is queued:
+ var rtQueueSlice = rtDrawSlice.findDescendentSlice(
+ RENDER_THREAD_QUEUE_NAME);
+ if (rtQueueSlice) {
+ return rtQueueSlice.end;
+ }
+ // failing that, end of swapbuffers:
+ var rtSwapSlice = rtDrawSlice.findDescendentSlice(RENDER_THREAD_SWAP_NAME);
+ if (rtSwapSlice) {
+ return rtSwapSlice.end;
+ }
+ // failing that, end of renderthread frame trace
+ return rtDrawSlice.end;
+ }
+
function getUiThreadDrivenFrames(app) {
if (!app.uiThread)
return [];
var preTraversalWorkRanges = [];
- if (app.uiDrawType == UI_DRAW_TYPE.LEGACY)
+ if (app.uiDrawType === UI_DRAW_TYPE.LEGACY)
preTraversalWorkRanges = getPreTraversalWorkRanges(app.uiThread);
var frames = [];
@@ -149,7 +179,7 @@ tr.exportTo('tr.model.helpers', function() {
// on SDK 21+ devices with RenderThread,
// account for time taken on RenderThread
var rtDrawSlice = findOverlappingDrawFrame(
- app.renderThread, slice.end);
+ app.renderThread, slice);
if (rtDrawSlice) {
var rtSyncSlice = rtDrawSlice.findDescendentSlice(THREAD_SYNC_NAME);
if (rtSyncSlice) {
@@ -162,7 +192,7 @@ tr.exportTo('tr.model.helpers', function() {
threadTimeRanges.push({
thread: app.renderThread,
start: rtDrawSlice.start,
- end: rtDrawSlice.end
+ end: getRtFrameEndTime(rtDrawSlice)
});
}
frames.push(makeFrame(threadTimeRanges, app.surfaceFlinger));
@@ -204,7 +234,7 @@ tr.exportTo('tr.model.helpers', function() {
var samples = undefined;
for (var counterName in process.counters) {
if (/^android\.aq\:pending/.test(counterName) &&
- process.counters[counterName].numSeries == 1) {
+ process.counters[counterName].numSeries === 1) {
samples = process.counters[counterName].series[0].samples;
break;
}
@@ -251,16 +281,17 @@ tr.exportTo('tr.model.helpers', function() {
this.frames_ = undefined;
this.inputs_ = undefined;
- };
+ }
AndroidApp.createForProcessIfPossible = function(process, surfaceFlinger) {
var uiThread = process.getThread(process.pid);
var uiDrawType = getUiDrawType(uiThread);
- if (uiDrawType == UI_DRAW_TYPE.NONE) {
+ if (uiDrawType === UI_DRAW_TYPE.NONE) {
uiThread = undefined;
}
var renderThreads = process.findAllThreadsNamed('RenderThread');
- var renderThread = renderThreads.length == 1 ? renderThreads[0] : undefined;
+ var renderThread = (renderThreads.length === 1 ?
+ renderThreads[0] : undefined);
if (uiThread || renderThread) {
return new AndroidApp(process, uiThread, renderThread, surfaceFlinger,
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_model_helper_test.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_model_helper_test.html
index 114bd5a8a10..9d9de28ed46 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_model_helper_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_model_helper_test.html
@@ -19,7 +19,7 @@ tr.b.unittest.testSuite(function() {
var newCounterNamed = tr.c.TestUtils.newCounterNamed;
var newCounterSeries = tr.c.TestUtils.newCounterSeries;
- function createSurfaceFlingerWithVsyncs(model) {
+ function createSurfaceFlinger(model, vsyncCallback) {
if (model.getProcess(2))
throw new Error('process already exists');
@@ -34,12 +34,18 @@ tr.b.unittest.testSuite(function() {
duration: 2
}));
- var counter = sfProcess.getOrCreateCounter('android', 'VSYNC');
- var series = newCounterSeries();
- for (var i = 0; i <= 10; i++) {
- series.addCounterSample(i * 10, i % 2);
- }
- counter.addSeries(series);
+ vsyncCallback(sfProcess);
+ }
+
+ function createSurfaceFlingerWithVsync(model) {
+ createSurfaceFlinger(model, function(sfProcess) {
+ var counter = sfProcess.getOrCreateCounter('android', 'VSYNC');
+ var series = newCounterSeries();
+ for (var i = 0; i <= 10; i++) {
+ series.addCounterSample(i * 10, i % 2);
+ }
+ counter.addSeries(series);
+ });
}
/*
@@ -69,23 +75,25 @@ tr.b.unittest.testSuite(function() {
function(model) {
var uiThread = model.getOrCreateProcess(120).getOrCreateThread(120);
- // UI thread time - 19 (from 10 to 29)
+ // UI thread time - 19 (from 10 to 29, ignored after)
uiThread.asyncSliceGroup.push(
newAsyncSliceNamed('deliverInputEvent', 10, 9, uiThread, uiThread));
uiThread.sliceGroup.pushSlice(newSliceEx(
- {title: 'performTraversals', start: 20, duration: 10}));
+ {title: 'performTraversals', start: 20, duration: 110}));
uiThread.sliceGroup.pushSlice(newSliceEx(
- {title: 'draw', start: 20, duration: 8}));
+ {title: 'draw', start: 20, duration: 108}));
uiThread.sliceGroup.pushSlice(newSliceEx(
{title: 'Record View#draw()', start: 20, duration: 8}));
- // RenderThread time - 61 (from 29 to 90)
+ // RenderThread time - 61 (from 29 to 90, ignored after)
var renderThread = model.getOrCreateProcess(120).getOrCreateThread(200);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceEx(
- {title: 'DrawFrame', start: 29, duration: 61}));
+ {title: 'DrawFrame', start: 29, duration: 70}));
renderThread.sliceGroup.pushSlice(newSliceEx(
{title: 'syncFrameState', start: 29, duration: 1}));
+ renderThread.sliceGroup.pushSlice(newSliceEx(
+ {title: 'queueBuffer', start: 89, duration: 1}));
model.uiThread = uiThread;
model.renderThread = renderThread;
@@ -131,7 +139,7 @@ tr.b.unittest.testSuite(function() {
});
test('surfaceFlingerVsyncs', function() {
- var model = tr.c.TestUtils.newModel(createSurfaceFlingerWithVsyncs);
+ var model = tr.c.TestUtils.newModel(createSurfaceFlingerWithVsync);
var helper = model.getOrCreateHelper(AndroidModelHelper);
assert.isTrue(helper.surfaceFlinger.hasVsyncs);
@@ -147,6 +155,37 @@ tr.b.unittest.testSuite(function() {
assert.isUndefined(helper.surfaceFlinger.getFrameDeadline(105));
});
+ test('surfaceFlingerShiftedVsyncs', function() {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ createSurfaceFlinger(model, function(sfProcess) {
+ var appSeries = newCounterSeries();
+ var sfSeries = newCounterSeries();
+ for (var i = 0; i <= 10; i++) {
+ // SF vsync is 4ms after app
+ appSeries.addCounterSample(i * 16, i % 2);
+ sfSeries.addCounterSample(i * 16 + 4, i % 2);
+ }
+ sfProcess.getOrCreateCounter('android', 'VSYNC-sf')
+ .addSeries(sfSeries);
+ sfProcess.getOrCreateCounter('android', 'VSYNC-app')
+ .addSeries(appSeries);
+ });
+ });
+ var helper = model.getOrCreateHelper(AndroidModelHelper);
+ assert.isTrue(helper.surfaceFlinger.hasVsyncs);
+
+ // test querying the vsyncs - Frames should have 20ms window
+ assert.closeTo(helper.surfaceFlinger.getFrameKickoff(0), 0, 1e-5);
+ assert.closeTo(helper.surfaceFlinger.getFrameDeadline(0), 20, 1e-5);
+
+ assert.closeTo(helper.surfaceFlinger.getFrameKickoff(16), 16, 1e-5);
+ assert.closeTo(helper.surfaceFlinger.getFrameDeadline(16), 36, 1e-5);
+
+ // test undefined behavior outside of vsyncs.
+ assert.isUndefined(helper.surfaceFlinger.getFrameKickoff(-5));
+ assert.isUndefined(helper.surfaceFlinger.getFrameDeadline(165));
+ });
+
test('frameVsyncInterop', function() {
var model = tr.c.TestUtils.newModel(function(model) {
// app - 3 good, 3 bad frames
@@ -165,7 +204,7 @@ tr.b.unittest.testSuite(function() {
{title: 'performTraversals', start: 60, duration: 20}));
// surface flinger - vsync every 10ms
- createSurfaceFlingerWithVsyncs(model);
+ createSurfaceFlingerWithVsync(model);
});
var helper = model.getOrCreateHelper(AndroidModelHelper);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_surface_flinger.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_surface_flinger.html
index 0ecc05f1054..2a71afec94b 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/android_surface_flinger.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/android_surface_flinger.html
@@ -30,7 +30,7 @@ tr.exportTo('tr.model.helpers', function() {
if (!vsync)
vsync = process.counters[VSYNC_FALLBACK_NAME];
- if (vsync && vsync.numSeries == 1 && vsync.numSamples > 1)
+ if (vsync && vsync.numSeries === 1 && vsync.numSamples > 1)
return vsync.series[0].timestamps;
return undefined;
}
@@ -48,7 +48,12 @@ tr.exportTo('tr.model.helpers', function() {
this.appVsyncTimestamps_ = getVsyncTimestamps(process, VSYNC_APP_NAME);
this.sfVsyncTimestamps_ = getVsyncTimestamps(process, VSYNC_SF_NAME);
- };
+
+ // separation of vsync of app vs sf - assume app has at least window of 5ms
+ this.deadlineDelayMs_ =
+ this.appVsyncTimestamps_ !== this.sfVsyncTimestamps_ ?
+ 5 : TIMESTAMP_FUDGE_MS;
+ }
AndroidSurfaceFlinger.createForProcessIfPossible = function(process) {
var mainThread = process.getThread(process.pid);
@@ -60,7 +65,7 @@ tr.exportTo('tr.model.helpers', function() {
// older versions - another thread is named SurfaceFlinger
var primaryThreads = process.findAllThreadsNamed('SurfaceFlinger');
- if (primaryThreads.length == 1)
+ if (primaryThreads.length === 1)
return new AndroidSurfaceFlinger(process, primaryThreads[0]);
return undefined;
};
@@ -91,7 +96,7 @@ tr.exportTo('tr.model.helpers', function() {
var firstGreaterIndex =
findLowIndexInSortedArray(this.sfVsyncTimestamps_,
function(x) { return x; },
- timestamp + TIMESTAMP_FUDGE_MS);
+ timestamp + this.deadlineDelayMs_);
if (firstGreaterIndex >= this.sfVsyncTimestamps_.length)
return undefined;
return this.sfVsyncTimestamps_[firstGreaterIndex];
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_browser_helper.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_browser_helper.html
index f1f0a438e15..d958d69f4d1 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_browser_helper.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_browser_helper.html
@@ -18,8 +18,12 @@ tr.exportTo('tr.model.helpers', function() {
function ChromeBrowserHelper(modelHelper, process) {
tr.model.helpers.ChromeProcessHelper.call(this, modelHelper, process);
this.mainThread_ = process.findAtMostOneThreadNamed('CrBrowserMain');
+ if (!process.name)
+ process.name = ChromeBrowserHelper.PROCESS_NAME;
}
+ ChromeBrowserHelper.PROCESS_NAME = 'Browser';
+
ChromeBrowserHelper.isBrowserProcess = function(process) {
return !!process.findAtMostOneThreadNamed('CrBrowserMain');
};
@@ -91,9 +95,9 @@ tr.exportTo('tr.model.helpers', function() {
this.modelHelper.model.getAllThreads().forEach(function(thread) {
thread.asyncSliceGroup.slices.forEach(function(slice) {
var match = false;
- if (slice.category == 'net' || // old-style URLRequest/Resource
- slice.category == 'disabled-by-default-netlog' ||
- slice.category == 'netlog') {
+ if (slice.category === 'net' || // old-style URLRequest/Resource
+ slice.category === 'disabled-by-default-netlog' ||
+ slice.category === 'netlog') {
match = true;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_gpu_helper.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_gpu_helper.html
index fe3cb49e108..0683fde1b53 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_gpu_helper.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_gpu_helper.html
@@ -16,8 +16,12 @@ tr.exportTo('tr.model.helpers', function() {
function ChromeGpuHelper(modelHelper, process) {
tr.model.helpers.ChromeProcessHelper.call(this, modelHelper, process);
this.mainThread_ = process.findAtMostOneThreadNamed('CrGpuMain');
+ if (!process.name)
+ process.name = ChromeGpuHelper.PROCESS_NAME;
};
+ ChromeGpuHelper.PROCESS_NAME = 'GPU Process';
+
ChromeGpuHelper.isGpuProcess = function(process) {
// In some android builds the GPU thread is not in a separate process.
if (process.findAtMostOneThreadNamed('CrBrowserMain') ||
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper.html
index 51b762abb3c..d8276068b1e 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper.html
@@ -114,6 +114,34 @@ tr.exportTo('tr.model.helpers', function() {
get rendererHelpers() {
return this.rendererHelpers_;
+ },
+
+
+ /**
+ * Returns renderer with largest pid that is not chrome tracing ui.
+ *
+ * This is a very hacky approach to find the "target" renderer in metrics
+ * calculation. Often in telemetry tests we are only interested in
+ * calculating metrics for the page opened by the automated testing system,
+ * but currently in tbmv2 there is no way to reliably single out this
+ * renderer. One useful heuristic is that the page telemetry opens is opened
+ * after all the other renderers in chrome were opened, and therefore has
+ * the largest pid.
+ *
+ * TODO(dproy): Remove this when loading_metric supports all renderers.
+ * https://github.com/catapult-project/catapult/issues/2820
+ */
+ get rendererWithLargestPid() {
+ var largestPid = -1;
+ for (var pid in this.rendererHelpers) {
+ var rendererHelper = this.rendererHelpers[pid];
+ if (rendererHelper.isChromeTracingUI) continue;
+ if (pid > largestPid) largestPid = pid;
+ }
+
+ if (largestPid === -1) return undefined;
+
+ return this.rendererHelpers[largestPid];
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper_test.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper_test.html
index f9664840ade..5a4071cbb8c 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_model_helper_test.html
@@ -43,7 +43,7 @@ tr.b.unittest.testSuite(function() {
});
test('getFrametime', function() {
- var frame_ts;
+ var frameTs;
var events = [];
// Browser process 3507
events.push({'cat' : '__metadata', 'pid' : 3507, 'tid' : 3507, 'ts' : 0, 'ph' : 'M', 'name' : 'thread_name', 'args' : {'name' : 'CrBrowserMain'}}); // @suppress longLineCheck
@@ -59,27 +59,27 @@ tr.b.unittest.testSuite(function() {
// Compositor thread 3511
events.push({'cat' : '__metadata', 'pid' : 3509, 'tid' : 3511, 'ts' : 0, 'ph' : 'M', 'name' : 'thread_name', 'args' : {'name' : 'Compositor'}}); // @suppress longLineCheck
- frame_ts = 0;
+ frameTs = 0;
// Add impl rendering stats for browser process 3507
for (var i = 0; i < 10; i++) {
- events.push({'cat' : 'benchmark', 'pid' : 3507, 'tid' : 3507, 'ts' : frame_ts, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::ImplThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
- frame_ts += 16000 + 1000 * (i % 2);
+ events.push({'cat' : 'benchmark', 'pid' : 3507, 'tid' : 3507, 'ts' : frameTs, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::ImplThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
+ frameTs += 16000 + 1000 * (i % 2);
}
- frame_ts = 0;
+ frameTs = 0;
// Add main rendering stats for renderer process 3508
for (var i = 0; i < 10; i++) {
- events.push({'cat' : 'benchmark', 'pid' : 3508, 'tid' : 3508, 'ts' : frame_ts, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::MainThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
- frame_ts += 16000 + 1000 * (i % 2);
+ events.push({'cat' : 'benchmark', 'pid' : 3508, 'tid' : 3508, 'ts' : frameTs, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::MainThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
+ frameTs += 16000 + 1000 * (i % 2);
}
events.push({'cat' : 'benchmark', 'pid' : 3508, 'tid' : 3510, 'ts' : 1600, 'ph' : 'i', 'name' : 'KeepAlive', 's' : 't'}); // @suppress longLineCheck
- frame_ts = 0;
+ frameTs = 0;
// Add impl and main rendering stats for renderer process 3509
for (var i = 0; i < 10; i++) {
- events.push({'cat' : 'benchmark', 'pid' : 3509, 'tid' : 3511, 'ts' : frame_ts, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::ImplThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
- events.push({'cat' : 'benchmark', 'pid' : 3509, 'tid' : 3509, 'ts' : frame_ts, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::MainThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
- frame_ts += 16000 + 1000 * (i % 2);
+ events.push({'cat' : 'benchmark', 'pid' : 3509, 'tid' : 3511, 'ts' : frameTs, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::ImplThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
+ events.push({'cat' : 'benchmark', 'pid' : 3509, 'tid' : 3509, 'ts' : frameTs, 'ph' : 'i', 'name' : 'BenchmarkInstrumentation::MainThreadRenderingStats', 's' : 't'}); // @suppress longLineCheck
+ frameTs += 16000 + 1000 * (i % 2);
}
var m = tr.c.TestUtils.newModelWithEvents([events]);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper.html
index a75906feb1c..d12c303f801 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper.html
@@ -4,6 +4,8 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_driver.html">
<link rel="import" href="/tracing/model/helpers/chrome_process_helper.html">
<script>
@@ -28,7 +30,11 @@ tr.exportTo('tr.model.helpers', function() {
process.labels !== undefined &&
process.labels.length === 1 &&
process.labels[0] === 'chrome://tracing';
- };
+ if (!process.name)
+ process.name = ChromeRendererHelper.PROCESS_NAME;
+ }
+
+ ChromeRendererHelper.PROCESS_NAME = 'Renderer';
// Returns true if there is either a main thread or a compositor thread.
ChromeRendererHelper.isRenderProcess = function(process) {
@@ -59,7 +65,106 @@ tr.exportTo('tr.model.helpers', function() {
get isChromeTracingUI() {
return this.isChromeTracingUI_;
+ },
+
+ /**
+ * Generate a breakdown that attributes where time goes between |start| &
+ * |end| on renderer thread.
+ *
+ * @param {number} start
+ * @param {number} end
+ * @return {Object} A time breakdown object whose every key is a chrome
+ * userfriendly title & values are an object that show the total spent
+ * between |start| & |end|, and the list of event labels of the group and
+ * their total time between |start| & |end|.
+ *
+ * Example:
+ * {layout: {
+ * total: 100,
+ * events: {'FrameView::performPreLayoutTasks': 20,..}},
+ * v8_runtime: {
+ * total: 500,
+ * events: {'String::NewExternalTwoByte': 0.5,..}},
+ * ...
+ * }
+ *
+ *
+ */
+ generateTimeBreakdownTree: function(start, end) {
+ if (this.mainThread === null)
+ return;
+ var breakdownMap = {};
+ var range = tr.b.Range.fromExplicitRange(start, end);
+ for (var title of
+ tr.e.chrome.ChromeUserFriendlyCategoryDriver.ALL_TITLES) {
+ breakdownMap[title] = {total: 0, events: {}};
+ }
+ breakdownMap['idle'] = {total: 0, events: {}};
+ var totalIdleTime = end - start;
+ for (var event of this.mainThread.getDescendantEvents()) {
+ if (!range.intersectsExplicitRangeExclusive(event.start, event.end))
+ continue;
+ if (event.selfTime === undefined)
+ continue;
+ var title =
+ tr.e.chrome.ChromeUserFriendlyCategoryDriver.fromEvent(event);
+ var wallTimeIntersectionRatio = 0;
+ if (event.duration > 0) {
+ wallTimeIntersectionRatio =
+ range.findExplicitIntersectionDuration(event.start, event.end) /
+ event.duration;
+ }
+ var v8Runtime = event.args['runtime-call-stat'];
+ if (v8Runtime !== undefined) {
+ try {
+ var v8RuntimeObject = JSON.parse(v8Runtime);
+ for (var runtimeCall in v8RuntimeObject) {
+ if (v8RuntimeObject[runtimeCall].length === 2) {
+ if (breakdownMap['v8_runtime'].events[runtimeCall] ===
+ undefined) {
+ breakdownMap['v8_runtime'].events[runtimeCall] = 0;
+ }
+ // V8 Runtime Call Stats data is in us, while the
+ // breakdown tree timing is in ms.
+ var runtimeTime = v8RuntimeObject[runtimeCall][1] *
+ wallTimeIntersectionRatio / 1000;
+ breakdownMap['v8_runtime'].total += runtimeTime;
+ breakdownMap['v8_runtime'].events[runtimeCall] +=
+ runtimeTime;
+ }
+ }
+ } catch (e) {
+ console.warn(e);
+ }
+ }
+ // [ Slice 1 ] [ Slice 2 ] [ Slice 3 ]
+ // [ Slice 4 ] [ Slice 5 ]
+ // [ Slice 6 ] |
+ // | |
+ // | |
+ // v v
+ // start end
+ //
+ // For the case where the |start| or |end| overlapped with some existing
+ // slice (see above diagram), we approximate the overlapped self-time
+ // by multiplying the ratio of overlapped wall time to the self-time.
+ // There should be way to compute the exact number, but in practice,
+ // this should rarely happen, and when it does, the overlapped range
+ // is relative small so that using approximation here should be good
+ // enough.
+ var approximatedSelfTimeContribution =
+ event.selfTime * wallTimeIntersectionRatio;
+ breakdownMap[title].total += approximatedSelfTimeContribution;
+ if (breakdownMap[title].events[event.title] === undefined)
+ breakdownMap[title].events[event.title] = 0;
+ breakdownMap[title].events[event.title] +=
+ approximatedSelfTimeContribution;
+ totalIdleTime -= approximatedSelfTimeContribution;
+ }
+ breakdownMap['idle'].total = totalIdleTime;
+ return breakdownMap;
}
+
};
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper_test.html b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper_test.html
new file mode 100644
index 00000000000..c92125b809c
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/model/helpers/chrome_renderer_helper_test.html
@@ -0,0 +1,156 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+
+ var rendererPid = 12345;
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(rendererPid);
+ var mainThread = rendererProcess.getOrCreateThread(2);
+ mainThread.name = 'CrRendererMain';
+
+ // Our main thread looks like:
+ //
+ // [ parseHTML ] [ layout ] [ V8.Exec ]
+ // | [ V8.Exec ] | | | | [ layout ] |
+ // | | | | | | | | | |
+ // | | | | | | | | | |
+ // v v v v v v v v v v
+ // Ts: 200 250 300 400 450 550 570 600 620 650
+
+ // Add layout categories
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink',
+ title: 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser',
+ start: 200,
+ duration: 200,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'devtools.timeline',
+ title: 'Script',
+ start: 250,
+ duration: 50,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'v8',
+ title: 'V8.Execute',
+ start: 250,
+ duration: 50,
+ args: {'runtime-call-stat': '{"ICMiss": [3, 150], "GC": [10, 60]}'},
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink',
+ title: 'FrameView::layout',
+ start: 450,
+ duration: 100,
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'v8',
+ title: 'V8.Execute',
+ start: 570,
+ duration: 80,
+ args: {'runtime-call-stat': '{"DeOptimize": [1, 42], "GC": [3, 50]}'},
+ }));
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink',
+ title: 'WebViewImpl::layout',
+ start: 600,
+ duration: 20,
+ }));
+ });
+
+ var chromeHelper = model.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+
+ var rendererHelper = chromeHelper.rendererHelpers[rendererPid];
+
+ test('testTimeBreakdownNoIntersectingBoundary', function() {
+ var breakdownTree = rendererHelper.generateTimeBreakdownTree(0, 1000);
+ assert.deepEqual({
+ total: 150,
+ events: {
+ 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 150
+ }
+ }, breakdownTree['parseHTML']);
+ assert.deepEqual({
+ total: 120,
+ events: {
+ 'FrameView::layout': 100,
+ 'WebViewImpl::layout': 20,
+ }
+ }, breakdownTree['layout']);
+ assert.deepEqual({
+ total: 110,
+ events: {
+ 'V8.Execute': 110,
+ }
+ }, breakdownTree['script_execute']);
+ assert.deepEqual({
+ total: 0.302,
+ events: {
+ 'DeOptimize': 0.042,
+ 'GC': 0.11,
+ 'ICMiss': 0.15,
+ }
+ }, breakdownTree['v8_runtime']);
+ });
+
+ test('testTimeBreakdownIntersectingBoundary', function() {
+
+ // Our main thread looks like:
+ //
+ // [ parseHTML ] [ layout ] [ V8.Exec ]
+ // | [ V8.Exec ] | | | | [ layout ] |
+ // | | | | | | | | | |
+ // | | | | | | | | | |
+ // v v v v v v v v v v
+ // Ts: 200 250 300 400 450 550 570 600 620 650
+ // | |
+ // 275 610
+
+ var breakdownTree = rendererHelper.generateTimeBreakdownTree(275, 610);
+ assert.deepEqual({
+ total: 93.75,
+ events: {
+ 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 93.75
+ }
+ }, breakdownTree['parseHTML']);
+ assert.deepEqual({
+ total: 110,
+ events: {
+ 'FrameView::layout': 100,
+ 'WebViewImpl::layout': 10,
+ }
+ }, breakdownTree['layout']);
+ assert.deepEqual({
+ total: 55,
+ events: {
+ 'V8.Execute': 55,
+ }
+ }, breakdownTree['script_execute']);
+ assert.deepEqual({
+ total: 0.151,
+ events: {
+ 'DeOptimize': 0.021,
+ 'GC': 0.055,
+ 'ICMiss': 0.075,
+ }
+ }, breakdownTree['v8_runtime']);
+ });
+
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/model/instant_event.html b/chromium/third_party/catapult/tracing/tracing/model/instant_event.html
index 5c50132116c..2f8d4b09efc 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/instant_event.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/instant_event.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -31,7 +31,7 @@ tr.exportTo('tr.model', function() {
this.args = args;
this.type = undefined;
- };
+ }
InstantEvent.prototype = {
__proto__: tr.model.TimedEvent.prototype
@@ -49,13 +49,13 @@ tr.exportTo('tr.model', function() {
function GlobalInstantEvent(category, title, colorId, start, args) {
InstantEvent.apply(this, arguments);
this.type = InstantEventType.GLOBAL;
- };
+ }
GlobalInstantEvent.prototype = {
__proto__: InstantEvent.prototype,
get userFriendlyName() {
return 'Global instant event ' + this.title + ' @ ' +
- tr.v.Unit.byName.timeStampInMs.format(start);
+ tr.b.Unit.byName.timeStampInMs.format(start);
}
};
@@ -70,14 +70,14 @@ tr.exportTo('tr.model', function() {
function ProcessInstantEvent(category, title, colorId, start, args) {
InstantEvent.apply(this, arguments);
this.type = InstantEventType.PROCESS;
- };
+ }
ProcessInstantEvent.prototype = {
__proto__: InstantEvent.prototype,
get userFriendlyName() {
return 'Process-level instant event ' + this.title + ' @ ' +
- tr.v.Unit.byName.timeStampInMs.format(start);
+ tr.b.Unit.byName.timeStampInMs.format(start);
}
};
@@ -85,9 +85,7 @@ tr.exportTo('tr.model', function() {
InstantEvent,
{
name: 'instantEvent',
- pluralName: 'instantEvents',
- singleViewElementName: 'tr-ui-a-single-instant-event-sub-view',
- multiViewElementName: 'tr-ui-a-multi-instant-event-sub-view'
+ pluralName: 'instantEvents'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/location.html b/chromium/third_party/catapult/tracing/tracing/model/location.html
index 11d31eef7e4..8654157172d 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/location.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/location.html
@@ -41,7 +41,7 @@ tr.exportTo('tr.model', function() {
function Location(xWorld, yComponents) {
this.xWorld_ = xWorld;
this.yComponents_ = yComponents;
- };
+ }
/**
* Returns a new Location given by x and y coordinates with respect to
@@ -69,7 +69,7 @@ tr.exportTo('tr.model', function() {
elem = elem.parentElement;
}
- if (yComponents.length == 0)
+ if (yComponents.length === 0)
return;
return new Location(xWorld, yComponents);
}
@@ -96,7 +96,7 @@ tr.exportTo('tr.model', function() {
elem = elem.parentElement;
}
- if (yComponents.length == 0)
+ if (yComponents.length === 0)
return;
return new Location(xWorld, yComponents);
}
diff --git a/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump.html b/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump.html
index 5e83a75e362..65ecfa9b554 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -59,7 +59,7 @@ tr.exportTo('tr.model', function() {
// For debugging purposes.
this.guid = opt_guid;
- };
+ }
/**
* Size numeric names. Please refer to the Memory Dump Graph Metric
@@ -142,7 +142,7 @@ tr.exportTo('tr.model', function() {
}
};
- // TODO(petrcermak): Consider moving this to tr.v.Numeric.
+ // TODO(petrcermak): Consider moving this to tr.v.Histogram.
MemoryAllocatorDump.aggregateNumerics = function(numerics, opt_model) {
var shouldLogWarning = !!opt_model;
var aggregatedUnit = undefined;
@@ -167,7 +167,7 @@ tr.exportTo('tr.model', function() {
}
// Use the most generic unit when the numerics don't agree (best
// effort).
- aggregatedUnit = tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ aggregatedUnit = tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
}
aggregatedValue += numeric.value;
diff --git a/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump_test.html b/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump_test.html
index 440dc5ffcd1..47df6ec9068 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/memory_allocator_dump_test.html
@@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/model/memory_dump_test_utils.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -20,9 +20,9 @@ tr.b.unittest.testSuite(function() {
var MemoryAllocatorDumpLink = tr.model.MemoryAllocatorDumpLink;
var ScalarNumeric = tr.v.ScalarNumeric;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
- var sizeInBytes = tr.v.Unit.byName.sizeInBytes;
- var powerInWatts = tr.v.Unit.byName.powerInWatts;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
+ var sizeInBytes = tr.b.Unit.byName.sizeInBytes;
+ var powerInWatts = tr.b.Unit.byName.powerInWatts;
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addChildDump = tr.model.MemoryDumpTestUtils.addChildDump;
var checkDumpNumericsAndDiagnostics =
@@ -42,48 +42,50 @@ tr.b.unittest.testSuite(function() {
test('memoryAllocatorDumps_aggregateNumericsRecursively', function() {
var md = new ContainerMemoryDump(42);
- var oilpanDump = newAllocatorDump(md, 'oilpan', {
- 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 7)
- });
+ var oilpanDump = newAllocatorDump(md, 'oilpan', {numerics: {
+ objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 7)
+ }});
- addChildDump(oilpanDump, 'bucket1', {
+ addChildDump(oilpanDump, 'bucket1', {numerics: {
size: 512,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 3),
inner_size: 256,
outer_size: 1024
- });
+ }});
var oilpanBucket2Dump = addChildDump(oilpanDump, 'bucket2');
var oilpanBucket2StringsDump = addChildDump(oilpanBucket2Dump, 'strings', {
- size: 512,
- objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
- inner_size: 512,
- outer_size: 2048
+ numerics: {
+ size: 512,
+ objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
+ inner_size: 512,
+ outer_size: 2048
+ }
});
oilpanDump.aggregateNumericsRecursively();
// oilpan has *some* numerics aggregated.
checkDumpNumericsAndDiagnostics(oilpanDump, {
- 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 7),
- 'inner_size': 768,
- 'outer_size': 3072
+ objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 7),
+ inner_size: 768,
+ outer_size: 3072
}, {});
// oilpan/bucket2 has *all* numerics aggregated (except for size).
checkDumpNumericsAndDiagnostics(oilpanBucket2Dump, {
- 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
- 'inner_size': 512,
- 'outer_size': 2048
+ objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
+ inner_size: 512,
+ outer_size: 2048
}, {});
// oilpan/bucket2/strings has *no* numerics aggregated.
checkDumpNumericsAndDiagnostics(oilpanBucket2StringsDump, {
- 'size': 512,
- 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
- 'inner_size': 512,
- 'outer_size': 2048
+ size: 512,
+ objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 4),
+ inner_size: 512,
+ outer_size: 2048
}, {});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/memory_dump_test_utils.html b/chromium/third_party/catapult/tracing/tracing/model/memory_dump_test_utils.html
index 55a499192bf..eaad055b4d3 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/memory_dump_test_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/memory_dump_test_utils.html
@@ -5,13 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/global_memory_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/model/process_memory_dump.html">
<link rel="import" href="/tracing/model/vm_region.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -28,7 +28,7 @@ tr.exportTo('tr.model', function() {
var VMRegionClassificationNode = tr.model.VMRegionClassificationNode;
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
function castToScalarNumeric(value) {
@@ -38,22 +38,56 @@ tr.exportTo('tr.model', function() {
return value;
}
+ function getOption(opt_options, key, opt_defaultValue) {
+ if (opt_options && (key in opt_options))
+ return opt_options[key];
+ else
+ return opt_defaultValue;
+ }
+
function MemoryDumpTestUtils() {
throw new Error('Static class');
}
MemoryDumpTestUtils.SIZE_DELTA = 0.0001;
- MemoryDumpTestUtils.addGlobalMemoryDump = function(
- model, timestamp, opt_levelOfDetail) {
+ /**
+ * Create a new global memory dump and add it to a model.
+ *
+ * @param {!tr.Model} model The trace model to which the new global dump
+ * should be added.
+ * @param {!{
+ * ts: (number|undefined),
+ * duration: (number|undefined),
+ * levelOfDetail: (!tr.model.ContainerMemoryDump.LevelOfDetail|undefined)
+ * }=} opt_options Options for creating the new global dump.
+ * @return {!tr.model.GlobalMemoryDump} The newly created global memory dump.
+ */
+ MemoryDumpTestUtils.addGlobalMemoryDump = function(model, opt_options) {
+ var timestamp = getOption(opt_options, 'ts', 0);
var gmd = new GlobalMemoryDump(model, timestamp);
- gmd.levelOfDetail = opt_levelOfDetail === undefined ?
- LIGHT : opt_levelOfDetail;
+ gmd.levelOfDetail = getOption(opt_options, 'levelOfDetail', LIGHT);
+ gmd.duration = getOption(opt_options, 'duration', 0);
model.globalMemoryDumps.push(gmd);
return gmd;
};
- MemoryDumpTestUtils.addProcessMemoryDump = function(gmd, process, timestamp) {
+ /**
+ * Create a new process memory dump and add it to a global memory dump.
+ *
+ * @param {!tr.model.GlobalMemoryDump} gmd The global dump to which the new
+ * process dump should be added.
+ * @param {!tr.model.Process} pmd The process associated with the process
+ * dump.
+ * @param {!{
+ * ts: (number|undefined)
+ * }=} opt_options Options for creating the new process dump.
+ * @return {!tr.model.ProcessMemoryDump} The newly created process memory
+ * dump.
+ */
+ MemoryDumpTestUtils.addProcessMemoryDump =
+ function(gmd, process, opt_options) {
+ var timestamp = getOption(opt_options, 'ts', gmd.start);
var pmd = new ProcessMemoryDump(gmd, process, timestamp);
process.memoryDumps.push(pmd);
if (process.pid in gmd.processMemoryDumps) {
@@ -65,22 +99,52 @@ tr.exportTo('tr.model', function() {
return pmd;
};
+ /**
+ * Create a new memory allocator dump.
+ *
+ * @param {!tr.model.ContainerMemoryDump} containerDump The container dump
+ * associated with the new allocator dump.
+ * @param {string} fullName The full name of the new allocator dump
+ * (including ancestors).
+ * @param {!{
+ * guid: (number|undefined),
+ * numerics: (!Object<string, (number|!tr.v.ScalarNumeric)>|undefined)
+ * }=} opt_options Options for creating the new allocator dump.
+ * @return {!tr.model.MemoryAllocatorDump} The newly created memory allocator
+ * dump.
+ */
MemoryDumpTestUtils.newAllocatorDump = function(
- containerDump, fullName, opt_numerics, opt_guid) {
- var dump = new MemoryAllocatorDump(containerDump, fullName, opt_guid);
- if (opt_numerics !== undefined) {
- tr.b.iterItems(opt_numerics, function(numericName, value) {
+ containerDump, fullName, opt_options) {
+ var dump = new MemoryAllocatorDump(containerDump, fullName,
+ getOption(opt_options, 'guid'));
+ var numerics = getOption(opt_options, 'numerics');
+ if (numerics) {
+ tr.b.iterItems(numerics, function(numericName, value) {
dump.addNumeric(numericName, castToScalarNumeric(value));
});
}
return dump;
};
- MemoryDumpTestUtils.addChildDump =
- function(parentDump, name, opt_numerics, opt_guid) {
+ /**
+ * Create a new child memory allocator dump and add it to a parent memory
+ * allocator dump.
+ *
+ * @param {!tr.model.MemoryAllocatorDump} parentDump The parent allocator
+ * dump.
+ * @param {string} name The name of the child allocator dump (excluding
+ * ancestors).
+ * @param {!{
+ * guid: (number|undefined),
+ * numerics: (!Object<string, (number|!tr.v.ScalarNumeric)>|undefined)
+ * }=} opt_options Options for creating the child allocator dump.
+ * @return {!tr.model.MemoryAllocatorDump} The newly created child memory
+ * allocator dump.
+ */
+ MemoryDumpTestUtils.addChildDump = function(parentDump, name, opt_options) {
var childDump = MemoryDumpTestUtils.newAllocatorDump(
parentDump.containerMemoryDump, parentDump.fullName + '/' + name,
- opt_numerics, opt_guid);
+ opt_options);
childDump.parent = parentDump;
parentDump.children.push(childDump);
return childDump;
diff --git a/chromium/third_party/catapult/tracing/tracing/model/model.html b/chromium/third_party/catapult/tracing/tracing/model/model.html
index b1164f7ebf7..81a279b47a8 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/model.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/model.html
@@ -11,6 +11,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/quad.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/task.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/auditor.html">
<link rel="import" href="/tracing/core/filter.html">
<link rel="import" href="/tracing/model/alert.html">
@@ -31,9 +33,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/stack_frame.html">
<link rel="import" href="/tracing/model/user_model/user_expectation.html">
<link rel="import" href="/tracing/model/user_model/user_model.html">
-<link rel="import" href="/tracing/ui/base/overlay.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -197,7 +196,7 @@ tr.exportTo('tr', function() {
convertTimestampToModelTime: function(sourceClockDomainName, ts) {
if (sourceClockDomainName !== 'traceEventClock')
throw new Error('Only traceEventClock is supported.');
- return tr.v.Unit.timestampFromUs(ts) +
+ return tr.b.Unit.timestampFromUs(ts) +
this.timestampShiftToZeroAmount_;
},
@@ -246,7 +245,7 @@ tr.exportTo('tr', function() {
this.categories = [];
for (var category in categoriesDict)
- if (category != '')
+ if (category !== '')
this.categories.push(category);
},
@@ -369,7 +368,7 @@ tr.exportTo('tr', function() {
*/
get intrinsicTimeUnit() {
if (this.intrinsicTimeUnit_ === undefined)
- return tr.v.TimeDisplayModes.ms;
+ return tr.b.TimeDisplayModes.ms;
return this.intrinsicTimeUnit_;
},
@@ -550,10 +549,11 @@ tr.exportTo('tr', function() {
this.patchupsToApply_ = unresolved;
},
- replacePIDRefsInPatchups: function(old_pid_ref, new_pid_ref) {
+ replacePIDRefsInPatchups: function(oldPidRef, newPidRef) {
this.patchupsToApply_.forEach(function(patchup) {
- if (patchup.pidRef === old_pid_ref)
- patchup.pidRef = new_pid_ref;
+ if (patchup.pidRef === oldPidRef) {
+ patchup.pidRef = newPidRef;
+ }
});
},
diff --git a/chromium/third_party/catapult/tracing/tracing/model/model_stats.html b/chromium/third_party/catapult/tracing/tracing/model/model_stats.html
index fd5bf957dc8..8a3f1d4056d 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/model_stats.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/model_stats.html
@@ -5,8 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/base.html">
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/base/unit.html">
<script>
'use strict';
@@ -47,7 +46,7 @@ tr.exportTo('tr.model', function() {
eventStats.numEvents++;
var timeIntervalKey = Math.floor(
- tr.v.Unit.timestampFromUs(ts) / this.TIME_INTERVAL_SIZE_IN_MS);
+ tr.b.Unit.timestampFromUs(ts) / this.TIME_INTERVAL_SIZE_IN_MS);
var eventStatsByTimeInverval =
this.traceEventStatsInTimeIntervals_.get(timeIntervalKey);
if (eventStatsByTimeInverval === undefined) {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/model_test.html b/chromium/third_party/catapult/tracing/tracing/model/model_test.html
index 75c1f9d5155..88e9d1ae36f 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/model_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/model_test.html
@@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/time_display_modes.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">
<link rel="import" href="/tracing/importer/import.html">
<link rel="import" href="/tracing/model/annotation.html">
<link rel="import" href="/tracing/model/model.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
<script>
'use strict';
@@ -273,7 +273,7 @@ tr.b.unittest.testSuite(function() {
});
test('model_intrinsicTimeUnit', function() {
- var unit = tr.v.TimeDisplayModes;
+ var unit = tr.b.TimeDisplayModes;
var m = new tr.Model();
// by default it should be milliseconds
@@ -318,7 +318,7 @@ tr.b.unittest.testSuite(function() {
};
var typeName = 'RefCountingSnapshot';
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
RefCountingSnapshot,
{typeName: typeName});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/object_collection.html b/chromium/third_party/catapult/tracing/tracing/model/object_collection.html
index 93122c8d4f5..4055a202489 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/object_collection.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/object_collection.html
@@ -49,7 +49,7 @@ tr.exportTo('tr.model', function() {
createObjectInstance_: function(
parent, scopedId, category, name, creationTs, opt_baseTypeName) {
- var constructor = tr.model.ObjectInstance.getConstructor(
+ var constructor = tr.model.ObjectInstance.subTypes.getConstructor(
category, name);
var instance = new constructor(
parent, scopedId, category, name, creationTs, opt_baseTypeName);
@@ -90,7 +90,7 @@ tr.exportTo('tr.model', function() {
var instanceMap = this.getOrCreateInstanceMap_(scopedId);
var snapshot = instanceMap.addSnapshot(
category, name, ts, args, opt_baseTypeName);
- if (snapshot.objectInstance.category != category) {
+ if (snapshot.objectInstance.category !== category) {
var msg = 'Added snapshot name=' + name + ' with cat=' + category +
' impossible. It instance was created/snapshotted with cat=' +
snapshot.objectInstance.category + ' name=' +
@@ -98,13 +98,13 @@ tr.exportTo('tr.model', function() {
throw new Error(msg);
}
if (opt_baseTypeName &&
- snapshot.objectInstance.baseTypeName != opt_baseTypeName) {
+ snapshot.objectInstance.baseTypeName !== opt_baseTypeName) {
throw new Error('Could not add snapshot with baseTypeName=' +
opt_baseTypeName + '. It ' +
'was previously created with name=' +
snapshot.objectInstance.baseTypeName);
}
- if (snapshot.objectInstance.name != name) {
+ if (snapshot.objectInstance.name !== name) {
throw new Error('Could not add snapshot with name=' + name + '. It ' +
'was previously created with name=' +
snapshot.objectInstance.name);
@@ -117,7 +117,7 @@ tr.exportTo('tr.model', function() {
var deletedInstance = instanceMap.idWasDeleted(category, name, ts);
if (!deletedInstance)
return;
- if (deletedInstance.category != category) {
+ if (deletedInstance.category !== category) {
var msg = 'Deleting object ' + deletedInstance.name +
' with a different category ' +
'than when it was created. It previous had cat=' +
@@ -125,7 +125,7 @@ tr.exportTo('tr.model', function() {
'had cat=' + category;
throw new Error(msg);
}
- if (deletedInstance.baseTypeName != name) {
+ if (deletedInstance.baseTypeName !== name) {
throw new Error('Deletion requested for name=' +
name + ' could not proceed: ' +
'An existing object with baseTypeName=' +
@@ -137,7 +137,7 @@ tr.exportTo('tr.model', function() {
tr.b.iterItems(this.instanceMapsByScopedId_, function(scope, imapById) {
tr.b.iterItems(imapById, function(id, i2imap) {
var lastInstance = i2imap.lastInstance;
- if (lastInstance.deletionTs != Number.MAX_VALUE)
+ if (lastInstance.deletionTs !== Number.MAX_VALUE)
return;
i2imap.idWasDeleted(
lastInstance.category, lastInstance.name, maxTimestamp);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/object_collection_test.html b/chromium/third_party/catapult/tracing/tracing/model/object_collection_test.html
index 7137f89b201..953b535db49 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/object_collection_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/object_collection_test.html
@@ -25,7 +25,7 @@ tr.b.unittest.testSuite(function() {
test('objectInstanceSubtype', function() {
// Register that TestObjects are bound to TestObjectInstance.
- tr.model.ObjectInstance.register(
+ tr.model.ObjectInstance.subTypes.register(
TestObjectInstance,
{typeName: 'TestObject'});
@@ -49,7 +49,7 @@ tr.b.unittest.testSuite(function() {
assert.instanceOf(testObject, tr.model.ObjectInstance);
assert.instanceOf(testObject, TestObjectInstance);
} finally {
- tr.model.ObjectInstance.unregister(TestObjectInstance);
+ tr.model.ObjectInstance.subTypes.unregister(TestObjectInstance);
}
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/object_instance.html b/chromium/third_party/catapult/tracing/tracing/model/object_instance.html
index 37337712073..7dcd853f949 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/object_instance.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/object_instance.html
@@ -5,7 +5,6 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/extension_registry.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/model/event.html">
@@ -65,7 +64,7 @@ tr.exportTo('tr.model', function() {
var lastSnapshot;
if (this.snapshots.length > 0) {
lastSnapshot = this.snapshots[this.snapshots.length - 1];
- if (lastSnapshot.ts == ts)
+ if (lastSnapshot.ts === ts)
throw new Error('Snapshots already exists at this time!');
if (ts < lastSnapshot.ts) {
throw new Error(
@@ -75,16 +74,16 @@ tr.exportTo('tr.model', function() {
// Update baseTypeName if needed.
if (opt_name &&
- (this.name != opt_name)) {
+ (this.name !== opt_name)) {
if (!opt_baseTypeName)
throw new Error('Must provide base type name for name update');
- if (this.baseTypeName != opt_baseTypeName)
+ if (this.baseTypeName !== opt_baseTypeName)
throw new Error('Cannot update type name: base types dont match');
this.name = opt_name;
}
var snapshotConstructor =
- tr.model.ObjectSnapshot.getConstructor(
+ tr.model.ObjectSnapshot.subTypes.getConstructor(
this.category, this.name);
var snapshot = new snapshotConstructor(this, ts, args);
this.snapshots.push(snapshot);
@@ -143,7 +142,7 @@ tr.exportTo('tr.model', function() {
snapshots,
function(snapshot) { return snapshot.ts; },
function(snapshot, i) {
- if (i == snapshots.length - 1)
+ if (i === snapshots.length - 1)
return snapshots[i].objectInstance.deletionTs;
return snapshots[i + 1].ts - snapshots[i].ts;
},
@@ -164,7 +163,7 @@ tr.exportTo('tr.model', function() {
updateBounds: function() {
this.bounds.reset();
this.bounds.addValue(this.creationTs);
- if (this.deletionTs != Number.MAX_VALUE)
+ if (this.deletionTs !== Number.MAX_VALUE)
this.bounds.addValue(this.deletionTs);
else if (this.snapshots.length > 0)
this.bounds.addValue(this.snapshots[this.snapshots.length - 1].ts);
@@ -172,7 +171,7 @@ tr.exportTo('tr.model', function() {
shiftTimestampsForward: function(amount) {
this.creationTs += amount;
- if (this.deletionTs != Number.MAX_VALUE)
+ if (this.deletionTs !== Number.MAX_VALUE)
this.deletionTs += amount;
this.snapshots.forEach(function(snapshot) {
snapshot.ts += amount;
@@ -188,17 +187,9 @@ tr.exportTo('tr.model', function() {
ObjectInstance,
{
name: 'objectInstance',
- pluralName: 'objectInstances',
- singleViewElementName: 'tr-ui-a-single-object-instance-sub-view',
- multiViewElementName: 'tr-ui-a-multi-object-sub-view'
+ pluralName: 'objectInstances'
});
- var options = new tr.b.ExtensionRegistryOptions(
- tr.b.TYPE_BASED_REGISTRY_MODE);
- options.mandatoryBaseClass = ObjectInstance;
- options.defaultConstructor = ObjectInstance;
- tr.b.decorateExtensionRegistry(ObjectInstance, options);
-
return {
ObjectInstance: ObjectInstance
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/object_snapshot.html b/chromium/third_party/catapult/tracing/tracing/model/object_snapshot.html
index eb9ca657db3..0bf19e6548d 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/object_snapshot.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/object_snapshot.html
@@ -5,9 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/extension_registry.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -75,7 +74,7 @@ tr.exportTo('tr.model', function() {
return 'Snapshot of ' +
this.objectInstance.typeName + ' ' +
this.objectInstance.id + ' @ ' +
- tr.v.Unit.byName.timeStampInMs.format(this.ts);
+ tr.b.Unit.byName.timeStampInMs.format(this.ts);
}
};
@@ -83,17 +82,9 @@ tr.exportTo('tr.model', function() {
ObjectSnapshot,
{
name: 'objectSnapshot',
- pluralName: 'objectSnapshots',
- singleViewElementName: 'tr-ui-a-single-object-snapshot-sub-view',
- multiViewElementName: 'tr-ui-a-multi-object-sub-view'
+ pluralName: 'objectSnapshots'
});
- var options = new tr.b.ExtensionRegistryOptions(
- tr.b.TYPE_BASED_REGISTRY_MODE);
- options.mandatoryBaseClass = ObjectSnapshot;
- options.defaultConstructor = ObjectSnapshot;
- tr.b.decorateExtensionRegistry(ObjectSnapshot, options);
-
return {
ObjectSnapshot: ObjectSnapshot
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/object_snapshot_test.html b/chromium/third_party/catapult/tracing/tracing/model/object_snapshot_test.html
index 67c510248c7..7e7a4b01a31 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/object_snapshot_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/object_snapshot_test.html
@@ -25,14 +25,14 @@ tr.b.unittest.testSuite(function() {
var instance = new tr.model.ObjectInstance(
{}, '0x1000', 'cat', 'MySnapshot', 10);
try {
- tr.model.ObjectSnapshot.register(
+ tr.model.ObjectSnapshot.subTypes.register(
MySnapshot,
{typeName: 'MySnapshot'});
var snapshot = instance.addSnapshot(15, {foo: 'bar'});
assert.instanceOf(snapshot, MySnapshot);
assert.equal(snapshot.myFoo, 'bar');
} finally {
- tr.model.ObjectSnapshot.unregister(MySnapshot);
+ tr.model.ObjectSnapshot.subTypes.unregister(MySnapshot);
}
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/power_sample.html b/chromium/third_party/catapult/tracing/tracing/model/power_sample.html
index 62de34ab591..d4809c1d1d9 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/power_sample.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/power_sample.html
@@ -17,17 +17,17 @@ tr.exportTo('tr.model', function() {
var EventRegistry = tr.model.EventRegistry;
/**
- * A sample that contains a power measurement (in mW).
+ * A sample that contains a power measurement (in W).
*
* @constructor
* @extends {Event}
*/
- function PowerSample(series, start, power) {
+ function PowerSample(series, start, powerInW) {
Event.call(this);
this.series_ = series;
this.start_ = start;
- this.power_ = power;
+ this.powerInW_ = powerInW;
}
PowerSample.prototype = {
@@ -45,12 +45,12 @@ tr.exportTo('tr.model', function() {
this.start_ = value;
},
- get power() {
- return this.power_;
+ get powerInW() {
+ return this.powerInW_;
},
- set power(value) {
- this.power_ = value;
+ set powerInW(value) {
+ this.powerInW_ = value;
},
addBoundsToRange: function(range) {
@@ -62,9 +62,7 @@ tr.exportTo('tr.model', function() {
PowerSample,
{
name: 'powerSample',
- pluralName: 'powerSamples',
- singleViewElementName: 'tr-ui-a-single-power-sample-sub-view',
- multiViewElementName: 'tr-ui-a-multi-power-sample-sub-view'
+ pluralName: 'powerSamples'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/power_sample_test.html b/chromium/third_party/catapult/tracing/tracing/model/power_sample_test.html
index 6625ed4ed59..d90fb374c5e 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/power_sample_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/power_sample_test.html
@@ -24,11 +24,11 @@ tr.b.unittest.testSuite(function() {
assert.equal(sample1.series, series);
assert.equal(sample1.start, 0.0);
- assert.equal(sample1.power, 1000.0);
+ assert.equal(sample1.powerInW, 1000.0);
assert.equal(sample2.series, series);
assert.equal(sample2.start, 1.0);
- assert.equal(sample2.power, 2000.0);
+ assert.equal(sample2.powerInW, 2000.0);
});
test('addBoundsToRange', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/power_series.html b/chromium/third_party/catapult/tracing/tracing/model/power_series.html
index f3a873bab50..e5442415978 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/power_series.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/power_series.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/model/event_container.html">
<link rel="import" href="/tracing/model/power_sample.html">
@@ -60,10 +61,10 @@ tr.exportTo('tr.model', function() {
* Returns the total energy (in Joules) consumed between the specified
* start and end timestamps (in milliseconds).
*/
- getEnergyConsumed: function(start, end) {
+ getEnergyConsumedInJ: function(start, end) {
var measurementRange = tr.b.Range.fromExplicitRange(start, end);
- var energyConsumed = 0;
+ var energyConsumedInJ = 0;
var startIndex = tr.b.findLowIndexInSortedArray(
this.samples, x => x.start, start) - 1;
var endIndex = tr.b.findLowIndexInSortedArray(
@@ -80,15 +81,16 @@ tr.exportTo('tr.model', function() {
sampleRange.addValue(sample.start);
sampleRange.addValue(nextSample ? nextSample.start : sample.start);
- var timeIntersection = measurementRange.findIntersection(sampleRange);
+ var intersectionRangeInMs = measurementRange.findIntersection(
+ sampleRange);
- // Divide by 1000 to convert milliseconds to seconds.
- var durationInSeconds = timeIntersection.duration / 1000;
+ var durationInS = tr.b.convertUnit(intersectionRangeInMs.duration,
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
- energyConsumed += durationInSeconds * sample.power;
+ energyConsumedInJ += durationInS * sample.powerInW;
}
- return energyConsumed;
+ return energyConsumedInJ;
},
getSamplesWithinRange: function(start, end) {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/power_series_test.html b/chromium/third_party/catapult/tracing/tracing/model/power_series_test.html
index 034cae8b786..10bb85ff030 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/power_series_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/power_series_test.html
@@ -47,7 +47,7 @@ tr.b.unittest.testSuite(function() {
series.addPowerSample(0, 1);
series.addPowerSample(1000, 2);
- assert.equal(series.getEnergyConsumed(0, 1000), 1);
+ assert.equal(series.getEnergyConsumedInJ(0, 1000), 1);
});
test('getEnergyConsumed_twoIntervals', function() {
@@ -56,14 +56,14 @@ tr.b.unittest.testSuite(function() {
series.addPowerSample(1000, 2);
series.addPowerSample(2000, 2);
- assert.equal(series.getEnergyConsumed(0, 2000), 3);
+ assert.equal(series.getEnergyConsumedInJ(0, 2000), 3);
});
test('getEnergyConsumed_oneSample', function() {
var series = new PowerSeries(new Model().device);
series.addPowerSample(1000, 1);
- assert.equal(series.getEnergyConsumed(0, 2000), 0);
+ assert.equal(series.getEnergyConsumedInJ(0, 2000), 0);
});
test('getEnergyConsumed_samplesAfterStart', function() {
@@ -71,7 +71,7 @@ tr.b.unittest.testSuite(function() {
series.addPowerSample(1000, 1);
series.addPowerSample(2000, 2);
- assert.equal(series.getEnergyConsumed(0, 2000), 1);
+ assert.equal(series.getEnergyConsumedInJ(0, 2000), 1);
});
test('getEnergyConsumed_extraSamplesBeforeStart', function() {
@@ -81,7 +81,7 @@ tr.b.unittest.testSuite(function() {
series.addPowerSample(2000, 1);
series.addPowerSample(3000, 1);
- assert.equal(series.getEnergyConsumed(2000, 4000), 1);
+ assert.equal(series.getEnergyConsumedInJ(2000, 4000), 1);
});
test('getEnergyConsumed_extraSamplesAfterEnd', function() {
@@ -91,7 +91,7 @@ tr.b.unittest.testSuite(function() {
series.addPowerSample(2000, 1);
series.addPowerSample(3000, 10);
- assert.equal(series.getEnergyConsumed(0, 2000), 2);
+ assert.equal(series.getEnergyConsumedInJ(0, 2000), 2);
});
test('shiftTimestampsForward', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/process.html b/chromium/third_party/catapult/tracing/tracing/model/process.html
index 47ed4100427..f46986cbd23 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/process.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/process.html
@@ -157,4 +157,3 @@ tr.exportTo('tr.model', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump.html b/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump.html
index c9d60715703..7f806bcf6dc 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/model/vm_region.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -63,14 +63,14 @@ tr.exportTo('tr.model', function() {
this.tracingOverheadOwnershipSetUp_ = false;
this.tracingOverheadDiscountedFromVmRegions_ = false;
- };
+ }
ProcessMemoryDump.prototype = {
__proto__: tr.model.ContainerMemoryDump.prototype,
get userFriendlyName() {
return 'Process memory dump at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
},
get containerName() {
@@ -234,9 +234,7 @@ tr.exportTo('tr.model', function() {
ProcessMemoryDump,
{
name: 'processMemoryDump',
- pluralName: 'processMemoryDumps',
- singleViewElementName: 'tr-ui-a-container-memory-dump-sub-view',
- multiViewElementName: 'tr-ui-a-container-memory-dump-sub-view'
+ pluralName: 'processMemoryDumps'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump_test.html b/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump_test.html
index 4b1c2a32c71..c8d6d4864d9 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/process_memory_dump_test.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/global_memory_dump.html">
<link rel="import" href="/tracing/model/memory_dump_test_utils.html">
@@ -12,7 +13,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/process_memory_dump.html">
<link rel="import" href="/tracing/model/vm_region.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -24,7 +24,7 @@ tr.b.unittest.testSuite(function() {
var VMRegionClassificationNode = tr.model.VMRegionClassificationNode;
var ScalarNumeric = tr.v.ScalarNumeric;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addChildDump = tr.model.MemoryDumpTestUtils.addChildDump;
var addOwnershipLink = tr.model.MemoryDumpTestUtils.addOwnershipLink;
@@ -96,31 +96,31 @@ tr.b.unittest.testSuite(function() {
var dump2 = createProcessMemoryDump(2, m);
dump2.vmRegions = createClassificationNode();
dump2.memoryAllocatorDumps = [
- newAllocatorDump(dump2, 'oilpan', {
+ newAllocatorDump(dump2, 'oilpan', {numerics: {
size: 1024,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 7),
inner_size: 768
- }),
- newAllocatorDump(dump2, 'v8', {
+ }}),
+ newAllocatorDump(dump2, 'v8', {numerics: {
size: 2048,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 15),
inner_size: 1999
- })
+ }})
];
// A dump with malloc and V8 allocator dumps.
var dump3 = createProcessMemoryDump(3, m);
dump3.memoryAllocatorDumps = [
- newAllocatorDump(dump3, 'malloc', {
+ newAllocatorDump(dump3, 'malloc', {numerics: {
size: 1024,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 7),
inner_size: 768
- }),
- newAllocatorDump(dump3, 'v8', {
+ }}),
+ newAllocatorDump(dump3, 'v8', {numerics: {
size: 2048,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 15),
inner_size: 1999
- })
+ }})
];
// A dump with VM regions.
@@ -148,8 +148,8 @@ tr.b.unittest.testSuite(function() {
test('checkDiscountTracingOverhead_undefinedFields', function() {
var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'v8', { size: 2048 }),
- newAllocatorDump(pmd, 'tracing', { size: 1024 })
+ newAllocatorDump(pmd, 'v8', {numerics: {size: 2048}}),
+ newAllocatorDump(pmd, 'tracing', {numerics: {size: 1024}})
];
});
@@ -158,31 +158,32 @@ tr.b.unittest.testSuite(function() {
var v8Dump = pmd.getMemoryAllocatorDumpByFullName('v8');
checkDumpNumericsAndDiagnostics(v8Dump, {
- 'size': 2048,
- 'effective_size': 2048
+ size: 2048,
+ effective_size: 2048
}, {});
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
checkDumpNumericsAndDiagnostics(tracingDump, {
- 'size': 1024,
- 'effective_size': 1024
+ size: 1024,
+ effective_size: 1024
}, {});
});
test('checkDiscountTracingOverhead_definedFields', function() {
var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
- pmd.totals = { residentBytes: 10240 };
+ pmd.totals = {residentBytes: 10240};
pmd.vmRegions = createClassificationNode(6000, {
privateDirtyResident: 4096,
proportionalResident: 5120,
swapped: 1536
});
- var mallocDump = newAllocatorDump(pmd, 'malloc', { size: 3072 });
- addChildDump(mallocDump, 'allocated_objects', { size: 2560 });
+ var mallocDump = newAllocatorDump(pmd, 'malloc',
+ {numerics: {size: 3072}});
+ addChildDump(mallocDump, 'allocated_objects', {numerics: {size: 2560}});
var tracingDump = newAllocatorDump(
- pmd, 'tracing', { size: 1024, resident_size: 1000 });
+ pmd, 'tracing', {numerics: {size: 1024, resident_size: 1000}});
pmd.memoryAllocatorDumps = [mallocDump, tracingDump];
});
@@ -220,8 +221,8 @@ tr.b.unittest.testSuite(function() {
var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc');
checkDumpNumericsAndDiagnostics(mallocDump, {
- 'size': 3072,
- 'effective_size': 2048
+ size: 3072,
+ effective_size: 2048
}, {});
assert.lengthOf(
mallocDump.children, 2 /* 'allocated_objects' and '<unspecified>' */);
@@ -229,8 +230,8 @@ tr.b.unittest.testSuite(function() {
var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName(
'malloc/allocated_objects');
checkDumpNumericsAndDiagnostics(allocatedObjectsDump, {
- 'size': 2560,
- 'effective_size': 1536
+ size: 2560,
+ effective_size: 1536
}, {});
assert.lengthOf(
allocatedObjectsDump.children,
@@ -241,15 +242,15 @@ tr.b.unittest.testSuite(function() {
assert.strictEqual(discountDump.parent, allocatedObjectsDump);
assert.include(allocatedObjectsDump.children, discountDump);
checkDumpNumericsAndDiagnostics(discountDump, {
- 'size': 1024,
- 'effective_size': 0
+ size: 1024,
+ effective_size: 0
}, {});
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
checkDumpNumericsAndDiagnostics(tracingDump, {
- 'size': 1024,
- 'effective_size': 1024,
- 'resident_size': 1000
+ size: 1024,
+ effective_size: 1024,
+ resident_size: 1000
}, {});
assert.strictEqual(tracingDump.owns.target, discountDump);
});
@@ -257,8 +258,8 @@ tr.b.unittest.testSuite(function() {
test('checkDiscountTracingOverhead_winheap', function() {
var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'tracing', { size: 2048 }),
- newAllocatorDump(pmd, 'winheap', { size: 5120 })
+ newAllocatorDump(pmd, 'tracing', {numerics: {size: 2048}}),
+ newAllocatorDump(pmd, 'winheap', {numerics: {size: 5120}})
];
});
@@ -267,8 +268,8 @@ tr.b.unittest.testSuite(function() {
var winheapDump = pmd.getMemoryAllocatorDumpByFullName('winheap');
checkDumpNumericsAndDiagnostics(winheapDump, {
- 'size': 5120,
- 'effective_size': 3072
+ size: 5120,
+ effective_size: 3072
}, {});
assert.lengthOf(winheapDump.children,
2 /* 'allocated_objects' and '<unspecified>' */);
@@ -276,8 +277,8 @@ tr.b.unittest.testSuite(function() {
var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName(
'winheap/allocated_objects');
checkDumpNumericsAndDiagnostics(allocatedObjectsDump, {
- 'size': 2048,
- 'effective_size': 0
+ size: 2048,
+ effective_size: 0
}, {});
assert.lengthOf(
allocatedObjectsDump.children, 1 /* 'tracing_overhead' */);
@@ -287,31 +288,32 @@ tr.b.unittest.testSuite(function() {
assert.strictEqual(discountDump.parent, allocatedObjectsDump);
assert.include(allocatedObjectsDump.children, discountDump);
checkDumpNumericsAndDiagnostics(discountDump, {
- 'size': 2048,
- 'effective_size': 0
+ size: 2048,
+ effective_size: 0
}, {});
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
checkDumpNumericsAndDiagnostics(tracingDump, {
- 'size': 2048,
- 'effective_size': 2048
+ size: 2048,
+ effective_size: 2048
}, {});
assert.strictEqual(tracingDump.owns.target, discountDump);
});
test('checkDiscountTracingOverhead_withMostRecentVmRegionsLinks', function() {
var pmds = createFinalizedProcessMemoryDumps([42, 90], function(pmds) {
- pmds[0].totals = { residentBytes: 1000, peakResidentBytes: 2000 };
+ pmds[0].totals = {residentBytes: 1000, peakResidentBytes: 2000};
pmds[0].vmRegions = createClassificationNode(6000, {
privateDirtyResident: 4096
});
pmds[0].memoryAllocatorDumps = [
- newAllocatorDump(pmds[0], 'tracing', { size: 300, resident_size: 100 })
+ newAllocatorDump(pmds[0], 'tracing',
+ {numerics: {size: 300, resident_size: 100}})
];
- pmds[1].totals = { peakResidentBytes: 3000 };
+ pmds[1].totals = {peakResidentBytes: 3000};
pmds[1].memoryAllocatorDumps = [
- newAllocatorDump(pmds[0], 'tracing', { resident_size: 200 })
+ newAllocatorDump(pmds[0], 'tracing', {numerics: {resident_size: 200}})
];
});
@@ -359,7 +361,8 @@ tr.b.unittest.testSuite(function() {
swapped: 1536
});
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'tracing', { size: 1000, resident_size: 1024 })
+ newAllocatorDump(pmd, 'tracing',
+ {numerics: {size: 1000, resident_size: 1024}})
];
});
@@ -398,7 +401,8 @@ tr.b.unittest.testSuite(function() {
swapped: 1536
});
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'tracing', { size: 1000, resident_size: 1024 })
+ newAllocatorDump(pmd, 'tracing',
+ {numerics: {size: 1000, resident_size: 1024}})
];
});
@@ -431,7 +435,8 @@ tr.b.unittest.testSuite(function() {
var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
pmd.vmRegions = createClassificationNode(10000);
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'tracing', { size: 1000, resident_size: 1024 })
+ newAllocatorDump(pmd, 'tracing',
+ {numerics: {size: 1000, resident_size: 1024}})
];
});
@@ -456,7 +461,8 @@ tr.b.unittest.testSuite(function() {
swapped: 1536
});
pmd.memoryAllocatorDumps = [
- newAllocatorDump(pmd, 'tracing', { size: 1000, resident_size: 1024 })
+ newAllocatorDump(pmd, 'tracing',
+ {numerics: {size: 1000, resident_size: 1024}})
];
});
@@ -477,7 +483,7 @@ tr.b.unittest.testSuite(function() {
test('checkDiscountTracingOverhead_existingLink', function() {
var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
- pmd.totals = { residentBytes: 10240 };
+ pmd.totals = {residentBytes: 10240};
pmd.vmRegions = createClassificationNode(6000, {
privateDirtyResident: 4096,
@@ -485,9 +491,10 @@ tr.b.unittest.testSuite(function() {
proportionalResident: 5120
});
- var mallocDump = newAllocatorDump(pmd, 'malloc', { size: 3072 });
+ var mallocDump = newAllocatorDump(pmd, 'malloc',
+ {numerics: {size: 3072}});
var tracingDump = newAllocatorDump(pmd, 'tracing',
- { size: 1024, resident_size: 1000 });
+ {numerics: {size: 1024, resident_size: 1000}});
var ownedDump = newAllocatorDump(pmd, 'owned');
// The code for discounting tracing overhead should *not* override an
@@ -529,23 +536,23 @@ tr.b.unittest.testSuite(function() {
var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc');
checkDumpNumericsAndDiagnostics(mallocDump, {
- 'size': 3072,
- 'effective_size': 3072
+ size: 3072,
+ effective_size: 3072
}, {});
assert.lengthOf(mallocDump.children, 0);
var ownedDump = pmd.getMemoryAllocatorDumpByFullName('owned');
checkDumpNumericsAndDiagnostics(ownedDump, {
- 'size': 1024,
- 'effective_size': 0
+ size: 1024,
+ effective_size: 0
}, {});
assert.lengthOf(ownedDump.children, 0);
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
checkDumpNumericsAndDiagnostics(tracingDump, {
- 'size': 1024,
- 'effective_size': 1024,
- 'resident_size': 1000
+ size: 1024,
+ effective_size: 1024,
+ resident_size: 1000
}, {});
assert.strictEqual(tracingDump.owns.target, ownedDump);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/process_test.html b/chromium/third_party/catapult/tracing/tracing/model/process_test.html
index 46c2ca802a3..449decbf3ea 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/process_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/process_test.html
@@ -44,11 +44,11 @@ tr.b.unittest.testSuite(function() {
var shiftCount = 0;
thread.shiftTimestampsForward = function(ts) {
- if (ts == 0.32)
+ if (ts === 0.32)
shiftCount++;
};
ctr.shiftTimestampsForward = function(ts) {
- if (ts == 0.32)
+ if (ts === 0.32)
shiftCount++;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/sample.html b/chromium/third_party/catapult/tracing/tracing/model/sample.html
index a0936a3a8ed..48435cfbcf9 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/sample.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/sample.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -49,7 +49,7 @@ tr.exportTo('tr.model', function() {
},
get userFriendlyName() {
- return 'Sample at ' + tr.v.Unit.byName.timeStampInMs.format(this.start);
+ return 'Sample at ' + tr.b.Unit.byName.timeStampInMs.format(this.start);
}
};
@@ -57,9 +57,7 @@ tr.exportTo('tr.model', function() {
Sample,
{
name: 'sample',
- pluralName: 'samples',
- singleViewElementName: 'tr-ui-a-single-sample-sub-view',
- multiViewElementName: 'tr-ui-a-multi-sample-sub-view'
+ pluralName: 'samples'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/slice.html b/chromium/third_party/catapult/tracing/tracing/model/slice.html
index 7c53deb305d..28d43c19993 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/slice.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -23,7 +23,10 @@ tr.exportTo('tr.model', function() {
*/
function Slice(category, title, colorId, start, args, opt_duration,
opt_cpuStart, opt_cpuDuration, opt_argsStripped,
- opt_bind_id) {
+ opt_bindId) {
+ if (new.target) {
+ throw new Error("Can't instantiate pure virtual class Slice");
+ }
tr.model.TimedEvent.call(this, start);
this.category = category || '';
@@ -42,7 +45,7 @@ tr.exportTo('tr.model', function() {
this.parentContainer = undefined;
this.argsStripped = false;
- this.bind_id_ = opt_bind_id;
+ this.bind_id_ = opt_bindId;
// parentSlice and isTopLevel will be set by SliceGroup.
this.parentSlice = undefined;
@@ -73,7 +76,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Slice ' + this.title + ' at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
},
get stableId() {
@@ -87,7 +90,7 @@ tr.exportTo('tr.model', function() {
return undefined;
for (var i = 0; i < this.subSlices.length; i++) {
- if (this.subSlices[i].title == targetTitle)
+ if (this.subSlices[i].title === targetTitle)
return this.subSlices[i];
var slice = this.subSlices[i].findDescendentSlice(targetTitle);
if (slice) return slice;
@@ -202,29 +205,25 @@ tr.exportTo('tr.model', function() {
/**
* Obtains the parents of a slice, from the most immediate to the root.
*
- * For instance, E.iterateAllAncestors() in the following example:
+ * For instance, E.enumerateAllAncestors() in the following example:
* [ A ]
* [ B][ D ][ G ]
* [C] [E][F] [H]
- * will pass D, then A to the provided callback, in the order from the
- * leaves to the root.
+ * will yield D, then A, in the order from the leaves to the root.
*/
- iterateAllAncestors: function(callback, opt_this) {
+ enumerateAllAncestors: function*() {
var curSlice = this;
while (curSlice.parentSlice) {
curSlice = curSlice.parentSlice;
- callback.call(opt_this, curSlice);
+ yield curSlice;
}
},
get ancestorSlices() {
var res = [];
-
- this.iterateAllAncestors(function(ancestor) {
- res.push(ancestor);
- });
-
+ for (var slice of this.enumerateAllAncestors())
+ res.push(slice);
return res;
},
@@ -259,9 +258,8 @@ tr.exportTo('tr.model', function() {
res.push(this);
- this.iterateAllAncestors(function(aSlice) {
+ for (var aSlice of this.enumerateAllAncestors())
res.push(aSlice);
- });
this.iterateAllSubsequentSlices(function(sSlice) {
res.push(sSlice);
@@ -270,20 +268,17 @@ tr.exportTo('tr.model', function() {
return res;
},
- iterateAllDescendents: function(callback, opt_this) {
- this.subSlices.forEach(callback, opt_this);
- this.subSlices.forEach(function(subSlice) {
- subSlice.iterateAllDescendents(callback, opt_this);
- }, opt_this);
+ enumerateAllDescendents: function*() {
+ for (var slice of this.subSlices)
+ yield slice;
+ for (var slice of this.subSlices)
+ yield * slice.enumerateAllDescendents();
},
get descendentSlices() {
var res = [];
-
- this.iterateAllDescendents(function(des) {
- res.push(des);
- });
-
+ for (var slice of this.enumerateAllDescendents())
+ res.push(slice);
return res;
}
@@ -294,4 +289,3 @@ tr.exportTo('tr.model', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/model/slice_group.html b/chromium/third_party/catapult/tracing/tracing/model/slice_group.html
index 9c14e8bf54e..bdecceecf58 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/slice_group.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/slice_group.html
@@ -10,6 +10,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/core/filter.html">
<link rel="import" href="/tracing/model/event_container.html">
+<link rel="import" href="/tracing/model/thread_slice.html">
<script>
'use strict';
@@ -19,7 +20,7 @@ found in the LICENSE file.
*/
tr.exportTo('tr.model', function() {
var ColorScheme = tr.b.ColorScheme;
- var Slice = tr.model.Slice;
+ var ThreadSlice = tr.model.ThreadSlice;
function getSliceLo(s) {
return s.start;
@@ -46,8 +47,11 @@ tr.exportTo('tr.model', function() {
this.parentContainer_ = parentContainer;
- var sliceConstructor = opt_sliceConstructor || Slice;
+ var sliceConstructor = opt_sliceConstructor || ThreadSlice;
this.sliceConstructor = sliceConstructor;
+ this.sliceConstructorSubTypes = this.sliceConstructor.subTypes;
+ if (!this.sliceConstructorSubTypes)
+ throw new Error('opt_sliceConstructor must have a subtype registry.');
this.openPartialSlices_ = [];
@@ -139,10 +143,12 @@ tr.exportTo('tr.model', function() {
var colorId = opt_colorId ||
ColorScheme.getColorIdForGeneralPurposeString(title);
- var slice = new this.sliceConstructor(category, title, colorId, ts,
- opt_args ? opt_args : {}, null,
- opt_tts, undefined,
- opt_argsStripped);
+ var sliceConstructorSubTypes = this.sliceConstructorSubTypes;
+ var sliceType = sliceConstructorSubTypes.getConstructor(category, title);
+ var slice = new sliceType(category, title, colorId, ts,
+ opt_args ? opt_args : {}, null,
+ opt_tts, undefined,
+ opt_argsStripped);
this.openPartialSlices_.push(slice);
slice.didNotFinish = true;
this.pushSlice(slice);
@@ -215,13 +221,15 @@ tr.exportTo('tr.model', function() {
*/
pushCompleteSlice: function(category, title, ts, duration, tts,
cpuDuration, opt_args, opt_argsStripped,
- opt_colorId, opt_bind_id) {
+ opt_colorId, opt_bindId) {
var colorId = opt_colorId ||
ColorScheme.getColorIdForGeneralPurposeString(title);
- var slice = new this.sliceConstructor(category, title, colorId, ts,
- opt_args ? opt_args : {},
- duration, tts, cpuDuration,
- opt_argsStripped, opt_bind_id);
+ var sliceConstructorSubTypes = this.sliceConstructorSubTypes;
+ var sliceType = sliceConstructorSubTypes.getConstructor(category, title);
+ var slice = new sliceType(category, title, colorId, ts,
+ opt_args ? opt_args : {},
+ duration, tts, cpuDuration,
+ opt_argsStripped, opt_bindId);
if (duration === undefined)
slice.didNotFinish = true;
this.pushSlice(slice);
@@ -268,7 +276,10 @@ tr.exportTo('tr.model', function() {
},
copySlice: function(slice) {
- var newSlice = new this.sliceConstructor(slice.category, slice.title,
+ var sliceConstructorSubTypes = this.sliceConstructorSubTypes;
+ var sliceType = sliceConstructorSubTypes.getConstructor(slice.category,
+ slice.title);
+ var newSlice = new sliceType(slice.category, slice.title,
slice.colorId, slice.start,
slice.args, slice.duration, slice.cpuStart, slice.cpuDuration);
newSlice.didNotFinish = slice.didNotFinish;
@@ -293,7 +304,7 @@ tr.exportTo('tr.model', function() {
getSlicesOfName: function(title) {
var slices = [];
for (var i = 0; i < this.slices.length; i++) {
- if (this.slices[i].title == title) {
+ if (this.slices[i].title === title) {
slices.push(this.slices[i]);
}
}
@@ -310,7 +321,8 @@ tr.exportTo('tr.model', function() {
end,
function(topLevelSlice) {
callback(topLevelSlice);
- topLevelSlice.iterateAllDescendents(callback);
+ for (var slice of topLevelSlice.enumerateAllDescendents())
+ callback(slice);
});
return ret;
},
@@ -330,7 +342,7 @@ tr.exportTo('tr.model', function() {
this.topLevelSlices,
getSliceLo, getSliceHi,
ts);
- if (i == -1 || i == this.topLevelSlices.length)
+ if (i === -1 || i === this.topLevelSlices.length)
return undefined;
var curSlice = this.topLevelSlices[i];
@@ -341,7 +353,7 @@ tr.exportTo('tr.model', function() {
curSlice.subSlices,
getSliceLo, getSliceHi,
ts);
- if (i == -1 || i == curSlice.subSlices.length)
+ if (i === -1 || i === curSlice.subSlices.length)
return curSlice;
curSlice = curSlice.subSlices[i];
}
@@ -394,20 +406,15 @@ tr.exportTo('tr.model', function() {
createSubSlicesImpl_: function() {
var precisionUnit = this.model.intrinsicTimeUnit;
- function addSliceIfBounds(root, child) {
- // Because we know that the start time of child is >= the start time
- // of all other slices seen so far, we can just check the last slice
- // of each row for bounding.
- if (root.bounds(child, precisionUnit)) {
- if (root.subSlices && root.subSlices.length > 0) {
- if (addSliceIfBounds(root.subSlices[root.subSlices.length - 1],
- child))
- return true;
- }
- child.parentSlice = root;
- if (root.subSlices === undefined)
- root.subSlices = [];
- root.subSlices.push(child);
+
+ // Note that this doesn't check whether |child| should be added to
+ // |parent|'s descendant slices instead of |parent| directly.
+ function addSliceIfBounds(parent, child) {
+ if (parent.bounds(child, precisionUnit)) {
+ child.parentSlice = parent;
+ if (parent.subSlices === undefined)
+ parent.subSlices = [];
+ parent.subSlices.push(child);
return true;
}
return false;
@@ -428,7 +435,7 @@ tr.exportTo('tr.model', function() {
ops.sort(function(ix, iy) {
var x = originalSlices[ix];
var y = originalSlices[iy];
- if (x.start != y.start)
+ if (x.start !== y.start)
return x.start - y.start;
// Elements get inserted into the slices array in order of when the
@@ -450,11 +457,15 @@ tr.exportTo('tr.model', function() {
rootSlice.isTopLevel = true;
for (var i = 1; i < slices.length; i++) {
var slice = slices[i];
- if (!addSliceIfBounds(rootSlice, slice)) {
- rootSlice = slice;
- rootSlice.isTopLevel = true;
- this.topLevelSlices.push(rootSlice);
+ while (rootSlice !== undefined &&
+ (!addSliceIfBounds(rootSlice, slice))) {
+ rootSlice = rootSlice.parentSlice;
+ }
+ if (rootSlice === undefined) {
+ this.topLevelSlices.push(slice);
+ slice.isTopLevel = true;
}
+ rootSlice = slice;
}
// Keep the slices in sorted form.
@@ -464,7 +475,7 @@ tr.exportTo('tr.model', function() {
var SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
var sliceIdx = 0;
timeSlices.forEach(function(timeSlice) {
- if (timeSlice.schedulingState == SCHEDULING_STATE.RUNNING) {
+ if (timeSlice.schedulingState === SCHEDULING_STATE.RUNNING) {
while (sliceIdx < this.topLevelSlices.length) {
if (this.addCpuTimeToSubslice_(this.topLevelSlices[sliceIdx],
timeSlice)) {
@@ -566,10 +577,10 @@ tr.exportTo('tr.model', function() {
if (groupB.openPartialSlices_.length > 0)
throw new Error('groupB has open partial slices');
- if (groupA.parentContainer != groupB.parentContainer)
+ if (groupA.parentContainer !== groupB.parentContainer)
throw new Error('Different parent threads. Cannot merge');
- if (groupA.sliceConstructor != groupB.sliceConstructor)
+ if (groupA.sliceConstructor !== groupB.sliceConstructor)
throw new Error('Different slice constructors. Cannot merge');
var result = new SliceGroup(groupA.parentContainer,
@@ -594,7 +605,7 @@ tr.exportTo('tr.model', function() {
var newSlice = result.copySlice(oldSlice);
newSlice.start = when;
newSlice.duration = oldEnd - when;
- if (newSlice.title.indexOf(' (cont.)') == -1)
+ if (newSlice.title.indexOf(' (cont.)') === -1)
newSlice.title += ' (cont.)';
oldSlice.duration = when - oldSlice.start;
openB[i] = newSlice;
diff --git a/chromium/third_party/catapult/tracing/tracing/model/slice_group_test.html b/chromium/third_party/catapult/tracing/tracing/model/slice_group_test.html
index 8ae66bc41d1..f6aaa7eb5dc 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/slice_group_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/slice_group_test.html
@@ -143,6 +143,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(group.topLevelSlices.length, 2);
assert.deepEqual(group.topLevelSlices, [sA, sB]);
+ assert.isTrue(sA.isTopLevel);
+ assert.isTrue(sB.isTopLevel);
assert.equal(group.findSliceAtTs(3), sA);
});
@@ -180,7 +182,7 @@ tr.b.unittest.testSuite(function() {
// Pattern being tested:
// [ a ]
- // [ b1 ] []<- b2 where b2.duration = 0 and b2.end == a.end.
+ // [ b1 ] []<- b2 where b2.duration = 0 and b2.end === a.end.
var sA = group.pushSlice(newSliceEx({title: 'a', start: 1, duration: 3}));
var sB1 = group.pushSlice(newSliceEx({title: 'b1', start: 1, duration: 2}));
var sB2 = group.pushSlice(newSliceEx({title: 'b2', start: 4, duration: 0}));
@@ -327,6 +329,11 @@ tr.b.unittest.testSuite(function() {
TestSlice.prototype = {
__proto__: Slice.prototype
};
+ TestSlice.subTypes = {
+ getConstructor: function(category, title) {
+ return TestSlice;
+ }
+ };
var thread = newFakeThread();
var a = new SliceGroup(thread, TestSlice);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/slice_test.html b/chromium/third_party/catapult/tracing/tracing/model/slice_test.html
index a80c080b7e0..64cfba6e4c2 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/slice_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/slice_test.html
@@ -73,7 +73,7 @@ tr.b.unittest.testSuite(function() {
assert.deepEqual([sC1, sC2], foundSlices);
});
- test('iterateAllDescendents', function() {
+ test('enumerateAllDescendents', function() {
var group = new SliceGroup(newFakeThread());
var sA = group.pushSlice(newSliceEx(
@@ -106,7 +106,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(sC.mostTopLevelSlice, sA);
});
- test('iterateAllAncestors', function() {
+ test('enumerateAllAncestors', function() {
var group = new SliceGroup(newFakeThread());
var sA = group.pushSlice(newSliceEx(
@@ -215,5 +215,23 @@ tr.b.unittest.testSuite(function() {
assert.equal(group.stableId + '.1', sB.stableId);
assert.equal(group.stableId + '.2', sC.stableId);
});
+
+ test('cantInstantiateDirectly', function() {
+ assert.throws(function() {
+ new Slice('', 'Test', 0, 0, { });
+ });
+ });
+
+ test('canInstantiateSubclasses', function() {
+ function TestSlice() {
+ Slice.call(this, '', 'Test', 0, 0, { });
+ }
+ TestSlice.prototype = {
+ __proto__: Slice.prototype
+ };
+ assert.doesNotThrow(function() {
+ new TestSlice();
+ });
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/model/stack_frame.html b/chromium/third_party/catapult/tracing/tracing/model/stack_frame.html
index 50f3126a1e5..1bc48c95070 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/stack_frame.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/stack_frame.html
@@ -55,7 +55,7 @@ tr.exportTo('tr.model', function() {
set parentFrame(parentFrame) {
if (this.parentFrame_)
- this.parentFrame_.removeChild(this);
+ Polymer.dom(this.parentFrame_).removeChild(this);
this.parentFrame_ = parentFrame;
if (this.parentFrame_)
this.parentFrame_.addChild(this);
@@ -67,7 +67,7 @@ tr.exportTo('tr.model', function() {
removeChild: function(child) {
var i = this.children.indexOf(child.id);
- if (i == -1)
+ if (i === -1)
throw new Error('omg');
this.children.splice(i, 1);
},
diff --git a/chromium/third_party/catapult/tracing/tracing/model/thread.html b/chromium/third_party/catapult/tracing/tracing/model/thread.html
index c11aeb13d1d..b34add1ed95 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/thread.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/thread.html
@@ -21,7 +21,6 @@ found in the LICENSE file.
tr.exportTo('tr.model', function() {
var AsyncSlice = tr.model.AsyncSlice;
var AsyncSliceGroup = tr.model.AsyncSliceGroup;
- var Slice = tr.model.Slice;
var SliceGroup = tr.model.SliceGroup;
var ThreadSlice = tr.model.ThreadSlice;
var ThreadTimeSlice = tr.model.ThreadTimeSlice;
@@ -192,7 +191,7 @@ tr.exportTo('tr.model', function() {
createSubSlices: function() {
this.sliceGroup.createSubSlices();
this.samples_ = this.parent.model.samples.filter(function(sample) {
- return sample.thread == this;
+ return sample.thread === this;
}, this);
},
@@ -256,7 +255,7 @@ tr.exportTo('tr.model', function() {
threadTimeSlice.end);
var intersection = freqRange.findIntersection(range);
- if (threadTimeSlice.schedulingState ==
+ if (threadTimeSlice.schedulingState ===
tr.model.SCHEDULING_STATE.RUNNING) {
var cpu = threadTimeSlice.cpuOnWhichThreadWasRunning;
if (!(cpu.cpuNumber in stats))
diff --git a/chromium/third_party/catapult/tracing/tracing/model/thread_slice.html b/chromium/third_party/catapult/tracing/tracing/model/thread_slice.html
index d1c8edcb313..49672bb86b7 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/thread_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/thread_slice.html
@@ -32,9 +32,9 @@ tr.exportTo('tr.model', function() {
*/
function ThreadSlice(cat, title, colorId, start, args, opt_duration,
opt_cpuStart, opt_cpuDuration, opt_argsStripped,
- opt_bind_id) {
+ opt_bindId) {
Slice.call(this, cat, title, colorId, start, args, opt_duration,
- opt_cpuStart, opt_cpuDuration, opt_argsStripped, opt_bind_id);
+ opt_cpuStart, opt_cpuDuration, opt_argsStripped, opt_bindId);
// Do not modify this directly.
// subSlices is configured by SliceGroup.rebuildSubRows_.
this.subSlices = [];
@@ -59,9 +59,7 @@ tr.exportTo('tr.model', function() {
ThreadSlice,
{
name: 'slice',
- pluralName: 'slices',
- singleViewElementName: 'tr-ui-a-single-thread-slice-sub-view',
- multiViewElementName: 'tr-ui-a-multi-thread-slice-sub-view'
+ pluralName: 'slices'
});
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/model/thread_test.html b/chromium/third_party/catapult/tracing/tracing/model/thread_test.html
index fc88dda7501..4b5ebd613ac 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/thread_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/thread_test.html
@@ -66,7 +66,7 @@ tr.b.unittest.testSuite(function() {
var shiftCount = 0;
t.asyncSliceGroup.shiftTimestampsForward = function(ts) {
- if (ts == 0.32)
+ if (ts === 0.32)
shiftCount++;
};
@@ -85,7 +85,7 @@ tr.b.unittest.testSuite(function() {
var shiftCount = 0;
t.asyncSliceGroup.shiftTimestampsForward = function(ts) {
- if (ts == 0.32)
+ if (ts === 0.32)
shiftCount++;
};
diff --git a/chromium/third_party/catapult/tracing/tracing/model/thread_time_slice.html b/chromium/third_party/catapult/tracing/tracing/model/thread_time_slice.html
index e63a136d05d..9b5a86bf6c6 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/thread_time_slice.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/thread_time_slice.html
@@ -147,9 +147,7 @@ tr.exportTo('tr.model', function() {
ThreadTimeSlice,
{
name: 'threadTimeSlice',
- pluralName: 'threadTimeSlices',
- singleViewElementName: 'tr-ui-a-single-thread-time-slice-sub-view',
- multiViewElementName: 'tr-ui-a-multi-thread-time-slice-sub-view'
+ pluralName: 'threadTimeSlices'
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/time_to_object_instance_map.html b/chromium/third_party/catapult/tracing/tracing/model/time_to_object_instance_map.html
index bd30fc102bc..5b54daa1028 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/time_to_object_instance_map.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/time_to_object_instance_map.html
@@ -34,7 +34,7 @@ tr.exportTo('tr.model', function() {
TimeToObjectInstanceMap.prototype = {
idWasCreated: function(category, name, ts) {
- if (this.instances.length == 0) {
+ if (this.instances.length === 0) {
this.instances.push(this.createObjectInstanceFunction_(
this.parent, this.scopedId, category, name, ts));
this.instances[0].creationTsWasExplicit = true;
@@ -54,7 +54,7 @@ tr.exportTo('tr.model', function() {
},
addSnapshot: function(category, name, ts, args, opt_baseTypeName) {
- if (this.instances.length == 0) {
+ if (this.instances.length === 0) {
this.instances.push(this.createObjectInstanceFunction_(
this.parent, this.scopedId, category, name, ts, opt_baseTypeName));
}
@@ -74,7 +74,7 @@ tr.exportTo('tr.model', function() {
'At the provided timestamp, no instance was still alive');
}
- if (instance.snapshots.length != 0) {
+ if (instance.snapshots.length !== 0) {
throw new Error(
'Cannot shift creationTs forward, ' +
'snapshots have been added. First snap was at ts=' +
@@ -104,7 +104,8 @@ tr.exportTo('tr.model', function() {
var tmp = this.instances[i];
if (ts >= tmp.deletionTs)
break;
- if (tmp.creationTsWasExplicit == false && tmp.snapshots.length == 0)
+ if (tmp.creationTsWasExplicit === false &&
+ tmp.snapshots.length === 0)
lastValidIndex = i;
}
if (lastValidIndex === undefined) {
@@ -122,20 +123,20 @@ tr.exportTo('tr.model', function() {
},
get lastInstance() {
- if (this.instances.length == 0)
+ if (this.instances.length === 0)
return undefined;
return this.instances[this.instances.length - 1];
},
idWasDeleted: function(category, name, ts) {
- if (this.instances.length == 0) {
+ if (this.instances.length === 0) {
this.instances.push(this.createObjectInstanceFunction_(
this.parent, this.scopedId, category, name, ts));
}
var lastInstance = this.instances[this.instances.length - 1];
if (ts < lastInstance.creationTs)
throw new Error('Cannot delete an id before it was created');
- if (lastInstance.deletionTs == Number.MAX_VALUE) {
+ if (lastInstance.deletionTs === Number.MAX_VALUE) {
lastInstance.wasDeleted(ts);
return lastInstance;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/model/timed_event.html b/chromium/third_party/catapult/tracing/tracing/model/timed_event.html
index 381a8a2f455..11347fe4cc6 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/timed_event.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/timed_event.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/guid.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
<link rel="import" href="/tracing/model/event.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
<script>
'use strict';
@@ -42,11 +42,12 @@ tr.exportTo('tr.model', function() {
range.addValue(this.end);
},
+ // TODO(charliea): Can this be implemented in terms of Event.range()?
// Returns true if 'that' TimedEvent is fully contained within 'this' timed
// event.
bounds: function(that, opt_precisionUnit) {
if (opt_precisionUnit === undefined)
- opt_precisionUnit = tr.v.TimeDisplayModes.ms;
+ opt_precisionUnit = tr.b.TimeDisplayModes.ms;
var startsBefore = opt_precisionUnit.roundedLess(that.start, this.start);
var endsAfter = opt_precisionUnit.roundedLess(this.end, that.end);
diff --git a/chromium/third_party/catapult/tracing/tracing/model/timed_event_test.html b/chromium/third_party/catapult/tracing/tracing/model/timed_event_test.html
index 4beba912298..5659b71d9a2 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/timed_event_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/timed_event_test.html
@@ -7,14 +7,13 @@ found in the LICENSE file.
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
test('bounds_startPrecision', function() {
- var unit = tr.v.TimeDisplayModes;
+ var unit = tr.b.TimeDisplayModes;
var outer = new tr.model.TimedEvent(10.0001);
outer.duration = 0.9999;
@@ -28,7 +27,7 @@ tr.b.unittest.testSuite(function() {
});
test('bounds_endPrecision', function() {
- var unit = tr.v.TimeDisplayModes;
+ var unit = tr.b.TimeDisplayModes;
var outer = new tr.model.TimedEvent(10.0000);
outer.duration = 0.9999;
@@ -42,4 +41,3 @@ tr.b.unittest.testSuite(function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/animation_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/animation_expectation.html
index 9d73f060d92..2ba066b25a0 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/animation_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/animation_expectation.html
@@ -37,7 +37,7 @@ tr.exportTo('tr.model.um', function() {
}
};
- tr.model.um.UserExpectation.register(AnimationExpectation, {
+ tr.model.um.UserExpectation.subTypes.register(AnimationExpectation, {
stageTitle: 'Animation',
colorId: tr.b.ColorScheme.getColorIdForReservedName('rail_animation')
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/idle_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/idle_expectation.html
index 80c22c0483b..0438be4990d 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/idle_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/idle_expectation.html
@@ -22,7 +22,7 @@ tr.exportTo('tr.model.um', function() {
constructor: IdleExpectation
};
- tr.model.um.UserExpectation.register(IdleExpectation, {
+ tr.model.um.UserExpectation.subTypes.register(IdleExpectation, {
stageTitle: 'Idle',
colorId: tr.b.ColorScheme.getColorIdForReservedName('rail_idle')
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/load_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/load_expectation.html
index a4ec0113fab..a40bdfa9be0 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/load_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/load_expectation.html
@@ -56,7 +56,7 @@ tr.exportTo('tr.model.um', function() {
constructor: LoadExpectation
};
- tr.model.um.UserExpectation.register(LoadExpectation, {
+ tr.model.um.UserExpectation.subTypes.register(LoadExpectation, {
stageTitle: 'Load',
colorId: tr.b.ColorScheme.getColorIdForReservedName('rail_load')
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/response_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/response_expectation.html
index 9608467cfa4..9ebe9da4b7f 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/response_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/response_expectation.html
@@ -23,7 +23,7 @@ tr.exportTo('tr.model.um', function() {
constructor: ResponseExpectation
};
- tr.model.um.UserExpectation.register(ResponseExpectation, {
+ tr.model.um.UserExpectation.subTypes.register(ResponseExpectation, {
stageTitle: 'Response',
colorId: tr.b.ColorScheme.getColorIdForReservedName('rail_response')
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/startup_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/startup_expectation.html
index 630c79c2cb5..6228046844f 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/startup_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/startup_expectation.html
@@ -21,7 +21,7 @@ tr.exportTo('tr.model.um', function() {
constructor: StartupExpectation
};
- tr.model.um.UserExpectation.register(StartupExpectation, {
+ tr.model.um.UserExpectation.subTypes.register(StartupExpectation, {
stageTitle: 'Startup',
colorId: tr.b.ColorScheme.getColorIdForReservedName('startup')
});
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/user_expectation.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/user_expectation.html
index 43e8888740c..8f40ae0234c 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/user_expectation.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/user_expectation.html
@@ -7,10 +7,10 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/range_utils.html">
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/compound_event_selection_state.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/timed_event.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -18,11 +18,11 @@ found in the LICENSE file.
tr.exportTo('tr.model.um', function() {
var CompoundEventSelectionState = tr.model.CompoundEventSelectionState;
- function UserExpectation(parentModel, initiatorTitle, start, duration) {
+ function UserExpectation(parentModel, initiatorType, start, duration) {
tr.model.TimedEvent.call(this, start);
this.associatedEvents = new tr.model.EventSet();
this.duration = duration;
- this.initiatorTitle_ = initiatorTitle;
+ this.initiatorType_ = initiatorType;
this.parentModel = parentModel;
this.typeInfo_ = undefined;
@@ -31,6 +31,21 @@ tr.exportTo('tr.model.um', function() {
this.sourceEvents = new tr.model.EventSet();
}
+ // Strings used to name IRs.
+ var INITIATOR_TYPE = {
+ KEYBOARD: 'Keyboard',
+ MOUSE: 'Mouse',
+ MOUSE_WHEEL: 'MouseWheel',
+ TAP: 'Tap',
+ PINCH: 'Pinch',
+ FLING: 'Fling',
+ TOUCH: 'Touch',
+ SCROLL: 'Scroll',
+ CSS: 'CSS',
+ WEBGL: 'WebGL',
+ VIDEO: 'Video'
+ };
+
UserExpectation.prototype = {
__proto__: tr.model.TimedEvent.prototype,
@@ -65,7 +80,7 @@ tr.exportTo('tr.model.um', function() {
get userFriendlyName() {
return this.title + ' User Expectation at ' +
- tr.v.Unit.byName.timeStampInMs.format(this.start);
+ tr.b.Unit.byName.timeStampInMs.format(this.start);
},
get stableId() {
@@ -73,8 +88,10 @@ tr.exportTo('tr.model.um', function() {
},
get typeInfo() {
- if (!this.typeInfo_)
- this.typeInfo_ = UserExpectation.findTypeInfo(this.constructor);
+ if (!this.typeInfo_) {
+ this.typeInfo_ = UserExpectation.subTypes.findTypeInfo(
+ this.constructor);
+ }
// If you set Subclass.prototype = {}, then you must explicitly specify
// constructor in that prototype object!
@@ -94,15 +111,15 @@ tr.exportTo('tr.model.um', function() {
return this.typeInfo.metadata.stageTitle;
},
- get initiatorTitle() {
- return this.initiatorTitle_;
+ get initiatorType() {
+ return this.initiatorType_;
},
get title() {
- if (!this.initiatorTitle)
+ if (!this.initiatorType)
return this.stageTitle;
- return this.initiatorTitle + ' ' + this.stageTitle;
+ return this.initiatorType + ' ' + this.stageTitle;
},
/**
@@ -118,10 +135,11 @@ tr.exportTo('tr.model.um', function() {
}
};
+ var subTypes = {};
var options = new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);
- tr.b.decorateExtensionRegistry(UserExpectation, options);
+ tr.b.decorateExtensionRegistry(subTypes, options);
- UserExpectation.addEventListener('will-register', function(e) {
+ subTypes.addEventListener('will-register', function(e) {
var metadata = e.typeInfo.metadata;
if (metadata.stageTitle === undefined) {
@@ -138,14 +156,14 @@ tr.exportTo('tr.model.um', function() {
tr.model.EventRegistry.register(
UserExpectation,
{
- name: 'user-expectation',
- pluralName: 'user-expectations',
- singleViewElementName: 'tr-ui-a-single-user-expectation-sub-view',
- multiViewElementName: 'tr-ui-a-multi-user-expectation-sub-view'
+ name: 'userExpectation',
+ pluralName: 'userExpectations',
+ subTypes: subTypes
});
return {
- UserExpectation: UserExpectation
+ UserExpectation: UserExpectation,
+ INITIATOR_TYPE: INITIATOR_TYPE
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/model/user_model/user_model.html b/chromium/third_party/catapult/tracing/tracing/model/user_model/user_model.html
index fd30d6a610b..07d73f3e5e0 100644
--- a/chromium/third_party/catapult/tracing/tracing/model/user_model/user_model.html
+++ b/chromium/third_party/catapult/tracing/tracing/model/user_model/user_model.html
@@ -29,9 +29,7 @@ tr.exportTo('tr.model.um', function() {
},
sortExpectations: function() {
- Array.prototype.sort.call(this.expectations_, function(x, y) {
- return x.start - y.start;
- });
+ this.expectations_.sortEvents((x, y) => (x.start - y.start));
},
get expectations() {
@@ -64,4 +62,3 @@ tr.exportTo('tr.model.um', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/__init__.py b/chromium/third_party/catapult/tracing/tracing/mre/__init__.py
new file mode 100644
index 00000000000..50b23dff631
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/cloud_storage.py b/chromium/third_party/catapult/tracing/tracing/mre/cloud_storage.py
new file mode 100644
index 00000000000..877ddaa0645
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/cloud_storage.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import os
+import subprocess
+import sys
+
+_GSUTIL_PATH = os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ '..', '..', 'third_party', 'gsutil', 'gsutil'))
+
+
+class CloudStorageError(Exception):
+
+ @staticmethod
+ def _GetConfigInstructions():
+ command = _GSUTIL_PATH
+ return ('To configure your credentials:\n'
+ ' 1. Run "%s config" and follow its instructions.\n'
+ ' 2. If you have a @google.com account, use that account.\n'
+ ' 3. For the project-id, just enter 0.' % command)
+
+
+class PermissionError(CloudStorageError):
+
+ def __init__(self):
+ super(PermissionError, self).__init__(
+ 'Attempted to access a file from Cloud Storage but you don\'t '
+ 'have permission. ' + self._GetConfigInstructions())
+
+
+class CredentialsError(CloudStorageError):
+
+ def __init__(self):
+ super(CredentialsError, self).__init__(
+ 'Attempted to access a file from Cloud Storage but you have no '
+ 'configured credentials. ' + self._GetConfigInstructions())
+
+
+class NotFoundError(CloudStorageError):
+ pass
+
+
+class ServerError(CloudStorageError):
+ pass
+
+
+def Copy(src, dst):
+ # TODO(simonhatch): switch to use py_utils.cloud_storage.
+ args = [sys.executable, _GSUTIL_PATH, 'cp', src, dst]
+ gsutil = subprocess.Popen(args, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ _, stderr = gsutil.communicate()
+
+ if gsutil.returncode:
+ if stderr.startswith((
+ 'You are attempting to access protected data with no configured',
+ 'Failure: No handler was ready to authenticate.')):
+ raise CredentialsError()
+ if ('status=403' in stderr or 'status 403' in stderr or
+ '403 Forbidden' in stderr):
+ raise PermissionError()
+ if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or
+ 'No URLs matched' in stderr or
+ 'One or more URLs matched no' in stderr):
+ raise NotFoundError(stderr)
+ if '500 Internal Server Error' in stderr:
+ raise ServerError(stderr)
+ raise CloudStorageError(stderr)
+ return gsutil.returncode
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver.py b/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver.py
new file mode 100644
index 00000000000..28bb8a208b7
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class CorpusDriver(object):
+
+ def GetTraceHandles(self):
+ raise NotImplementedError()
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver_cmdline.py b/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver_cmdline.py
new file mode 100644
index 00000000000..06d70ba8f68
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/corpus_driver_cmdline.py
@@ -0,0 +1,23 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+from tracing.mre import local_directory_corpus_driver
+
+
+_CORPUS_DRIVERS = {
+ 'local-directory': {
+ 'description': 'Use traces from a local directory.',
+ 'class': local_directory_corpus_driver.LocalDirectoryCorpusDriver
+ }
+}
+_CORPUS_DRIVER_DEFAULT = 'local-directory'
+
+
+def GetCorpusDriver(parser, args):
+ # With parse_known_args, optional arguments aren't guaranteed to be there so
+ # we need to check if it's there, and use the default otherwise.
+ corpus = _CORPUS_DRIVER_DEFAULT
+
+ cls = _CORPUS_DRIVERS[corpus]['class']
+ init_args = cls.CheckAndCreateInitArguments(parser, args)
+ return cls(**init_args)
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/failure.html b/chromium/third_party/catapult/tracing/tracing/mre/failure.html
new file mode 100644
index 00000000000..39b8460e49e
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/failure.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/base/base.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+ function Failure(job, functionHandleString, traceCanonicalUrl,
+ failureTypeName, description, stack) {
+ this.job = job;
+ this.functionHandleString = functionHandleString;
+ this.traceCanonicalUrl = traceCanonicalUrl;
+ this.failureTypeName = failureTypeName;
+ this.description = description;
+ this.stack = stack;
+ }
+
+ Failure.prototype = {
+ asDict: function() {
+ // TODO(eakuefner): Serialize job once reduction is implemented.
+ return {
+ function_handle_string: this.functionHandleString,
+ trace_canonical_url: this.traceCanonicalUrl,
+ type: this.failureTypeName,
+ description: this.description,
+ stack: this.stack
+ };
+ }
+ };
+
+ Failure.fromDict = function(failureDict) {
+ return new Failure(undefined, failureDict.function_handle_string,
+ failureDict.trace_canonical_url, failureDict.type,
+ failureDict.description, failureDict.stack);
+ };
+
+ return {
+ Failure: Failure
+ };
+});
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/failure.py b/chromium/third_party/catapult/tracing/tracing/mre/failure.py
new file mode 100644
index 00000000000..8c0713e1d8b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/failure.py
@@ -0,0 +1,53 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from tracing.mre import job as job_module
+
+
+class Failure(object):
+
+ def __init__(self, job, function_handle_string, trace_canonical_url,
+ failure_type_name, description, stack):
+ assert isinstance(job, job_module.Job)
+
+ self.job = job
+ self.function_handle_string = function_handle_string
+ self.trace_canonical_url = trace_canonical_url
+ self.failure_type_name = failure_type_name
+ self.description = description
+ self.stack = stack
+
+ def __str__(self):
+ return (
+ 'Failure for job %s with function handle %s and trace handle %s:\n'
+ 'of type %s wtih description %s. Stack:\n\n%s' % (
+ self.job.guid, self.function_handle_string,
+ self.trace_canonical_url, self.failure_type_name,
+ self.description, self.stack))
+
+ def AsDict(self):
+ return {
+ 'job_guid': str(self.job.guid),
+ 'function_handle_string': self.function_handle_string,
+ 'trace_canonical_url': self.trace_canonical_url,
+ 'type': self.failure_type_name,
+ 'description': self.description,
+ 'stack': self.stack
+ }
+
+ @staticmethod
+ def FromDict(failure_dict, job, failure_names_to_constructors=None):
+ if failure_names_to_constructors is None:
+ failure_names_to_constructors = {}
+ failure_type_name = failure_dict['type']
+ if failure_type_name in failure_names_to_constructors:
+ cls = failure_names_to_constructors[failure_type_name]
+ else:
+ cls = Failure
+
+ return cls(job,
+ failure_dict['function_handle_string'],
+ failure_dict['trace_canonical_url'],
+ failure_type_name, failure_dict['description'],
+ failure_dict['stack'])
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/failure_test.html b/chromium/third_party/catapult/tracing/tracing/mre/failure_test.html
new file mode 100644
index 00000000000..6a76da0a0b7
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/failure_test.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/mre/failure.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('failureAsDictTest', function() {
+ var failure = new tr.mre.Failure(undefined, 'foo.html:Foo',
+ 'file://foo.html', 'err', 'desc', 'stack');
+
+ assert.deepEqual(failure.asDict(), {
+ function_handle_string: 'foo.html:Foo',
+ trace_canonical_url: 'file://foo.html',
+ type: 'err',
+ description: 'desc',
+ stack: 'stack'
+ });
+ });
+
+ test('failureFromDictTest', function() {
+ var failureDict = {
+ function_handle_string: 'foo.html:Foo',
+ trace_canonical_url: 'file://foo.html',
+ type: 'err',
+ description: 'desc',
+ stack: 'stack'
+ };
+
+ var failure = tr.mre.Failure.fromDict(failureDict);
+
+ assert.equal(failure.functionHandleString, 'foo.html:Foo');
+ assert.equal(failure.traceCanonicalUrl, 'file://foo.html');
+ assert.equal(failure.failureTypeName, 'err');
+ assert.equal(failure.description, 'desc');
+ assert.equal(failure.stack, 'stack');
+ });
+});
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/failure_unittest.py b/chromium/third_party/catapult/tracing/tracing/mre/failure_unittest.py
new file mode 100644
index 00000000000..1140b17aa66
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/failure_unittest.py
@@ -0,0 +1,56 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from tracing.mre import function_handle
+from tracing.mre import failure as failure_module
+from tracing.mre import job as job_module
+
+
+def _SingleFileFunctionHandle(filename, function_name, guid):
+ return function_handle.FunctionHandle(
+ modules_to_load=[function_handle.ModuleToLoad(filename=filename)],
+ function_name=function_name, guid=guid)
+
+
+class FailureTests(unittest.TestCase):
+
+ def testAsDict(self):
+ map_function_handle = _SingleFileFunctionHandle('foo.html', 'Foo', '2')
+ job = job_module.Job(map_function_handle, '1')
+ failure = failure_module.Failure(job, 'foo.html:Foo',
+ 'file://foo.html',
+ 'err', 'desc', 'stack')
+
+ self.assertEquals(failure.AsDict(), {
+ 'job_guid': '1',
+ 'function_handle_string': 'foo.html:Foo',
+ 'trace_canonical_url': 'file://foo.html',
+ 'type': 'err',
+ 'description': 'desc',
+ 'stack': 'stack'
+ })
+
+ def testFromDict(self):
+ map_function_handle = _SingleFileFunctionHandle('foo.html', 'Foo', '2')
+ job = job_module.Job(map_function_handle, '1')
+
+ failure_dict = {
+ 'job_guid': '1',
+ 'function_handle_string': 'foo.html:Foo',
+ 'trace_canonical_url': 'file://foo.html',
+ 'type': 'err',
+ 'description': 'desc',
+ 'stack': 'stack'
+ }
+
+ failure = failure_module.Failure.FromDict(failure_dict, job)
+
+ self.assertEquals(failure.job.guid, '1')
+ self.assertEquals(failure.function_handle_string, 'foo.html:Foo')
+ self.assertEquals(failure.trace_canonical_url, 'file://foo.html')
+ self.assertEquals(failure.failure_type_name, 'err')
+ self.assertEquals(failure.description, 'desc')
+ self.assertEquals(failure.stack, 'stack')
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/file_handle.html b/chromium/third_party/catapult/tracing/tracing/mre/file_handle.html
new file mode 100644
index 00000000000..85c1dd18abf
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/file_handle.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/base/guid.html">
+<link rel="import" href="/tracing/base/utils.html">
+<link rel="import" href="/tracing/base/xhr.html">
+<link rel="import" href="/tracing/extras/full_config.html">
+<link rel="import" href="/tracing/importer/import.html">
+<link rel="import" href="/tracing/model/model.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+ function FileHandle(canonicalUrl) {
+ this.canonicalUrl_ = canonicalUrl;
+ }
+
+ FileHandle.prototype = {
+ get canonicalUrl() { return this.canonicalUrl_; },
+
+ asDict: function() {
+ var d = {
+ canonical_url: this.canonicalUrl_
+ };
+
+ this._asDictInto(d);
+ if (d.type === undefined)
+ throw new Error('_asDictInto must set type field');
+ },
+
+ load: function() {
+ throw new Error('Not implemented');
+ }
+ };
+
+ FileHandle.fromDict = function(handleDict) {
+ if (handleDict.type === 'url')
+ return URLFileHandle.fromDict(handleDict);
+ if (handleDict.type === 'in-memory')
+ return InMemoryFileHandle.fromDict(handleDict);
+
+ throw new Error('Not implemented: fromDict for ' + handleDict.type);
+ };
+
+
+ function URLFileHandle(canonicalUrl, urlToLoad) {
+ // TODO(eakuefner): assert startswith file://
+ FileHandle.call(this, canonicalUrl);
+ this.urlToLoad = urlToLoad;
+ }
+
+ URLFileHandle.prototype = {
+ __proto__: FileHandle.prototype,
+
+ _asDictInto: function(handleDict) {
+ handleDict.urlToLoad = this.urlToLoad;
+ handleDict.type = 'url';
+ },
+
+ load: function() {
+ try {
+ return tr.b.getSync(this.urlToLoad);
+ } catch (ex) {
+ var err = new Error('Could not open ' + this.urlToLoad);
+ err.name = 'FileLoadingError';
+ throw err;
+ }
+ }
+ };
+
+
+ URLFileHandle.fromDict = function(handleDict) {
+ return new URLFileHandle(handleDict.canonical_url, handleDict.url_to_load);
+ };
+
+ function InMemoryFileHandle(fileData, canonicalUrl) {
+ FileHandle.call(this, canonicalUrl);
+ this.fileData = fileData;
+ }
+
+ InMemoryFileHandle.prototype = {
+ __proto__: FileHandle.prototype,
+
+ _asDictInto: function(handleDict) {
+ handleDict.data = this.fileData;
+ handleDict.type = 'in-memory';
+ },
+
+ load: function() {
+ return this.fileData;
+ }
+ };
+
+ InMemoryFileHandle.fromDict = function(handleDict) {
+ return new InMemoryFileHandle(
+ handleDict.data, handleDict.canonical_url);
+ };
+
+ return {
+ FileHandle: FileHandle,
+ URLFileHandle: URLFileHandle,
+ InMemoryFileHandle: InMemoryFileHandle,
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/file_handle.py b/chromium/third_party/catapult/tracing/tracing/mre/file_handle.py
new file mode 100644
index 00000000000..e89b2f348f0
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/file_handle.py
@@ -0,0 +1,100 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import contextlib
+import os
+import tempfile
+
+from tracing.mre import cloud_storage
+
+
+class FilePreparationError(Exception):
+ """Raised if something goes wrong while preparing a file for processing."""
+
+
+class FileHandle(object):
+ def __init__(self, canonical_url):
+ self._canonical_url = canonical_url
+
+ @property
+ def canonical_url(self):
+ return self._canonical_url
+
+ @contextlib.contextmanager
+ def PrepareFileForProcessing(self):
+ """Ensure that the URL to the file will be acessible during processing.
+
+ This function must do any pre-work to ensure that mappers will
+ be able to read from the URL contained in the file handle.
+
+ Raises:
+ FilePreparationError: If something went wrong while preparing the file.
+ """
+ yield self._WillProcess()
+ self._DidProcess()
+
+ def _WillProcess(self):
+ raise NotImplementedError()
+
+ def _DidProcess(self):
+ raise NotImplementedError()
+
+
+class URLFileHandle(FileHandle):
+ def __init__(self, canonical_url, url_to_load):
+ super(URLFileHandle, self).__init__(canonical_url)
+
+ self._url_to_load = url_to_load
+
+ def AsDict(self):
+ return {
+ 'type': 'url',
+ 'canonical_url': self._canonical_url,
+ 'url_to_load': self._url_to_load
+ }
+
+ def _WillProcess(self):
+ return self
+
+ def _DidProcess(self):
+ pass
+
+
+class GCSFileHandle(FileHandle):
+ def __init__(self, canonical_url, cache_directory):
+ super(GCSFileHandle, self).__init__(canonical_url)
+ file_name = canonical_url.split('/')[-1]
+ self.cache_file = os.path.join(
+ cache_directory, file_name + '.gz')
+
+ def _WillProcess(self):
+ if not os.path.exists(self.cache_file):
+ try:
+ cloud_storage.Copy(self.canonical_url, self.cache_file)
+ except cloud_storage.CloudStorageError:
+ return None
+ return URLFileHandle(self.canonical_url, 'file://' + self.cache_file)
+
+ def _DidProcess(self):
+ pass
+
+
+class InMemoryFileHandle(FileHandle):
+ def __init__(self, canonical_url, data):
+ super(InMemoryFileHandle, self).__init__(canonical_url)
+
+ self.data = data
+ self._temp_file_path = None
+
+ def _WillProcess(self):
+ temp_file = tempfile.NamedTemporaryFile(delete=False)
+ temp_file.write(self.data)
+ temp_file.close()
+ self._temp_file_path = temp_file.name
+
+ return URLFileHandle(self.canonical_url, 'file://' + self._temp_file_path)
+
+ def _DidProcess(self):
+ os.remove(self._temp_file_path)
+ self._temp_file_path = None
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/function_handle.html b/chromium/third_party/catapult/tracing/tracing/mre/function_handle.html
new file mode 100644
index 00000000000..b02889aff06
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/function_handle.html
@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ var FunctionRegistry = {
+ allFunctions_: [],
+ allFunctionsByName_: {},
+ get allFunctions() { return this.allFunctions_; },
+ get allFunctionsByName() { return this.allFunctionsByName_; }
+ };
+
+ FunctionRegistry.getFunction = function(name) {
+ return this.allFunctionsByName_[name];
+ };
+
+ FunctionRegistry.register = function(func) {
+ if (func.name === '')
+ throw new Error('Registered functions must not be anonymous');
+ if (this.allFunctionsByName[func.name] !== undefined)
+ throw new Error('Function named ' + func.name + 'is already registered.');
+ this.allFunctionsByName[func.name] = func;
+ this.allFunctions.push(func);
+ };
+
+ function ModuleToLoad(href, filename) {
+ if ((href !== undefined) ? (filename !== undefined) :
+ (filename === undefined)) {
+ throw new Error('ModuleToLoad must specify exactly one of href or ' +
+ 'filename');
+ }
+ this.href = href;
+ this.filename = filename;
+ }
+
+ ModuleToLoad.prototype = {
+ asDict: function() {
+ if (this.href !== undefined)
+ return {'href': this.href};
+ return {'filename': this.filename};
+ },
+
+ toString: function() {
+ if (this.href !== undefined)
+ return 'ModuleToLoad(href="' + this.href + '")';
+ return 'ModuleToLoad(filename="' + this.filename + '")';
+ }
+ };
+
+ ModuleToLoad.fromDict = function(moduleDict) {
+ return new ModuleToLoad(moduleDict.href, moduleDict.filename);
+ };
+
+ function FunctionHandle(modulesToLoad, functionName, opt_options) {
+ if (!(modulesToLoad instanceof Array))
+ throw new Error('modulesToLoad in FunctionHandle must be an array');
+ if (typeof(functionName) !== 'string')
+ throw new Error('functionName in FunctionHandle must be a string');
+ this.modulesToLoad = modulesToLoad;
+ this.functionName = functionName;
+ this.options_ = opt_options;
+ };
+
+ FunctionHandle.prototype = {
+ get options() {
+ return this.options_;
+ },
+
+ asDict: function() {
+ return {
+ 'modules_to_load': this.modulesToLoad.map(
+ function(m) {return m.asDict();}),
+ 'function_name': this.functionName,
+ 'options': this.options_
+ };
+ },
+
+ asUserFriendlyString: function() {
+ var parts = this.modulesToLoad.map(function(mtl) {return mtl.filename});
+ parts.push(this.functionName);
+ parts.push(JSON.stringify(this.options_));
+ return parts.join(',');
+ },
+
+ hasHrefs: function() {
+ for (var module in this.modulesToLoad) {
+ if (this.modulesToLoad[module].href !== undefined) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ load: function() {
+ if (this.hasHrefs()) {
+ var err = new Error(
+ 'FunctionHandle named ' + this.functionName +
+ ' specifies hrefs, which cannot be loaded.');
+ err.name = 'FunctionLoadingError';
+ throw err;
+ }
+
+ for (var module in this.modulesToLoad) {
+ var filename = this.modulesToLoad[module].filename;
+ try {
+ HTMLImportsLoader.loadHTMLFile(filename);
+ } catch (err) {
+ err.name = 'FunctionLoadingError';
+ throw err;
+ }
+ }
+
+ var func = FunctionRegistry.getFunction(this.functionName);
+ if (func === undefined) {
+ var err = new Error(
+ 'No registered function named ' + this.functionName);
+ err.name = 'FunctionNotDefinedError';
+ throw err;
+ }
+
+ return func;
+ },
+
+ toString: function() {
+ var modulesToLoadStr = this.modulesToLoad.map(function(module) {
+ return module.toString();
+ });
+ return 'FunctionHandle(modulesToLoad=[' + modulesToLoadStr + '], ' +
+ 'functionName="' + this.functionName + '", options="' +
+ JSON.stringify(this.options_) + '")';
+ }
+ };
+
+ FunctionHandle.loadFromFilename_ = function(filename) {
+ try {
+ var numFunctionsBefore = FunctionRegistry.allFunctions.length;
+ HTMLImportsLoader.loadHTMLFile(filename);
+ } catch (err) {
+ err.name = 'FunctionLoadingError';
+ throw err;
+ }
+
+ // Verify a new function was registered.
+ var numFunctionsNow = FunctionRegistry.allFunctions.length;
+ if (numFunctionsNow !== (numFunctionsBefore + 1)) {
+ var err = new Error(filename + " didn't call FunctionRegistry.register");
+ err.name = 'FunctionNotDefinedError';
+ throw err;
+ }
+
+ return FunctionRegistry.allFunctions[numFunctionsNow - 1];
+ };
+
+ FunctionHandle.fromDict = function(handleDict) {
+ var options = handleDict.options;
+ if (handleDict.modules_to_load !== undefined) {
+ var modulesToLoad = handleDict.modules_to_load.map(function(module) {
+ return ModuleToLoad.fromDict(module);
+ });
+ }
+ return new FunctionHandle(modulesToLoad, handleDict.function_name, options);
+ };
+
+ return {
+ FunctionHandle: FunctionHandle,
+ ModuleToLoad: ModuleToLoad,
+ FunctionRegistry: FunctionRegistry
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/function_handle.py b/chromium/third_party/catapult/tracing/tracing/mre/function_handle.py
new file mode 100644
index 00000000000..1efa5d647a9
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/function_handle.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import uuid
+
+
+class AbspathInvalidError(Exception):
+ """Raised if an abspath cannot be sanitized based on an app's source paths."""
+
+
+class UserFriendlyStringInvalidError(Exception):
+ """Raised if a user friendly string cannot be parsed."""
+
+
+class ModuleToLoad(object):
+
+ def __init__(self, href=None, filename=None):
+ if bool(href) == bool(filename):
+ raise Exception('ModuleToLoad must specify exactly one of href and '
+ 'filename.')
+ self.href = href
+ self.filename = filename
+
+ def __repr__(self):
+ if self.href:
+ return 'ModuleToLoad(href="%s")' % self.href
+ return 'ModuleToLoad(filename="%s")' % self.filename
+
+ def AsDict(self):
+ if self.href:
+ return {'href': self.href}
+ return {'filename': self.filename}
+
+ @staticmethod
+ def FromDict(module_dict):
+ return ModuleToLoad(module_dict.get('href'), module_dict.get('filename'))
+
+
+class FunctionHandle(object):
+
+ def __init__(self, modules_to_load=None, function_name=None,
+ options=None, guid=uuid.uuid4()):
+ self.modules_to_load = modules_to_load
+ self.function_name = function_name
+ self.options = options
+ self._guid = guid
+
+ def __repr__(self):
+ return 'FunctionHandle(modules_to_load=[%s], function_name="%s")' % (
+ ', '.join([str(module) for module in self.modules_to_load]),
+ self.function_name)
+
+ @property
+ def guid(self):
+ return self._guid
+
+ @property
+ def has_hrefs(self):
+ return any(module.href for module in self.modules_to_load)
+
+ def AsDict(self):
+ handle_dict = {
+ 'function_name': self.function_name
+ }
+
+ if self.modules_to_load is not None:
+ handle_dict['modules_to_load'] = [module.AsDict() for module in
+ self.modules_to_load]
+ if self.options is not None:
+ handle_dict['options'] = self.options
+
+ return handle_dict
+
+ def ConvertHrefsToAbsFilenames(self, app):
+ """Converts hrefs to absolute filenames in the context of |app|.
+
+ In an app-serving context, functions must only reside in files which the app
+ is serving, in order to prevent directory traversal attacks. In addition, we
+ rely on paths being absolute when actually executing functions.
+
+ Args:
+ app: A dev server instance requesting abspath conversion.
+
+ Returns:
+ A new FunctionHandle instance with no hrefs.
+
+ Raises:
+ AbspathInvalidError: If there is no source path with which a given abspath
+ shares a common prefix.
+ """
+ new_modules_to_load = []
+ for module in self.modules_to_load:
+ if module.href:
+ abspath = app.GetAbsFilenameForHref(module.href)
+ else:
+ assert os.path.abspath(module.filename) == module.filename
+ abspath = module.filename
+
+ if not abspath:
+ raise AbspathInvalidError('Filename %s invalid', abspath)
+
+ new_modules_to_load.append(ModuleToLoad(filename=abspath))
+
+ return FunctionHandle(modules_to_load=new_modules_to_load,
+ function_name=self.function_name)
+
+ @staticmethod
+ def FromDict(handle_dict):
+ if handle_dict.get('modules_to_load') is not None:
+ modules_to_load = [ModuleToLoad.FromDict(module_dict) for module_dict in
+ handle_dict['modules_to_load']]
+ else:
+ modules_to_load = []
+ options = handle_dict.get('options')
+ return FunctionHandle(modules_to_load=modules_to_load,
+ function_name=handle_dict['function_name'],
+ options=options)
+
+ def AsUserFriendlyString(self, app):
+ parts = [module.filename for module in
+ self.ConvertHrefsToAbsFilenames(app).modules_to_load]
+ parts.append(self.function_name)
+
+ return ':'.join(parts)
+
+ @staticmethod
+ def FromUserFriendlyString(user_str):
+ parts = user_str.split(':')
+ if len(parts) < 2:
+ raise UserFriendlyStringInvalidError(
+ 'Tried to deserialize string with less than two parts: ' + user_str)
+
+ modules_to_load = [ModuleToLoad(filename=name) for name in parts[:-1]]
+
+ return FunctionHandle(modules_to_load=modules_to_load,
+ function_name=parts[-1])
+
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/function_handle_test.html b/chromium/third_party/catapult/tracing/tracing/mre/function_handle_test.html
new file mode 100644
index 00000000000..df917cc1728
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/function_handle_test.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/mre/function_handle.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('moduleToLoadExactlyOneHrefOrFilename', function() {
+ assert.throws(function() {tr.mre.ModuleToLoad('foo', 'foo')});
+ assert.throws(tr.mre.ModuleToLoad);
+ });
+
+ test('moduleToLoadAsDictTest', function() {
+ var mtl0 = new tr.mre.ModuleToLoad('/foo');
+ var mtl1 = new tr.mre.ModuleToLoad(undefined, 'foo.html');
+
+ assert.deepEqual(mtl0.asDict(), {'href': '/foo'});
+ assert.deepEqual(mtl1.asDict(), {'filename': 'foo.html'});
+ });
+
+ test('moduleToLoadFromDictTest', function() {
+ var moduleDict0 = {
+ href: '/foo'
+ };
+ var moduleDict1 = {
+ filename: 'foo.html'
+ };
+
+ var mtl0 = tr.mre.ModuleToLoad.fromDict(moduleDict0);
+ var mtl1 = tr.mre.ModuleToLoad.fromDict(moduleDict1);
+
+ assert.equal(mtl0.href, '/foo');
+ assert.isUndefined(mtl0.filename);
+ assert.equal(mtl1.filename, 'foo.html');
+ assert.isUndefined(mtl1.href);
+ });
+
+ test('moduleToLoadToStringTest', function() {
+ var mtl0 = new tr.mre.ModuleToLoad('/foo');
+ var mtl1 = new tr.mre.ModuleToLoad(undefined, 'foo.html');
+
+ assert.equal(
+ mtl0.toString(),
+ 'ModuleToLoad(href="/foo")');
+ assert.equal(
+ mtl1.toString(),
+ 'ModuleToLoad(filename="foo.html")');
+ });
+
+ test('modulesToLoadMustBeArrayTest', function() {
+ assert.throws(tr.mre.FunctionHandle);
+ });
+
+ test('functionNameMustBeStringTest', function() {
+ assert.throws(function() {tr.mre.FunctionHandle([], 3);});
+ });
+
+ test('asDictTest', function() {
+ var module = new tr.mre.ModuleToLoad('/foo');
+ var handle = new tr.mre.FunctionHandle([module], 'Bar', {'a': 'b'});
+
+ assert.deepEqual(handle.asDict(), {
+ modules_to_load: [{href: '/foo'}],
+ function_name: 'Bar',
+ options: {'a': 'b'}
+ });
+ });
+
+ test('fromDictTest', function() {
+ var handleDict = {
+ modules_to_load: [{href: '/foo'}],
+ function_name: 'Bar'
+ };
+
+ var handle = tr.mre.FunctionHandle.fromDict(handleDict);
+
+ assert.equal(handle.modulesToLoad.length, 1);
+ assert.equal(handle.modulesToLoad[0].href, '/foo');
+ assert.equal(handle.functionName, 'Bar');
+ });
+
+ test('hasHrefsTest', function() {
+ var module0 = new tr.mre.ModuleToLoad('/foo');
+ var handle0 = new tr.mre.FunctionHandle([module0], 'Bar');
+ var module1 = new tr.mre.ModuleToLoad(undefined, 'foo.html');
+ var handle1 = new tr.mre.FunctionHandle([module1], 'Bar');
+
+ assert.isTrue(handle0.hasHrefs());
+ assert.isFalse(handle1.hasHrefs());
+ });
+
+ test('loadFailsWithHrefs', function() {
+ var module = new tr.mre.ModuleToLoad('/foo');
+ var handle = new tr.mre.FunctionHandle([module], 'railMapFunction');
+
+ assert.throws(handle.load);
+ });
+
+ test('loadFailsUnregistered', function() {
+ var handle = new tr.mre.FunctionHandle([], 'Bar');
+
+ assert.throws(handle.load);
+ });
+
+ test('toStringTest', function() {
+ var module = new tr.mre.ModuleToLoad('/foo');
+ var handle = new tr.mre.FunctionHandle([module], 'Bar', {'a': 'b'});
+
+ assert.equal(
+ handle.toString(),
+ 'FunctionHandle(modulesToLoad=[ModuleToLoad(href="/foo")], ' +
+ 'functionName="Bar", options="{"a":"b"}")');
+ });
+});
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/function_handle_unittest.py b/chromium/third_party/catapult/tracing/tracing/mre/function_handle_unittest.py
new file mode 100644
index 00000000000..d3bf71dfe66
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/function_handle_unittest.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from tracing.mre import function_handle
+
+
+class ModuleToLoadTests(unittest.TestCase):
+
+ def testExactlyOneHrefOrFilename(self):
+ with self.assertRaises(Exception):
+ function_handle.ModuleToLoad()
+
+ with self.assertRaises(Exception):
+ function_handle.ModuleToLoad('foo', 'foo')
+
+ def testRepr(self):
+ mtl0 = function_handle.ModuleToLoad(href='/foo')
+ mtl1 = function_handle.ModuleToLoad(filename='foo.html')
+
+ self.assertEquals(str(mtl0), 'ModuleToLoad(href="/foo")')
+ self.assertEquals(str(mtl1), 'ModuleToLoad(filename="foo.html")')
+
+ def testAsDict(self):
+ mtl0 = function_handle.ModuleToLoad(href='/foo')
+ mtl1 = function_handle.ModuleToLoad(filename='foo.html')
+
+ self.assertEquals(mtl0.AsDict(), {
+ 'href': '/foo'
+ })
+
+ self.assertEquals(mtl1.AsDict(), {
+ 'filename': 'foo.html'
+ })
+
+ def testFromDict(self):
+ module_dict0 = {
+ 'href': '/foo'
+ }
+
+ module_dict1 = {
+ 'filename': 'foo.html'
+ }
+
+ mtl0 = function_handle.ModuleToLoad.FromDict(module_dict0)
+ mtl1 = function_handle.ModuleToLoad.FromDict(module_dict1)
+
+ self.assertEquals(mtl0.href, '/foo')
+ self.assertIsNone(mtl0.filename)
+ self.assertEquals(mtl1.filename, 'foo.html')
+ self.assertIsNone(mtl1.href)
+
+
+class FunctionHandleTests(unittest.TestCase):
+
+ def testRepr(self):
+ module = function_handle.ModuleToLoad(href='/foo')
+ handle = function_handle.FunctionHandle([module], 'Bar')
+
+ self.assertEquals(
+ str(handle),
+ 'FunctionHandle(modules_to_load=[ModuleToLoad(href="/foo")], '
+ 'function_name="Bar")')
+
+ def testAsDict(self):
+ module = function_handle.ModuleToLoad(href='/foo')
+ handle = function_handle.FunctionHandle([module], 'Bar')
+
+ self.assertEquals(
+ handle.AsDict(), {
+ 'modules_to_load': [{'href': '/foo'}],
+ 'function_name': 'Bar'
+ })
+
+ def testFromDict(self):
+ handle_dict = {
+ 'modules_to_load': [{'href': '/foo'}],
+ 'function_name': 'Bar'
+ }
+
+ handle = function_handle.FunctionHandle.FromDict(handle_dict)
+ self.assertEquals(len(handle.modules_to_load), 1)
+ self.assertEquals(handle.modules_to_load[0].href, '/foo')
+ self.assertEquals(handle.function_name, 'Bar')
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/gtest_progress_reporter.py b/chromium/third_party/catapult/tracing/tracing/mre/gtest_progress_reporter.py
new file mode 100644
index 00000000000..e59ff699bc6
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/gtest_progress_reporter.py
@@ -0,0 +1,88 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import time
+import sys
+
+from tracing.mre import progress_reporter
+
+
+class GTestRunReporter(progress_reporter.RunReporter):
+
+ def __init__(self, canonical_url, output_stream, timestamp):
+ super(GTestRunReporter, self).__init__(canonical_url)
+ self._output_stream = output_stream
+ self._timestamp = timestamp
+
+ def _GetMs(self):
+ assert self._timestamp is not None, 'Did not call WillRun.'
+ return (time.time() - self._timestamp) * 1000
+
+ def DidAddFailure(self, failure):
+ super(GTestRunReporter, self).DidAddFailure(failure)
+ print >> self._output_stream, failure.stack
+ self._output_stream.flush()
+
+ def DidRun(self, run_failed):
+ super(GTestRunReporter, self).DidRun(run_failed)
+ if run_failed:
+ print >> self._output_stream, '[ FAILED ] %s (%0.f ms)' % (
+ self.canonical_url, self._GetMs())
+ else:
+ print >> self._output_stream, '[ OK ] %s (%0.f ms)' % (
+ self.canonical_url, self._GetMs())
+ self._output_stream.flush()
+
+
+class GTestProgressReporter(progress_reporter.ProgressReporter):
+ """A progress reporter that outputs the progress report in gtest style.
+
+ Be careful each print should only handle one string. Otherwise, the output
+ might be interrupted by Chrome logging, and the output interpretation might
+ be incorrect. For example:
+ print >> self._output_stream, "[ OK ]", testname
+ should be written as
+ print >> self._output_stream, "[ OK ] %s" % testname
+ """
+
+ def __init__(self, output_stream=sys.stdout):
+ super(GTestProgressReporter, self).__init__()
+ self._output_stream = output_stream
+
+ def WillRun(self, canonical_url):
+ super(GTestProgressReporter, self).WillRun(canonical_url)
+ print >> self._output_stream, '[ RUN ] %s' % (canonical_url)
+ self._output_stream.flush()
+ return GTestRunReporter(canonical_url, self._output_stream, time.time())
+
+ def DidFinishAllRuns(self, result_list):
+ super(GTestProgressReporter, self).DidFinishAllRuns(result_list)
+ successful_runs = 0
+ failed_canonical_urls = []
+ failed_runs = 0
+ for run in result_list:
+ if len(run.failures) != 0:
+ failed_runs += 1
+ for f in run.failures:
+ failed_canonical_urls.append(f.trace_canonical_url)
+ else:
+ successful_runs += 1
+
+ unit = 'test' if successful_runs == 1 else 'tests'
+ print >> self._output_stream, '[ PASSED ] %d %s.' % (
+ (successful_runs, unit))
+ if len(failed_canonical_urls) > 0:
+ unit = 'test' if len(failed_canonical_urls) == 1 else 'tests'
+ print >> self._output_stream, '[ FAILED ] %d %s, listed below:' % (
+ (failed_runs, unit))
+ for failed_canonical_url in failed_canonical_urls:
+ print >> self._output_stream, '[ FAILED ] %s' % (
+ failed_canonical_url)
+ print >> self._output_stream
+ count = len(failed_canonical_urls)
+ unit = 'TEST' if count == 1 else 'TESTS'
+ print >> self._output_stream, '%d FAILED %s' % (count, unit)
+ print >> self._output_stream
+
+ self._output_stream.flush()
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/job.html b/chromium/third_party/catapult/tracing/tracing/mre/job.html
new file mode 100644
index 00000000000..b92dad0c75d
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/job.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/base/guid.html">
+<link rel="import" href="/tracing/mre/function_handle.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ function Job(mapFunctionHandle, opt_guid) {
+ this.mapFunctionHandle_ = mapFunctionHandle;
+ if (opt_guid === undefined)
+ this.guid_ = tr.b.GUID.allocateSimple();
+ else
+ this.guid_ = opt_guid;
+ }
+
+ Job.prototype = {
+ get mapFunctionHandle() { return this.mapFunctionHandle_; },
+ get guid() { return this.guid_; },
+
+ asDict: function() {
+ return {
+ map_function_handle: this.mapFunctionHandle_.asDict(),
+ guid: this.guid_.toString()
+ };
+ }
+ };
+
+ Job.fromDict = function(jobDict) {
+ var mapFunctionHandle = null;
+ if (jobDict.map_function_handle !== null) {
+ mapFunctionHandle = tr.mre.FunctionHandle.fromDict(
+ jobDict.map_function_handle);
+ }
+
+ return new Job(mapFunctionHandle, jobDict.guid);
+ };
+
+ return {
+ Job: Job
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/job.py b/chromium/third_party/catapult/tracing/tracing/mre/job.py
new file mode 100644
index 00000000000..1c3a978c83c
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/job.py
@@ -0,0 +1,36 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import uuid
+
+from tracing.mre import function_handle
+
+
+class Job(object):
+
+ def __init__(self, map_function_handle, guid=uuid.uuid4()):
+ assert map_function_handle is not None
+
+ self._map_function_handle = map_function_handle
+ self._guid = guid
+
+ @property
+ def guid(self):
+ return self._guid
+
+ @property
+ def map_function_handle(self):
+ return self._map_function_handle
+
+ def AsDict(self):
+ values_dict = {
+ 'map_function_handle': self._map_function_handle.AsDict(),
+ 'guid': str(self._guid)
+ }
+ return values_dict
+
+ @staticmethod
+ def FromDict(job_dict):
+ return Job(
+ function_handle.FunctionHandle.FromDict(
+ job_dict['map_function_handle']))
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/json_output_formatter.py b/chromium/third_party/catapult/tracing/tracing/mre/json_output_formatter.py
new file mode 100644
index 00000000000..aafc8838de3
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/json_output_formatter.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import json
+
+from tracing.mre import output_formatter
+
+
+class JSONOutputFormatter(output_formatter.OutputFormatter):
+
+ def __init__(self, output_file):
+ # TODO(nduca): Resolve output_file here vs output_stream in base class.
+ super(JSONOutputFormatter, self).__init__(output_file)
+ self.output_file = output_file
+
+ def Format(self, result_list):
+ d = [result.AsDict() for result in result_list]
+ json.dump(d, self.output_file, indent=2)
+ if hasattr(self.output_file, 'flush'):
+ self.output_file.flush()
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/local_directory_corpus_driver.py b/chromium/third_party/catapult/tracing/tracing/mre/local_directory_corpus_driver.py
new file mode 100644
index 00000000000..c156f7311d7
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/local_directory_corpus_driver.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import os
+
+from tracing.mre import corpus_driver
+from tracing.mre import file_handle
+
+
+def _GetFilesIn(basedir):
+ data_files = []
+ for dirpath, dirnames, filenames in os.walk(basedir, followlinks=True):
+ new_dirnames = [d for d in dirnames if not d.startswith('.')]
+ del dirnames[:]
+ dirnames += new_dirnames
+ for f in filenames:
+ if f.startswith('.'):
+ continue
+ if f == 'README.md':
+ continue
+ full_f = os.path.join(dirpath, f)
+ rel_f = os.path.relpath(full_f, basedir)
+ data_files.append(rel_f)
+
+ data_files.sort()
+ return data_files
+
+
+def _DefaultUrlResover(abspath):
+ return 'file:///%s' % abspath
+
+
+class LocalDirectoryCorpusDriver(corpus_driver.CorpusDriver):
+
+ def __init__(self, trace_directory, url_resolver=_DefaultUrlResover):
+ self.directory = trace_directory
+ self.url_resolver = url_resolver
+
+ @staticmethod
+ def CheckAndCreateInitArguments(parser, args):
+ trace_dir = os.path.abspath(os.path.expanduser(args.trace_directory))
+ if not os.path.exists(trace_dir):
+ parser.error('Trace directory does not exist')
+ return None
+ return {'trace_directory': trace_dir}
+
+ @staticmethod
+ def AddArguments(parser):
+ parser.add_argument(
+ '--trace_directory',
+ help='Local directory containing traces to process.')
+
+ def GetTraceHandles(self):
+ trace_handles = []
+
+ files = _GetFilesIn(self.directory)
+ for rel_filename in files:
+ filename = os.path.join(self.directory, rel_filename)
+
+ url = self.url_resolver(filename)
+ if url is None:
+ url = _DefaultUrlResover(filename)
+
+ th = file_handle.URLFileHandle(url, 'file://' + filename)
+ trace_handles.append(th)
+
+ return trace_handles
+
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_runner.py b/chromium/third_party/catapult/tracing/tracing/mre/map_runner.py
new file mode 100644
index 00000000000..5b3deca8ab8
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_runner.py
@@ -0,0 +1,105 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import multiprocessing
+import sys
+
+from tracing.mre import map_single_trace
+from tracing.mre import threaded_work_queue
+from tracing.mre import gtest_progress_reporter
+
+AUTO_JOB_COUNT = -1
+
+
+class MapError(Exception):
+
+ def __init__(self, *args):
+ super(MapError, self).__init__(*args)
+ self.canonical_url = None
+
+
+class MapRunner(object):
+ def __init__(self, trace_handles, job,
+ stop_on_error=False, progress_reporter=None,
+ jobs=AUTO_JOB_COUNT,
+ output_formatters=None,
+ extra_import_options=None):
+ self._job = job
+ self._stop_on_error = stop_on_error
+ self._failed_canonical_url_to_dump = None
+ if progress_reporter is None:
+ self._progress_reporter = gtest_progress_reporter.GTestProgressReporter(
+ sys.stdout)
+ else:
+ self._progress_reporter = progress_reporter
+ self._output_formatters = output_formatters or []
+ self._extra_import_options = extra_import_options
+
+ self._trace_handles = trace_handles
+ self._num_traces_merged_into_results = 0
+ self._map_results = None
+ self._map_results_file = None
+
+ if jobs == AUTO_JOB_COUNT:
+ jobs = multiprocessing.cpu_count()
+ self._wq = threaded_work_queue.ThreadedWorkQueue(num_threads=jobs)
+
+ def _ProcessOneTrace(self, trace_handle):
+ canonical_url = trace_handle.canonical_url
+ run_reporter = self._progress_reporter.WillRun(canonical_url)
+ result = map_single_trace.MapSingleTrace(
+ trace_handle,
+ self._job,
+ extra_import_options=self._extra_import_options)
+
+ had_failure = len(result.failures) > 0
+
+ for f in result.failures:
+ run_reporter.DidAddFailure(f)
+ run_reporter.DidRun(had_failure)
+
+ self._wq.PostMainThreadTask(
+ self._MergeResultIntoMaster, result, trace_handle)
+
+ def _MergeResultIntoMaster(self, result, trace_handle):
+ self._map_results[trace_handle.canonical_url] = result
+
+ had_failure = len(result.failures) > 0
+ if self._stop_on_error and had_failure:
+ err = MapError("Mapping error")
+ self._AbortMappingDueStopOnError(err)
+ raise err
+
+ self._num_traces_merged_into_results += 1
+ if self._num_traces_merged_into_results == len(self._trace_handles):
+ self._wq.PostMainThreadTask(self._AllMappingDone)
+
+ def _AbortMappingDueStopOnError(self, err):
+ self._wq.Stop(err)
+
+ def _AllMappingDone(self):
+ self._wq.Stop()
+
+ def RunMapper(self):
+ self._map_results = {}
+
+ if not self._trace_handles:
+ err = MapError("No trace handles specified.")
+ raise err
+
+ if self._job.map_function_handle:
+ for trace_handle in self._trace_handles:
+ self._wq.PostAnyThreadTask(self._ProcessOneTrace, trace_handle)
+
+ self._wq.Run()
+
+ return self._map_results
+
+ def Run(self):
+ results_by_trace = self.RunMapper()
+ results = results_by_trace.values()
+
+ for of in self._output_formatters:
+ of.Format(results)
+
+ return results
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.html b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.html
new file mode 100644
index 00000000000..6dea20fb5a9
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/base/base.html">
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/utils.html">
+<link rel="import" href="/tracing/base/xhr.html">
+<link rel="import" href="/tracing/extras/full_config.html">
+<link rel="import" href="/tracing/importer/import.html">
+<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/mre/failure.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ var Failure = tr.mre.Failure;
+
+ function runAndConvertErrorsToFailures(result, job,
+ traceHandle, cb, opt_this) {
+ try {
+ cb.call(opt_this);
+ } catch (e) {
+ var err = tr.b.normalizeException(e);
+ // TODO(eakuefner): Set job once reduction is implemented.
+ result.addFailure(new Failure(
+ job, job.mapFunctionHandle.asUserFriendlyString(),
+ traceHandle.canonicalUrl, err.typeName, err.message, err.stack));
+ }
+ }
+
+ function mapSingleTrace(result, model, options, mapFunction) {
+ // Map the function.
+ var numPairsBeforeMapping = tr.b.dictionaryLength(result.pairs);
+ var numFailuresBeforeMapping = result.failures.length;
+ try {
+ mapFunction(result, model, options);
+ } catch (ex) {
+ ex.name = 'MapFunctionError';
+ throw ex;
+ }
+
+ var addedPairs = (tr.b.dictionaryLength(result.pairs) >
+ numPairsBeforeMapping);
+ var addedFailures = result.failures.length > numFailuresBeforeMapping;
+ if (!(addedPairs || addedFailures)) {
+ var err = new Error('Mapper did not add any results!');
+ err.name = 'NoResultsAddedError';
+ throw err;
+ }
+ }
+
+ return {
+ mapSingleTrace: mapSingleTrace,
+ runAndConvertErrorsToFailures: runAndConvertErrorsToFailures
+ };
+});
+</script>
+
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.py b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.py
new file mode 100644
index 00000000000..2bbde42170f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace.py
@@ -0,0 +1,135 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import json
+import os
+import re
+import sys
+import tempfile
+import types
+
+import tracing_project
+import vinn
+
+from tracing.mre import failure
+from tracing.mre import mre_result
+
+_MAP_SINGLE_TRACE_CMDLINE_PATH = os.path.join(
+ tracing_project.TracingProject.tracing_src_path, 'mre',
+ 'map_single_trace_cmdline.html')
+
+class TemporaryMapScript(object):
+ def __init__(self, js):
+ temp_file = tempfile.NamedTemporaryFile(delete=False)
+ temp_file.write("""
+<!DOCTYPE html>
+<script>
+%s
+</script>
+""" % js)
+ temp_file.close()
+ self._filename = temp_file.name
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args, **kwargs):
+ os.remove(self._filename)
+ self._filename = None
+
+ @property
+ def filename(self):
+ return self._filename
+
+
+class FunctionLoadingFailure(failure.Failure):
+ pass
+
+class FunctionNotDefinedFailure(failure.Failure):
+ pass
+
+class MapFunctionFailure(failure.Failure):
+ pass
+
+class FileLoadingFailure(failure.Failure):
+ pass
+
+class TraceImportFailure(failure.Failure):
+ pass
+
+class NoResultsAddedFailure(failure.Failure):
+ pass
+
+class InternalMapError(Exception):
+ pass
+
+_FAILURE_NAME_TO_FAILURE_CONSTRUCTOR = {
+ 'FileLoadingError': FileLoadingFailure,
+ 'FunctionLoadingError': FunctionLoadingFailure,
+ 'FunctionNotDefinedError': FunctionNotDefinedFailure,
+ 'TraceImportError': TraceImportFailure,
+ 'MapFunctionError': MapFunctionFailure,
+ 'NoResultsAddedError': NoResultsAddedFailure
+}
+
+
+def MapSingleTrace(trace_handle,
+ job,
+ extra_import_options=None):
+ assert (type(extra_import_options) is types.NoneType or
+ type(extra_import_options) is types.DictType), (
+ 'extra_import_options should be a dict or None.')
+ project = tracing_project.TracingProject()
+
+ all_source_paths = list(project.source_paths)
+ all_source_paths.append(project.trace_processor_root_path)
+
+ result = mre_result.MreResult()
+
+ with trace_handle.PrepareFileForProcessing() as prepared_trace_handle:
+ js_args = [
+ json.dumps(prepared_trace_handle.AsDict()),
+ json.dumps(job.AsDict()),
+ ]
+ if extra_import_options:
+ js_args.append(json.dumps(extra_import_options))
+
+ res = vinn.RunFile(
+ _MAP_SINGLE_TRACE_CMDLINE_PATH,
+ source_paths=all_source_paths,
+ js_args=js_args,
+ # Use 8gb heap space to make sure we don't OOM'ed on big trace.
+ v8_args=['--max-old-space-size=8192'])
+
+ if res.returncode != 0:
+ sys.stderr.write(res.stdout)
+ result.AddFailure(failure.Failure(
+ job,
+ trace_handle.canonical_url,
+ 'Error', 'vinn runtime error while mapping trace.',
+ 'vinn runtime error while mapping trace.', 'Unknown stack'))
+ return result
+
+ for line in res.stdout.split('\n'):
+ m = re.match('^MRE_RESULT: (.+)', line, re.DOTALL)
+ if m:
+ found_dict = json.loads(m.group(1))
+ failures = [
+ failure.Failure.FromDict(f, job, _FAILURE_NAME_TO_FAILURE_CONSTRUCTOR)
+ for f in found_dict['failures']]
+
+ for f in failures:
+ result.AddFailure(f)
+
+ for k, v in found_dict['pairs'].iteritems():
+ result.AddPair(k, v)
+
+ else:
+ if len(line) > 0:
+ sys.stderr.write(line)
+ sys.stderr.write('\n')
+
+ if not (len(result.pairs) or len(result.failures)):
+ raise InternalMapError('Internal error: No results were produced!')
+
+ return result
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_cmdline.html b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_cmdline.html
new file mode 100644
index 00000000000..175835eeb36
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_cmdline.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/mre/failure.html">
+<link rel="import" href="/tracing/mre/file_handle.html">
+<link rel="import" href="/tracing/mre/function_handle.html">
+<link rel="import" href="/tracing/mre/job.html">
+<link rel="import" href="/tracing/mre/map_single_trace.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ var Failure = tr.mre.Failure;
+
+ function createModelFromTraceData(traceData,
+ canonicalUrl,
+ opt_extraImportOptions) {
+ var model = new tr.Model();
+ try {
+ var importOptions = new tr.importer.ImportOptions();
+ importOptions.pruneEmptyContainers = false;
+ importOptions.showImportWarnings = false;
+ if (opt_extraImportOptions !== undefined) {
+ for (var property in opt_extraImportOptions) {
+ if (opt_extraImportOptions.hasOwnProperty(property)) {
+ importOptions[property] = opt_extraImportOptions[property];
+ }
+ }
+ }
+
+ var i = new tr.importer.Import(model, importOptions);
+ i.importTraces([traceData]);
+ } catch (ex) {
+ ex.name = 'TraceImportError';
+ throw ex;
+ }
+
+ model.canonicalUrl = canonicalUrl;
+
+ return model;
+ }
+
+ function mapSingleTraceWithResult(options) {
+ var result = new tr.mre.MreResult();
+
+ tr.mre.runAndConvertErrorsToFailures(
+ result, options.job, options.traceHandle,
+ function() {
+ var mapFunction = options.job.mapFunctionHandle.load();
+ var traceData = options.traceHandle.load();
+ var model = createModelFromTraceData(
+ traceData, options.traceHandle.canonicalUrl,
+ options.extraImportOptions);
+ var opt_options = options.job.mapFunctionHandle.options;
+ tr.mre.mapSingleTrace(result, model, opt_options, mapFunction);
+ });
+ return result;
+ }
+
+ function mapSingleTraceMain(args) {
+ if (args.length !== 2 && args.length !== 3)
+ throw new Error('Must provide two or three arguments.');
+
+ var options = {
+ traceHandle: tr.mre.FileHandle.fromDict(JSON.parse(args[0])),
+ job: tr.mre.Job.fromDict(JSON.parse(args[1])),
+ extraImportOptions: args.length === 3 ? JSON.parse(args[2]) : undefined
+ };
+
+ var result = mapSingleTraceWithResult(options);
+
+ console.log('MRE_RESULT: ' + JSON.stringify(result.asDict()));
+ return 0;
+ }
+
+ return {
+ mapSingleTraceMain: mapSingleTraceMain,
+ mapSingleTraceWithResult: mapSingleTraceWithResult
+ };
+});
+
+if (tr.isHeadless)
+ quit(tr.mre.mapSingleTraceMain(sys.argv.slice(1)));
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_unittest.py b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_unittest.py
new file mode 100644
index 00000000000..44744aa6b89
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_single_trace_unittest.py
@@ -0,0 +1,208 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import json
+import unittest
+
+from tracing.mre import function_handle
+from tracing.mre import map_single_trace
+from tracing.mre import file_handle
+from tracing.mre import failure
+from tracing.mre import job as job_module
+
+
+def _Handle(filename):
+ module = function_handle.ModuleToLoad(filename=filename)
+ map_handle = function_handle.FunctionHandle(
+ modules_to_load=[module], function_name='MyMapFunction')
+ return job_module.Job(map_handle, None)
+
+
+class MapSingleTraceTests(unittest.TestCase):
+
+ def testPassingMapScript(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'b', 'cat': 'c',
+ 'ts': 3, 'dur': 5, 'args': {}}
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(result, model) {
+ var canonicalUrl = model.canonicalUrl;
+ result.addPair('result', {
+ numProcesses: model.getAllProcesses().length
+ });
+ });
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertFalse(result.failures)
+ r = result.pairs['result']
+ self.assertEquals(r['numProcesses'], 1)
+
+
+ def testProcessingGiantTrace(self):
+ # Populate a string trace of 2 million events.
+ trace_events = ['[']
+ for i in xrange(2000000):
+ trace_events.append(
+ '{"pid": 1, "tid": %i, "ph": "X", "name": "a", "cat": "c",'
+ '"ts": %i, "dur": 1, "args": {}},' % (i % 5, 2 * i))
+ trace_events.append('{}]')
+ trace_data = ''.join(trace_events)
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', trace_data)
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(result, model) {
+ var canonicalUrl = model.canonicalUrl;
+ var numEvents = 0;
+ for (var e of model.getProcess(1).getDescendantEvents()) {
+ numEvents++;
+ }
+ result.addPair('result', {
+ numEvents: numEvents
+ });
+ });
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertFalse(result.failures,
+ msg='\n'.join(str(f) for f in result.failures))
+ r = result.pairs['result']
+ self.assertEquals(r['numEvents'], 2000000)
+
+
+
+ def testTraceDidntImport(self):
+ trace_string = 'This is intentionally not a trace-formatted string.'
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', trace_string)
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(results, model) {
+ });
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, map_single_trace.TraceImportFailure)
+
+ def testMapFunctionThatThrows(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'b', 'cat': 'c',
+ 'ts': 3, 'dur': 5, 'args': {}}
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(results, model) {
+ throw new Error('Expected error');
+ });
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, map_single_trace.MapFunctionFailure)
+
+ def testMapperWithLoadError(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'b', 'cat': 'c',
+ 'ts': 3, 'dur': 5, 'args': {}}
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ throw new Error('Expected load error');
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, map_single_trace.FunctionLoadingFailure)
+
+ def testMapperWithUnexpectedError(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ quit(100);
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, failure.Failure)
+
+ def testNoMapper(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'b', 'cat': 'c',
+ 'ts': 3, 'dur': 5, 'args': {}}
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, map_single_trace.FunctionNotDefinedFailure)
+
+ def testMapperDoesntAddValues(self):
+ events = [
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'a', 'cat': 'c',
+ 'ts': 0, 'dur': 10, 'args': {}},
+ {'pid': 1, 'tid': 2, 'ph': 'X', 'name': 'b', 'cat': 'c',
+ 'ts': 3, 'dur': 5, 'args': {}}
+ ]
+ trace_handle = file_handle.InMemoryFileHandle(
+ '/a.json', json.dumps(events))
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(results, model) {
+ });
+ """) as map_script:
+ result = map_single_trace.MapSingleTrace(trace_handle,
+ _Handle(map_script.filename))
+
+ self.assertEquals(len(result.failures), 1)
+ self.assertEquals(len(result.pairs), 0)
+ f = result.failures[0]
+ self.assertIsInstance(f, map_single_trace.NoResultsAddedFailure)
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_traces.py b/chromium/third_party/catapult/tracing/tracing/mre/map_traces.py
new file mode 100644
index 00000000000..749e7acab39
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_traces.py
@@ -0,0 +1,67 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import argparse
+import sys
+
+from tracing.mre import corpus_driver_cmdline
+from tracing.mre import map_runner
+from tracing.mre import function_handle
+from tracing.mre import job as job_module
+from tracing.mre import json_output_formatter
+
+
+def Main(argv):
+ parser = argparse.ArgumentParser(
+ description='Bulk trace processing')
+ parser.add_argument('--map_function_handle')
+ parser.add_argument('-j', '--jobs', type=int,
+ default=map_runner.AUTO_JOB_COUNT)
+ parser.add_argument('-o', '--output-file')
+ parser.add_argument('-s', '--stop-on-error',
+ action='store_true')
+
+ if len(sys.argv) == 1:
+ parser.print_help()
+ sys.exit(0)
+
+ args = parser.parse_args(argv[1:])
+
+ corpus_driver = corpus_driver_cmdline.GetCorpusDriver(parser, args)
+
+ if args.output_file:
+ ofile = open(args.output_file, 'w')
+ else:
+ ofile = sys.stdout
+
+ output_formatter = json_output_formatter.JSONOutputFormatter(ofile)
+
+ try:
+ map_handle = None
+ if args.map_function_handle:
+ map_handle = function_handle.FunctionHandle.FromUserFriendlyString(
+ args.map_function_handle)
+ job = job_module.Job(map_handle)
+ except function_handle.UserFriendlyStringInvalidError:
+ error_lines = [
+ 'The map_traces command-line API has changed! You must now specify the',
+ 'filenames to load and the map function name, separated by :. For '
+ 'example, a mapper in',
+ 'foo.html called Foo would be written as foo.html:Foo .'
+ ]
+ parser.error('\n'.join(error_lines))
+
+ try:
+ trace_handles = corpus_driver.GetTraceHandles()
+ runner = map_runner.MapRunner(trace_handles, job,
+ stop_on_error=args.stop_on_error,
+ jobs=args.jobs,
+ output_formatters=[output_formatter])
+ results = runner.Run()
+ if not any(result.failures for result in results):
+ return 0
+ else:
+ return 255
+ finally:
+ if ofile != sys.stdout:
+ ofile.close()
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/map_traces_handler.py b/chromium/third_party/catapult/tracing/tracing/mre/map_traces_handler.py
new file mode 100644
index 00000000000..ea9b0b6d533
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/map_traces_handler.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import webapp2
+
+
+def MapTrace(trace_corpus_driver): # pylint: disable=unused-argument
+ pass
+
+
+class MapTracesHandler(webapp2.RequestHandler):
+
+ def post(self, *args, **kwargs): # pylint: disable=unused-argument
+ pass
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/mre_result.html b/chromium/third_party/catapult/tracing/tracing/mre/mre_result.html
new file mode 100644
index 00000000000..e4f37cb53ed
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/mre_result.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/mre/failure.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+ class MreResult {
+ constructor(failures, pairs) {
+ if (failures === undefined)
+ failures = [];
+ if (pairs === undefined)
+ pairs = {};
+ this.failures = failures;
+ this.pairs = pairs;
+ }
+
+ addFailure(failure) {
+ this.failures.push(failure);
+ }
+
+ addPair(key, value) {
+ if (key in this.pairs)
+ throw new Error('Key ' + key + ' already exists in result.');
+ this.pairs[key] = value;
+ }
+
+ asDict() {
+ var d = {
+ pairs: this.pairs
+ };
+
+ if (this.failures)
+ d.failures = this.failures.map(function(f) {return f.asDict();});
+
+ return d;
+ }
+
+ hadFailures() {
+ return this.failures.length > 0;
+ }
+
+ static fromDict(resultDict) {
+ if (resultDict.failures !== undefined)
+ var failures = resultDict.failures.map(tr.mre.Failure.fromDict);
+ var pairs = resultDict.pairs;
+ return new MreResult(failures, pairs);
+ }
+ };
+
+ return {
+ MreResult: MreResult
+ };
+});
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/mre_result.py b/chromium/third_party/catapult/tracing/tracing/mre/mre_result.py
new file mode 100644
index 00000000000..f3d128e23a8
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/mre_result.py
@@ -0,0 +1,48 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from tracing.mre import failure as failure_module
+
+class DuplicateKeyError(Exception):
+ """Raised if an attempt is made to set a key more than once."""
+
+
+class MreResult(object):
+
+ def __init__(self, failures=None, pairs=None):
+ if failures is None:
+ failures = []
+ if pairs is None:
+ pairs = {}
+ self._failures = failures
+ self._pairs = pairs
+
+ @property
+ def failures(self):
+ return self._failures
+
+ @property
+ def pairs(self):
+ return self._pairs
+
+ def AsDict(self):
+ d = {
+ 'pairs': self._pairs
+ }
+
+ if self.failures:
+ d['failures'] = [failure.AsDict() for failure in self._failures]
+
+ return d
+
+ def AddFailure(self, failure):
+ if not isinstance(failure, failure_module.Failure):
+ raise ValueError('Attempted to add %s as Failure', failure)
+
+ self._failures.append(failure)
+
+ def AddPair(self, key, value):
+ if key in self._pairs:
+ raise DuplicateKeyError('Key ' + key + 'already exists in result.')
+ self._pairs[key] = value
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/mre_result_test.html b/chromium/third_party/catapult/tracing/tracing/mre/mre_result_test.html
new file mode 100644
index 00000000000..6fb94ea9d0e
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/mre_result_test.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/mre/failure.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('mreResultAsDictTest', function() {
+ var result = new tr.mre.MreResult();
+
+ var failure = new tr.mre.Failure('1', '2', '3', 'err', 'desc', 'stack');
+ result.addFailure(failure);
+
+ result.addPair('foo', 'bar');
+
+ var resultDict = result.asDict();
+
+ assert.deepEqual(resultDict.failures, [failure.asDict()]);
+ assert.deepEqual(resultDict.pairs, {foo: 'bar'});
+ });
+});
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/mre_result_unittest.py b/chromium/third_party/catapult/tracing/tracing/mre/mre_result_unittest.py
new file mode 100644
index 00000000000..2bdb5a8f19a
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/mre_result_unittest.py
@@ -0,0 +1,46 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from tracing.mre import function_handle
+from tracing.mre import map_single_trace
+from tracing.mre import failure as failure_module
+from tracing.mre import job as job_module
+from tracing.mre import mre_result
+
+
+class MreResultTests(unittest.TestCase):
+
+ def testAsDict(self):
+ result = mre_result.MreResult()
+
+ with map_single_trace.TemporaryMapScript("""
+ tr.mre.FunctionRegistry.register(
+ function MyMapFunction(result, model) {
+ var canonicalUrl = model.canonicalUrl;
+ result.addPair('result', {
+ numProcesses: model.getAllProcesses().length
+ });
+ });
+ """) as map_script:
+
+ module = function_handle.ModuleToLoad(filename=map_script.filename)
+ map_handle = function_handle.FunctionHandle(
+ modules_to_load=[module], function_name='MyMapFunction')
+ job = job_module.Job(map_handle, None)
+ failure = failure_module.Failure(job, '2', '3', 'err', 'desc', 'stack')
+ result.AddFailure(failure)
+
+ result.AddPair('foo', 'bar')
+
+ result_dict = result.AsDict()
+
+ self.assertEquals(result_dict['failures'], [failure.AsDict()])
+ self.assertEquals(result_dict['pairs'], {'foo': 'bar'})
+
+ def testAddingNonFailure(self):
+ result = mre_result.MreResult()
+ with self.assertRaises(ValueError):
+ result.AddFailure('foo')
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/output_formatter.py b/chromium/third_party/catapult/tracing/tracing/mre/output_formatter.py
new file mode 100644
index 00000000000..5a4be13acce
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/output_formatter.py
@@ -0,0 +1,19 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Derived from telemetry OutputFormatter. Should stay close in architecture
+# to telemetry OutputFormatter.
+
+
+class OutputFormatter(object):
+
+ def __init__(self, output_stream):
+ self._output_stream = output_stream
+
+ def Format(self, results):
+ raise NotImplementedError()
+
+ @property
+ def output_stream(self):
+ return self._output_stream
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/progress_reporter.py b/chromium/third_party/catapult/tracing/tracing/mre/progress_reporter.py
new file mode 100644
index 00000000000..b33d744da13
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/progress_reporter.py
@@ -0,0 +1,27 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class RunReporter(object):
+
+ def __init__(self, canonical_url):
+ self.canonical_url = canonical_url
+
+ def DidAddFailure(self, failure):
+ pass
+
+ def DidRun(self, run_failed):
+ pass
+
+
+# Derived from telemetry ProgressReporter. Should stay close in architecture
+# to telemetry ProgressReporter.
+class ProgressReporter(object):
+
+ def WillRun(self, canonical_url):
+ return RunReporter(canonical_url)
+
+ # TODO(eakuefner): Implement reduction, make this not take a result list.
+ def DidFinishAllRuns(self, result_list):
+ pass
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results.html b/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results.html
new file mode 100644
index 00000000000..85640090811
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/mre/failure.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ function reduceMapResults(jobResults, key, mapResults, reduceFunction) {
+ try {
+ var result = reduceFunction(key, mapResults);
+ jobResults.addPair(key, result);
+ } catch (ex) {
+ ex.name = 'ReduceFunctionError';
+ throw ex;
+ }
+ }
+
+ return {
+ reduceMapResults: reduceMapResults
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results_cmdline.html b/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results_cmdline.html
new file mode 100644
index 00000000000..1a99fcad758
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/reduce_map_results_cmdline.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/xhr.html">
+<link rel="import" href="/tracing/mre/file_handle.html">
+<link rel="import" href="/tracing/mre/job.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
+<link rel="import" href="/tracing/mre/reduce_map_results.html">
+<link rel="import" href="/tracing/mre/run_and_convert_errors_to_failures.html">
+<link rel="import" href="/tracing/value/histogram.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+
+ function jsonReplacer(key, value) {
+ if (value instanceof tr.v.Histogram) {
+ return value.asDict();
+ }
+ return value;
+ }
+
+ function reduceMapResultsMain(args) {
+ if (args.length !== 3)
+ throw new Error('Must provide three arguments');
+
+ var options = {
+ key: args[0],
+ fileHandle: tr.mre.FileHandle.fromDict(JSON.parse(args[1])),
+ job: tr.mre.Job.fromDict(JSON.parse(args[2]))
+ };
+
+ var mapResultsLoaded = options.fileHandle.load();
+ var mapResults = JSON.parse(mapResultsLoaded);
+
+ var jobResults = new tr.mre.MreResult();
+
+ tr.mre.runAndConvertErrorsToFailures(
+ jobResults, options.job, options.job.reduceFunctionHandle,
+ undefined,
+ function() {
+ var reduceFunction = options.job.reduceFunctionHandle.load();
+ tr.mre.reduceMapResults(jobResults, options.key, mapResults.pairs,
+ reduceFunction);
+ });
+
+ if (Object.keys(jobResults.pairs).length !== 0)
+ console.log('JOB_RESULTS: ' + JSON.stringify(jobResults.pairs,
+ jsonReplacer));
+ jobResults.failures.forEach(function(failure) {
+ console.log('JOB_FAILURE: ' + JSON.stringify(failure.asDict()));
+ });
+ return 0;
+ }
+
+ return {
+ reduceMapResultsMain: reduceMapResultsMain
+ };
+});
+
+
+if (tr.isHeadless)
+ quit(tr.mre.reduceMapResultsMain(sys.argv.slice(1)));
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/run_and_convert_errors_to_failures.html b/chromium/third_party/catapult/tracing/tracing/mre/run_and_convert_errors_to_failures.html
new file mode 100644
index 00000000000..6f7f4db9fbf
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/run_and_convert_errors_to_failures.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!--
+Copyright 2015 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/utils.html">
+<link rel="import" href="/tracing/mre/failure.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.mre', function() {
+ function runAndConvertErrorsToFailures(results, job, functionHandle,
+ traceHandle, cb, opt_this) {
+ try {
+ cb.call(opt_this);
+ } catch (e) {
+ var err = tr.b.normalizeException(e);
+ results.addFailure(new tr.mre.Failure(
+ job, functionHandle, traceHandle, err.typeName,
+ err.message, err.stack));
+ }
+ }
+
+ return {
+ runAndConvertErrorsToFailures: runAndConvertErrorsToFailures
+ };
+});
+
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue.py b/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue.py
new file mode 100644
index 00000000000..5bd29c46e32
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue.py
@@ -0,0 +1,121 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import threading
+import traceback
+import Queue
+
+
+class ThreadedWorkQueue(object):
+
+ def __init__(self, num_threads):
+ self._num_threads = num_threads
+
+ self._main_thread_tasks = None
+ self._any_thread_tasks = None
+
+ self._running = False
+ self._stop = False
+ self._stop_result = None
+
+ self.Reset()
+
+ @property
+ def is_running(self):
+ return self._running
+
+ def Run(self):
+ if self.is_running:
+ raise Exception('Already running')
+
+ self._running = True
+ self._stop = False
+ self._stop_result = None
+
+ if self._num_threads == 1:
+ self._RunSingleThreaded()
+ else:
+ self._RunMultiThreaded()
+
+ self._main_thread_tasks = Queue.Queue()
+ self._any_thread_tasks = Queue.Queue()
+
+ r = self._stop_result
+ self._stop_result = None
+ self._running = False
+
+ return r
+
+ def Stop(self, stop_result=None):
+ if not self.is_running:
+ raise Exception('Not running')
+
+ if self._stop:
+ return False
+ self._stop_result = stop_result
+ self._stop = True
+ return True
+
+ def Reset(self):
+ assert not self.is_running
+ self._main_thread_tasks = Queue.Queue()
+ self._any_thread_tasks = Queue.Queue()
+
+ def PostMainThreadTask(self, cb, *args, **kwargs):
+ def RunTask():
+ cb(*args, **kwargs)
+ self._main_thread_tasks.put(RunTask)
+
+ def PostAnyThreadTask(self, cb, *args, **kwargs):
+ def RunTask():
+ cb(*args, **kwargs)
+ self._any_thread_tasks.put(RunTask)
+
+ def _TryToRunOneTask(self, queue, block=False):
+ if block:
+ try:
+ task = queue.get(True, 0.1)
+ except Queue.Empty:
+ return
+ else:
+ if queue.empty():
+ return
+ task = queue.get()
+
+ try:
+ task()
+ except KeyboardInterrupt as ex:
+ raise ex
+ except Exception: # pylint: disable=broad-except
+ traceback.print_exc()
+ finally:
+ queue.task_done()
+
+ def _RunSingleThreaded(self):
+ while True:
+ if self._stop:
+ break
+ self._TryToRunOneTask(self._any_thread_tasks)
+ self._TryToRunOneTask(self._main_thread_tasks)
+
+ def _RunMultiThreaded(self):
+ threads = []
+ for _ in range(self._num_threads):
+ t = threading.Thread(target=self._ThreadMain)
+ t.setDaemon(True)
+ t.start()
+ threads.append(t)
+
+ while True:
+ if self._stop:
+ break
+ self._TryToRunOneTask(self._main_thread_tasks)
+
+ for t in threads:
+ t.join()
+
+ def _ThreadMain(self):
+ while True:
+ if self._stop:
+ break
+ self._TryToRunOneTask(self._any_thread_tasks, block=True)
diff --git a/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue_unittest.py b/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue_unittest.py
new file mode 100644
index 00000000000..6e93744540a
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/mre/threaded_work_queue_unittest.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import unittest
+
+from tracing.mre import threaded_work_queue
+
+
+class ThreadedWorkQueueTests(unittest.TestCase):
+
+ def testSingleThreaded(self):
+ wq = threaded_work_queue.ThreadedWorkQueue(num_threads=1)
+ self._RunSimpleDecrementingTest(wq)
+
+ def testMultiThreaded(self):
+ wq = threaded_work_queue.ThreadedWorkQueue(num_threads=4)
+ self._RunSimpleDecrementingTest(wq)
+
+ def _RunSimpleDecrementingTest(self, wq):
+
+ remaining = [10]
+
+ def Decrement():
+ remaining[0] -= 1
+ if remaining[0]:
+ wq.PostMainThreadTask(Done)
+
+ def Done():
+ wq.Stop(314)
+
+ wq.PostAnyThreadTask(Decrement)
+ res = wq.Run()
+ self.assertEquals(res, 314)
diff --git a/chromium/third_party/catapult/tracing/tracing/results2_template.html b/chromium/third_party/catapult/tracing/tracing/results2_template.html
index be556f742f8..3d9d0f157af 100644
--- a/chromium/third_party/catapult/tracing/tracing/results2_template.html
+++ b/chromium/third_party/catapult/tracing/tracing/results2_template.html
@@ -4,8 +4,8 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
-<link rel="import" href="/tracing/value/ui/value_set_table.html">
<link rel="import" href="/tracing/value/ui/value_set_view.html">
<link rel="import" href="/tracing/value/value_set.html">
@@ -17,6 +17,7 @@ found in the LICENSE file.
<script>
'use strict';
+
document.addEventListener('DOMContentLoaded', function() {
var valueSetJson = document.getElementById('value-set-json');
var values = new tr.v.ValueSet();
diff --git a/chromium/third_party/catapult/tracing/tracing/results_renderer.py b/chromium/third_party/catapult/tracing/tracing/results_renderer.py
new file mode 100644
index 00000000000..3c0c53502b9
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/results_renderer.py
@@ -0,0 +1,40 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+import re
+
+import tracing_project
+from py_vulcanize import generate
+
+
+_JSON_TAG = '<div id="value-set-json">%s</div>'
+
+
+def ReadExistingResults(output_stream):
+ output_stream.seek(0)
+ results_html = output_stream.read()
+ if not results_html:
+ return []
+ m = re.search(_JSON_TAG % '(.*?)', results_html, re.MULTILINE
+ | re.DOTALL)
+ if not m:
+ logging.warn('Failed to extract previous results from HTML output')
+ return []
+ return json.loads(m.group(1))
+
+
+def RenderHTMLView(values, output_stream, reset_results=False):
+ if not reset_results:
+ values += ReadExistingResults(output_stream)
+ vulcanizer = tracing_project.TracingProject().CreateVulcanizer()
+ load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(
+ ['tracing.results2_template'])
+ html = generate.GenerateStandaloneHTMLAsString(load_sequence)
+ html = html.replace(_JSON_TAG % '',
+ _JSON_TAG % json.dumps(values, separators=(',', ':')))
+ output_stream.seek(0)
+ output_stream.write(html)
+ output_stream.truncate()
diff --git a/chromium/third_party/catapult/tracing/tracing/results_renderer_unittest.py b/chromium/third_party/catapult/tracing/tracing/results_renderer_unittest.py
new file mode 100644
index 00000000000..c1d85350e01
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/results_renderer_unittest.py
@@ -0,0 +1,79 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import codecs
+import StringIO
+import json
+import unittest
+import os
+import tempfile
+
+from tracing import results_renderer
+
+
+# Wrap string IO with a .name property so that it behaves more like a file.
+class StringIOFile(StringIO.StringIO):
+ name = 'fake_output_file'
+
+
+class ResultsRendererTest(unittest.TestCase):
+
+ def setUp(self):
+ tmp = tempfile.NamedTemporaryFile(delete=False)
+ tmp.close()
+ self.output_file = tmp.name
+ self.output_stream = codecs.open(self.output_file,
+ mode='r+',
+ encoding='utf-8')
+
+ def GetOutputFileContent(self):
+ self.output_stream.seek(0)
+ return self.output_stream.read()
+
+ def tearDown(self):
+ self.output_stream.close()
+ os.remove(self.output_file)
+
+ def testBasic(self):
+ value0 = {'foo': 0}
+ value0_json = json.dumps(value0, separators=(',', ':'))
+
+ results_renderer.RenderHTMLView([], self.output_stream, False)
+ self.assertEquals([],
+ results_renderer.ReadExistingResults(self.output_stream))
+ results_renderer.RenderHTMLView([value0], self.output_stream, False)
+ self.assertEquals(
+ sorted([value0]),
+ sorted(results_renderer.ReadExistingResults(self.output_stream)))
+ self.assertIn(value0_json, self.GetOutputFileContent())
+
+ def testExistingResults(self):
+ value0 = {'foo': 0}
+ value0_json = json.dumps(value0, separators=(',', ':'))
+
+ value1 = {'bar': 1}
+ value1_json = json.dumps(value1, separators=(',', ':'))
+
+ results_renderer.RenderHTMLView([value0], self.output_stream, False)
+ results_renderer.RenderHTMLView([value1], self.output_stream, False)
+ self.assertEquals(
+ sorted([value0, value1]),
+ sorted(results_renderer.ReadExistingResults(self.output_stream)))
+ self.assertIn(value0_json, self.GetOutputFileContent())
+ self.assertIn(value1_json, self.GetOutputFileContent())
+
+ def testExistingResultsReset(self):
+ value0 = {'foo': 0}
+ value0_json = json.dumps(value0, separators=(',', ':'))
+
+ value1 = {'bar': 1}
+ value1_json = json.dumps(value1, separators=(',', ':'))
+
+ results_renderer.RenderHTMLView([value0], self.output_stream, False)
+ results_renderer.RenderHTMLView([value1], self.output_stream, True)
+ self.assertEquals(
+ sorted([value1]),
+ sorted(results_renderer.ReadExistingResults(self.output_stream)))
+ self.assertNotIn(value0_json, self.GetOutputFileContent())
+ self.assertIn(value1_json, self.GetOutputFileContent())
diff --git a/chromium/third_party/catapult/tracing/tracing/tests.html b/chromium/third_party/catapult/tracing/tracing/tests.html
index 11291418f0d..7924c0d039d 100644
--- a/chromium/third_party/catapult/tracing/tracing/tests.html
+++ b/chromium/third_party/catapult/tracing/tracing/tests.html
@@ -12,9 +12,7 @@ found in the LICENSE file.
<link rel="shortcut icon" href="data:image/x-icon;base64,"
type="image/x-icon">
- <script src="/components/webcomponentsjs/webcomponents.js"></script>
-
- <link rel="import" href="/components/polymer/polymer.html">
+ <link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
<link rel="import" href="/tracing/base/unittest/interactive_test_runner.html">
<style>
html, body {
@@ -30,14 +28,13 @@ found in the LICENSE file.
<script>
'use strict';
-
window.addEventListener('load', function() {
tr.b.unittest.loadAndRunTests({
title: 'All Trace-Viewer Tests',
getAllSuiteRelPathsAsync: function() {
return tr.b.getAsync('/tracing/tests').then(function(json) {
return JSON.parse(json).test_relpaths;
- }).catch (function(e) {
+ }).catch(function(e) {
throw e;
});
},
@@ -49,7 +46,6 @@ found in the LICENSE file.
]
});
});
-
</script>
</body>
</html>
diff --git a/chromium/third_party/catapult/tracing/tracing/trace2html.html b/chromium/third_party/catapult/tracing/tracing/trace2html.html
index 05790b5e676..4b410cb040e 100644
--- a/chromium/third_party/catapult/tracing/tracing/trace2html.html
+++ b/chromium/third_party/catapult/tracing/tracing/trace2html.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/base64.html">
+<link rel="import" href="/tracing/ui/base/base.html">
<link rel="import" href="/tracing/ui/timeline_view.html">
<script>
'use strict';
@@ -30,8 +31,8 @@ var g_timelineViewEl;
' outline: none;',
'}'
];
- styleEl.textContent = lines.join('\n');
- document.head.appendChild(styleEl);
+ Polymer.dom(styleEl).textContent = lines.join('\n');
+ Polymer.dom(document.head).appendChild(styleEl);
})();
document.addEventListener('DOMContentLoaded', function() {
@@ -39,16 +40,17 @@ document.addEventListener('DOMContentLoaded', function() {
container.id = 'track_view_container';
g_timelineViewEl = document.createElement('tr-ui-timeline-view');
- g_timelineViewEl.appendChild(container);
+ Polymer.dom(g_timelineViewEl).appendChild(container);
- document.body.appendChild(g_timelineViewEl);
+ Polymer.dom(document.body).appendChild(g_timelineViewEl);
var traces = [];
- var viewerDataScripts = document.querySelectorAll('#viewer-data');
+ var viewerDataScripts = Polymer.dom(document).querySelectorAll(
+ '#viewer-data');
for (var i = 0; i < viewerDataScripts.length; i++) {
- var text = viewerDataScripts[i].textContent;
+ var text = Polymer.dom(viewerDataScripts[i]).textContent;
// Trim leading newlines off the text. They happen during writing.
- while (text[0] == '\n')
+ while (text[0] === '\n')
text = text.substring(1);
traces.push(tr.b.Base64.atob(text));
}
@@ -65,7 +67,7 @@ document.addEventListener('DOMContentLoaded', function() {
},
function(err) {
var overlay = new tr.ui.b.Overlay();
- overlay.textContent = tr.b.normalizeException(err).message;
+ Polymer.dom(overlay).textContent = tr.b.normalizeException(err).message;
overlay.title = 'Import error';
overlay.visible = true;
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html
index 67ff160cea9..0d2cfecf43a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2015 The Chromium Authors. All rights reserved.
+Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
@@ -8,13 +8,13 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name="tr-ui-a-alert-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-alert-sub-view'>
<template>
<style>
:host {
@@ -24,138 +24,157 @@ found in the LICENSE file.
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table">
</tr-ui-b-table>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.currentSelection_ = undefined;
- this.$.table.tableColumns = [
- {
- title: 'Label',
- value: function(row) { return row.name; },
- width: '150px'
- },
- {
- title: 'Value',
- width: '100%',
- value: function(row) { return row.value; }
- }
- ];
- this.$.table.showHeader = false;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- this.currentSelection_ = selection;
- this.updateContents_();
- },
-
- getRowsForSingleAlert_: function(alert) {
- var rows = [];
-
- // Arguments
- for (var argName in alert.args) {
- var argView =
- document.createElement('tr-ui-a-generic-object-view');
- argView.object = alert.args[argName];
- rows.push({ name: argName, value: argView });
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-alert-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ ready: function() {
+ this.currentSelection_ = undefined;
+ this.$.table.tableColumns = [
+ {
+ title: 'Label',
+ value: function(row) { return row.name; },
+ width: '150px'
+ },
+ {
+ title: 'Value',
+ width: '100%',
+ value: function(row) { return row.value; }
}
+ ];
+ this.$.table.showHeader = false;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ this.currentSelection_ = selection;
+ this.updateContents_();
+ },
+
+ getRowsForSingleAlert_: function(alert) {
+ var rows = [];
+
+ // Arguments
+ for (var argName in alert.args) {
+ var argView =
+ document.createElement('tr-ui-a-generic-object-view');
+ argView.object = alert.args[argName];
+ rows.push({ name: argName, value: argView });
+ }
- // Associated events
- if (alert.associatedEvents.length) {
- alert.associatedEvents.forEach(function(event, i) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return event;
- }, event.title);
-
- var valueString = '';
- if (event instanceof tr.model.TimedEvent)
- valueString = 'took ' + event.duration.toFixed(2) + 'ms';
-
- rows.push({
- name: linkEl,
- value: valueString
- });
- });
- }
+ // Associated events
+ if (alert.associatedEvents.length) {
+ alert.associatedEvents.forEach(function(event, i) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(
+ new tr.model.EventSet(event), event.title);
- // Description
- var descriptionEl = tr.ui.b.createDiv({
- textContent: alert.info.description,
- maxWidth: '300px'
- });
- rows.push({
- name: 'Description',
- value: descriptionEl
+ var valueString = '';
+ if (event instanceof tr.model.TimedEvent)
+ valueString = 'took ' + event.duration.toFixed(2) + 'ms';
+
+ rows.push({
+ name: linkEl,
+ value: valueString
+ });
});
+ }
- // Additional Reading Links
- if (alert.info.docLinks) {
- alert.info.docLinks.forEach(function(linkObject) {
- var linkEl = document.createElement('a');
- linkEl.target = '_blank';
- linkEl.href = linkObject.href;
- linkEl.textContent = linkObject.textContent;
- rows.push({
- name: linkObject.label,
- value: linkEl
- });
+ // Description
+ var descriptionEl = tr.ui.b.createDiv({
+ textContent: alert.info.description,
+ maxWidth: '300px'
+ });
+ rows.push({
+ name: 'Description',
+ value: descriptionEl
+ });
+
+ // Additional Reading Links
+ if (alert.info.docLinks) {
+ alert.info.docLinks.forEach(function(linkObject) {
+ var linkEl = document.createElement('a');
+ linkEl.target = '_blank';
+ linkEl.href = linkObject.href;
+ Polymer.dom(linkEl).textContent = Polymer.dom(linkObject).textContent;
+ rows.push({
+ name: linkObject.label,
+ value: linkEl
});
- }
+ });
+ }
+ return rows;
+ },
+
+ getRowsForAlerts_: function(alerts) {
+ if (alerts.length === 1) {
+ var rows = [{
+ name: 'Alert',
+ value: tr.b.getOnlyElement(alerts).title
+ }];
+ var detailRows = this.getRowsForSingleAlert_(tr.b.getOnlyElement(alerts));
+ rows.push.apply(rows, detailRows);
return rows;
- },
-
- getRowsForAlerts_: function(alerts) {
- if (alerts.length == 1) {
- var rows = [{
+ } else {
+ return alerts.map(function(alert) {
+ return {
name: 'Alert',
- value: tr.b.getOnlyElement(alerts).title
- }];
- var detailRows = this.getRowsForSingleAlert_(alerts[0]);
- rows.push.apply(rows, detailRows);
- return rows;
- } else {
- return alerts.map(function(alert) {
- return {
- name: 'Alert',
- value: alert.title,
- isExpanded: alerts.size < 10, // This is somewhat arbitrary for now.
- subRows: this.getRowsForSingleAlert_(alert)
- };
- }, this);
- }
- },
-
- updateContents_: function() {
- if (this.currentSelection_ === undefined) {
- this.$.table.rows = [];
- this.$.table.rebuild();
- return;
- }
+ value: alert.title,
+ isExpanded: alerts.size < 10, // This is somewhat arbitrary for now.
+ subRows: this.getRowsForSingleAlert_(alert)
+ };
+ }, this);
+ }
+ },
- var alerts = this.currentSelection_;
- this.$.table.tableRows = this.getRowsForAlerts_(alerts);
+ updateContents_: function() {
+ if (this.currentSelection_ === undefined) {
+ this.$.table.rows = [];
this.$.table.rebuild();
- },
-
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- var result = new tr.model.EventSet();
- for (var event of this.currentSelection_)
- result.addEventSet(event.associatedEvents);
- return result;
+ return;
}
- });
- </script>
-</polymer-element>
+
+ var alerts = this.currentSelection_;
+ this.$.table.tableRows = this.getRowsForAlerts_(alerts);
+ this.$.table.rebuild();
+ },
+
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ var result = new tr.model.EventSet();
+ for (var event of this.currentSelection_)
+ result.addEventSet(event.associatedEvents);
+ return result;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-alert-sub-view',
+ tr.model.Alert,
+ {
+ multi: false,
+ title: 'Alert',
+ });
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-alert-sub-view',
+ tr.model.Alert,
+ {
+ multi: true,
+ title: 'Alerts',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html
index 3619e4a9b40..a0fd79af567 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html
@@ -9,116 +9,137 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/brushing_state_controller.html">
-<polymer-element name="tr-ui-a-analysis-link" is="a"
- on-click="{{onClicked_}}"
- on-mouseenter="{{onMouseEnter_}}"
- on-mouseleave="{{onMouseLeave_}}">
+<dom-module id='tr-ui-a-analysis-link'>
<template>
<style>
:host {
display: inline;
- color: -webkit-link;
cursor: pointer;
- text-decoration: underline;
cursor: pointer;
+ white-space: nowrap;
+ }
+ a {
+ text-decoration: underline;
}
</style>
- <content></content>
+ <a href="{{href}}" on-click="onClicked_" on-mouseenter="onMouseEnter_" on-mouseleave="onMouseLeave_"><content></content></a>
+
</template>
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- this.selection_ = undefined;
- },
-
- attached: function() {
- // Save an instance of the controller since it's going to be used in
- // detached() where it can no longer be obtained.
- this.controller_ =
- tr.c.BrushingStateController.getControllerForElement(this);
- },
-
- detached: function() {
- // Reset highlights.
- this.clearHighlight_();
- this.controller_ = undefined;
- },
-
- /**
- * @return {*|function():*}
- */
- get selection() {
- return this.selection_;
- },
-
- /**
- * |selection| can be anything except a function, or else a function that
- * can return anything.
- *
- * In the context of trace_viewer, |selection| is typically an EventSet,
- * whose events will be highlighted by trace_viewer when this link is
- * clicked or mouse-entered.
- *
- * If |selection| is not a function, then it will be dispatched to this
- * link's embedder via a RequestSelectionChangeEvent when this link is
- * clicked or mouse-entered.
- *
- * If |selection| is a function, then it will be called when this link is
- * clicked or mouse-entered, and its result will be dispatched to this
- * link's embedder via a RequestSelectionChangeEvent.
- *
- * @param {*|function():*} selection
- */
- set selection(selection) {
- this.selection_ = selection;
- this.textContent = selection.userFriendlyName;
- },
-
- setSelectionAndContent: function(selection, opt_textContent) {
- this.selection_ = selection;
- if (opt_textContent)
- this.textContent = opt_textContent;
- },
-
- /**
- * If |selection| is a function, call it and return the result.
- * Otherwise return |selection| directly.
- *
- * @return {*}
- */
- getCurrentSelection_: function() {
- // Gets the current selection, invoking the selection function if needed.
- if (typeof this.selection_ === 'function')
- return this.selection_();
- return this.selection_;
- },
-
- setHighlight_: function(opt_eventSet) {
- if (this.controller_)
- this.controller_.changeAnalysisLinkHoveredEvents(opt_eventSet);
- },
-
- clearHighlight_: function(opt_eventSet) {
- this.setHighlight_();
- },
-
- onClicked_: function() {
- if (!this.selection_)
- return;
-
- var event = new tr.model.RequestSelectionChangeEvent();
- event.selection = this.getCurrentSelection_();
- this.dispatchEvent(event);
- },
-
- onMouseEnter_: function() {
- this.setHighlight_(this.getCurrentSelection_());
- },
-
- onMouseLeave_: function() {
- this.clearHighlight_();
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-analysis-link',
+
+ properties: {
+ href: {
+ type: String
}
- });
- </script>
-</polymer-element>
+ },
+
+ listeners: {
+ 'click': 'onClicked_',
+ 'mouseenter': 'onMouseEnter_',
+ 'mouseleave': 'onMouseLeave_'
+ },
+
+ ready: function() {
+ this.selection_ = undefined;
+ },
+
+ attached: function() {
+ // Save an instance of the controller since it's going to be used in
+ // detached() where it can no longer be obtained.
+ this.controller_ =
+ tr.c.BrushingStateController.getControllerForElement(this);
+ },
+
+ detached: function() {
+ // Reset highlights.
+ this.clearHighlight_();
+ this.controller_ = undefined;
+ },
+
+ set color(c) {
+ this.style.color = c;
+ },
+
+ /**
+ * @return {*|function():*}
+ */
+ get selection() {
+ return this.selection_;
+ },
+
+ /**
+ * |selection| can be anything except a function, or else a function that
+ * can return anything.
+ *
+ * In the context of trace_viewer, |selection| is typically an EventSet,
+ * whose events will be highlighted by trace_viewer when this link is
+ * clicked or mouse-entered.
+ *
+ * If |selection| is not a function, then it will be dispatched to this
+ * link's embedder via a RequestSelectionChangeEvent when this link is
+ * clicked or mouse-entered.
+ *
+ * If |selection| is a function, then it will be called when this link is
+ * clicked or mouse-entered, and its result will be dispatched to this
+ * link's embedder via a RequestSelectionChangeEvent.
+ *
+ * @param {*|function():*} selection
+ */
+ set selection(selection) {
+ this.selection_ = selection;
+ Polymer.dom(this).textContent = selection.userFriendlyName;
+ },
+
+ setSelectionAndContent: function(selection, opt_textContent) {
+ this.selection_ = selection;
+ if (opt_textContent)
+ Polymer.dom(this).textContent = opt_textContent;
+ },
+
+ /**
+ * If |selection| is a function, call it and return the result.
+ * Otherwise return |selection| directly.
+ *
+ * @return {*}
+ */
+ getCurrentSelection_: function() {
+ // Gets the current selection, invoking the selection function if needed.
+ if (typeof this.selection_ === 'function')
+ return this.selection_();
+ return this.selection_;
+ },
+
+ setHighlight_: function(opt_eventSet) {
+ if (this.controller_)
+ this.controller_.changeAnalysisLinkHoveredEvents(opt_eventSet);
+ },
+
+ clearHighlight_: function(opt_eventSet) {
+ this.setHighlight_();
+ },
+
+ onClicked_: function(clickEvent) {
+ if (!this.selection_)
+ return;
+
+ clickEvent.stopPropagation();
+
+ var event = new tr.model.RequestSelectionChangeEvent();
+ event.selection = this.getCurrentSelection_();
+ this.dispatchEvent(event);
+ },
+
+ onMouseEnter_: function() {
+ this.setHighlight_(this.getCurrentSelection_());
+ },
+
+ onMouseLeave_: function() {
+ this.clearHighlight_();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html
index 203eed642df..66bae5772d4 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html
@@ -1,21 +1,25 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2014 The Chromium Authors. All rights reserved.
+Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/base.html">
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/model/event_set.html">
<!--
@fileoverview Polymer element for various analysis sub-views.
-->
-<polymer-element name="tr-ui-a-sub-view">
- <script>
- 'use strict';
- Polymer({
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+
+ var AnalysisSubView = {
set tabLabel(label) {
- return this.setAttribute('tab-label', label);
+ Polymer.dom(this).setAttribute('tab-label', label);
},
get tabLabel() {
@@ -41,6 +45,222 @@ found in the LICENSE file.
get selection() {
throw new Error('Not implemented!');
}
- });
- </script>
-</polymer-element>
+ };
+
+ // Basic registry.
+ var allTypeInfosByEventProto = new Map();
+ var onlyRootTypeInfosByEventProto = undefined;
+ var eventProtoToRootTypeInfoMap = undefined;
+
+ function AnalysisSubViewTypeInfo(eventConstructor, options) {
+ if (options.multi === undefined)
+ throw new Error('missing field: multi');
+ if (options.title === undefined)
+ throw new Error('missing field: title');
+ this.eventConstructor = eventConstructor;
+
+ this.singleTagName = undefined;
+ this.singleTitle = undefined;
+
+ this.multiTagName = undefined;
+ this.multiTitle = undefined;
+
+ // This is computed by rebuildRootSubViewTypeInfos, so don't muck with it!
+ this.childrenTypeInfos_ = undefined;
+ };
+
+ AnalysisSubViewTypeInfo.prototype = {
+ get childrenTypeInfos() {
+ return this.childrenTypeInfos_;
+ },
+
+ resetchildrenTypeInfos: function() {
+ this.childrenTypeInfos_ = [];
+ }
+ };
+
+ AnalysisSubView.register = function(tagName, eventConstructor, options) {
+ var typeInfo = allTypeInfosByEventProto.get(eventConstructor.prototype);
+ if (typeInfo === undefined) {
+ typeInfo = new AnalysisSubViewTypeInfo(eventConstructor, options);
+ allTypeInfosByEventProto.set(typeInfo.eventConstructor.prototype,
+ typeInfo);
+
+ onlyRootTypeInfosByEventProto = undefined;
+ }
+
+ if (!options.multi) {
+ if (typeInfo.singleTagName !== undefined)
+ throw new Error('SingleTagName already set');
+ typeInfo.singleTagName = tagName;
+ typeInfo.singleTitle = options.title;
+ } else {
+ if (typeInfo.multiTagName !== undefined)
+ throw new Error('MultiTagName already set');
+ typeInfo.multiTagName = tagName;
+ typeInfo.multiTitle = options.title;
+ }
+ return typeInfo;
+ };
+
+ function rebuildRootSubViewTypeInfos() {
+ onlyRootTypeInfosByEventProto = new Map();
+ allTypeInfosByEventProto.forEach(function(typeInfo) {
+ typeInfo.resetchildrenTypeInfos();
+ });
+
+ // Find all root typeInfos.
+ allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) {
+ var eventPrototype = typeInfo.eventConstructor.prototype;
+
+ var lastEventProto = eventPrototype;
+ var curEventProto = eventPrototype.__proto__;
+ while (true) {
+ if (!allTypeInfosByEventProto.has(curEventProto)) {
+ var rootTypeInfo = allTypeInfosByEventProto.get(lastEventProto);
+ var rootEventProto = lastEventProto;
+
+ var isNew = onlyRootTypeInfosByEventProto.has(rootEventProto);
+ onlyRootTypeInfosByEventProto.set(rootEventProto,
+ rootTypeInfo);
+ break;
+ }
+
+ lastEventProto = curEventProto;
+ curEventProto = curEventProto.__proto__;
+ }
+ });
+
+ // Build the childrenTypeInfos array.
+ allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) {
+ var eventPrototype = typeInfo.eventConstructor.prototype;
+ var parentEventProto = eventPrototype.__proto__;
+ var parentTypeInfo = allTypeInfosByEventProto.get(parentEventProto);
+ if (!parentTypeInfo)
+ return;
+ parentTypeInfo.childrenTypeInfos.push(typeInfo);
+ });
+
+ // Build the eventProto to rootTypeInfo map.
+ eventProtoToRootTypeInfoMap = new Map();
+ allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) {
+ var eventPrototype = typeInfo.eventConstructor.prototype;
+
+ var curEventProto = eventPrototype;
+ while (true) {
+ if (onlyRootTypeInfosByEventProto.has(curEventProto)) {
+ var rootTypeInfo = onlyRootTypeInfosByEventProto.get(
+ curEventProto);
+ eventProtoToRootTypeInfoMap.set(eventPrototype,
+ rootTypeInfo);
+ break;
+ }
+ curEventProto = curEventProto.__proto__;
+ }
+ });
+ }
+
+ function findLowestTypeInfoForEvents(thisTypeInfo, events) {
+ if (events.length === 0)
+ return thisTypeInfo;
+ var event0 = tr.b.getFirstElement(events);
+
+ var candidateSubTypeInfo;
+ for (var i = 0; i < thisTypeInfo.childrenTypeInfos.length; i++) {
+ var childTypeInfo = thisTypeInfo.childrenTypeInfos[i];
+ if (event0 instanceof childTypeInfo.eventConstructor) {
+ candidateSubTypeInfo = childTypeInfo;
+ break;
+ }
+ }
+ if (!candidateSubTypeInfo)
+ return thisTypeInfo;
+
+ // Validate that all the other events are instances of the candidate type.
+ var allMatch = true;
+ for (var event of events) {
+ if (event instanceof candidateSubTypeInfo.eventConstructor)
+ continue;
+ allMatch = false;
+ break;
+ }
+
+ if (!allMatch) {
+ return thisTypeInfo;
+ }
+
+ return findLowestTypeInfoForEvents(candidateSubTypeInfo, events);
+ }
+
+ var primaryEventProtoToTypeInfoMap = new Map();
+ function getRootTypeInfoForEvent(event) {
+ var curProto = event.__proto__;
+ var typeInfo = primaryEventProtoToTypeInfoMap.get(curProto);
+ if (typeInfo)
+ return typeInfo;
+ return getRootTypeInfoForEventSlow(event);
+ }
+
+ function getRootTypeInfoForEventSlow(event) {
+ var typeInfo;
+ var curProto = event.__proto__;
+ while (true) {
+ if (curProto === Object.prototype)
+ throw new Error('No view registered for ' + event.toString());
+ typeInfo = onlyRootTypeInfosByEventProto.get(curProto);
+ if (typeInfo) {
+ primaryEventProtoToTypeInfoMap.set(event.__proto__, typeInfo);
+ return typeInfo;
+ }
+ curProto = curProto.__proto__;
+ }
+ }
+
+ AnalysisSubView.getEventsOrganizedByTypeInfo = function(selection) {
+ if (onlyRootTypeInfosByEventProto === undefined)
+ rebuildRootSubViewTypeInfos();
+
+ // Base grouping.
+ var eventsByRootTypeInfo = tr.b.groupIntoMap(
+ selection,
+ function(event) {
+ return getRootTypeInfoForEvent(event);
+ },
+ this, tr.model.EventSet);
+
+ // Now, try to lower the typeinfo to the most specific type that still
+ // encompasses the event group.
+ //
+ // For instance, if we have 3 ThreadSlices, and all three are V8 slices,
+ // then we can convert this to use the V8Slices's typeinfos. But, if one
+ // of those slices was not a V8Slice, then we must still use
+ // ThreadSlice.
+ //
+ // The reason for this is for the confusion that might arise from the
+ // alternative. Suppose you click on a set of mixed slices, we want to show
+ // you the most correct information, and let you navigate to . If we instead
+ // showed you a V8 slices tab, and a Slices tab, we present the user with an
+ // ambiguity: is the V8 slice also in the Slices tab? Or is it not? Better,
+ // we think, to just only ever show an event in one place at a time, and
+ // avoid the possible confusion.
+ var eventsByLowestTypeInfo = new Map();
+ eventsByRootTypeInfo.forEach(function(events, typeInfo) {
+ var lowestTypeInfo = findLowestTypeInfoForEvents(typeInfo, events);
+ eventsByLowestTypeInfo.set(lowestTypeInfo, events);
+ });
+
+ return eventsByLowestTypeInfo;
+ };
+
+ return {
+ AnalysisSubView: AnalysisSubView,
+ AnalysisSubViewTypeInfo: AnalysisSubViewTypeInfo
+ };
+});
+
+// Dummy element for testing
+Polymer({
+ is: 'tr-ui-a-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView]
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html
index b5961acda7d..f5a8a387a08 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html
@@ -12,7 +12,6 @@ found in the LICENSE file.
<link rel="import"
href="/tracing/ui/analysis/container_memory_dump_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/counter_sample_sub_view.html">
-<link rel="import" href="/tracing/ui/analysis/layout_tree_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_async_slice_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_cpu_slice_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_flow_event_sub_view.html">
@@ -46,14 +45,13 @@ found in the LICENSE file.
href="/tracing/ui/analysis/single_thread_time_slice_sub_view.html">
<link rel="import"
href="/tracing/ui/analysis/single_user_expectation_sub_view.html">
-<link rel="import" href="/tracing/ui/base/polymer_utils.html">
<link rel="import" href="/tracing/ui/base/tab_view.html">
<!--
@fileoverview A component used to display an analysis of a selection,
using custom elements specialized for different event types.
-->
-<polymer-element name="tr-ui-a-analysis-view">
+<dom-module id='tr-ui-a-analysis-view'>
<template>
<style>
:host {
@@ -67,192 +65,138 @@ using custom elements specialized for different event types.
:host(.tall-mode) {
height: 525px;
}
-
- ::content > * {
- flex: 1 0 auto;
- }
</style>
<content></content>
</template>
- <script>
- 'use strict';
- (function() {
- var EventRegistry = tr.model.EventRegistry;
-
- Polymer({
- ready: function() {
- this.tabView_ = document.createElement('tr-ui-a-tab-view');
- this.tabView_.style.flex = '1 1 auto';
- this.appendChild(this.tabView_);
- this.brushingStateController_ = undefined;
- this.onSelectedTabChange_ = this.onSelectedTabChange_.bind(this);
- this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
-
- this.lastSeenSelection_ = new tr.model.EventSet();
- },
+</dom-module>
+<script>
+'use strict';
+(function() {
+ var EventRegistry = tr.model.EventRegistry;
+
+ /** Returns the label that goes next to the list of tabs. */
+ function getTabStripLabel(numEvents) {
+ if (numEvents === 0)
+ return 'Nothing selected. Tap stuff.';
+ else if (numEvents === 1)
+ return '1 item selected.';
+ return numEvents + ' items selected.';
+ }
+
+ function createSubView(subViewTypeInfo, selection) {
+ var tagName;
+ if (selection.length === 1)
+ tagName = subViewTypeInfo.singleTagName;
+ else
+ tagName = subViewTypeInfo.multiTagName;
+
+ if (tagName === undefined) {
+ throw new Error('No view registered for ' +
+ subViewTypeInfo.eventConstructor.name);
+ }
+ var subView = document.createElement(tagName);
+
+ var title;
+ if (selection.length === 1)
+ title = subViewTypeInfo.singleTitle;
+ else
+ title = subViewTypeInfo.multiTitle;
+ title += ' (' + selection.length + ')';
+ subView.tabLabel = title;
+
+ subView.selection = selection;
+ return subView;
+ }
+
+ Polymer({
+ is: 'tr-ui-a-analysis-view',
+
+ ready: function() {
+ this.brushingStateController_ = undefined;
+ this.lastSelection_ = undefined;
+ this.tabView_ = document.createElement('tr-ui-b-tab-view');
+ this.tabView_.addEventListener(
+ 'selected-tab-change', this.onSelectedSubViewChanged_.bind(this));
+
+ Polymer.dom(this).appendChild(this.tabView_);
+ },
+
+ set tallMode(value) {
+ Polymer.dom(this).classList.toggle('tall-mode', value);
+ },
+
+ get tallMode() {
+ return Polymer.dom(this).classList.contains('tall-mode');
+ },
+
+ get tabView() {
+ return this.tabView_;
+ },
+
+ get brushingStateController() {
+ return this.brushingStateController_;
+ },
+
+ set brushingStateController(brushingStateController) {
+ if (this.brushingStateController_) {
+ this.brushingStateController_.removeEventListener(
+ 'change', this.onSelectionChanged_.bind(this));
+ }
- set tallMode(value) {
- if (value)
- this.classList.add('tall-mode');
- else
- this.classList.remove('tall-mode');
- },
+ this.brushingStateController_ = brushingStateController;
+ if (this.brushingStateController) {
+ this.brushingStateController_.addEventListener(
+ 'change', this.onSelectionChanged_.bind(this));
+ }
- get tallMode() {
- return this.classList.contains('tall-mode');
- },
+ // The new brushing controller may have a different selection than the
+ // last one, so we have to refresh the subview.
+ this.onSelectionChanged_();
+ },
- get tabView() {
- return this.tabView_;
- },
+ get selection() {
+ return this.brushingStateController_.selection;
+ },
- get brushingStateController() {
- return this.brushingStateController_;
- },
+ onSelectionChanged_: function(e) {
+ if (this.lastSelection_ && this.selection.equals(this.lastSelection_))
+ return;
+ this.lastSelection_ = this.selection;
- set brushingStateController(brushingStateController) {
- if (this.brushingStateController) {
- this.brushingStateController_.removeEventListener(
- 'change', this.onSelectionChanged_);
- }
- this.brushingStateController_ = brushingStateController;
- if (this.brushingStateController) {
- this.brushingStateController_.addEventListener(
- 'change', this.onSelectionChanged_);
- }
- this.onSelectionChanged_();
- },
+ this.tallMode = false;
- get selection() {
- return this.brushingStateController_.selection;
- },
+ this.tabView_.label = getTabStripLabel(this.selection.length);
+ var eventsByBaseTypeName =
+ this.selection.getEventsOrganizedByBaseType(true);
- onSelectionChanged_: function(e) {
- var selection = this.brushingStateController_.selection;
+ var ASV = tr.ui.analysis.AnalysisSubView;
+ var eventsByTagName = ASV.getEventsOrganizedByTypeInfo(this.selection);
+ var newSubViews = [];
+ eventsByTagName.forEach(function(events, typeInfo) {
+ newSubViews.push(createSubView(typeInfo, events));
+ });
- var selectionHasSameValue = this.lastSeenSelection_.equals(selection);
- this.lastSeenSelection_ = selection;
- if (selectionHasSameValue)
- return;
+ this.tabView_.resetSubViews(newSubViews);
+ },
- var lastSelectedTabTagName;
- var lastSelectedTabTypeName;
- if (this.tabView_.selectedTab) {
- lastSelectedTabTagName = this.tabView_.selectedTab.tagName;
- lastSelectedTabTypeName = this.tabView_.selectedTab._eventTypeName;
- }
+ onSelectedSubViewChanged_: function() {
+ var selectedSubView = this.tabView_.selectedSubView;
+ if (!selectedSubView) {
this.tallMode = false;
-
- var previouslySelectedTab = this.tabView_.selectedTab;
- this.tabView_.removeEventListener(
- 'selected-tab-change', this.onSelectedTabChange_);
-
- var previousSubViews = {};
- for (var i = 0; i < this.tabView_.children.length; i++) {
- var previousSubView = this.tabView_.children[i];
- previousSubViews[previousSubView._eventTypeName] = previousSubView;
- }
-
- this.tabView_.saveTabStates();
- this.tabView_.textContent = '';
- if (selection.length == 0) {
- this.tabView_.tabStripHeadingText = 'Nothing selected. Tap stuff.';
- } else if (selection.length == 1) {
- this.tabView_.tabStripHeadingText = '1 item selected: ';
- } else {
- this.tabView_.tabStripHeadingText = selection.length +
- ' items selected: ';
- }
-
- var eventsByBaseTypeName = selection.getEventsOrganizedByBaseType(true);
-
- var numBaseTypesToAnalyze = tr.b.dictionaryLength(eventsByBaseTypeName);
- for (var eventTypeName in eventsByBaseTypeName) {
- var subSelection = eventsByBaseTypeName[eventTypeName];
- var subView = this.createSubViewForSelection_(
- eventTypeName, subSelection, previousSubViews[eventTypeName]);
- // Store the eventTypeName for future tab restoration.
- subView._eventTypeName = eventTypeName;
- this.tabView_.appendChild(subView);
-
- subView.selection = subSelection;
- }
-
- // Restore the tab type that was previously selected. First try by tag
- // name.
- var tab;
- if (lastSelectedTabTagName)
- tab = this.tabView_.querySelector(lastSelectedTabTagName);
-
- // If that fails, look for a tab with that typeName.
- if (!tab && lastSelectedTabTypeName) {
- var tab = tr.b.findFirstInArray(
- this.tabView_.children, function(tab) {
- return tab._eventTypeName === lastSelectedTabTypeName;
- });
- }
- // If all else fails, pick the first tab.
- if (!tab)
- tab = this.tabView_.firstChild;
-
- this.tabView_.selectedTab = tab;
- this.onSelectedTabChange_();
-
- this.tabView_.addEventListener(
- 'selected-tab-change', this.onSelectedTabChange_);
- },
-
- createSubViewForSelection_: function(eventTypeName, subSelection,
- previousSubView) {
- // Find.
- var eventTypeInfo = EventRegistry.getEventTypeInfoByTypeName(
- eventTypeName);
- var singleMode = subSelection.length == 1;
- var tagName;
- if (subSelection.length === 1)
- tagName = eventTypeInfo.metadata.singleViewElementName;
- else
- tagName = eventTypeInfo.metadata.multiViewElementName;
-
- if (!tr.ui.b.getPolymerElementNamed(tagName))
- throw new Error('Element not registered: ' + tagName);
-
- // Create if necessary.
- var subView;
- if (previousSubView &&
- previousSubView.tagName === tagName.toUpperCase())
- subView = previousSubView;
- else
- subView = document.createElement(tagName);
-
- // Set label.
- var camelLabel;
- if (subSelection.length === 1)
- camelLabel = EventRegistry.getUserFriendlySingularName(eventTypeName);
- else
- camelLabel = EventRegistry.getUserFriendlyPluralName(eventTypeName);
- subView.tabLabel = camelLabel + ' (' + subSelection.length + ')';
-
- return subView;
- },
-
- onSelectedTabChange_: function() {
- var brushingStateController = this.brushingStateController_;
- if (this.tabView_.selectedTab) {
- var selectedTab = this.tabView_.selectedTab;
- this.tallMode = selectedTab.requiresTallView;
- if (brushingStateController) {
- var rlth = selectedTab.relatedEventsToHighlight;
- brushingStateController.changeAnalysisViewRelatedEvents(rlth);
- }
- } else {
- this.tallMode = false;
- if (brushingStateController)
- brushingStateController.changeAnalysisViewRelatedEvents(undefined);
- }
+ this.maybeChangeRelatedEvents_(undefined);
+ return;
}
- });
- })();
- </script>
-</polymer-element>
+
+ this.tallMode = selectedSubView.requiresTallView;
+ this.maybeChangeRelatedEvents_(selectedSubView.relatedEventsToHighlight);
+ },
+
+ /** Changes the highlighted related events if possible. */
+ maybeChangeRelatedEvents_: function(events) {
+ if (this.brushingStateController)
+ this.brushingStateController.changeAnalysisViewRelatedEvents(events);
+ }
+ });
+})();
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
index 37776f819bd..7f88d256ab5 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
@@ -74,7 +74,7 @@ tr.b.unittest.testSuite(function() {
analysisView.brushingStateController = controller;
function checkSelectedTab(expectedSelectedTab, expectedRelatedEvents) {
- assert.strictEqual(tabView.selectedTab, expectedSelectedTab);
+ assert.strictEqual(tabView.selectedSubView, expectedSelectedTab);
assertEventSet(controller.currentBrushingState.analysisViewRelatedEvents,
expectedRelatedEvents);
}
@@ -99,7 +99,7 @@ tr.b.unittest.testSuite(function() {
checkSelectedTab(sampleTab2, []);
// 3. Tab selection: single thread slice tab.
- tabView.selectedTab = singleThreadSliceTab2;
+ tabView.selectedSubView = singleThreadSliceTab2;
checkSelectedTab(singleThreadSliceTab2, []);
// 4. Event selection: one sample, two thread slices, and one
@@ -111,8 +111,6 @@ tr.b.unittest.testSuite(function() {
checkTab(sampleTab4,
'tr-ui-a-counter-sample-sub-view',
[sample3]);
- // Reuse tab (same event type and sub-view tag name).
- assert.strictEqual(sampleTab4, sampleTab2);
var singleRecordTab4 = tabView.tabs[2];
checkTab(singleRecordTab4,
'tr-ui-a-single-user-expectation-sub-view',
@@ -125,7 +123,7 @@ tr.b.unittest.testSuite(function() {
checkSelectedTab(multiThreadSliceTab4, []);
// 5. Tab selection: single user expectation tab.
- tabView.selectedTab = singleRecordTab4;
+ tabView.selectedSubView = singleRecordTab4;
checkSelectedTab(singleRecordTab4, [sample1, slice1]);
// 6. Event selection: one user expectation.
@@ -136,8 +134,6 @@ tr.b.unittest.testSuite(function() {
checkTab(singleRecordTab6,
'tr-ui-a-single-user-expectation-sub-view',
[record2]);
- // Reuse tab (same event type and sub-view tag name).
- assert.strictEqual(singleRecordTab6, singleRecordTab4);
// Remember selected tab.
checkSelectedTab(singleRecordTab6, [sample2, sample3, slice1]);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html
index d6a437e775a..ba55bd7739c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html
@@ -6,27 +6,34 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/model/container_memory_dump.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_header_pane.html">
<link rel="import" href="/tracing/ui/analysis/stacked_pane_view.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-container-memory-dump-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-container-memory-dump-sub-view'>
<template>
+ <style>
+ tr-ui-b-table {
+ font-size: 12px;
+ }
+ </style>
<div id="content"></div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui.analysis', function() {
- Polymer('tr-ui-a-container-memory-dump-sub-view', {
+ Polymer({
+ is: 'tr-ui-a-container-memory-dump-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
set selection(selection) {
if (selection === undefined) {
this.currentSelection_ = undefined;
@@ -67,7 +74,7 @@ tr.exportTo('tr.ui.analysis', function() {
},
updateContents_: function() {
- this.$.content.textContent = '';
+ Polymer.dom(this.$.content).textContent = '';
if (this.dumpsByContainerName_ === undefined)
return;
@@ -87,7 +94,7 @@ tr.exportTo('tr.ui.analysis', function() {
tr.b.dictionaryValues(this.dumpsByContainerName_)[0];
var dumpView = this.ownerDocument.createElement(
'tr-ui-a-stacked-pane-view');
- this.$.content.appendChild(dumpView);
+ Polymer.dom(this.$.content).appendChild(dumpView);
dumpView.setPaneBuilder(function() {
var headerPane = document.createElement(
'tr-ui-a-memory-dump-header-pane');
@@ -126,22 +133,23 @@ tr.exportTo('tr.ui.analysis', function() {
singleDumpValue_: function(row) {
var linkEl = ownerDocument.createElement('tr-ui-a-analysis-link');
linkEl.setSelectionAndContent(new tr.model.EventSet([row]));
- linkEl.appendChild(tr.v.ui.createScalarSpan(row.start, {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: ownerDocument
- }));
+ Polymer.dom(linkEl).appendChild(tr.v.ui.createScalarSpan(
+ row.start, {
+ unit: tr.b.Unit.byName.timeStampInMs,
+ ownerDocument: ownerDocument
+ }));
return linkEl;
},
groupedDumpValue_: function(row) {
var linkEl = ownerDocument.createElement('tr-ui-a-analysis-link');
linkEl.setSelectionAndContent(new tr.model.EventSet(row.subRows));
- linkEl.appendChild(tr.ui.b.createSpan({
+ Polymer.dom(linkEl).appendChild(tr.ui.b.createSpan({
ownerDocument: ownerDocument,
textContent: row.subRows.length + ' memory dump' +
(row.subRows.length === 1 ? '' : 's') + ' in '
}));
- linkEl.appendChild(tr.ui.b.createSpan({
+ Polymer.dom(linkEl).appendChild(tr.ui.b.createSpan({
ownerDocument: ownerDocument,
textContent: row.containerName,
bold: true
@@ -156,10 +164,42 @@ tr.exportTo('tr.ui.analysis', function() {
table.tableRows = rows;
table.showHeader = false;
table.rebuild();
- this.$.content.appendChild(table);
+ Polymer.dom(this.$.content).appendChild(table);
}
});
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-container-memory-dump-sub-view',
+ tr.model.GlobalMemoryDump,
+ {
+ multi: false,
+ title: 'Global Memory Dump',
+ });
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-container-memory-dump-sub-view',
+ tr.model.GlobalMemoryDump,
+ {
+ multi: true,
+ title: 'Global Memory Dumps',
+ });
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-container-memory-dump-sub-view',
+ tr.model.ProcessMemoryDump,
+ {
+ multi: false,
+ title: 'Process Memory Dump',
+ });
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-container-memory-dump-sub-view',
+ tr.model.ProcessMemoryDump,
+ {
+ multi: true,
+ title: 'Process Memory Dumps',
+ });
+
return {};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html
index 0619106cd1f..05004a84f99 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html
@@ -27,7 +27,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement(
'tr-ui-a-container-memory-dump-sub-view');
if (opt_parentElement)
- opt_parentElement.appendChild(viewEl);
+ Polymer.dom(opt_parentElement).appendChild(viewEl);
if (selection === undefined) {
viewEl.selection = undefined;
} else {
@@ -281,7 +281,7 @@ tr.b.unittest.testSuite(function() {
}, containerEl);
// Destroy the first container memory view.
- containerEl.textContent = '';
+ Polymer.dom(containerEl).textContent = '';
// Create the second container memory view.
createAndCheckContainerMemoryDumpView(this,
@@ -321,11 +321,11 @@ tr.b.unittest.testSuite(function() {
var rows = tableEl.tableRows;
var col = tableEl.tableColumns[0];
- assert.equal(col.value(rows[0]).textContent,
+ assert.equal(Polymer.dom(col.value(rows[0])).textContent,
'2 memory dumps in Process 1');
- assert.equal(col.value(rows[1]).textContent,
+ assert.equal(Polymer.dom(col.value(rows[1])).textContent,
'3 memory dumps in Process 2');
- assert.equal(col.value(rows[2]).textContent,
+ assert.equal(Polymer.dom(col.value(rows[2])).textContent,
'1 memory dump in Process 4');
// Check that the analysis link is associated with the right dumps.
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html
index 40ae156078c..db03cdb4e30 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html
@@ -9,18 +9,20 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name='tr-ui-a-counter-sample-sub-view'
- extends='tr-ui-a-sub-view'>
+<dom-module id='tr-ui-a-counter-sample-sub-view'>
<template>
<style>
:host {
display: flex;
flex-direction: column;
}
+ tr-ui-b-table {
+ font-size: 12px;
+ }
</style>
<tr-ui-b-table id='table'></tr-ui-b-table>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -48,7 +50,10 @@ found in the LICENSE file.
}
];
- Polymer('tr-ui-a-counter-sample-sub-view', {
+ Polymer({
+ is: 'tr-ui-a-counter-sample-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
ready: function() {
this.currentSelection_ = undefined;
this.$.table.tableColumns = COUNTER_SAMPLE_TABLE_COLUMNS;
@@ -116,5 +121,21 @@ found in the LICENSE file.
});
}
});
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-counter-sample-sub-view',
+ tr.model.CounterSample,
+ {
+ multi: false,
+ title: 'Counter Sample',
+ });
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-counter-sample-sub-view',
+ tr.model.CounterSample,
+ {
+ multi: true,
+ title: 'Counter Samples',
+ });
})();
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html
index 87162a4e023..e86e76f8180 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html
@@ -17,11 +17,11 @@ frame.
This chart aims to help users understand the shape of the power consumption
curve over the course of a frame or set of frames.
-->
-<polymer-element name="tr-ui-a-frame-power-usage-chart">
+<dom-module id='tr-ui-a-frame-power-usage-chart'>
<template>
<div id="content"></div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -32,7 +32,9 @@ var CHART_TITLE = 'Power (W) by ms since vertical sync';
// TODO(charliea): Find out how to make this specifiable via CSS.
var CHART_WIDTH_FRACTION_OF_BODY = 0.5;
-Polymer('tr-ui-a-frame-power-usage-chart', {
+Polymer({
+ is: 'tr-ui-a-frame-power-usage-chart',
+
ready: function() {
this.chart_ = undefined;
this.samples_ = new EventSet();
@@ -71,7 +73,7 @@ Polymer('tr-ui-a-frame-power-usage-chart', {
return;
this.chart_ = this.createChart_(data);
- this.$.content.appendChild(this.chart_);
+ Polymer.dom(this.$.content).appendChild(this.chart_);
},
createChart_: function(data) {
@@ -86,8 +88,8 @@ Polymer('tr-ui-a-frame-power-usage-chart', {
clearChart_: function() {
var content = this.$.content;
- while (content.firstChild)
- content.removeChild(content.firstChild);
+ while (Polymer.dom(content).firstChild)
+ Polymer.dom(content).removeChild(Polymer.dom(content).firstChild);
this.chart_ = undefined;
},
@@ -123,7 +125,7 @@ Polymer('tr-ui-a-frame-power-usage-chart', {
return;
var point = { x: sample.start - lastVSyncTimestamp };
- point['f' + frameNumber] = sample.power;
+ point['f' + frameNumber] = sample.powerInW;
points.push(point);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html
index 521699ee129..14797a9aa38 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html
@@ -16,8 +16,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/value/numeric.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<polymer-element name="tr-ui-a-generic-object-view"
- is="HTMLUnknownElement">
+<dom-module id='tr-ui-a-generic-object-view'>
<template>
<style>
:host {
@@ -28,277 +27,285 @@ found in the LICENSE file.
<div id="content">
</div>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+var URL_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // eslint-disable-line max-len
- function isTable(object) {
- if (!(object instanceof Array) ||
- (object.length < 2)) return false;
- for (var colName in object[0]) {
- if (typeof colName !== 'string') return false;
+function isTable(object) {
+ if (!(object instanceof Array) ||
+ (object.length < 2)) return false;
+ for (var colName in object[0]) {
+ if (typeof colName !== 'string') return false;
+ }
+ for (var i = 0; i < object.length; ++i) {
+ if (!(object[i] instanceof Object)) return false;
+ for (var colName in object[i]) {
+ if (i && (object[0][colName] === undefined)) return false;
+ var cellType = typeof object[i][colName];
+ if (cellType !== 'string' && cellType !== 'number') return false;
}
- for (var i = 0; i < object.length; ++i) {
- if (!(object[i] instanceof Object)) return false;
- for (var colName in object[i]) {
- if (i && (object[0][colName] === undefined)) return false;
- var cellType = typeof object[i][colName];
- if (cellType !== 'string' && cellType != 'number') return false;
- }
- if (i) {
- for (var colName in object[0]) {
- if (object[i][colName] === undefined) return false;
- }
+ if (i) {
+ for (var colName in object[0]) {
+ if (object[i][colName] === undefined) return false;
}
}
- return true;
}
+ return true;
+}
+
+Polymer({
+ is: 'tr-ui-a-generic-object-view',
+
+ ready: function() {
+ this.object_ = undefined;
+ },
+
+ get object() {
+ return this.object_;
+ },
+
+ set object(object) {
+ this.object_ = object;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ Polymer.dom(this.$.content).textContent = '';
+ this.appendElementsForType_('', this.object_, 0, 0, 5, '');
+ },
+
+ appendElementsForType_: function(
+ label, object, indent, depth, maxDepth, suffix) {
+ if (depth > maxDepth) {
+ this.appendSimpleText_(
+ label, indent, '<recursion limit reached>', suffix);
+ return;
+ }
- Polymer({
- ready: function() {
- this.object_ = undefined;
- },
-
- get object() {
- return this.object_;
- },
-
- set object(object) {
- this.object_ = object;
- this.updateContents_();
- },
-
- updateContents_: function() {
- this.$.content.textContent = '';
- this.appendElementsForType_('', this.object_, 0, 0, 5, '');
- },
-
- appendElementsForType_: function(
- label, object, indent, depth, maxDepth, suffix) {
- if (depth > maxDepth) {
- this.appendSimpleText_(
- label, indent, '<recursion limit reached>', suffix);
- return;
- }
-
- if (object === undefined) {
- this.appendSimpleText_(label, indent, 'undefined', suffix);
- return;
- }
+ if (object === undefined) {
+ this.appendSimpleText_(label, indent, 'undefined', suffix);
+ return;
+ }
- if (object === null) {
- this.appendSimpleText_(label, indent, 'null', suffix);
- return;
- }
+ if (object === null) {
+ this.appendSimpleText_(label, indent, 'null', suffix);
+ return;
+ }
- if (!(object instanceof Object)) {
- var type = typeof object;
- if (type == 'string') {
- var objectReplaced = false;
- if ((object[0] == '{' && object[object.length - 1] == '}') ||
- (object[0] == '[' && object[object.length - 1] == ']')) {
- try {
- object = JSON.parse(object);
- objectReplaced = true;
- } catch (e) {
- }
- }
- if (!objectReplaced) {
- if (object.indexOf('\n') !== -1) {
- var lines = object.split('\n');
- lines.forEach(function(line, i) {
- var text, ioff, ll, ss;
- if (i == 0) {
- text = '"' + line;
- ioff = 0;
- ll = label;
- ss = '';
- } else if (i < lines.length - 1) {
- text = line;
- ioff = 1;
- ll = '';
- ss = '';
- } else {
- text = line + '"';
- ioff = 1;
- ll = '';
- ss = suffix;
- }
-
- var el = this.appendSimpleText_(
- ll, indent + ioff * label.length + ioff, text, ss);
- el.style.whiteSpace = 'pre';
- return el;
- }, this);
- return;
- } else {
- this.appendSimpleText_(
- label, indent, '"' + object + '"', suffix);
- return;
- }
+ if (!(object instanceof Object)) {
+ var type = typeof object;
+ if (type === 'string') {
+ var objectReplaced = false;
+ if ((object[0] === '{' && object[object.length - 1] === '}') ||
+ (object[0] === '[' && object[object.length - 1] === ']')) {
+ try {
+ object = JSON.parse(object);
+ objectReplaced = true;
+ } catch (e) {
}
- else {
- /* Fall through to the flow below */
+ }
+ if (!objectReplaced) {
+ if (object.indexOf('\n') !== -1) {
+ var lines = object.split('\n');
+ lines.forEach(function(line, i) {
+ var text, ioff, ll, ss;
+ if (i === 0) {
+ text = '"' + line;
+ ioff = 0;
+ ll = label;
+ ss = '';
+ } else if (i < lines.length - 1) {
+ text = line;
+ ioff = 1;
+ ll = '';
+ ss = '';
+ } else {
+ text = line + '"';
+ ioff = 1;
+ ll = '';
+ ss = suffix;
+ }
+
+ var el = this.appendSimpleText_(
+ ll, indent + ioff * label.length + ioff, text, ss);
+ el.style.whiteSpace = 'pre';
+ return el;
+ }, this);
+ return;
+ } else if (object.match(URL_REGEX)) {
+ var link = document.createElement('a');
+ link.href = object;
+ link.textContent = object;
+ this.appendElementWithLabel_(label, indent, link, suffix);
+ return;
+ } else {
+ this.appendSimpleText_(
+ label, indent, '"' + object + '"', suffix);
+ return;
}
- } else {
- return this.appendSimpleText_(label, indent, object, suffix);
}
+ else {
+ /* Fall through to the flow below */
+ }
+ } else {
+ return this.appendSimpleText_(label, indent, object, suffix);
}
+ }
- if (object instanceof tr.model.ObjectSnapshot) {
- var link = document.createElement('tr-ui-a-analysis-link');
- link.selection = new tr.model.EventSet(object);
- this.appendElementWithLabel_(label, indent, link, suffix);
- return;
- }
-
- if (object instanceof tr.model.ObjectInstance) {
- var link = document.createElement('tr-ui-a-analysis-link');
- link.selection = new tr.model.EventSet(object);
- this.appendElementWithLabel_(label, indent, link, suffix);
- return;
- }
+ if (object instanceof tr.model.ObjectSnapshot) {
+ var link = document.createElement('tr-ui-a-analysis-link');
+ link.selection = new tr.model.EventSet(object);
+ this.appendElementWithLabel_(label, indent, link, suffix);
+ return;
+ }
- if (object instanceof tr.b.Rect) {
- this.appendSimpleText_(label, indent, object.toString(), suffix);
- return;
- }
+ if (object instanceof tr.model.ObjectInstance) {
+ var link = document.createElement('tr-ui-a-analysis-link');
+ link.selection = new tr.model.EventSet(object);
+ this.appendElementWithLabel_(label, indent, link, suffix);
+ return;
+ }
- if (object instanceof tr.v.ScalarNumeric) {
- var el = this.ownerDocument.createElement('tr-v-ui-scalar-span');
- el.value = object;
- this.appendElementWithLabel_(label, indent, el, suffix);
- return;
- }
+ if (object instanceof tr.b.Rect) {
+ this.appendSimpleText_(label, indent, object.toString(), suffix);
+ return;
+ }
- if (object instanceof Array) {
- this.appendElementsForArray_(
- label, object, indent, depth, maxDepth, suffix);
- return;
- }
+ if (object instanceof tr.v.ScalarNumeric) {
+ var el = this.ownerDocument.createElement('tr-v-ui-scalar-span');
+ el.value = object;
+ this.appendElementWithLabel_(label, indent, el, suffix);
+ return;
+ }
- this.appendElementsForObject_(
+ if (object instanceof Array) {
+ this.appendElementsForArray_(
label, object, indent, depth, maxDepth, suffix);
- },
+ return;
+ }
- appendElementsForArray_: function(
- label, object, indent, depth, maxDepth, suffix) {
- if (object.length == 0) {
- this.appendSimpleText_(label, indent, '[]', suffix);
- return;
- }
+ this.appendElementsForObject_(
+ label, object, indent, depth, maxDepth, suffix);
+ },
- if (isTable(object)) {
- var table = document.createElement('tr-ui-b-table');
- var columns = [];
- tr.b.iterItems(object[0], function(colName) {
- var allStrings = true;
- var allNumbers = true;
- for (var i = 0; i < object.length; ++i) {
- if (typeof(object[i][colName]) !== 'string')
- allStrings = false;
-
- if (typeof(object[i][colName]) !== 'number')
- allNumbers = false;
-
- if (!allStrings && !allNumbers)
- break;
- }
+ appendElementsForArray_: function(
+ label, object, indent, depth, maxDepth, suffix) {
+ if (object.length === 0) {
+ this.appendSimpleText_(label, indent, '[]', suffix);
+ return;
+ }
- var column = {title: colName};
- column.value = function(row) {
- return row[colName];
- };
+ if (isTable(object)) {
+ var table = document.createElement('tr-ui-b-table');
+ var columns = [];
+ tr.b.iterItems(object[0], function(colName) {
+ var allStrings = true;
+ var allNumbers = true;
+ for (var i = 0; i < object.length; ++i) {
+ if (typeof(object[i][colName]) !== 'string')
+ allStrings = false;
+
+ if (typeof(object[i][colName]) !== 'number')
+ allNumbers = false;
+
+ if (!allStrings && !allNumbers)
+ break;
+ }
- if (allStrings) {
- column.cmp = function(x, y) {
- return x[colName].localeCompare(y[colName]);
- };
- } else if (allNumbers) {
- column.cmp = function(x, y) {
- return x[colName] - y[colName];
- };
- }
- columns.push(column);
- });
- table.tableColumns = columns;
- table.tableRows = object;
- this.appendElementWithLabel_(label, indent, table, suffix);
- table.rebuild();
- return;
- }
+ var column = {title: colName};
+ column.value = function(row) {
+ return row[colName];
+ };
- this.appendElementsForType_(
- label + '[',
- object[0],
- indent, depth + 1, maxDepth,
- object.length > 1 ? ',' : ']' + suffix);
- for (var i = 1; i < object.length; i++) {
- this.appendElementsForType_(
- '',
- object[i],
- indent + label.length + 1, depth + 1, maxDepth,
- i < object.length - 1 ? ',' : ']' + suffix);
- }
+ if (allStrings) {
+ column.cmp = function(x, y) {
+ return x[colName].localeCompare(y[colName]);
+ };
+ } else if (allNumbers) {
+ column.cmp = function(x, y) {
+ return x[colName] - y[colName];
+ };
+ }
+ columns.push(column);
+ });
+ table.tableColumns = columns;
+ table.tableRows = object;
+ this.appendElementWithLabel_(label, indent, table, suffix);
+ table.rebuild();
return;
- },
-
- appendElementsForObject_: function(
- label, object, indent, depth, maxDepth, suffix) {
- var keys = tr.b.dictionaryKeys(object);
- if (keys.length == 0) {
- this.appendSimpleText_(label, indent, '{}', suffix);
- return;
- }
+ }
+ this.appendElementsForType_(
+ label + '[',
+ object[0],
+ indent, depth + 1, maxDepth,
+ object.length > 1 ? ',' : ']' + suffix);
+ for (var i = 1; i < object.length; i++) {
this.appendElementsForType_(
- label + '{' + keys[0] + ': ',
- object[keys[0]],
- indent, depth, maxDepth,
- keys.length > 1 ? ',' : '}' + suffix);
- for (var i = 1; i < keys.length; i++) {
- this.appendElementsForType_(
- keys[i] + ': ',
- object[keys[i]],
- indent + label.length + 1, depth + 1, maxDepth,
- i < keys.length - 1 ? ',' : '}' + suffix);
- }
- },
-
- appendElementWithLabel_: function(label, indent, dataElement, suffix) {
- var row = document.createElement('div');
-
- var indentSpan = document.createElement('span');
- indentSpan.style.whiteSpace = 'pre';
- for (var i = 0; i < indent; i++)
- indentSpan.textContent += ' ';
- row.appendChild(indentSpan);
-
- var labelSpan = document.createElement('span');
- labelSpan.textContent = label;
- row.appendChild(labelSpan);
-
- row.appendChild(dataElement);
- var suffixSpan = document.createElement('span');
- suffixSpan.textContent = suffix;
- row.appendChild(suffixSpan);
-
- row.dataElement = dataElement;
- this.$.content.appendChild(row);
- },
+ '',
+ object[i],
+ indent + label.length + 1, depth + 1, maxDepth,
+ i < object.length - 1 ? ',' : ']' + suffix);
+ }
+ return;
+ },
+
+ appendElementsForObject_: function(
+ label, object, indent, depth, maxDepth, suffix) {
+ var keys = tr.b.dictionaryKeys(object);
+ if (keys.length === 0) {
+ this.appendSimpleText_(label, indent, '{}', suffix);
+ return;
+ }
- appendSimpleText_: function(label, indent, text, suffix) {
- var el = this.ownerDocument.createElement('span');
- el.textContent = text;
- this.appendElementWithLabel_(label, indent, el, suffix);
- return el;
+ this.appendElementsForType_(
+ label + '{' + keys[0] + ': ',
+ object[keys[0]],
+ indent, depth, maxDepth,
+ keys.length > 1 ? ',' : '}' + suffix);
+ for (var i = 1; i < keys.length; i++) {
+ this.appendElementsForType_(
+ keys[i] + ': ',
+ object[keys[i]],
+ indent + label.length + 1, depth + 1, maxDepth,
+ i < keys.length - 1 ? ',' : '}' + suffix);
}
- });
- </script>
-</polymer-element>
+ },
+
+ appendElementWithLabel_: function(label, indent, dataElement, suffix) {
+ var row = document.createElement('div');
+
+ var indentSpan = document.createElement('span');
+ indentSpan.style.whiteSpace = 'pre';
+ for (var i = 0; i < indent; i++)
+ Polymer.dom(indentSpan).textContent += ' ';
+ Polymer.dom(row).appendChild(indentSpan);
+
+ var labelSpan = document.createElement('span');
+ Polymer.dom(labelSpan).textContent = label;
+ Polymer.dom(row).appendChild(labelSpan);
+
+ Polymer.dom(row).appendChild(dataElement);
+ var suffixSpan = document.createElement('span');
+ Polymer.dom(suffixSpan).textContent = suffix;
+ Polymer.dom(row).appendChild(suffixSpan);
+
+ row.dataElement = dataElement;
+ Polymer.dom(this.$.content).appendChild(row);
+ },
+
+ appendSimpleText_: function(label, indent, text, suffix) {
+ var el = this.ownerDocument.createElement('span');
+ Polymer.dom(el).textContent = text;
+ this.appendElementWithLabel_(label, indent, el, suffix);
+ return el;
+ }
+});
+</script>
-<polymer-element name="tr-ui-a-generic-object-view-with-label"
- is="HTMLUnknownElement">
+<dom-module id='tr-ui-a-generic-object-view-with-label'>
<template>
<style>
:host {
@@ -306,34 +313,35 @@ found in the LICENSE file.
}
</style>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.labelEl_ = document.createElement('div');
- this.genericObjectView_ =
- document.createElement('tr-ui-a-generic-object-view');
- this.shadowRoot.appendChild(this.labelEl_);
- this.shadowRoot.appendChild(this.genericObjectView_);
- },
-
- get label() {
- return this.labelEl_.textContent;
- },
-
- set label(label) {
- this.labelEl_.textContent = label;
- },
-
- get object() {
- return this.genericObjectView_.object;
- },
-
- set object(object) {
- this.genericObjectView_.object = object;
- }
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-generic-object-view-with-label',
+
+ ready: function() {
+ this.labelEl_ = document.createElement('div');
+ this.genericObjectView_ =
+ document.createElement('tr-ui-a-generic-object-view');
+ Polymer.dom(this.root).appendChild(this.labelEl_);
+ Polymer.dom(this.root).appendChild(this.genericObjectView_);
+ },
+
+ get label() {
+ return Polymer.dom(this.labelEl_).textContent;
+ },
+
+ set label(label) {
+ Polymer.dom(this.labelEl_).textContent = label;
+ },
+
+ get object() {
+ return this.genericObjectView_.object;
+ },
+
+ set object(object) {
+ this.genericObjectView_.object = object;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
index 50997e18622..64b0e04a2fc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
@@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/object_instance.html">
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
<link rel="import" href="/tracing/ui/base/deep_utils.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -18,19 +18,19 @@ tr.b.unittest.testSuite(function() {
test('undefinedValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object = undefined;
- assert.equal(view.$.content.textContent, 'undefined');
+ assert.equal(Polymer.dom(view.$.content).textContent, 'undefined');
});
test('nullValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object = null;
- assert.equal(view.$.content.textContent, 'null');
+ assert.equal(Polymer.dom(view.$.content).textContent, 'null');
});
test('stringValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object = 'string value';
- assert.equal(view.$.content.textContent, '"string value"');
+ assert.equal(Polymer.dom(view.$.content).textContent, '"string value"');
});
test('multiLineStringValue', function() {
@@ -65,13 +65,13 @@ tr.b.unittest.testSuite(function() {
test('booleanValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object = false;
- assert.equal(view.$.content.textContent, 'false');
+ assert.equal(Polymer.dom(view.$.content).textContent, 'false');
});
test('numberValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object = 3.14159;
- assert.equal(view.$.content.textContent, '3.14159');
+ assert.equal(Polymer.dom(view.$.content).textContent, '3.14159');
});
test('objectSnapshotValue', function() {
@@ -179,14 +179,14 @@ tr.b.unittest.testSuite(function() {
test('timeDurationValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object =
- new tr.v.ScalarNumeric(tr.v.Unit.byName.timeDurationInMs, 3);
+ new tr.v.ScalarNumeric(tr.b.Unit.byName.timeDurationInMs, 3);
assert.isDefined(tr.b.findDeepElementMatching(
view.$.content, 'tr-v-ui-scalar-span'));
});
test('timeStampValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
- view.object = new tr.v.ScalarNumeric(tr.v.Unit.byName.timeStampInMs, 3);
+ view.object = new tr.v.ScalarNumeric(tr.b.Unit.byName.timeStampInMs, 3);
assert.isDefined(tr.b.findDeepElementMatching(
view.$.content, 'tr-v-ui-scalar-span'));
});
@@ -194,13 +194,23 @@ tr.b.unittest.testSuite(function() {
test('scalarValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
view.object =
- new tr.v.ScalarNumeric(tr.v.Unit.byName.normalizedPercentage, .3);
+ new tr.v.ScalarNumeric(tr.b.Unit.byName.normalizedPercentage, .3);
var m = tr.b.findDeepElementMatching(
view.$.content, 'tr-v-ui-scalar-span');
assert.isDefined(m);
assert.equal(m.value, .3);
- assert.equal(m.unit, tr.v.Unit.byName.normalizedPercentage);
+ assert.equal(m.unit, tr.b.Unit.byName.normalizedPercentage);
});
+ test('httpLink', function() {
+ var view = document.createElement('tr-ui-a-generic-object-view');
+ var url = 'https://google.com/chrome';
+ view.object = {a: url};
+ this.addHTMLOutput(view);
+ var a = tr.b.findDeepElementMatching(view.$.content, 'a');
+ assert.isDefined(a);
+ assert.strictEqual(url, a.href);
+ assert.strictEqual(url, a.textContent);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
index df1d38264aa..e410eaca58d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
@@ -7,17 +7,16 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
-<link rel="import"
- href="/tracing/ui/analysis/memory_dump_heap_details_pane.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_pane.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/ui/analysis/stacked_pane.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/table.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-memory-dump-allocator-details-pane"
- extends="tr-ui-a-stacked-pane">
+
+<dom-module id='tr-ui-a-memory-dump-allocator-details-pane'>
<template>
<style>
:host {
@@ -54,6 +53,7 @@ found in the LICENSE file.
display: none; /* Hide until memory allocator dumps are set. */
flex: 1 0 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<div id="label">Component details</div>
@@ -62,7 +62,7 @@ found in the LICENSE file.
<tr-ui-b-table id="table"></tr-ui-b-table>
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -210,7 +210,7 @@ tr.exportTo('tr.ui.analysis', function() {
appendSizeIfDefined: function(size) {
if (size !== undefined)
- this.append(' (', tr.v.Unit.byName.sizeInBytes.format(size), ')');
+ this.append(' (', tr.b.Unit.byName.sizeInBytes.format(size), ')');
},
appendSomeTimestampsQuantifier: function() {
@@ -492,7 +492,10 @@ tr.exportTo('tr.ui.analysis', function() {
}
];
- Polymer('tr-ui-a-memory-dump-allocator-details-pane', {
+ Polymer({
+ is: 'tr-ui-a-memory-dump-allocator-details-pane',
+ behaviors: [tr.ui.analysis.StackedPane],
+
created: function() {
this.memoryAllocatorDumps_ = undefined;
this.heapDumps_ = undefined;
@@ -518,7 +521,7 @@ tr.exportTo('tr.ui.analysis', function() {
*/
set memoryAllocatorDumps(memoryAllocatorDumps) {
this.memoryAllocatorDumps_ = memoryAllocatorDumps;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get memoryAllocatorDumps() {
@@ -530,19 +533,19 @@ tr.exportTo('tr.ui.analysis', function() {
// (view) instead.
set heapDumps(heapDumps) {
this.heapDumps_ = heapDumps;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
set aggregationMode(aggregationMode) {
this.aggregationMode_ = aggregationMode;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get aggregationMode() {
return this.aggregationMode_;
},
- rebuildPane_: function() {
+ onRebuild_: function() {
if (this.memoryAllocatorDumps_ === undefined ||
this.memoryAllocatorDumps_.length === 0) {
// Show the info text (hide the table).
@@ -830,11 +833,16 @@ tr.exportTo('tr.ui.analysis', function() {
var titleColumn = new AllocatorDumpNameColumn();
titleColumn.width = '200px';
- var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'numericCells', this.aggregationMode_, NUMERIC_COLUMN_RULES);
- var diagnosticColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'diagnosticCells', this.aggregationMode_,
- DIAGNOSTIC_COLUMN_RULES);
+ var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'numericCells',
+ aggregationMode: this.aggregationMode_,
+ rules: NUMERIC_COLUMN_RULES
+ });
+ var diagnosticColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'diagnosticCells',
+ aggregationMode: this.aggregationMode_,
+ rules: DIAGNOSTIC_COLUMN_RULES
+ });
var fieldColumns = numericColumns.concat(diagnosticColumns);
tr.ui.analysis.MemoryColumn.spaceEqually(fieldColumns);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
index cc0f99ffc81..7c6a8ba4203 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/heap_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
@@ -16,7 +17,6 @@ found in the LICENSE file.
href="/tracing/ui/analysis/memory_dump_sub_view_test_utils.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -25,9 +25,9 @@ tr.b.unittest.testSuite(function() {
var MemoryAllocatorDump = tr.model.MemoryAllocatorDump;
var ScalarNumeric = tr.v.ScalarNumeric;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var HeapDump = tr.model.HeapDump;
var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode;
var checkNumericFields = tr.ui.analysis.checkNumericFields;
@@ -66,7 +66,8 @@ tr.b.unittest.testSuite(function() {
}
function newSuballocationDump(ownerDump, parentDump, name, size) {
- var suballocationDump = addChildDump(parentDump, name, { size: size });
+ var suballocationDump = addChildDump(parentDump, name,
+ {numerics: {size: size}});
if (ownerDump !== undefined)
addOwnershipLink(ownerDump, suballocationDump);
return suballocationDump;
@@ -77,49 +78,51 @@ tr.b.unittest.testSuite(function() {
var process = model.getOrCreateProcess(1);
// First timestamp.
- var gmd1 = addGlobalMemoryDump(model, -10);
- var pmd1 = addProcessMemoryDump(gmd1, process, -11);
+ var gmd1 = addGlobalMemoryDump(model, {ts: -10});
+ var pmd1 = addProcessMemoryDump(gmd1, process, {ts: -11});
pmd1.memoryAllocatorDumps = (function() {
- var v8Dump = newAllocatorDump(pmd1, 'v8', {
+ var v8Dump = newAllocatorDump(pmd1, 'v8', {numerics: {
size: 1073741824 /* 1 GiB */,
inner_size: 2097152 /* 2 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204)
- });
+ }});
var v8HeapsDump = addChildDump(v8Dump, 'heaps',
- { size: 805306368 /* 768 MiB */ });
+ {numerics: {size: 805306368 /* 768 MiB */}});
addChildDump(v8HeapsDump, 'heap42',
- { size: 804782080 /* 767.5 MiB */ });
+ {numerics: {size: 804782080 /* 767.5 MiB */}});
var v8ObjectsDump = addChildDump(v8Dump, 'objects');
v8ObjectsDump.addDiagnostic('url', 'http://example.com');
- addChildDump(v8ObjectsDump, 'foo', { size: 1022976 /* 999 KiB */ });
- addChildDump(v8ObjectsDump, 'bar', { size: 1024000 /* 1000 KiB */ });
+ addChildDump(v8ObjectsDump, 'foo',
+ {numerics: {size: 1022976 /* 999 KiB */}});
+ addChildDump(v8ObjectsDump, 'bar',
+ {numerics: {size: 1024000 /* 1000 KiB */}});
var oilpanDump = newAllocatorDump(pmd1, 'oilpan',
- { size: 125829120 /* 120 MiB */ });
+ {numerics: {size: 125829120 /* 120 MiB */}});
newSuballocationDump(
oilpanDump, v8Dump, '__99BEAD', 150994944 /* 144 MiB */);
var oilpanSubDump = addChildDump(oilpanDump, 'animals');
var oilpanSubDump1 = addChildDump(oilpanSubDump, 'cow',
- { size: 33554432 /* 32 MiB */ });
+ {numerics: {size: 33554432 /* 32 MiB */}});
newSuballocationDump(
oilpanSubDump1, v8Dump, '__42BEEF', 67108864 /* 64 MiB */);
var oilpanSubDump2 = addChildDump(oilpanSubDump, 'chicken',
- { size: 16777216 /* 16 MiB */ });
+ {numerics: {size: 16777216 /* 16 MiB */}});
newSuballocationDump(
oilpanSubDump2, v8Dump, '__68DEAD', 33554432 /* 32 MiB */);
var skiaDump = newAllocatorDump(pmd1, 'skia',
- { size: 8388608 /* 8 MiB */ });
+ {numerics: {size: 8388608 /* 8 MiB */}});
var suballocationDump = newSuballocationDump(
skiaDump, v8Dump, '__15FADE', 16777216 /* 16 MiB */);
var ccDump = newAllocatorDump(pmd1, 'cc',
- { size: 4194304 /* 4 MiB */ });
+ {numerics: {size: 4194304 /* 4 MiB */}});
newSuballocationDump(
ccDump, v8Dump, '__12FEED', 5242880 /* 5 MiB */).addDiagnostic(
'url', 'localhost:1234');
@@ -128,25 +131,27 @@ tr.b.unittest.testSuite(function() {
})();
// Second timestamp.
- var gmd2 = addGlobalMemoryDump(model, 10);
- var pmd2 = addProcessMemoryDump(gmd2, process, 11);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 10});
+ var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 11});
pmd2.memoryAllocatorDumps = (function() {
- var v8Dump = newAllocatorDump(pmd2, 'v8', {
+ var v8Dump = newAllocatorDump(pmd2, 'v8', {numerics: {
size: 1073741824 /* 1 GiB */,
inner_size: 2097152 /* 2 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204)
- });
+ }});
var v8ObjectsDump = addChildDump(v8Dump, 'objects');
v8ObjectsDump.addDiagnostic('url', 'http://sample.net');
- addChildDump(v8ObjectsDump, 'foo', { size: 1020928 /* 997 KiB */ });
- addChildDump(v8ObjectsDump, 'bar', { size: 1026048 /* 1002 KiB */ });
+ addChildDump(v8ObjectsDump, 'foo',
+ {numerics: {size: 1020928 /* 997 KiB */}});
+ addChildDump(v8ObjectsDump, 'bar',
+ {numerics: {size: 1026048 /* 1002 KiB */}});
newSuballocationDump(
undefined, v8Dump, '__99BEAD', 268435456 /* 256 MiB */);
var ccDump = newAllocatorDump(pmd2, 'cc',
- { size: 7340032 /* 7 MiB */ });
+ {numerics: {size: 7340032 /* 7 MiB */}});
newSuballocationDump(
ccDump, v8Dump, '__13DEED', 11534336 /* 11 MiB */).addDiagnostic(
'url', 'localhost:5678');
@@ -209,8 +214,8 @@ tr.b.unittest.testSuite(function() {
var process = model.getOrCreateProcess(1);
for (var i = 0; i < count; i++) {
var timestamp = 10 + i;
- var gmd = addGlobalMemoryDump(model, timestamp);
- pmds[i] = addProcessMemoryDump(gmd, process, timestamp);
+ var gmd = addGlobalMemoryDump(model, {ts: timestamp});
+ pmds[i] = addProcessMemoryDump(gmd, process, {ts: timestamp});
}
preFinalizeDumpsCallback(pmds);
});
@@ -298,7 +303,7 @@ tr.b.unittest.testSuite(function() {
var suballocationsSubRow = rootRow.subRows[2];
checkRow(columns, suballocationsSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'suballocations');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations');
assert.equal(formattedTitle.title, '');
},
size: [135266304],
@@ -310,7 +315,7 @@ tr.b.unittest.testSuite(function() {
var oilpanSuballocationSubRow = suballocationsSubRow.subRows[0];
checkRow(columns, oilpanSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'oilpan');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'oilpan');
assert.equal(formattedTitle.title, '');
},
size: [125829120],
@@ -323,7 +328,7 @@ tr.b.unittest.testSuite(function() {
oilpanSuballocationSubRow.subRows[0];
checkRow(columns, oilpanUnspecifiedSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, '<unspecified>');
+ assert.equal(Polymer.dom(formattedTitle).textContent, '<unspecified>');
assert.equal(formattedTitle.title, 'v8/__99BEAD');
},
size: [75497472],
@@ -334,7 +339,7 @@ tr.b.unittest.testSuite(function() {
var oilpanAnimalsSuballocationSubRow = oilpanSuballocationSubRow.subRows[1];
checkRow(columns, oilpanAnimalsSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'animals');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'animals');
assert.equal(formattedTitle.title, '');
},
size: [50331648],
@@ -347,7 +352,7 @@ tr.b.unittest.testSuite(function() {
oilpanAnimalsSuballocationSubRow.subRows[0];
checkRow(columns, oilpanCowSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'cow');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'cow');
assert.equal(formattedTitle.title, 'v8/__42BEEF');
},
size: [33554432],
@@ -358,7 +363,7 @@ tr.b.unittest.testSuite(function() {
var skiaSuballocationSubRow = suballocationsSubRow.subRows[1];
checkRow(columns, skiaSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'skia');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'skia');
assert.equal(formattedTitle.title, 'v8/__15FADE');
},
size: [8388608],
@@ -369,7 +374,7 @@ tr.b.unittest.testSuite(function() {
var ccSuballocationSubRow = suballocationsSubRow.subRows[2];
checkRow(columns, ccSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'cc');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'cc');
assert.equal(formattedTitle.title, 'v8/__12FEED');
},
size: [1048576],
@@ -440,7 +445,7 @@ tr.b.unittest.testSuite(function() {
var suballocationsSubRow = rootRow.subRows[3];
checkRow(columns, suballocationsSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'suballocations');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations');
assert.equal(formattedTitle.title, '');
},
size: [135266304, 272629760],
@@ -452,7 +457,7 @@ tr.b.unittest.testSuite(function() {
var oilpanSuballocationSubRow = suballocationsSubRow.subRows[0];
checkRow(columns, oilpanSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'oilpan');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'oilpan');
assert.equal(formattedTitle.title, '');
},
size: [125829120, 268435456],
@@ -465,7 +470,7 @@ tr.b.unittest.testSuite(function() {
oilpanSuballocationSubRow.subRows[0];
checkRow(columns, oilpanUnspecifiedSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, '<unspecified>');
+ assert.equal(Polymer.dom(formattedTitle).textContent, '<unspecified>');
assert.equal(formattedTitle.title, 'v8/__99BEAD');
},
size: [75497472, 268435456],
@@ -476,7 +481,7 @@ tr.b.unittest.testSuite(function() {
var oilpanAnimalsSuballocationSubRow = oilpanSuballocationSubRow.subRows[1];
checkRow(columns, oilpanAnimalsSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'animals');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'animals');
assert.equal(formattedTitle.title, '');
},
size: [50331648, undefined],
@@ -489,7 +494,7 @@ tr.b.unittest.testSuite(function() {
oilpanAnimalsSuballocationSubRow.subRows[0];
checkRow(columns, oilpanCowSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'cow');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'cow');
assert.equal(formattedTitle.title, 'v8/__42BEEF');
},
size: [33554432, undefined],
@@ -500,7 +505,7 @@ tr.b.unittest.testSuite(function() {
var skiaSuballocationSubRow = suballocationsSubRow.subRows[1];
checkRow(columns, skiaSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'skia');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'skia');
assert.equal(formattedTitle.title, 'v8/__15FADE');
},
size: [8388608, undefined],
@@ -511,7 +516,7 @@ tr.b.unittest.testSuite(function() {
var ccSuballocationSubRow = suballocationsSubRow.subRows[2];
checkRow(columns, ccSuballocationSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'cc');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'cc');
assert.equal(formattedTitle.title, 'v8/__12FEED, v8/__13DEED');
},
size: [1048576, 4194304],
@@ -592,7 +597,7 @@ tr.b.unittest.testSuite(function() {
var suballocationsSubRow = rootRow.subRows[3];
checkRow(columns, suballocationsSubRow, {
title: function(formattedTitle) {
- assert.equal(formattedTitle.textContent, 'suballocations');
+ assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations');
assert.equal(formattedTitle.title, '');
},
size: [135266304, undefined, 272629760],
@@ -648,7 +653,7 @@ tr.b.unittest.testSuite(function() {
// Sub-allocation row.
var row = c.formatTitle({title: 'Suballocation row', suballocation: true});
- assert.strictEqual(row.textContent, 'Suballocation row');
+ assert.strictEqual(Polymer.dom(row).textContent, 'Suballocation row');
assert.strictEqual(row.style.fontStyle, 'italic');
});
@@ -696,10 +701,10 @@ tr.b.unittest.testSuite(function() {
AggregationMode.DIFF);
var pmds = buildProcessMemoryDumps(4 /* count */, function(pmds) {
addRootDumps(pmds[0], ['v8'], function(v8Dump) {
- addChildDump(v8Dump, 'heaps', { size: 64 });
+ addChildDump(v8Dump, 'heaps', {numerics: {size: 64}});
});
addRootDumps(pmds[2], ['v8'], function(v8Dump) {
- addChildDump(v8Dump, 'heaps', { size: 128 });
+ addChildDump(v8Dump, 'heaps', {numerics: {size: 128}});
});
addRootDumps(pmds[3], ['v8'], function(v8Dump) {});
});
@@ -729,28 +734,28 @@ tr.b.unittest.testSuite(function() {
AggregationMode.MAX);
var pmds = buildProcessMemoryDumps(5 /* count */, function(pmds) {
addRootDumps(pmds[0], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
addOwnershipLink(v8HeapsDump, oilpanObjectsDump);
});
addRootDumps(pmds[1], ['v8'], function(v8Dump) {
- addChildDump(v8Dump, 'heaps', { size: 32 });
+ addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
// Missing oilpan/objects dump.
});
addRootDumps(pmds[2], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
// Missing v8/heaps dump.
});
addRootDumps(pmds[3], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- addChildDump(v8Dump, 'heaps', { size: 32 });
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
// Missing ownership link.
});
addRootDumps(pmds[4], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 2);
});
});
@@ -835,44 +840,51 @@ tr.b.unittest.testSuite(function() {
AggregationMode.DIFF);
var pmds = buildProcessMemoryDumps(6 /* count */, function(pmds) {
addRootDumps(pmds[0], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 });
- var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
+ var v8QueuesDump = addChildDump(v8Dump, 'queues',
+ {numerics: {size: 8}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
addOwnershipLink(v8HeapsDump, oilpanObjectsDump);
addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1);
});
addRootDumps(pmds[1], ['v8'], function(v8Dump) {});
addRootDumps(pmds[2], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 });
- var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 });
- var v8PilesDump = addChildDump(v8Dump, 'piles', { size: 48 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
+ var v8QueuesDump = addChildDump(v8Dump, 'queues',
+ {numerics: {size: 8}});
+ var v8PilesDump = addChildDump(v8Dump, 'piles', {numerics: {size: 48}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 2);
addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1);
addOwnershipLink(v8PilesDump, oilpanObjectsDump);
});
addRootDumps(pmds[3], ['v8', 'blink'], function(v8Dump, blinkDump) {
- var blinkHandlesDump = addChildDump(blinkDump, 'handles', { size: 32 });
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 64 });
- var blinkObjectsDump = addChildDump(blinkDump, 'objects', { size: 32 });
+ var blinkHandlesDump = addChildDump(blinkDump, 'handles',
+ {numerics: {size: 32}});
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 64}});
+ var blinkObjectsDump = addChildDump(blinkDump, 'objects',
+ {numerics: {size: 32}});
addOwnershipLink(blinkHandlesDump, v8HeapsDump, -273);
addOwnershipLink(v8HeapsDump, blinkObjectsDump, 3);
});
addRootDumps(pmds[4], ['v8', 'gpu'], function(v8Dump, gpuDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 64 });
- var gpuTile1Dump = addChildDump(gpuDump, 'tile1', { size: 100 });
- var gpuTile2Dump = addChildDump(gpuDump, 'tile2', { size: 99 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 64}});
+ var gpuTile1Dump = addChildDump(gpuDump, 'tile1',
+ {numerics: {size: 100}});
+ var gpuTile2Dump = addChildDump(gpuDump, 'tile2',
+ {numerics: {size: 99}});
addOwnershipLink(v8HeapsDump, gpuTile1Dump, 3);
addOwnershipLink(gpuTile2Dump, gpuTile1Dump, -1);
});
addRootDumps(pmds[5], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 });
- var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 });
- var v8PilesDump = addChildDump(v8Dump, 'piles', { size: 48 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}});
+ var v8QueuesDump = addChildDump(v8Dump, 'queues',
+ {numerics: {size: 8}});
+ var v8PilesDump = addChildDump(v8Dump, 'piles', {numerics: {size: 48}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 64 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 64}});
addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 1);
addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1);
addOwnershipLink(v8PilesDump, oilpanObjectsDump, 7);
@@ -1023,54 +1035,71 @@ tr.b.unittest.testSuite(function() {
var pmds = buildProcessMemoryDumps(7 /* count */, function(pmds) {
addRootDumps(pmds[0], ['v8'], function(v8Dump) {
// Single direct overlap (v8/objects -> v8/heaps).
- var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1536 });
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
+ var v8ObjectsDump = addChildDump(v8Dump, 'objects',
+ {numerics: {size: 1536}});
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
addOwnershipLink(v8ObjectsDump, v8HeapsDump);
});
// pmd[1] intentionally skipped.
addRootDumps(pmds[2], ['v8'], function(v8Dump, oilpanDump) {
// Single direct overlap with inconsistent owned dump size.
- var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 3072 });
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
+ var v8ObjectsDump = addChildDump(v8Dump, 'objects',
+ {numerics: {size: 3072}});
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
addOwnershipLink(v8ObjectsDump, v8HeapsDump);
});
addRootDumps(pmds[3], ['v8'], function(v8Dump) {
// Single indirect overlap (v8/objects/X -> v8/heaps/42).
- var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1536 });
- var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', { size: 512 });
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
- var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', { size: 1024 });
+ var v8ObjectsDump = addChildDump(v8Dump, 'objects',
+ {numerics: {size: 1536}});
+ var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X',
+ {numerics: {size: 512}});
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
+ var v8Heaps42Dump = addChildDump(v8HeapsDump, '42',
+ {numerics: {size: 1024}});
addOwnershipLink(v8ObjectsXDump, v8Heaps42Dump);
});
addRootDumps(pmds[4], ['v8'], function(v8Dump) {
// Multiple overlaps.
- var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1024 });
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
+ var v8ObjectsDump = addChildDump(v8Dump, 'objects',
+ {numerics: {size: 1024}});
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
- var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', { size: 512 });
- var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', { size: 1280 });
+ var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X',
+ {numerics: {size: 512}});
+ var v8Heaps42Dump = addChildDump(v8HeapsDump, '42',
+ {numerics: {size: 1280}});
addOwnershipLink(v8ObjectsXDump, v8Heaps42Dump);
- var v8ObjectsYDump = addChildDump(v8ObjectsDump, 'Y', { size: 128 });
- var v8Heaps90Dump = addChildDump(v8HeapsDump, '90', { size: 256 });
+ var v8ObjectsYDump = addChildDump(v8ObjectsDump, 'Y',
+ {numerics: {size: 128}});
+ var v8Heaps90Dump = addChildDump(v8HeapsDump, '90',
+ {numerics: {size: 256}});
addOwnershipLink(v8ObjectsYDump, v8Heaps90Dump);
- var v8BlocksDump = addChildDump(v8Dump, 'blocks', { size: 768 });
+ var v8BlocksDump = addChildDump(v8Dump, 'blocks',
+ {numerics: {size: 768}});
addOwnershipLink(v8BlocksDump, v8Heaps42Dump);
});
addRootDumps(pmds[5], ['v8'], function(v8Dump) {
// No overlaps, inconsistent parent size.
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
- addChildDump(v8HeapsDump, '42', { size: 1536 });
- addChildDump(v8HeapsDump, '90', { size: 615 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
+ addChildDump(v8HeapsDump, '42', {numerics: {size: 1536}});
+ addChildDump(v8HeapsDump, '90', {numerics: {size: 615}});
});
addRootDumps(pmds[6], ['v8', 'oilpan'], function(v8Dump, oilpanDump) {
// No overlaps, inconsistent parent and owned dump size.
- var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 });
- addChildDump(v8HeapsDump, '42', { size: 1536 });
- addChildDump(v8HeapsDump, '90', { size: 615 });
+ var v8HeapsDump = addChildDump(v8Dump, 'heaps',
+ {numerics: {size: 2048}});
+ addChildDump(v8HeapsDump, '42', {numerics: {size: 1536}});
+ addChildDump(v8HeapsDump, '90', {numerics: {size: 615}});
var oilpanObjectsDump =
- addChildDump(oilpanDump, 'objects', { size: 3072 });
+ addChildDump(oilpanDump, 'objects', {numerics: {size: 3072}});
addOwnershipLink(oilpanObjectsDump, v8HeapsDump);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html
index 7b9ea7ce06e..3033295062f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html
@@ -5,14 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_overview_pane.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/ui/analysis/stacked_pane.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-memory-dump-header-pane"
- extends="tr-ui-a-stacked-pane">
+<dom-module id='tr-ui-a-memory-dump-header-pane'>
<template>
<style>
:host {
@@ -45,31 +44,33 @@ found in the LICENSE file.
<!-- Aggregation mode selector (added in Polymer.ready()) -->
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui.analysis', function() {
+ Polymer({
+ is: 'tr-ui-a-memory-dump-header-pane',
+ behaviors: [tr.ui.analysis.StackedPane],
- Polymer('tr-ui-a-memory-dump-header-pane', {
created: function() {
this.containerMemoryDumps_ = undefined;
},
ready: function() {
- this.$.aggregation_mode_container.appendChild(tr.ui.b.createSelector(
- this, 'aggregationMode', 'memoryDumpHeaderPane.aggregationMode',
- tr.ui.analysis.MemoryColumn.AggregationMode.DIFF,
- [
- {
- label: 'Diff',
- value: tr.ui.analysis.MemoryColumn.AggregationMode.DIFF
- },
- {
- label: 'Max',
- value: tr.ui.analysis.MemoryColumn.AggregationMode.MAX
- }
- ]));
+ Polymer.dom(this.$.aggregation_mode_container).appendChild(
+ tr.ui.b.createSelector(this, 'aggregationMode',
+ 'memoryDumpHeaderPane.aggregationMode',
+ tr.ui.analysis.MemoryColumn.AggregationMode.DIFF, [
+ {
+ label: 'Diff',
+ value: tr.ui.analysis.MemoryColumn.AggregationMode.DIFF
+ },
+ {
+ label: 'Max',
+ value: tr.ui.analysis.MemoryColumn.AggregationMode.MAX
+ }
+ ]));
},
/**
@@ -89,7 +90,7 @@ tr.exportTo('tr.ui.analysis', function() {
*/
set containerMemoryDumps(containerMemoryDumps) {
this.containerMemoryDumps_ = containerMemoryDumps;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get containerMemoryDumps() {
@@ -98,45 +99,46 @@ tr.exportTo('tr.ui.analysis', function() {
set aggregationMode(aggregationMode) {
this.aggregationMode_ = aggregationMode;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get aggregationMode() {
return this.aggregationMode_;
},
- rebuildPane_: function() {
+ onRebuild_: function() {
this.updateLabel_();
this.updateAggregationModeSelector_();
this.changeChildPane_();
},
updateLabel_: function() {
- this.$.label.textContent = '';
+ Polymer.dom(this.$.label).textContent = '';
if (this.containerMemoryDumps_ === undefined ||
this.containerMemoryDumps_.length <= 0) {
- this.$.label.textContent = 'No memory dumps selected';
+ Polymer.dom(this.$.label).textContent = 'No memory dumps selected';
return;
}
var containerDumpCount = this.containerMemoryDumps_.length;
var isMultiSelection = containerDumpCount > 1;
- this.$.label.appendChild(document.createTextNode(
+ Polymer.dom(this.$.label).appendChild(document.createTextNode(
'Selected ' + containerDumpCount + ' memory dump' +
(isMultiSelection ? 's' : '') +
' in ' + this.containerMemoryDumps_[0].containerName + ' at '));
// TODO(petrcermak): Use <tr-v-ui-scalar-span> once it can be displayed
// inline. See https://github.com/catapult-project/catapult/issues/1371.
- this.$.label.appendChild(document.createTextNode(
- tr.v.Unit.byName.timeStampInMs.format(
+ Polymer.dom(this.$.label).appendChild(document.createTextNode(
+ tr.b.Unit.byName.timeStampInMs.format(
this.containerMemoryDumps_[0].start)));
if (isMultiSelection) {
var ELLIPSIS = String.fromCharCode(8230);
- this.$.label.appendChild(document.createTextNode(ELLIPSIS));
- this.$.label.appendChild(document.createTextNode(
- tr.v.Unit.byName.timeStampInMs.format(
+ Polymer.dom(this.$.label).appendChild(
+ document.createTextNode(ELLIPSIS));
+ Polymer.dom(this.$.label).appendChild(document.createTextNode(
+ tr.b.Unit.byName.timeStampInMs.format(
this.containerMemoryDumps_[containerDumpCount - 1].start)));
}
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html
index f3e220605e8..8bdf26243af 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html
@@ -35,7 +35,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(viewEl.aggregationMode, AggregationMode.DIFF);
// Check the text in the label.
- assert.equal(viewEl.$.label.textContent, expectedLabelText);
+ assert.equal(Polymer.dom(viewEl.$.label).textContent, expectedLabelText);
// Check the visibility of aggregation mode selector.
var aggregationModeContainerVisible =
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html
new file mode 100644
index 00000000000..90f796799a5
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html
@@ -0,0 +1,276 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/color_scheme.html">
+<link rel="import" href="/tracing/base/event.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
+<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html">
+<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/tab_view.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/value/ui/scalar_context_controller.html">
+
+<dom-module id='tr-ui-a-memory-dump-heap-details-breakdown-view'>
+ <template>
+ <tr-ui-b-tab-view id="tabs"></tr-ui-b-tab-view>
+ </template>
+</dom-module>
+
+<dom-module id='tr-ui-a-memory-dump-heap-details-breakdown-view-tab'>
+ <template>
+ <tr-v-ui-scalar-context-controller></tr-v-ui-scalar-context-controller>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+
+ /** @constructor */
+ function EmptyFillerColumn() {}
+
+ EmptyFillerColumn.prototype = {
+ title: '',
+
+ value: function() {
+ return '';
+ },
+ };
+
+ Polymer({
+ is: 'tr-ui-a-memory-dump-heap-details-breakdown-view',
+ behaviors: [tr.ui.analysis.RebuildableBehavior],
+
+ created: function() {
+ this.displayedNode_ = undefined;
+ this.dimensionToTab_ = new Map();
+ },
+
+ ready: function() {
+ this.scheduleRebuild_();
+ this.root.addEventListener('keydown', this.onKeyDown_.bind(this), true);
+ },
+
+ get displayedNode() {
+ return this.displayedNode_;
+ },
+
+ set displayedNode(node) {
+ this.displayedNode_ = node;
+ this.scheduleRebuild_();
+ },
+
+ get aggregationMode() {
+ return this.aggregationMode_;
+ },
+
+ set aggregationMode(aggregationMode) {
+ this.aggregationMode_ = aggregationMode;
+ for (var tab of this.$.tabs.tabs)
+ tab.aggregationMode = aggregationMode;
+ },
+
+ onRebuild_: function() {
+ var previouslySelectedTab = this.$.tabs.selectedSubView;
+ var previouslySelectedTabFocused = false;
+ var previouslySelectedDimension = undefined;
+ if (previouslySelectedTab) {
+ previouslySelectedTabFocused = previouslySelectedTab.isFocused;
+ previouslySelectedDimension = previouslySelectedTab.dimension;
+ }
+
+ for (var tab of this.$.tabs.tabs) {
+ tab.nodes = undefined;
+ }
+ this.$.tabs.clearSubViews();
+
+ if (this.displayedNode_ === undefined) {
+ this.$.tabs.label = 'No heap node provided.';
+ return;
+ }
+
+ for (var [dimension, children] of this.displayedNode_.childNodes) {
+ if (!this.dimensionToTab_.has(dimension)) {
+ this.dimensionToTab_.set(dimension, document.createElement(
+ 'tr-ui-a-memory-dump-heap-details-breakdown-view-tab'));
+ }
+ var tab = this.dimensionToTab_.get(dimension);
+ tab.aggregationMode = this.aggregationMode_;
+ tab.dimension = dimension;
+ tab.nodes = children;
+ this.$.tabs.addSubView(tab);
+ tab.rebuild();
+ if (dimension === previouslySelectedDimension) {
+ this.$.tabs.selectedSubView = tab;
+ if (previouslySelectedTabFocused)
+ tab.focus();
+ }
+ }
+
+ if (this.$.tabs.tabs.length > 0)
+ this.$.tabs.label = 'Break selected node further by:';
+ else
+ this.$.tabs.label = 'Selected node cannot be broken down any further.';
+ },
+
+ onKeyDown_: function(keyEvent) {
+ if (!this.displayedNode_)
+ return;
+
+ var keyHandled = false;
+ switch (keyEvent.keyCode) {
+ case 8: // Backspace.
+ if (!this.displayedNode_.parentNode)
+ break;
+
+ // Enter the parent node upon pressing backspace.
+ var viewEvent = new tr.b.Event('enter-node');
+ viewEvent.node = this.displayedNode_.parentNode;
+ this.dispatchEvent(viewEvent);
+ keyHandled = true;
+ break;
+
+ case 37: // Left arrow.
+ case 39: // Right arrow.
+ var wasFocused = this.$.tabs.selectedSubView.isFocused;
+ keyHandled = keyEvent.keyCode === 37 ?
+ this.$.tabs.selectPreviousTabIfPossible() :
+ this.$.tabs.selectNextTabIfPossible();
+ if (wasFocused && keyHandled)
+ this.$.tabs.selectedSubView.focus(); // Restore focus to new tab.
+ }
+
+ if (!keyHandled)
+ return;
+ keyEvent.stopPropagation();
+ keyEvent.preventDefault();
+ }
+ });
+
+ Polymer({
+ is: 'tr-ui-a-memory-dump-heap-details-breakdown-view-tab',
+ behaviors: [tr.ui.analysis.RebuildableBehavior],
+
+ created: function() {
+ this.dimension_ = undefined;
+ this.nodes_ = undefined;
+ this.aggregationMode_ = undefined;
+ },
+
+ ready: function() {
+ this.$.table.addEventListener('step-into', function(tableEvent) {
+ var viewEvent = new tr.b.Event('enter-node');
+ viewEvent.node = tableEvent.tableRow;
+ this.dispatchEvent(viewEvent);
+ }.bind(this));
+ },
+
+ get dimension() {
+ return this.dimension_;
+ },
+
+ set dimension(dimension) {
+ this.dimension_ = dimension;
+ this.scheduleRebuild_();
+ },
+
+ get nodes() {
+ return this.nodes_;
+ },
+
+ set nodes(nodes) {
+ this.nodes_ = nodes;
+ this.scheduleRebuild_();
+ },
+
+ get dimensionLabel_() {
+ if (this.dimension_ === undefined)
+ return '(undefined)'
+ return this.dimension_.label;
+ },
+
+ get tabLabel() {
+ var nodeCount = 0;
+ if (this.nodes_)
+ nodeCount = this.nodes_.length;
+ return this.dimensionLabel_ + ' (' + nodeCount + ')';
+ },
+
+ get tabIcon() {
+ if (this.dimension_ === undefined ||
+ this.dimension_ === tr.ui.analysis.HeapDetailsRowDimension.ROOT) {
+ return undefined;
+ }
+ return {
+ text: this.dimension_.symbol,
+ style: 'color: ' + tr.b.ColorScheme.getColorForReservedNameAsString(
+ this.dimension_.color) + ';'
+ };
+ },
+
+ get aggregationMode() {
+ return this.aggregationMode_;
+ },
+
+ set aggregationMode(aggregationMode) {
+ this.aggregationMode_ = aggregationMode;
+ this.scheduleRebuild_();
+ },
+
+ focus: function() {
+ this.$.table.focus();
+ },
+
+ blur: function() {
+ this.$.table.blur();
+ },
+
+ get isFocused() {
+ return this.$.table.isFocused;
+ },
+
+ onRebuild_: function() {
+ this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ this.$.table.emptyValue = 'Cannot break down by ' +
+ this.dimensionLabel_.toLowerCase() + ' any further.';
+ var rows = this.nodes_ || [];
+ this.$.table.tableRows = rows;
+ this.$.table.tableColumns = this.createColumns_(rows);
+ if (this.$.table.sortColumnIndex === undefined) {
+ this.$.table.sortColumnIndex = 0;
+ this.$.table.sortDescending = false;
+ }
+ this.$.table.rebuild();
+ },
+
+ createColumns_: function(rows) {
+ var titleColumn = new tr.ui.analysis.HeapDetailsTitleColumn(
+ this.dimensionLabel_);
+ titleColumn.width = '200px';
+
+ var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'cells',
+ aggregationMode: this.aggregationMode_,
+ rules: tr.ui.analysis.HEAP_DETAILS_COLUMN_RULES,
+ shouldSetContextGroup: true
+ });
+ if (numericColumns.length === 0) {
+ numericColumns.push(new EmptyFillerColumn());
+ }
+ tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns);
+
+ var columns = [titleColumn].concat(numericColumns);
+ return columns;
+ }
+ });
+
+ return {};
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
index 05d4ad5d689..7b53e66ab5c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
@@ -8,16 +8,17 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/color_scheme.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/multi_dimensional_view.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_path_view.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/ui/analysis/stacked_pane.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<link rel='import' href='/tracing/ui/base/info_bar.html'>
-<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/base/drag_handle.html">
+<link rel="import" href="/tracing/ui/base/info_bar.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-memory-dump-heap-details-pane"
- extends="tr-ui-a-stacked-pane">
+<dom-module id='tr-ui-a-memory-dump-heap-details-pane'>
<template>
<style>
:host {
@@ -39,7 +40,7 @@ found in the LICENSE file.
#label {
flex: 1 1 auto;
padding: 8px;
- font-size: 15px;
+ font-size: 15px;
font-weight: bold;
}
@@ -63,10 +64,24 @@ found in the LICENSE file.
text-align: center;
}
- #table {
+ #split_view {
display: none; /* Hide until memory allocator dumps are set. */
flex: 1 0 auto;
align-self: stretch;
+ flex-direction: row;
+ }
+
+ #path_view {
+ width: 50%;
+ }
+
+ #breakdown_view {
+ flex: 1 1 auto;
+ width: 0;
+ }
+
+ #path_view, #breakdown_view {
+ overflow-x: auto; /* Show scrollbar if necessary. */
}
</style>
<div id="header">
@@ -79,11 +94,19 @@ found in the LICENSE file.
<div id="contents">
<tr-ui-b-info-bar id="info_bar" class="info-bar-hidden">
</tr-ui-b-info-bar>
+
<div id="info_text">No heap dump selected</div>
- <tr-ui-b-table id="table"></tr-ui-b-table>
+
+ <div id="split_view">
+ <tr-ui-a-memory-dump-heap-details-path-view id="path_view">
+ </tr-ui-a-memory-dump-heap-details-path-view>
+ <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle>
+ <tr-ui-a-memory-dump-heap-details-breakdown-view id="breakdown_view">
+ </tr-ui-a-memory-dump-heap-details-breakdown-view>
+ </div>
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -91,144 +114,203 @@ tr.exportTo('tr.ui.analysis', function() {
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
- var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
+ var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter;
var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder;
var TotalState = tr.b.MultiDimensionalViewNode.TotalState;
- /** @{enum} */
- var RowDimension = {
- ROOT: -1,
- STACK_FRAME: 0,
- OBJECT_TYPE: 1
- };
-
- var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192);
- var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9);
-
/** @{constructor} */
- function HeapDumpNodeTitleColumn(title) {
- tr.ui.analysis.TitleColumn.call(this, title);
+ function HeapDumpTreeNode(
+ stackFrameNodes, dimension, title, heavyView, parentNode) {
+ this.dimension = dimension;
+ this.title = title;
+ this.parentNode = parentNode;
+
+ this.heavyView_ = heavyView;
+ this.stackFrameNodes_ = stackFrameNodes;
+ this.lazyCells_ = undefined;
+ this.lazyChildNodes_ = undefined;
}
- HeapDumpNodeTitleColumn.prototype = {
- __proto__: tr.ui.analysis.TitleColumn.prototype,
-
- formatTitle: function(row) {
- var title = row.title;
- var dimension = row.dimension;
- switch (dimension) {
- case RowDimension.ROOT:
- return title;
-
- case RowDimension.STACK_FRAME:
- case RowDimension.OBJECT_TYPE:
- return this.formatSubRow_(title, dimension);
-
- default:
- throw new Error('Invalid row dimension: ' + row.dimension);
+ HeapDumpTreeNode.prototype = {
+ get minDisplayedTotalState_() {
+ if (this.heavyView_) {
+ // Show lower-bound and exact values in heavy views.
+ return TotalState.LOWER_BOUND;
+ } else {
+ // Show only exact values in tree view.
+ return TotalState.EXACT;
}
},
- cmp: function(rowA, rowB) {
- if (rowA.dimension !== rowB.dimension)
- return rowA.dimension - rowB.dimension;
- return tr.ui.analysis.TitleColumn.prototype.cmp.call(this, rowA, rowB);
+ get childNodes() {
+ if (!this.lazyChildNodes_) {
+ this.lazyChildNodes_ = new Map();
+ this.addDimensionChildNodes_(
+ tr.ui.analysis.HeapDetailsRowDimension.STACK_FRAME, 0);
+ this.addDimensionChildNodes_(
+ tr.ui.analysis.HeapDetailsRowDimension.OBJECT_TYPE, 1);
+ this.releaseStackFrameNodesIfPossible_();
+ }
+ return this.lazyChildNodes_;
},
- formatSubRow_: function(title, dimension) {
- var titleEl = document.createElement('span');
+ get cells() {
+ if (!this.lazyCells_) {
+ this.addCells_();
+ this.releaseStackFrameNodesIfPossible_();
+ }
+ return this.lazyCells_;
+ },
- var symbolEl = document.createElement('span');
- var symbolColorName;
- if (dimension === RowDimension.STACK_FRAME) {
- symbolEl.textContent = LATIN_SMALL_LETTER_F_WITH_HOOK;
- symbolEl.title = 'Stack frame';
- symbolColorName = 'heap_dump_stack_frame';
- } else {
- symbolEl.textContent = CIRCLED_LATIN_CAPITAL_LETTER_T;
- symbolEl.title = 'Object type';
- symbolColorName = 'heap_dump_object_type';
+ releaseStackFrameNodesIfPossible_: function() {
+ if (this.lazyCells_ && this.lazyChildNodes_) {
+ // Don't unnecessarily hold a reference to the stack frame nodes when
+ // we don't need them anymore.
+ this.stackFrameNodes_ = undefined;
}
- symbolEl.style.color =
- tr.b.ColorScheme.getColorForReservedNameAsString(symbolColorName);
- symbolEl.style.paddingRight = '4px';
- symbolEl.style.cursor = 'help';
- symbolEl.style.weight = 'bold';
- titleEl.appendChild(symbolEl);
+ },
- titleEl.appendChild(document.createTextNode(title));
+ addDimensionChildNodes_: function(dimension, dimensionIndex) {
+ // Child title -> Timestamp (list index) -> Child
+ // MultiDimensionalViewNode.
+ var dimensionChildTitleToStackFrameNodes = tr.b.invertArrayOfDicts(
+ this.stackFrameNodes_,
+ node => this.convertStackFrameNodeDimensionToChildDict_(
+ node, dimensionIndex));
+
+ // Child title (list index) -> Child HeapDumpTreeNode.
+ var dimensionChildNodes = [];
+ tr.b.iterItems(dimensionChildTitleToStackFrameNodes,
+ function(childTitle, childStackFrameNodes) {
+ dimensionChildNodes.push(new HeapDumpTreeNode(childStackFrameNodes,
+ dimension, childTitle, this.heavyView_, this));
+ }, this);
+ this.lazyChildNodes_.set(dimension, dimensionChildNodes);
+ },
- return titleEl;
- }
- };
+ convertStackFrameNodeDimensionToChildDict_: function(
+ stackFrameNode, dimensionIndex) {
+ var childDict = {};
+
+ var displayedChildrenTotalSize = 0;
+ var displayedChildrenTotalCount = 0;
+ var hasDisplayedChildren = false;
+ var allDisplayedChildrenHaveDisplayedCounts = true;
+ for (var child of stackFrameNode.children[dimensionIndex].values()) {
+ if (child.values[0].totalState < this.minDisplayedTotalState_)
+ continue;
+ if (child.values[1].totalState < this.minDisplayedTotalState_)
+ allDisplayedChildrenHaveDisplayedCounts = false;
+ childDict[child.title[dimensionIndex]] = child;
+ displayedChildrenTotalSize += child.values[0].total;
+ displayedChildrenTotalCount += child.values[1].total;
+ hasDisplayedChildren = true;
+ }
- /** @constructor */
- function AllocationCountColumn(name, cellPath, aggregationMode) {
- tr.ui.analysis.DetailsNumericMemoryColumn.call(
- this, name, cellPath, aggregationMode);
- }
+ var nodeTotalSize = stackFrameNode.values[0].total;
+ var nodeTotalCount = stackFrameNode.values[1].total;
+
+ // Add '<other>' node if necessary in tree-view.
+ var hasUnclassifiedSizeOrCount =
+ displayedChildrenTotalSize < nodeTotalSize ||
+ displayedChildrenTotalCount < nodeTotalCount;
+ if (!this.heavyView_ && hasUnclassifiedSizeOrCount &&
+ hasDisplayedChildren) {
+ var otherTitle = stackFrameNode.title.slice();
+ otherTitle[dimensionIndex] = '<other>';
+ var otherNode = new tr.b.MultiDimensionalViewNode(otherTitle, 2);
+ childDict[otherTitle[dimensionIndex]] = otherNode;
+
+ // '<other>' node size.
+ otherNode.values[0].total = nodeTotalSize - displayedChildrenTotalSize;
+ otherNode.values[0].totalState = this.minDisplayedTotalState_;
+
+ // '<other>' node allocation count.
+ otherNode.values[1].total =
+ nodeTotalCount - displayedChildrenTotalCount;
+ // Don't show allocation count of the '<other>' node if there is a
+ // displayed child node that did NOT display allocation count.
+ otherNode.values[1].totalState =
+ allDisplayedChildrenHaveDisplayedCounts ?
+ this.minDisplayedTotalState_ : TotalState.NOT_PROVIDED;
+ }
- AllocationCountColumn.prototype = {
- __proto__: tr.ui.analysis.DetailsNumericMemoryColumn.prototype,
+ return childDict;
+ },
- getFormattingContext: function(unit) {
- return { minimumFractionDigits: 0 };
+ addCells_: function() {
+ // Transform a chronological list of heap stack frame tree nodes into a
+ // dictionary of cells (where each cell contains a chronological list
+ // of the values of its numeric).
+ this.lazyCells_ = tr.ui.analysis.createCells(this.stackFrameNodes_,
+ function(stackFrameNode) {
+ var size = stackFrameNode.values[0].total;
+ var numerics = {
+ 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size)
+ };
+ var countValue = stackFrameNode.values[1];
+ if (countValue.totalState >= this.minDisplayedTotalState_) {
+ var count = countValue.total;
+ numerics['Count'] = new ScalarNumeric(
+ count_smallerIsBetter, count);
+ numerics['Average size per allocation'] = new ScalarNumeric(
+ sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count);
+ }
+ return numerics;
+ }, this);
}
};
- var COLUMN_RULES = [
- {
- condition: 'Size',
- importance: 3,
- columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
- },
- {
- condition: 'Count',
- importance: 2,
- columnConstructor: AllocationCountColumn
- },
- {
- condition: 'Average size per allocation',
- importance: 1,
- columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
- },
- {
- importance: 0,
- columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
- }
- ];
+ Polymer({
+ is: 'tr-ui-a-memory-dump-heap-details-pane',
+ behaviors: [tr.ui.analysis.StackedPane],
- Polymer('tr-ui-a-memory-dump-heap-details-pane', {
created: function() {
this.heapDumps_ = undefined;
- this.aggregationMode_ = undefined;
this.viewMode_ = undefined;
+ this.aggregationMode_ = undefined;
},
ready: function() {
- this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
this.$.info_bar.message = 'Note: Values displayed in the heavy view ' +
'are lower bounds (except for the root).';
- this.$.view_mode_container.appendChild(tr.ui.b.createSelector(
- this, 'viewMode', 'memoryDumpHeapDetailsPane.viewMode',
- MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW,
- [
- {
- label: 'Top-down (Tree)',
- value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW
- },
- {
- label: 'Top-down (Heavy)',
- value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW
- },
- {
- label: 'Bottom-up (Heavy)',
- value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW
- }
- ]));
+ Polymer.dom(this.$.view_mode_container).appendChild(
+ tr.ui.b.createSelector(
+ this, 'viewMode', 'memoryDumpHeapDetailsPane.viewMode',
+ MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW,
+ [
+ {
+ label: 'Top-down (Tree)',
+ value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW
+ },
+ {
+ label: 'Top-down (Heavy)',
+ value:
+ MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW
+ },
+ {
+ label: 'Bottom-up (Heavy)',
+ value:
+ MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW
+ }
+ ]));
+
+ this.$.drag_handle.target = this.$.path_view;
+ this.$.drag_handle.horizontal = false;
+
+ // If the user selects a node in the path view, show its children in the
+ // breakdown view.
+ this.$.path_view.addEventListener('selected-node-changed', (function(e) {
+ this.$.breakdown_view.displayedNode = this.$.path_view.selectedNode;
+ }).bind(this));
+
+ // If the user double-clicks on a node in the breakdown view, select the
+ // node in the path view.
+ this.$.breakdown_view.addEventListener('enter-node', (function(e) {
+ this.$.path_view.selectedNode = e.node;
+ }).bind(this));
},
/**
@@ -246,7 +328,7 @@ tr.exportTo('tr.ui.analysis', function() {
*/
set heapDumps(heapDumps) {
this.heapDumps_ = heapDumps;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get heapDumps() {
@@ -255,7 +337,8 @@ tr.exportTo('tr.ui.analysis', function() {
set aggregationMode(aggregationMode) {
this.aggregationMode_ = aggregationMode;
- this.scheduleRebuildPane_();
+ this.$.path_view.aggregationMode = aggregationMode;
+ this.$.breakdown_view.aggregationMode = aggregationMode;
},
get aggregationMode() {
@@ -264,7 +347,7 @@ tr.exportTo('tr.ui.analysis', function() {
set viewMode(viewMode) {
this.viewMode_ = viewMode;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get viewMode() {
@@ -281,36 +364,44 @@ tr.exportTo('tr.ui.analysis', function() {
}
},
- rebuildPane_: function() {
+ onRebuild_: function() {
if (this.heapDumps_ === undefined ||
this.heapDumps_.length === 0) {
// Show the info text (hide the table and the view mode selector).
this.$.info_text.style.display = 'block';
- this.$.table.style.display = 'none';
+ this.$.split_view.style.display = 'none';
this.$.view_mode_container.style.display = 'none';
this.$.info_bar.visible = false;
-
- this.$.table.clear();
- this.$.table.rebuild();
+ this.$.path_view.selectedNode = undefined;
return;
}
// Show the table and the view mode selector (hide the info text).
this.$.info_text.style.display = 'none';
- this.$.table.style.display = 'block';
+ this.$.split_view.style.display = 'flex';
this.$.view_mode_container.style.display = 'block';
// Show the info bar if in heavy view mode.
this.$.info_bar.visible = this.heavyView;
+ this.$.path_view.selectedNode = this.createHeapTree_();
+ this.$.path_view.rebuild();
+ this.$.breakdown_view.rebuild();
+ },
+
+ createHeapTree_: function() {
+ var definedHeapDump = tr.b.findFirstInArray(this.heapDumps_);
+ if (definedHeapDump === undefined)
+ return undefined;
+
+ // The title of the root node is the name of the allocator.
+ var rootRowTitle = definedHeapDump.allocatorName;
+
var stackFrameTrees = this.createStackFrameTrees_(this.heapDumps_);
- var rows = this.createRows_(stackFrameTrees);
- var columns = this.createColumns_(rows);
- this.$.table.tableRows = rows;
- this.$.table.tableColumns = columns;
- this.$.table.rebuild();
- tr.ui.analysis.expandTableRowsRecursively(this.$.table);
+ return new HeapDumpTreeNode(stackFrameTrees,
+ tr.ui.analysis.HeapDetailsRowDimension.ROOT, rootRowTitle,
+ this.heavyView);
},
createStackFrameTrees_: function(heapDumps) {
@@ -339,150 +430,9 @@ tr.exportTo('tr.ui.analysis', function() {
return builder.buildView(this.viewMode);
}, this);
- },
-
- createRows_: function(stackFrameTrees) {
- var definedHeapDump = tr.b.findFirstInArray(this.heapDumps);
- if (definedHeapDump === undefined)
- return [];
-
- // The title of the root row is the name of the allocator.
- var rootRowTitle = definedHeapDump.allocatorName;
- return [this.createHeapRowRecursively_(
- stackFrameTrees, RowDimension.ROOT, rootRowTitle)];
- },
-
- createHeapRowRecursively_: function(nodes, dimension, title) {
- // Transform a chronological list of stack frame tree nodes into a
- // dictionary of cells (where each cell contains a chronological list
- // of the values of its numeric).
- var cells = tr.ui.analysis.createCells(nodes, function(node) {
- var size = node.values[0].total;
- var row = {
- 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size)
- };
- var countValue = node.values[1];
- if (countValue.totalState >= this.minDisplayedTotalState_) {
- var count = countValue.total;
- row['Count'] = new ScalarNumeric(unitlessNumber_smallerIsBetter,
- count);
- row['Average size per allocation'] = new ScalarNumeric(
- sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count);
- }
- return row;
- }, this);
-
- var row = {
- dimension: dimension,
- title: title,
- contexts: nodes,
- cells: cells
- };
-
- // Recursively create sub-rows for children (if applicable).
- var stackFrameSubRows = this.createHeapDimensionSubRowsRecursively_(
- nodes, RowDimension.STACK_FRAME);
- var objectTypeSubRows = this.createHeapDimensionSubRowsRecursively_(
- nodes, RowDimension.OBJECT_TYPE);
- var subRows = stackFrameSubRows.concat(objectTypeSubRows);
- if (subRows.length > 0)
- row.subRows = subRows;
-
- return row;
- },
-
- get minDisplayedTotalState_() {
- if (this.heavyView) {
- // Show lower-bound and exact values in heavy views.
- return TotalState.LOWER_BOUND;
- } else {
- // Show only exact values in tree view.
- return TotalState.EXACT;
- }
- },
-
- createHeapDimensionSubRowsRecursively_: function(nodes, dimension) {
- // Sub-row name (list index) -> Timestamp (list index) -> Child
- // MultiDimensionalViewNode.
- var dimensionGroupedChildNodes = tr.b.dictionaryValues(
- tr.b.invertArrayOfDicts(nodes, function(node) {
- var childDict = {};
- var displayedChildrenTotalSize = 0;
- var displayedChildrenTotalCount = 0;
- var hasDisplayedChildren = false;
- var allDisplayedChildrenHaveDisplayedCounts = true;
- for (var child of node.children[dimension].values()) {
- if (child.values[0].totalState < this.minDisplayedTotalState_)
- continue;
- if (child.values[1].totalState < this.minDisplayedTotalState_)
- allDisplayedChildrenHaveDisplayedCounts = false;
- childDict[child.title[dimension]] = child;
- displayedChildrenTotalSize += child.values[0].total;
- displayedChildrenTotalCount += child.values[1].total;
- hasDisplayedChildren = true;
- }
-
- var nodeTotalSize = node.values[0].total;
- var nodeTotalCount = node.values[1].total;
-
- // Add '<other>' node if necessary in tree-view.
- var hasUnclassifiedSizeOrCount =
- displayedChildrenTotalSize < nodeTotalSize ||
- displayedChildrenTotalCount < nodeTotalCount;
- if (!this.heavyView && hasUnclassifiedSizeOrCount &&
- hasDisplayedChildren) {
- var otherTitle = node.title.slice();
- otherTitle[dimension] = '<other>';
- childDict['<other>'] = {
- title: otherTitle,
- values: [
- {
- self: 0,
- total: nodeTotalSize - displayedChildrenTotalSize,
- totalState: this.minDisplayedTotalState_
- },
- {
- self: 0,
- total: nodeTotalCount - displayedChildrenTotalCount,
- // Don't show allocation count of the '<other>' node if
- // there is a displayed child node that did NOT display
- // allocation count.
- totalState: allDisplayedChildrenHaveDisplayedCounts ?
- this.minDisplayedTotalState_ : TotalState.NOT_PROVIDED
- }
- ],
- children: [new Map(), new Map()]
- };
- }
-
- return childDict;
- }, this));
-
- // Sub-row name (list index) -> Sub-row.
- return dimensionGroupedChildNodes.map(function(subRowNodes) {
- var subRowTitle = tr.b.findFirstInArray(subRowNodes).title[dimension];
- return this.createHeapRowRecursively_(
- subRowNodes, dimension, subRowTitle);
- }, this);
- },
-
- createColumns_: function(rows) {
- var titleColumn = new HeapDumpNodeTitleColumn('Stack frame');
- titleColumn.width = '500px';
-
- var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'cells', this.aggregationMode_, COLUMN_RULES);
- tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns);
-
- var columns = [titleColumn].concat(numericColumns);
- return columns;
}
- });
+ });
- return {
- // Exported for testing.
- RowDimension: RowDimension,
- AllocationCountColumn: AllocationCountColumn
- };
+ return {};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html
index 1d1425dfb88..3fdd677213c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel='import' href='/tracing/base/iteration_helpers.html'>
<link rel='import' href='/tracing/base/multi_dimensional_view.html'>
+<link rel='import' href='/tracing/base/unit.html'>
<link rel='import' href='/tracing/core/test_utils.html'>
<link rel='import' href='/tracing/model/heap_dump.html'>
<link rel='import' href='/tracing/model/memory_dump_test_utils.html'>
@@ -15,7 +16,6 @@ found in the LICENSE file.
<link rel='import'
href='/tracing/ui/analysis/memory_dump_sub_view_test_utils.html'>
<link rel='import' href='/tracing/ui/analysis/memory_dump_sub_view_util.html'>
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -26,13 +26,12 @@ tr.b.unittest.testSuite(function() {
var TOP_DOWN_HEAVY_VIEW = ViewType.TOP_DOWN_HEAVY_VIEW;
var BOTTOM_UP_HEAVY_VIEW = ViewType.BOTTOM_UP_HEAVY_VIEW;
var HeapDump = tr.model.HeapDump;
- var RowDimension = tr.ui.analysis.RowDimension;
- var ROOT = RowDimension.ROOT;
- var STACK_FRAME = RowDimension.STACK_FRAME;
- var OBJECT_TYPE = RowDimension.OBJECT_TYPE;
+ var HeapDetailsRowDimension = tr.ui.analysis.HeapDetailsRowDimension;
+ var ROOT = HeapDetailsRowDimension.ROOT;
+ var STACK_FRAME = HeapDetailsRowDimension.STACK_FRAME;
+ var OBJECT_TYPE = HeapDetailsRowDimension.OBJECT_TYPE;
var TitleColumn = tr.ui.analysis.TitleColumn;
var NumericMemoryColumn = tr.ui.analysis.NumericMemoryColumn;
- var AllocationCountColumn = tr.ui.analysis.AllocationCountColumn;
var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode;
var addGlobalMemoryDump = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump;
var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump;
@@ -40,8 +39,7 @@ tr.b.unittest.testSuite(function() {
var checkNumericFields = tr.ui.analysis.checkNumericFields;
var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields;
var isElementDisplayed = tr.ui.analysis.isElementDisplayed;
- var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter;
function createHeapDumps(withCount) {
var model = new tr.Model();
@@ -55,8 +53,8 @@ tr.b.unittest.testSuite(function() {
}
// First timestamp.
- var gmd1 = addGlobalMemoryDump(model, -10);
- var pmd1 = addProcessMemoryDump(gmd1, process, -11);
+ var gmd1 = addGlobalMemoryDump(model, {ts: -10});
+ var pmd1 = addProcessMemoryDump(gmd1, process, {ts: -11});
var hd1 = new HeapDump(pmd1, 'partition_alloc');
addHeapEntry(hd1, undefined /* sum over all traces */,
@@ -124,8 +122,8 @@ tr.b.unittest.testSuite(function() {
undefined /* sum over all types */, 307200 /* 300 KiB */, 300);
// Second timestamp.
- var gmd2 = addGlobalMemoryDump(model, 10);
- var pmd2 = addProcessMemoryDump(gmd2, process, 11);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 10});
+ var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 11});
var hd2 = new HeapDump(pmd2, 'partition_alloc');
addHeapEntry(hd2, undefined /* sum over all traces */,
@@ -187,102 +185,103 @@ tr.b.unittest.testSuite(function() {
displayExpectations.infoText);
assert.strictEqual(isElementDisplayed(viewEl.$.info_bar),
displayExpectations.infoBar);
- assert.strictEqual(isElementDisplayed(viewEl.$.table),
- displayExpectations.tableAndSelector);
+ assert.strictEqual(isElementDisplayed(viewEl.$.split_view),
+ displayExpectations.tableAndSplitView);
assert.strictEqual(isElementDisplayed(viewEl.$.view_mode_container),
- displayExpectations.tableAndSelector);
+ displayExpectations.tableAndSplitView);
}
var EXPECTED_COLUMNS_WITHOUT_COUNT = [
- { title: 'Stack frame', type: TitleColumn, noAggregation: true },
+ { title: 'Current path', type: TitleColumn, noAggregation: true },
{ title: 'Size', type: NumericMemoryColumn }
];
var EXPECTED_COLUMNS_WITH_COUNT = EXPECTED_COLUMNS_WITHOUT_COUNT.concat([
- { title: 'Count', type: AllocationCountColumn },
+ { title: 'Count', type: NumericMemoryColumn },
{ title: 'Average size per allocation', type: NumericMemoryColumn }
]);
- function checkRow(columns, row, expectedDimension, expectedTitle,
- expectedSizes, expectedCounts, expectedAverageSizes,
- expectedDefinedValues) {
- var formattedTitle = columns[0].formatTitle(row);
- switch (expectedDimension) {
- case ROOT:
- assert.equal(formattedTitle, expectedTitle);
- break;
+ var EXPECTED_CELLS = ['Size', 'Count', 'Average size per allocation'];
- case STACK_FRAME:
- case OBJECT_TYPE:
- assert.lengthOf(formattedTitle.childNodes, 2);
- assert.strictEqual(formattedTitle.childNodes[0].textContent,
- expectedDimension === STACK_FRAME ? '\u0192' : '\u24C9');
- assert.strictEqual(
- formattedTitle.childNodes[1].textContent, expectedTitle);
- break;
+ function checkNode(node, expectedNodeStructure, expectedParentNode) {
+ assert.strictEqual(node.title, expectedNodeStructure.title);
+ assert.strictEqual(node.dimension, expectedNodeStructure.dimension);
+ assert.strictEqual(node.parentNode, expectedParentNode);
- default:
- throw new Error('Invalid expected dimension: ' + expectedDimension);
- }
+ // Check that there AREN'T any cells that we are NOT expecting.
+ var cells = node.cells;
+ assert.includeMembers(EXPECTED_CELLS, Object.keys(cells));
- checkSizeNumericFields(row, columns[1], expectedSizes);
- if (expectedCounts !== undefined) {
- // Test sanity check.
- assert.lengthOf(expectedCounts, expectedSizes.length);
- assert.lengthOf(expectedAverageSizes, expectedSizes.length);
+ var sizeCell = cells['Size'];
+ var sizeFields = sizeCell ? sizeCell.fields : undefined;
+ checkSizeNumericFields(sizeFields, undefined, expectedNodeStructure.size);
- checkNumericFields(row, columns[2], expectedCounts,
- unitlessNumber_smallerIsBetter);
- checkSizeNumericFields(row, columns[3], expectedAverageSizes);
- } else {
- // Test sanity check.
- assert.lengthOf(columns, EXPECTED_COLUMNS_WITHOUT_COUNT.length);
- assert.isUndefined(expectedAverageSizes);
- }
+ var countCell = cells['Count'];
+ var countFields = countCell ? countCell.fields : undefined;
+ checkNumericFields(countFields, undefined, expectedNodeStructure.count,
+ count_smallerIsBetter);
- var actualDefinedValues = new Array(row.contexts.length);
- for (var i = 0; i < row.contexts.length; i++)
- actualDefinedValues[i] = row.contexts[i] !== undefined;
- assert.deepEqual(actualDefinedValues, expectedDefinedValues);
- }
+ var averageSizeCell = cells['Average size per allocation'];
+ var averageSizeFields = averageSizeCell ? averageSizeCell.fields :
+ undefined;
+ checkSizeNumericFields(averageSizeFields, undefined,
+ expectedNodeStructure.averageSize);
+
+ assert.strictEqual(node.childNodes.size, 2);
- function checkRows(columns, rows, expectedStructure) {
- if (expectedStructure === undefined) {
- assert.isUndefined(rows);
+ // If |expectedNodeStructure.children| is undefined, check that there are
+ // no child nodes.
+ if (!expectedNodeStructure.children) {
+ assert.lengthOf(node.childNodes.get(STACK_FRAME), 0);
+ assert.lengthOf(node.childNodes.get(OBJECT_TYPE), 0);
return;
}
- if (typeof expectedStructure === 'number') {
- assert.lengthOf(rows, expectedStructure);
+ // If |expectedNodeStructure.children| is just a number, check total number
+ // of child nodes.
+ if (typeof expectedNodeStructure.children === 'number') {
+ assert.strictEqual(expectedNodeStructure.children,
+ node.childNodes.get(STACK_FRAME).length +
+ node.childNodes.get(OBJECT_TYPE).length);
return;
}
- assert.lengthOf(rows, expectedStructure.length);
+ // Check child nodes wrt both dimensions.
+ checkNodes(node.childNodes.get(STACK_FRAME),
+ expectedNodeStructure.children.filter(c => c.dimension === STACK_FRAME),
+ node);
+ checkNodes(node.childNodes.get(OBJECT_TYPE),
+ expectedNodeStructure.children.filter(c => c.dimension === OBJECT_TYPE),
+ node);
+ }
+
+ function checkNodes(nodes, expectedStructure, expectedParentNode) {
+ assert.lengthOf(nodes, expectedStructure.length);
for (var i = 0; i < expectedStructure.length; i++) {
- var row = rows[i];
- var expectedRowStructure = expectedStructure[i];
- checkRow(columns, row, expectedRowStructure.dimension,
- expectedRowStructure.title, expectedRowStructure.size,
- expectedRowStructure.count, expectedRowStructure.averageSize,
- expectedRowStructure.defined);
- checkRows(columns, row.subRows, expectedRowStructure.children);
+ checkNode(nodes[i], expectedStructure[i], expectedParentNode);
}
}
- function checkTable(viewEl, expectedConfig, expectedStructure) {
+ function checkSplitView(viewEl, expectedConfig, expectedStructure) {
checkDisplayedElements(viewEl, {
infoText: false,
- tableAndSelector: true,
+ tableAndSplitView: true,
infoBar: !!expectedConfig.expectedInfoBarDisplayed
});
- var table = viewEl.$.table;
- var columns = table.tableColumns;
- var rows = table.tableRows;
+
+ // Both the split view and breakdown view should be displaying the same
+ // node.
+ var selectedNode = viewEl.$.path_view.selectedNode;
+ assert.strictEqual(viewEl.$.breakdown_view.displayedNode, selectedNode);
+ checkNodes([selectedNode], expectedStructure,
+ undefined /* expectedParentNode */);
+
+ // TODO: Add proper tests for tr-ui-a-memory-dump-heap-details-path-view
+ // and tr-ui-a-memory-dump-heap-details-breakdown-view.
var expectedColumns = expectedConfig.expectedCountColumns ?
EXPECTED_COLUMNS_WITH_COUNT : EXPECTED_COLUMNS_WITHOUT_COUNT;
- checkColumns(columns, expectedColumns,
+ checkColumns(viewEl.$.path_view.$.table.tableColumns, expectedColumns,
expectedConfig.expectedAggregationMode);
- checkRows(columns, rows, expectedStructure);
}
function changeView(viewEl, viewType) {
@@ -290,97 +289,6 @@ tr.b.unittest.testSuite(function() {
viewEl.rebuild();
}
- /**
- * Helper function for generating the expected structures of heap details
- * pane tables. Given a table, this function generates its structure.
- *
- * This avoids the need to write such structures manually, which is very
- * tedious. However, the correctness of the generated structures needs to be
- * verified by the developer! Maximum line length must also be enforced
- * manually.
- */
- function printTable(test, viewEl) {
- var generator = new tr.c.TestUtils.SourceGenerator();
-
- function formatRows(rows) {
- generator.formatMultiLineList(rows, function(row) {
- generator.push('{');
- generator.indentBlock(2, true /* break line */, function() {
- generator.push('dimension: ');
- for (var dimensionTitle in RowDimension) {
- if (row.dimension === RowDimension[dimensionTitle]) {
- generator.push(dimensionTitle);
- break;
- }
- }
- generator.push(',');
- generator.breakLine();
-
- generator.push('title: \'', row.title, '\',');
- generator.breakLine();
-
-
- var sizeFields = row.cells['Size'].fields;
- generator.push('size: ');
- generator.formatSingleLineList(sizeFields, function(field) {
- generator.push(
- field === undefined ? 'undefined' : String(field.value));
- });
- generator.push(',');
- generator.breakLine();
-
- if (row.cells['Count'] !== undefined) {
- var countFields = row.cells['Count'].fields;
- generator.push('count: ');
- generator.formatSingleLineList(countFields, function(field) {
- generator.push(
- field === undefined ? 'undefined' : String(field.value));
- });
- generator.push(',');
- generator.breakLine();
-
- generator.push('averageSize: ');
- generator.formatSingleLineList(row.cells['Average size'].fields,
- function(field, index) {
- if (field === undefined) {
- generator.push('undefined');
- } else if (field.value === 0) {
- generator.push('0');
- } else {
- generator.push(String(sizeFields[index].value) + ' / ' +
- String(countFields[index].value));
- }
- });
- generator.push(',');
- generator.breakLine();
- }
-
- generator.push('defined: ');
- generator.formatSingleLineList(sizeFields, function(field) {
- generator.push(String(field !== undefined));
- });
-
- if (row.subRows && row.subRows.length > 0) {
- generator.push(',');
- generator.breakLine();
- generator.push('children: ');
- formatRows(row.subRows);
- }
- });
- generator.breakLine();
- generator.push('}');
- });
- }
-
- generator.indentBlock(8, false /* don't break line */,
- formatRows.bind(null, viewEl.$.table.tableRows));
-
- tr.c.TestUtils.addSourceListing(test, generator.build());
-
- throw new Error('This error is thrown to prevent accidentally ' +
- 'checking in a test which calls this function.');
- }
-
test('instantiate_empty', function() {
tr.ui.analysis.createAndCheckEmptyPanes(this,
'tr-ui-a-memory-dump-heap-details-pane', 'heapDumps',
@@ -388,7 +296,7 @@ tr.b.unittest.testSuite(function() {
// Check that the info text is shown.
checkDisplayedElements(viewEl, {
infoText: true,
- tableAndSelector: false,
+ tableAndSplitView: false,
infoBar: false
});
});
@@ -405,7 +313,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
// Top-down tree view (default).
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ /* empty expectedConfig */ },
[
{
@@ -417,7 +325,7 @@ tr.b.unittest.testSuite(function() {
]);
changeView(viewEl, TOP_DOWN_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ expectedInfoBarDisplayed: true },
[
{
@@ -429,7 +337,7 @@ tr.b.unittest.testSuite(function() {
]);
changeView(viewEl, BOTTOM_UP_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ expectedInfoBarDisplayed: true },
[
{
@@ -453,7 +361,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
// Top-down tree view (default).
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ /* empty expectedConfig */ },
[
{
@@ -761,7 +669,7 @@ tr.b.unittest.testSuite(function() {
]);
changeView(viewEl, BOTTOM_UP_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ expectedInfoBarDisplayed: true },
[
{
@@ -1541,7 +1449,7 @@ tr.b.unittest.testSuite(function() {
]);
changeView(viewEl, TOP_DOWN_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ expectedInfoBarDisplayed: true }, [
{
dimension: ROOT,
@@ -2331,7 +2239,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
changeView(viewEl, TOP_DOWN_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{
expectedAggregationMode: AggregationMode.DIFF,
expectedInfoBarDisplayed: true,
@@ -3567,7 +3475,7 @@ tr.b.unittest.testSuite(function() {
]);
changeView(viewEl, TOP_DOWN_TREE_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{
expectedAggregationMode: AggregationMode.DIFF,
expectedCountColumns: true
@@ -4047,7 +3955,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
changeView(viewEl, TOP_DOWN_HEAVY_VIEW);
- checkTable(viewEl,
+ checkSplitView(viewEl,
{
expectedAggregationMode: AggregationMode.MAX,
expectedInfoBarDisplayed: true
@@ -4075,7 +3983,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
// Top-down tree view (default).
- checkTable(viewEl,
+ checkSplitView(viewEl,
{ expectedAggregationMode: AggregationMode.DIFF },
[
{
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html
new file mode 100644
index 00000000000..de5e473049b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/color_scheme.html">
+<link rel="import" href="/tracing/base/event.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
+<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html">
+<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/value/ui/scalar_context_controller.html">
+
+<dom-module id='tr-ui-a-memory-dump-heap-details-path-view'>
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ </style>
+ <tr-v-ui-scalar-context-controller></tr-v-ui-scalar-context-controller>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</dom-module>
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+
+ var DOWNWARDS_ARROW_WITH_TIP_RIGHTWARDS = String.fromCharCode(0x21B3);
+
+ function HeapDetailsPathColumn(title) {
+ tr.ui.analysis.HeapDetailsTitleColumn.call(this, title);
+ }
+
+ HeapDetailsPathColumn.prototype = {
+ __proto__: tr.ui.analysis.HeapDetailsTitleColumn.prototype,
+
+ formatTitle: function(row) {
+ var title = tr.ui.analysis.HeapDetailsTitleColumn.prototype.
+ formatTitle.call(this, row);
+ if (row.dimension === tr.ui.analysis.HeapDetailsRowDimension.ROOT)
+ return title;
+
+ var arrowEl = document.createElement('span');
+ Polymer.dom(arrowEl).textContent = DOWNWARDS_ARROW_WITH_TIP_RIGHTWARDS;
+ arrowEl.style.paddingRight = '2px';
+ arrowEl.style.fontWeight = 'bold';
+ arrowEl.style.color = tr.b.ColorScheme.getColorForReservedNameAsString(
+ 'heap_dump_child_node_arrow');
+
+ var rowEl = document.createElement('span');
+ Polymer.dom(rowEl).appendChild(arrowEl);
+ Polymer.dom(rowEl).appendChild(tr.ui.b.asHTMLOrTextNode(title));
+ return rowEl;
+ }
+ }
+
+ Polymer({
+ is: 'tr-ui-a-memory-dump-heap-details-path-view',
+ behaviors: [tr.ui.analysis.RebuildableBehavior],
+
+ created: function() {
+ this.selectedNode_ = undefined;
+ this.aggregationMode_ = undefined;
+ },
+
+ ready: function() {
+ this.$.table.addEventListener('selection-changed', function(event) {
+ this.selectedNode_ = this.$.table.selectedTableRow;
+ this.didSelectedNodeChange_();
+ }.bind(this));
+ },
+
+ didSelectedNodeChange_: function() {
+ this.dispatchEvent(new tr.b.Event('selected-node-changed'));
+ },
+
+ get selectedNode() {
+ return this.selectedNode_;
+ },
+
+ set selectedNode(node) {
+ this.selectedNode_ = node;
+ this.didSelectedNodeChange_();
+ this.scheduleRebuild_();
+ },
+
+ get aggregationMode() {
+ return this.aggregationMode_;
+ },
+
+ set aggregationMode(aggregationMode) {
+ this.aggregationMode_ = aggregationMode;
+ this.scheduleRebuild_();
+ },
+
+ onRebuild_: function() {
+ if (this.selectedNode_ === undefined) {
+ this.$.table.clear();
+ return;
+ }
+
+ if (this.$.table.tableRows.includes(this.selectedNode_)) {
+ this.$.table.selectedTableRow = this.selectedNode_;
+ return;
+ }
+
+ this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ this.$.table.userCanModifySortOrder = false;
+ var rows = this.createRows_(this.selectedNode_);
+ this.$.table.tableRows = rows;
+ this.$.table.tableColumns = this.createColumns_(rows);
+ this.$.table.selectedTableRow = rows[rows.length - 1];
+ },
+
+ createRows_: function(node) {
+ var rows = [];
+ while (node) {
+ rows.push(node);
+ node = node.parentNode;
+ }
+ rows.reverse();
+ return rows;
+ },
+
+ createColumns_: function(rows) {
+ var titleColumn = new HeapDetailsPathColumn('Current path');
+ titleColumn.width = '200px';
+
+ var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'cells',
+ aggregationMode: this.aggregationMode_,
+ rules: tr.ui.analysis.HEAP_DETAILS_COLUMN_RULES,
+ shouldSetContextGroup: true
+ });
+ tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns);
+
+ return [titleColumn].concat(numericColumns);
+ }
+ });
+
+ return {};
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html
new file mode 100644
index 00000000000..d0c33aca21a
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/color_scheme.html">
+<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+
+ var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192);
+ var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9);
+
+ /** @{enum} */
+ var HeapDetailsRowDimension = {
+ ROOT: {},
+ STACK_FRAME: {
+ label: 'Stack frame',
+ symbol: LATIN_SMALL_LETTER_F_WITH_HOOK,
+ color: 'heap_dump_stack_frame'
+ },
+ OBJECT_TYPE: {
+ label: 'Object type',
+ symbol: CIRCLED_LATIN_CAPITAL_LETTER_T,
+ color: 'heap_dump_object_type'
+ }
+ };
+
+ /** @{constructor} */
+ function HeapDetailsTitleColumn(title) {
+ tr.ui.analysis.TitleColumn.call(this, title);
+ }
+
+ HeapDetailsTitleColumn.prototype = {
+ __proto__: tr.ui.analysis.TitleColumn.prototype,
+
+ formatTitle: function(row) {
+ if (row.dimension === HeapDetailsRowDimension.ROOT)
+ return row.title;
+
+ var symbolEl = document.createElement('span');
+ Polymer.dom(symbolEl).textContent = row.dimension.symbol;
+ symbolEl.title = row.dimension.label;
+ symbolEl.style.color = tr.b.ColorScheme.getColorForReservedNameAsString(
+ row.dimension.color);
+ symbolEl.style.paddingRight = '4px';
+ symbolEl.style.cursor = 'help';
+ symbolEl.style.fontWeight = 'bold';
+
+ var titleEl = document.createElement('span');
+ Polymer.dom(titleEl).appendChild(symbolEl);
+ Polymer.dom(titleEl).appendChild(document.createTextNode(row.title));
+
+ return titleEl;
+ }
+ };
+
+ /** @constructor */
+ function AllocationCountColumn(name, cellPath, aggregationMode) {
+ tr.ui.analysis.DetailsNumericMemoryColumn.call(
+ this, name, cellPath, aggregationMode);
+ }
+
+ AllocationCountColumn.prototype = {
+ __proto__: tr.ui.analysis.DetailsNumericMemoryColumn.prototype,
+
+ getFormattingContext: function(unit) {
+ return { minimumFractionDigits: 0 };
+ }
+ };
+
+ var HEAP_DETAILS_COLUMN_RULES = [
+ {
+ condition: 'Size',
+ importance: 3,
+ columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
+ },
+ {
+ condition: 'Count',
+ importance: 2,
+ columnConstructor: AllocationCountColumn
+ },
+ {
+ condition: 'Average size per allocation',
+ importance: 1,
+ columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
+ },
+ {
+ importance: 0,
+ columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn
+ }
+ ];
+
+ return {
+ HeapDetailsRowDimension: HeapDetailsRowDimension,
+ HeapDetailsTitleColumn: HeapDetailsTitleColumn,
+ AllocationCountColumn: AllocationCountColumn,
+ HEAP_DETAILS_COLUMN_RULES: HEAP_DETAILS_COLUMN_RULES
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
index 9f2152d1106..31118444e36 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
@@ -7,6 +7,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/color_scheme.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import"
href="/tracing/ui/analysis/memory_dump_allocator_details_pane.html">
@@ -19,11 +21,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/view_specific_brushing_state.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/unit_scale.html">
-<polymer-element name="tr-ui-a-memory-dump-overview-pane"
- extends="tr-ui-a-stacked-pane">
+<dom-module id='tr-ui-a-memory-dump-overview-pane'>
<template>
<style>
:host {
@@ -47,6 +46,7 @@ found in the LICENSE file.
flex: 1 0 auto;
align-self: stretch;
font-size: 12px;
+ overflow: auto;
}
#info_text {
@@ -60,6 +60,7 @@ found in the LICENSE file.
display: none; /* Hide until memory dumps are set. */
flex: 1 0 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-view-specific-brushing-state id="state"
@@ -71,7 +72,7 @@ found in the LICENSE file.
<tr-ui-b-table id="table"></tr-ui-b-table>
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -80,7 +81,7 @@ tr.exportTo('tr.ui.analysis', function() {
var ColorScheme = tr.b.ColorScheme;
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX = '_bytes';
@@ -150,7 +151,7 @@ tr.exportTo('tr.ui.analysis', function() {
},
getFormattingContext: function(unit) {
- return { unitPrefix: tr.v.UnitScale.Binary.MEBI };
+ return { unitPrefix: tr.b.UnitScale.Binary.MEBI };
},
color: function(numerics, processMemoryDumps) {
@@ -341,7 +342,7 @@ tr.exportTo('tr.ui.analysis', function() {
},
getFormattingContext: function(unit) {
- return { unitPrefix: tr.v.UnitScale.Binary.MEBI };
+ return { unitPrefix: tr.b.UnitScale.Binary.MEBI };
},
addInfos: function(numerics, processMemoryDumps, infos) {
@@ -455,7 +456,10 @@ tr.exportTo('tr.ui.analysis', function() {
}
];
- Polymer('tr-ui-a-memory-dump-overview-pane', {
+ Polymer({
+ is: 'tr-ui-a-memory-dump-overview-pane',
+ behaviors: [tr.ui.analysis.StackedPane],
+
created: function() {
this.processMemoryDumps_ = undefined;
this.aggregationMode_ = undefined;
@@ -490,7 +494,7 @@ tr.exportTo('tr.ui.analysis', function() {
*/
set processMemoryDumps(processMemoryDumps) {
this.processMemoryDumps_ = processMemoryDumps;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get processMemoryDumps() {
@@ -499,7 +503,7 @@ tr.exportTo('tr.ui.analysis', function() {
set aggregationMode(aggregationMode) {
this.aggregationMode_ = aggregationMode;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get aggregationMode() {
@@ -548,7 +552,7 @@ tr.exportTo('tr.ui.analysis', function() {
return selectedColumn.getChildPaneBuilder(selectedTableRow.contexts);
},
- rebuildPane_: function() {
+ onRebuild_: function() {
if (this.processMemoryDumps_ === undefined ||
this.processMemoryDumps_.length === 0) {
// Show the info text (hide the table).
@@ -685,13 +689,17 @@ tr.exportTo('tr.ui.analysis', function() {
var titleColumn = new ProcessNameColumn();
titleColumn.width = '200px';
- var usedMemorySizeColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'usedMemoryCells', this.aggregationMode_,
- UsedMemoryColumn.RULES);
+ var usedMemorySizeColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'usedMemoryCells',
+ aggregationMode: this.aggregationMode_,
+ rules: UsedMemoryColumn.RULES
+ });
- var allocatorSizeColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'allocatorCells', this.aggregationMode_,
- AllocatorColumn.RULES);
+ var allocatorSizeColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'allocatorCells',
+ aggregationMode: this.aggregationMode_,
+ rules: AllocatorColumn.RULES
+ });
var sizeColumns = usedMemorySizeColumns.concat(allocatorSizeColumns);
tr.ui.analysis.MemoryColumn.spaceEqually(sizeColumns);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
index bb377bba241..f4bfbfb68f3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
@@ -22,7 +22,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var MemoryAllocatorDump = tr.model.MemoryAllocatorDump;
var HeapDump = tr.model.HeapDump;
var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode;
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
return function(actualTitle) {
assert.instanceOf(actualTitle, HTMLElement);
assert.strictEqual(actualTitle.tagName, 'SPAN');
- assert.strictEqual(actualTitle.textContent, expectedTitle);
+ assert.strictEqual(Polymer.dom(actualTitle).textContent, expectedTitle);
};
}
@@ -115,7 +115,7 @@ tr.b.unittest.testSuite(function() {
function checkSpanWithColor(span, expectedText, expectedColorReservedName) {
assert.strictEqual(span.tagName, 'SPAN');
- assert.strictEqual(span.textContent, expectedText);
+ assert.strictEqual(Polymer.dom(span).textContent, expectedText);
checkColor(span.style.color, expectedColorReservedName);
}
@@ -168,9 +168,9 @@ tr.b.unittest.testSuite(function() {
var process = model.getOrCreateProcess(1);
fieldAndDumpMask.forEach(function(mask, i) {
var timestamp = 10 + i;
- var gmd = addGlobalMemoryDump(model, timestamp);
+ var gmd = addGlobalMemoryDump(model, {ts: timestamp});
if (mask & DUMP) {
- var pmd = addProcessMemoryDump(gmd, process, timestamp);
+ var pmd = addProcessMemoryDump(gmd, process, {ts: timestamp});
dumpCreatedCallback(pmd, mask);
}
});
@@ -372,8 +372,8 @@ tr.b.unittest.testSuite(function() {
var viewEl =
tr.ui.analysis.createTestPane('tr-ui-a-memory-dump-overview-pane');
var table = viewEl.$.table;
- containerEl.textContent = '';
- containerEl.appendChild(viewEl);
+ Polymer.dom(containerEl).textContent = '';
+ Polymer.dom(containerEl).appendChild(viewEl);
var displayedProcessMemoryDumps = processMemoryDumps.map(
function(memoryDumps) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
index 36235636c56..57c2dafc1c6 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/color.html">
<link rel="import" href="/tracing/base/color_scheme.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/global_memory_dump.html">
<link rel="import" href="/tracing/model/heap_dump.html">
@@ -14,7 +15,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/process_memory_dump.html">
<link rel="import" href="/tracing/model/vm_region.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -31,9 +31,9 @@ tr.exportTo('tr.ui.analysis', function() {
var VMRegionClassificationNode = tr.model.VMRegionClassificationNode;
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var unitlessNumber_smallerIsBetter =
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var HeapDump = tr.model.HeapDump;
var addGlobalMemoryDump = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump;
var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump;
@@ -50,11 +50,11 @@ tr.exportTo('tr.ui.analysis', function() {
// ======================================================================
// First timestamp.
// ======================================================================
- var gmd1 = addGlobalMemoryDump(model, 42);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 42});
// Totals and VM regions.
- var pmd1A = addProcessMemoryDump(gmd1, pA, 41);
- pmd1A.totals = { residentBytes: 31457280 /* 30 MiB */ };
+ var pmd1A = addProcessMemoryDump(gmd1, pA, {ts: 41});
+ pmd1A.totals = {residentBytes: 31457280 /* 30 MiB */};
pmd1A.vmRegions = VMRegionClassificationNode.fromRegions([
VMRegion.fromDict({
startAddress: 1024,
@@ -70,7 +70,7 @@ tr.exportTo('tr.ui.analysis', function() {
]);
// Everything.
- var pmd1B = addProcessMemoryDump(gmd1, pB, 42);
+ var pmd1B = addProcessMemoryDump(gmd1, pB, {ts: 42});
pmd1B.totals = {
residentBytes: 20971520, /* 20 MiB */
peakResidentBytes: 41943040, /* 40 MiB */
@@ -105,27 +105,28 @@ tr.exportTo('tr.ui.analysis', function() {
})
]);
pmd1B.memoryAllocatorDumps = [
- newAllocatorDump(pmd1B, 'malloc', { size: 3145728 /* 3 MiB */ }),
- newAllocatorDump(pmd1B, 'v8', { size: 5242880 /* 5 MiB */ }),
- newAllocatorDump(pmd1B, 'tracing', {
+ newAllocatorDump(pmd1B, 'malloc',
+ {numerics: {size: 3145728 /* 3 MiB */}}),
+ newAllocatorDump(pmd1B, 'v8', {numerics: {size: 5242880 /* 5 MiB */}}),
+ newAllocatorDump(pmd1B, 'tracing', {numerics: {
size: 1048576 /* 1 MiB */,
resident_size: 1572864 /* 1.5 MiB */
- })
+ }})
];
// Allocator dumps only.
- var pmd1C = addProcessMemoryDump(gmd1, pC, 43);
+ var pmd1C = addProcessMemoryDump(gmd1, pC, {ts: 43});
pmd1C.memoryAllocatorDumps = (function() {
- var oilpanDump = newAllocatorDump(pmd1C, 'oilpan', {
+ var oilpanDump = newAllocatorDump(pmd1C, 'oilpan', {numerics: {
size: 3221225472 /* 3 GiB */,
inner_size: 5242880 /* 5 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 2015)
- });
- var v8Dump = newAllocatorDump(pmd1C, 'v8', {
+ }});
+ var v8Dump = newAllocatorDump(pmd1C, 'v8', {numerics: {
size: 1073741824 /* 1 GiB */,
inner_size: 2097152 /* 2 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204)
- });
+ }});
addOwnershipLink(v8Dump, oilpanDump);
@@ -146,11 +147,11 @@ tr.exportTo('tr.ui.analysis', function() {
// ======================================================================
// Second timestamp.
// ======================================================================
- var gmd2 = addGlobalMemoryDump(model, 68);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 68});
// Everything.
- var pmd2A = addProcessMemoryDump(gmd2, pA, 67);
- pmd2A.totals = { residentBytes: 32505856 /* 31 MiB */ };
+ var pmd2A = addProcessMemoryDump(gmd2, pA, {ts: 67});
+ pmd2A.totals = {residentBytes: 32505856 /* 31 MiB */};
pmd2A.vmRegions = VMRegionClassificationNode.fromRegions([
VMRegion.fromDict({
startAddress: 1024,
@@ -176,15 +177,17 @@ tr.exportTo('tr.ui.analysis', function() {
})
]);
pmd2A.memoryAllocatorDumps = [
- newAllocatorDump(pmd2A, 'malloc', { size: 9437184 /* 9 MiB */ }),
- newAllocatorDump(pmd2A, 'tracing', {
+ newAllocatorDump(pmd2A, 'malloc', {numerics: {
+ size: 9437184 /* 9 MiB */
+ }}),
+ newAllocatorDump(pmd2A, 'tracing', {numerics: {
size: 2097152 /* 2 MiB */,
resident_size: 2621440 /* 2.5 MiB */
- })
+ }})
];
// Totals and allocator dumps only.
- var pmd2B = addProcessMemoryDump(gmd2, pB, 69);
+ var pmd2B = addProcessMemoryDump(gmd2, pB, {ts: 69});
pmd2B.totals = {
residentBytes: 19922944, /* 19 MiB */
peakResidentBytes: 41943040, /* 40 MiB */
@@ -194,19 +197,27 @@ tr.exportTo('tr.ui.analysis', function() {
}
};
pmd2B.memoryAllocatorDumps = [
- newAllocatorDump(pmd2B, 'malloc', { size: 2621440 /* 2.5 MiB */ }),
- newAllocatorDump(pmd2B, 'v8', { size: 5242880 /* 5 MiB */ }),
- newAllocatorDump(pmd2B, 'blink', { size: 7340032 /* 7 MiB */ }),
- newAllocatorDump(pmd2B, 'oilpan', { size: 1 }),
- newAllocatorDump(pmd2B, 'tracing', {
+ newAllocatorDump(pmd2B, 'malloc', {numerics: {
+ size: 2621440 /* 2.5 MiB */
+ }}),
+ newAllocatorDump(pmd2B, 'v8', {numerics: {
+ size: 5242880 /* 5 MiB */
+ }}),
+ newAllocatorDump(pmd2B, 'blink', {numerics: {
+ size: 7340032 /* 7 MiB */
+ }}),
+ newAllocatorDump(pmd2B, 'oilpan', {numerics: {size: 1}}),
+ newAllocatorDump(pmd2B, 'tracing', {numerics: {
size: 1572864 /* 1.5 MiB */,
resident_size: 2097152 /* 2 MiB */
- }),
- newAllocatorDump(pmd2B, 'gpu', { memtrack_pss: 524288 /* 512 KiB */ })
+ }}),
+ newAllocatorDump(pmd2B, 'gpu', {numerics: {
+ memtrack_pss: 524288 /* 512 KiB */
+ }})
];
// Resettable peak total size only.
- var pmd2D = addProcessMemoryDump(gmd2, pD, 71);
+ var pmd2D = addProcessMemoryDump(gmd2, pD, {ts: 71});
pmd2D.totals = {
peakResidentBytes: 17825792, /* 17 MiB */
arePeakResidentBytesResettable: true
@@ -215,10 +226,10 @@ tr.exportTo('tr.ui.analysis', function() {
// ======================================================================
// Third timestamp.
// ======================================================================
- var gmd3 = addGlobalMemoryDump(model, 100);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 100});
// Everything.
- var pmd3B = addProcessMemoryDump(gmd3, pB, 102);
+ var pmd3B = addProcessMemoryDump(gmd3, pB, {ts: 102});
pmd3B.totals = {
residentBytes: 18874368, /* 18 MiB */
peakResidentBytes: 44040192, /* 42 MiB */
@@ -242,32 +253,38 @@ tr.exportTo('tr.ui.analysis', function() {
})
]);
pmd3B.memoryAllocatorDumps = [
- newAllocatorDump(pmd3B, 'malloc', {size: 2883584 /* 2.75 MiB */ }),
- newAllocatorDump(pmd3B, 'v8', { size: 5767168 /* 5.5 MiB */ }),
- newAllocatorDump(pmd3B, 'blink', { size: 6291456 /* 7 MiB */ }),
- newAllocatorDump(pmd3B, 'tracing', {
+ newAllocatorDump(pmd3B, 'malloc', {numerics: {
+ size: 2883584 /* 2.75 MiB */
+ }}),
+ newAllocatorDump(pmd3B, 'v8', {numerics: {
+ size: 5767168 /* 5.5 MiB */
+ }}),
+ newAllocatorDump(pmd3B, 'blink', {numerics: {
+ size: 6291456 /* 7 MiB */
+ }}),
+ newAllocatorDump(pmd3B, 'tracing', {numerics: {
size: 2097152 /* 2 MiB */,
resident_size: 3145728 /* 3 MiB */
- }),
- newAllocatorDump(pmd3C, 'gpu', {
+ }}),
+ newAllocatorDump(pmd3C, 'gpu', {numerics: {
size: 1048576 /* 1 MiB */,
memtrack_pss: 786432 /* 768 KiB */
- })
+ }})
];
// Allocator dumps only.
- var pmd3C = addProcessMemoryDump(gmd3, pC, 100);
+ var pmd3C = addProcessMemoryDump(gmd3, pC, {ts: 100});
pmd3C.memoryAllocatorDumps = (function() {
- var oilpanDump = newAllocatorDump(pmd3C, 'oilpan', {
+ var oilpanDump = newAllocatorDump(pmd3C, 'oilpan', {numerics: {
size: 3221225472 /* 3 GiB */,
inner_size: 5242880 /* 5 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 2015)
- });
- var v8Dump = newAllocatorDump(pmd3C, 'v8', {
+ }});
+ var v8Dump = newAllocatorDump(pmd3C, 'v8', {numerics: {
size: 2147483648 /* 2 GiB */,
inner_size: 2097152 /* 2 MiB */,
objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204)
- });
+ }});
addOwnershipLink(v8Dump, oilpanDump);
@@ -291,7 +308,7 @@ tr.exportTo('tr.ui.analysis', function() {
};
// Resettable peak total size only.
- var pmd3D = addProcessMemoryDump(gmd3, pD, 99);
+ var pmd3D = addProcessMemoryDump(gmd3, pD, {ts: 99});
pmd3D.totals = {
peakResidentBytes: 17825792, /* 17 MiB */
arePeakResidentBytesResettable: true
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
index 74a38e81cda..1dc7c2f5f26 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
@@ -103,12 +103,14 @@ tr.exportTo('tr.ui.analysis', function() {
var prefixEl = tr.ui.b.createSpan({textContent: prefix});
// Enforce same width of '+++' and '---'.
prefixEl.style.fontFamily = 'monospace';
- titleEl.appendChild(prefixEl);
- titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(NO_BREAK_SPACE));
+ Polymer.dom(titleEl).appendChild(prefixEl);
+ Polymer.dom(titleEl).appendChild(
+ tr.ui.b.asHTMLOrTextNode(NO_BREAK_SPACE));
}
if (color !== undefined)
titleEl.style.color = color;
- titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedTitle));
+ Polymer.dom(titleEl).appendChild(
+ tr.ui.b.asHTMLOrTextNode(formattedTitle));
return titleEl;
},
@@ -133,6 +135,7 @@ tr.exportTo('tr.ui.analysis', function() {
function MemoryColumn(name, cellPath, aggregationMode) {
this.name = name;
this.cellPath = cellPath;
+ this.shouldSetContextGroup = false;
// See MemoryColumn.AggregationMode enum in this file.
this.aggregationMode = aggregationMode;
@@ -191,15 +194,26 @@ tr.exportTo('tr.ui.analysis', function() {
* [least important, right in the resulting table]
*
* where columns will be sorted alphabetically within each group.
+ *
+ * @param {!Array.<!Object>} rows
+ * @param {!Object} config
+ * @param {string} config.cellKey
+ * @param {!MemoryColumn.AggregationMode=} config.aggregationMode
+ * @param {!Array.<!{
+ * condition: (string|!RegExp)=,
+ * importance: number,
+ * columnConstructor: !function(new: MemoryColumn, ...)=,
+ * shouldSetContextGroup: boolean=
+ * }>} config.rules
*/
- MemoryColumn.fromRows = function(rows, cellKey, aggregationMode, rules) {
+ MemoryColumn.fromRows = function(rows, config) {
// Recursively find the names of all cells of the rows (and their sub-rows).
var cellNames = new Set();
function gatherCellNames(rows) {
rows.forEach(function(row) {
if (row === undefined)
return;
- var fieldCells = row[cellKey];
+ var fieldCells = row[config.cellKey];
if (fieldCells !== undefined) {
tr.b.iterItems(fieldCells, function(fieldName, fieldCell) {
if (fieldCell === undefined || fieldCell.fields === undefined)
@@ -218,10 +232,11 @@ tr.exportTo('tr.ui.analysis', function() {
// their importance.
var positions = [];
cellNames.forEach(function(cellName) {
- var cellPath = [cellKey, cellName];
- var matchingRule = MemoryColumn.findMatchingRule(cellName, rules);
+ var cellPath = [config.cellKey, cellName];
+ var matchingRule = MemoryColumn.findMatchingRule(cellName, config.rules);
var constructor = matchingRule.columnConstructor;
- var column = new constructor(cellName, cellPath, aggregationMode);
+ var column = new constructor(cellName, cellPath, config.aggregationMode);
+ column.shouldSetContextGroup = !!config.shouldSetContextGroup;
positions.push({
importance: matchingRule.importance,
column: column
@@ -331,7 +346,8 @@ tr.exportTo('tr.ui.analysis', function() {
fieldEl.style.display = 'flex';
fieldEl.style.alignItems = 'center';
fieldEl.style.justifyContent = 'flex-end';
- fieldEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedFields));
+ Polymer.dom(fieldEl).appendChild(
+ tr.ui.b.asHTMLOrTextNode(formattedFields));
// Add info icons with tooltips.
infos.forEach(function(info) {
@@ -339,11 +355,11 @@ tr.exportTo('tr.ui.analysis', function() {
infoEl.style.paddingLeft = '4px';
infoEl.style.cursor = 'help';
infoEl.style.fontWeight = 'bold';
- infoEl.textContent = info.icon;
+ Polymer.dom(infoEl).textContent = info.icon;
if (info.color !== undefined)
infoEl.style.color = info.color;
infoEl.title = info.message;
- fieldEl.appendChild(infoEl);
+ Polymer.dom(fieldEl).appendChild(infoEl);
}, this);
// Set the color of the element.
@@ -567,15 +583,15 @@ tr.exportTo('tr.ui.analysis', function() {
if (firstString === undefined) {
// String was added ("+NEW_VALUE" in red).
var spanEl = tr.ui.b.createSpan({color: 'red'});
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode('+'));
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode('+'));
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode(
this.formatSingleField(lastString)));
return spanEl;
} else if (lastString === undefined) {
// String was removed ("-OLD_VALUE" in green).
var spanEl = tr.ui.b.createSpan({color: 'green'});
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode('-'));
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode('-'));
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode(
this.formatSingleField(firstString)));
return spanEl;
} else if (firstString === lastString) {
@@ -584,11 +600,11 @@ tr.exportTo('tr.ui.analysis', function() {
} else {
// String changed ("OLD_VALUE -> NEW_VALUE" in orange).
var spanEl = tr.ui.b.createSpan({color: 'DarkOrange'});
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode(
this.formatSingleField(firstString)));
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode(
' ' + RIGHTWARDS_ARROW + ' '));
- spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(
+ Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode(
this.formatSingleField(lastString)));
return spanEl;
}
@@ -724,8 +740,14 @@ tr.exportTo('tr.ui.analysis', function() {
formatSingleField: function(numeric) {
var formattingContext = this.getFormattingContext(numeric.unit);
- var config = formattingContext !== undefined ?
- { context: formattingContext } : undefined;
+ var contextGroup = this.shouldSetContextGroup ? this.name : undefined;
+ var config = undefined;
+ if (formattingContext || contextGroup) {
+ config = {
+ context: formattingContext,
+ contextGroup: contextGroup
+ };
+ }
return tr.v.ui.createScalarSpan(numeric, config);
},
@@ -866,8 +888,8 @@ tr.exportTo('tr.ui.analysis', function() {
__proto__: NumericMemoryColumn.prototype,
getFormattingContext: function(unit) {
- if (unit.baseUnit === tr.v.Unit.byName.sizeInBytes)
- return { unitPrefix: tr.v.UnitScale.Binary.KIBI };
+ if (unit.baseUnit === tr.b.Unit.byName.sizeInBytes)
+ return { unitPrefix: tr.b.UnitScale.Binary.KIBI };
return undefined;
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
index 3a4350ec276..538a996d686 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
@@ -6,13 +6,13 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import"
href="/tracing/ui/analysis/memory_dump_sub_view_test_utils.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() {
tr.ui.analysis.aggregateTableRowCellsRecursively;
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields;
var checkNumericFields = tr.ui.analysis.checkNumericFields;
var checkStringFields = tr.ui.analysis.checkStringFields;
@@ -53,10 +53,10 @@ tr.b.unittest.testSuite(function() {
var node = tr.ui.b.asHTMLOrTextNode(value);
var spanEl = document.createElement('span');
- spanEl.appendChild(node);
+ Polymer.dom(spanEl).appendChild(node);
test.addHTMLOutput(spanEl);
- assert.strictEqual(node.textContent, expectedTextContent);
+ assert.strictEqual(Polymer.dom(node).textContent, expectedTextContent);
if (opt_expectedColor === undefined)
assert.notInstanceOf(node, HTMLElement);
else
@@ -118,8 +118,8 @@ tr.b.unittest.testSuite(function() {
[512, 513]),
'mixed': new MemoryCell(['0.01', '0.10']),
'mixed2': new MemoryCell([
- new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 2.43e18),
- new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 0.5433)
+ new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 2.43e18),
+ new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 0.5433)
])
}
}
@@ -129,38 +129,28 @@ tr.b.unittest.testSuite(function() {
title: 'Row 2',
fields: {
'cpu_temperature': undefined,
- 'mixed': buildScalarCell(tr.v.Unit.byName.timeDurationInMs,
+ 'mixed': buildScalarCell(tr.b.Unit.byName.timeDurationInMs,
[0.99, 0.999])
}
}
];
}
- function checkMemoryColumn(column, expectedName, expectedTitle,
- expectedAggregationMode, testRow, expectedCell, expectedType) {
- assert.strictEqual(column.name, expectedName);
- if (typeof expectedTitle === 'function')
- expectedTitle(column.title);
- else
- assert.strictEqual(column.title, expectedTitle);
- assert.strictEqual(column.aggregationMode, expectedAggregationMode);
- assert.strictEqual(column.cell(testRow), expectedCell);
- assert.instanceOf(column, expectedType);
- }
-
function checkCellValue(
test, value, expectedText, expectedColor, opt_expectedInfos) {
var expectedInfos = opt_expectedInfos || [];
- assert.lengthOf(value.childNodes, 1 + expectedInfos.length);
+ assert.lengthOf(Polymer.dom(value).childNodes, 1 + expectedInfos.length);
assert.strictEqual(value.style.color, expectedColor);
if (typeof expectedText === 'string')
- assert.strictEqual(value.childNodes[0].textContent, expectedText);
+ assert.strictEqual(
+ Polymer.dom(Polymer.dom(value).childNodes[0]).textContent,
+ expectedText);
else
- expectedText(value.childNodes[0]);
+ expectedText(Polymer.dom(value).childNodes[0]);
for (var i = 0; i < expectedInfos.length; i++) {
var expectedInfo = expectedInfos[i];
- var infoEl = value.childNodes[i + 1];
- assert.strictEqual(infoEl.textContent, expectedInfo.icon);
+ var infoEl = Polymer.dom(value).childNodes[i + 1];
+ assert.strictEqual(Polymer.dom(infoEl).textContent, expectedInfo.icon);
assert.strictEqual(infoEl.title, expectedInfo.message);
assert.strictEqual(infoEl.style.color, expectedInfo.color || '');
}
@@ -173,8 +163,8 @@ tr.b.unittest.testSuite(function() {
assert.strictEqual(element.tagName, 'TR-V-UI-SCALAR-SPAN');
assert.strictEqual(element.value, expectedValue);
assert.strictEqual(element.unit, opt_expectedIsDelta ?
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter :
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter :
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter);
assert.deepEqual(element.context, opt_expectedContext);
};
}
@@ -195,33 +185,33 @@ tr.b.unittest.testSuite(function() {
var row = {title: 'added', contexts: [undefined, undefined, undefined, {}]};
assert.equal(column.formatTitle(row), 'added');
var value = column.value(row);
- assert.equal(value.textContent, '+++\u00A0added');
+ assert.equal(Polymer.dom(value).textContent, '+++\u00A0added');
assert.equal(value.style.color, 'red');
var row = {title: 'removed', contexts: [true, true, undefined, undefined]};
assert.equal(column.formatTitle(row), 'removed');
var value = column.value(row);
- assert.equal(value.textContent, '---\u00A0removed');
+ assert.equal(Polymer.dom(value).textContent, '---\u00A0removed');
assert.equal(value.style.color, 'green');
var row = {title: 'flaky', contexts: [true, undefined, true, true]};
assert.equal(column.formatTitle(row), 'flaky');
var value = column.value(row);
- assert.equal(value.textContent, 'flaky');
+ assert.equal(Polymer.dom(value).textContent, 'flaky');
assert.equal(value.style.color, 'purple');
var row =
{title: 'added-flaky', contexts: [undefined, {}, undefined, true]};
assert.equal(column.formatTitle(row), 'added-flaky');
var value = column.value(row);
- assert.equal(value.textContent, '+++\u00A0added-flaky');
+ assert.equal(Polymer.dom(value).textContent, '+++\u00A0added-flaky');
assert.equal(value.style.color, 'purple');
var row =
{title: 'removed-flaky', contexts: [true, undefined, {}, undefined]};
assert.equal(column.formatTitle(row), 'removed-flaky');
var value = column.value(row);
- assert.equal(value.textContent, '---\u00A0removed-flaky');
+ assert.equal(Polymer.dom(value).textContent, '---\u00A0removed-flaky');
assert.equal(value.style.color, 'purple');
});
@@ -283,27 +273,49 @@ tr.b.unittest.testSuite(function() {
];
var rows = buildTestRows();
- var columns = MemoryColumn.fromRows(rows, 'fields', AggregationMode.MAX,
- rules);
+ var columns = MemoryColumn.fromRows(rows, {
+ cellKey: 'fields',
+ aggregationMode: AggregationMode.MAX,
+ rules: rules,
+ shouldSetContextGroup: true
+ });
assert.lengthOf(columns, 4);
var pageSizeColumn = columns[0];
- checkMemoryColumn(pageSizeColumn, 'page_size', 'MockColumn0',
- AggregationMode.MAX, {fields: {page_size: 'large'}}, 'large',
- MockColumn0);
+ assert.strictEqual(pageSizeColumn.name, 'page_size');
+ assert.strictEqual(pageSizeColumn.title, 'MockColumn0');
+ assert.strictEqual(pageSizeColumn.aggregationMode, AggregationMode.MAX);
+ assert.strictEqual(pageSizeColumn.cell({fields: {page_size: 'large'}}),
+ 'large');
+ assert.isTrue(pageSizeColumn.shouldSetContextGroup);
+ assert.instanceOf(pageSizeColumn, MockColumn0);
var mixedColumn = columns[1];
- checkMemoryColumn(mixedColumn, 'mixed', 'MockColumn2', AggregationMode.MAX,
- {fields: {mixed: 89}}, 89, MockColumn2);
+ assert.strictEqual(mixedColumn.name, 'mixed');
+ assert.strictEqual(mixedColumn.title, 'MockColumn2');
+ assert.strictEqual(mixedColumn.aggregationMode, AggregationMode.MAX);
+ assert.strictEqual(mixedColumn.cell({fields: {mixed: 89}}), 89);
+ assert.isTrue(mixedColumn.shouldSetContextGroup);
+ assert.instanceOf(mixedColumn, MockColumn2);
var mixed2Column = columns[2];
- checkMemoryColumn(mixed2Column, 'mixed2', 'MockColumn2',
- AggregationMode.MAX, {fields: {mixed2: 'invalid'}}, 'invalid',
- MemoryColumn);
+ assert.strictEqual(mixed2Column.name, 'mixed2');
+ assert.strictEqual(mixed2Column.title, 'MockColumn2');
+ assert.strictEqual(mixed2Column.aggregationMode, AggregationMode.MAX);
+ assert.strictEqual(mixed2Column.cell({fields: {mixed2: 'invalid'}}),
+ 'invalid');
+ assert.isTrue(mixed2Column.shouldSetContextGroup);
+ assert.instanceOf(mixed2Column, MockColumn2);
var cpuTemperatureColumn = columns[3];
- checkMemoryColumn(cpuTemperatureColumn, 'cpu_temperature', 'MockColumn1',
- AggregationMode.MAX, {fields: {cpu_temperature: 42}}, 42, MockColumn1);
+ assert.strictEqual(cpuTemperatureColumn.name, 'cpu_temperature');
+ assert.strictEqual(cpuTemperatureColumn.title, 'MockColumn1');
+ assert.strictEqual(cpuTemperatureColumn.aggregationMode,
+ AggregationMode.MAX);
+ assert.strictEqual(
+ cpuTemperatureColumn.cell({fields: {cpu_temperature: 42}}), 42);
+ assert.isTrue(cpuTemperatureColumn.shouldSetContextGroup);
+ assert.instanceOf(cpuTemperatureColumn, MockColumn1);
});
test('checkMemoryColumn_spaceEqually', function() {
@@ -365,8 +377,8 @@ tr.b.unittest.testSuite(function() {
assert.isUndefined(c.fields({x: new MemoryCell(undefined)}));
// Defined field(s) inside cell.
- var field1 = new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 1013.25);
- var field2 = new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 1065);
+ var field1 = new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 1013.25);
+ var field2 = new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 1065);
var row1 = {x: new MemoryCell([field1])};
var row2 = {x: new MemoryCell([field1, field2])};
assert.deepEqual(c.fields(row1), [field1]);
@@ -770,7 +782,7 @@ tr.b.unittest.testSuite(function() {
// With custom formatting context.
c.getFormattingContext = function(unit) {
assert.strictEqual(unit,
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter);
return { minimumFractionDigits: 2 };
};
checkCellValue(this, c.value(row),
@@ -783,19 +795,24 @@ tr.b.unittest.testSuite(function() {
var c = new NumericMemoryColumn('non_bytes_column', ['x'],
undefined /* aggregation mode */);
var value = c.formatSingleField(new ScalarNumeric(
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 123));
- assert.equal(value.tagName, 'TR-V-UI-SCALAR-SPAN');
- assert.equal(value.value, 123);
- assert.equal(value.unit, tr.v.Unit.byName.unitlessNumber_smallerIsBetter);
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 123));
+ assert.strictEqual(value.tagName, 'TR-V-UI-SCALAR-SPAN');
+ assert.strictEqual(value.value, 123);
+ assert.strictEqual(value.unit,
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter);
+ assert.isUndefined(value.contextGroup);
this.addHTMLOutput(value);
var c = new NumericMemoryColumn('bytes_column', ['x'],
undefined /* aggregation mode */);
+ c.shouldSetContextGroup = true;
var value = c.formatSingleField(new ScalarNumeric(
sizeInBytes_smallerIsBetter, 456));
- assert.equal(value.tagName, 'TR-V-UI-SCALAR-SPAN');
- assert.equal(value.value, 456);
- assert.equal(value.unit, tr.v.Unit.byName.sizeInBytes_smallerIsBetter);
+ assert.strictEqual(value.tagName, 'TR-V-UI-SCALAR-SPAN');
+ assert.strictEqual(value.value, 456);
+ assert.strictEqual(value.unit,
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter);
+ assert.strictEqual(value.contextGroup, 'bytes_column');
this.addHTMLOutput(value);
});
@@ -804,26 +821,26 @@ tr.b.unittest.testSuite(function() {
var c = new NumericMemoryColumn('non_bytes_column', ['x'],
AggregationMode.DIFF);
checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3],
- tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 2);
+ tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 2);
checkNumericMemoryColumnFieldFormat(this, c, [10, undefined],
- tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, -10);
+ tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, -10);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0],
- tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0);
+ tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0);
checkNumericMemoryColumnFieldFormat(
this, c, [2.71828, 2.71829] /* diff within epsilon */,
- tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0);
+ tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0);
var c = new NumericMemoryColumn('bytes_column', ['x'],
AggregationMode.DIFF);
checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3],
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 2);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 2);
checkNumericMemoryColumnFieldFormat(this, c, [10, undefined],
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, -10);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, -10);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0],
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0);
checkNumericMemoryColumnFieldFormat(
this, c, [1.41421, 1.41422] /* diff within epsilon */,
- tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0);
+ tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0);
});
test('checkNumericMemoryColumn_formatMultipleFields_max',
@@ -831,24 +848,24 @@ tr.b.unittest.testSuite(function() {
var c = new NumericMemoryColumn('non_bytes_column', ['x'],
AggregationMode.MAX);
checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3],
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 3);
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 3);
checkNumericMemoryColumnFieldFormat(this, c, [10, undefined],
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 10);
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 10);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0],
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 60);
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 60);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 10, 20, undefined],
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 20);
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 20);
var c = new NumericMemoryColumn('bytes_column', ['x'],
AggregationMode.MAX);
checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3],
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 3);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 3);
checkNumericMemoryColumnFieldFormat(this, c, [10, undefined],
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 10);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 10);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0],
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 60);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 60);
checkNumericMemoryColumnFieldFormat(this, c, [undefined, 10, 20, undefined],
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 20);
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 20);
});
test('checkNumericMemoryColumn_cmp', function() {
@@ -884,12 +901,12 @@ tr.b.unittest.testSuite(function() {
assert.isBelow(c.compareSingleFields(
new ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, 99),
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, 99),
new ScalarNumeric(
- tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, 100)), 0);
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, 100)), 0);
assert.equal(c.compareSingleFields(
- new ScalarNumeric(tr.v.Unit.byName.unitlessNumber, 0xEEE),
- new ScalarNumeric(tr.v.Unit.byName.unitlessNumber, 0xEEE)), 0);
+ new ScalarNumeric(tr.b.Unit.byName.unitlessNumber, 0xEEE),
+ new ScalarNumeric(tr.b.Unit.byName.unitlessNumber, 0xEEE)), 0);
assert.isAbove(c.compareSingleFields(
new ScalarNumeric(sizeInBytes_smallerIsBetter, 10),
new ScalarNumeric(sizeInBytes_smallerIsBetter, 2)), 0);
@@ -905,9 +922,9 @@ tr.b.unittest.testSuite(function() {
buildScalarCell(sizeInBytes_smallerIsBetter,
[5, 7, 8] /* diff +3 */).fields), 0);
assert.equal(c.compareMultipleFields(
- buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
[4, undefined] /* diff -4 */).fields,
- buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
[999, 995] /* diff -4 */).fields), 0);
assert.isAbove(c.compareMultipleFields(
buildScalarCell(sizeInBytes_smallerIsBetter,
@@ -915,9 +932,9 @@ tr.b.unittest.testSuite(function() {
buildScalarCell(sizeInBytes_smallerIsBetter,
[11, 50, 12] /* diff +1 */).fields), 0);
assert.equal(c.compareMultipleFields(
- buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter,
[17, undefined, 17] /* diff 0 */).fields,
- buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter,
[undefined, 100, undefined] /* diff 0 */).fields), 0);
assert.equal(c.compareMultipleFields(
buildScalarCell(sizeInBytes_smallerIsBetter,
@@ -935,18 +952,18 @@ tr.b.unittest.testSuite(function() {
[10, undefined, 12]).fields,
buildScalarCell(sizeInBytes_smallerIsBetter, [11, 50, 12]).fields), 0);
assert.equal(c.compareMultipleFields(
- buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
[999, undefined, -8888]).fields,
- buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
[undefined, 999, undefined]).fields), 0);
assert.isAbove(c.compareMultipleFields(
buildScalarCell(sizeInBytes_smallerIsBetter,
[10000, 10001, 10002]).fields,
buildScalarCell(sizeInBytes_smallerIsBetter, [5, 7, 8]).fields), 0);
assert.isBelow(c.compareMultipleFields(
- buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter,
[17, undefined, 17]).fields,
- buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter,
+ buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter,
[undefined, 100, undefined]).fields), 0);
});
@@ -1132,7 +1149,7 @@ tr.b.unittest.testSuite(function() {
var row = {
// Intentionally no testCells.
otherCells: {
- a: buildScalarCell(tr.v.Unit.byName.unitlessNumber,
+ a: buildScalarCell(tr.b.Unit.byName.unitlessNumber,
[5, undefined, undefined])
}
};
@@ -1155,7 +1172,7 @@ tr.b.unittest.testSuite(function() {
b: buildScalarCell(sizeInBytes_smallerIsBetter, [5])
},
otherCells: {
- a: buildScalarCell(tr.v.Unit.byName.unitlessNumber,
+ a: buildScalarCell(tr.b.Unit.byName.unitlessNumber,
[153, undefined, 257]),
b: new MemoryCell(['field-should-not-propagate-upwards', ''])
}
@@ -1175,7 +1192,7 @@ tr.b.unittest.testSuite(function() {
checkSizeNumericFields(row, ctc, undefined);
checkNumericFields(row, coa, [5, undefined, 257],
- tr.v.Unit.byName.unitlessNumber);
+ tr.b.Unit.byName.unitlessNumber);
checkStringFields(row, cob, undefined);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
index c16df525127..fe7af81eb27 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
@@ -6,14 +6,13 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
<link rel="import" href="/tracing/ui/analysis/stacked_pane.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane"
- extends="tr-ui-a-stacked-pane">
+<dom-module id='tr-ui-a-memory-dump-vm-regions-details-pane'>
<template>
<style>
:host {
@@ -50,6 +49,7 @@ found in the LICENSE file.
display: none; /* Hide until memory dumps are set. */
flex: 1 0 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<div id="label">Memory maps</div>
@@ -58,7 +58,7 @@ found in the LICENSE file.
<tr-ui-b-table id="table"></tr-ui-b-table>
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -66,7 +66,7 @@ tr.exportTo('tr.ui.analysis', function() {
var ScalarNumeric = tr.v.ScalarNumeric;
var sizeInBytes_smallerIsBetter =
- tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
+ tr.b.Unit.byName.sizeInBytes_smallerIsBetter;
var CONSTANT_COLUMN_RULES = [
{
@@ -153,7 +153,10 @@ tr.exportTo('tr.ui.analysis', function() {
});
}
- Polymer('tr-ui-a-memory-dump-vm-regions-details-pane', {
+ Polymer({
+ is: 'tr-ui-a-memory-dump-vm-regions-details-pane',
+ behaviors: [tr.ui.analysis.StackedPane],
+
created: function() {
this.vmRegions_ = undefined;
this.aggregationMode_ = undefined;
@@ -187,7 +190,7 @@ tr.exportTo('tr.ui.analysis', function() {
*/
set vmRegions(vmRegions) {
this.vmRegions_ = vmRegions;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get vmRegions() {
@@ -196,14 +199,14 @@ tr.exportTo('tr.ui.analysis', function() {
set aggregationMode(aggregationMode) {
this.aggregationMode_ = aggregationMode;
- this.scheduleRebuildPane_();
+ this.scheduleRebuild_();
},
get aggregationMode() {
return this.aggregationMode_;
},
- rebuildPane_: function() {
+ onRebuild_: function() {
if (this.vmRegions_ === undefined || this.vmRegions_.length === 0) {
// Show the info text (hide the table).
this.$.info_text.style.display = 'block';
@@ -362,10 +365,16 @@ tr.exportTo('tr.ui.analysis', function() {
var titleColumn = new tr.ui.analysis.TitleColumn('Mapped file');
titleColumn.width = '200px';
- var constantColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'constantCells', undefined, CONSTANT_COLUMN_RULES);
- var variableColumns = tr.ui.analysis.MemoryColumn.fromRows(
- rows, 'variableCells', this.aggregationMode_, VARIABLE_COLUMN_RULES);
+ var constantColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'constantCells',
+ aggregationMode: undefined,
+ rules: CONSTANT_COLUMN_RULES
+ });
+ var variableColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, {
+ cellKey: 'variableCells',
+ aggregationMode: this.aggregationMode_,
+ rules: VARIABLE_COLUMN_RULES
+ });
var fieldColumns = constantColumns.concat(variableColumns);
tr.ui.analysis.MemoryColumn.spaceEqually(fieldColumns);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
index 9c79c1b5753..abfd3b5c81e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
@@ -40,8 +40,8 @@ tr.b.unittest.testSuite(function() {
var process = model.getOrCreateProcess(1);
// First timestamp.
- var gmd1 = addGlobalMemoryDump(model, 42, DETAILED);
- var pmd1 = addProcessMemoryDump(gmd1, process, 42);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 42, levelOfDetail: DETAILED});
+ var pmd1 = addProcessMemoryDump(gmd1, process, {ts: 42});
pmd1.vmRegions = VMRegionClassificationNode.fromRegions([
VMRegion.fromDict({
mappedFile: '/lib/chrome.so',
@@ -111,12 +111,13 @@ tr.b.unittest.testSuite(function() {
// This is here so that we could test that tracing is discounted from the
// 'Native heap' category.
pmd1.memoryAllocatorDumps = [
- newAllocatorDump(pmd1, 'tracing', { size: 500, resident_size: 32 })
+ newAllocatorDump(pmd1, 'tracing',
+ {numerics: {size: 500, resident_size: 32}})
];
// Second timestamp.
- var gmd2 = addGlobalMemoryDump(model, 42, DETAILED);
- var pmd2 = addProcessMemoryDump(gmd2, process, 42);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 42, levelOfDetail: DETAILED});
+ var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 42});
pmd2.vmRegions = VMRegionClassificationNode.fromRegions([
VMRegion.fromDict({
mappedFile: '/lib/chrome.so',
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html
index f062aca2336..d97043e9ef3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html
@@ -10,8 +10,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/related_events.html">
-<polymer-element name="tr-ui-a-multi-async-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-async-slice-sub-view'>
<template>
<style>
:host {
@@ -33,40 +32,49 @@ found in the LICENSE file.
</div>
</div>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-multi-async-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- get selection() {
- return this.$.content.selection;
- },
+ get selection() {
+ return this.$.content.selection;
+ },
- set selection(selection) {
- this.$.content.selection = selection;
- this.$.relatedEvents.setRelatedEvents(selection);
- if (this.$.relatedEvents.hasRelatedEvents()) {
- this.$.relatedEvents.style.display = '';
- } else {
- this.$.relatedEvents.style.display = 'none';
- }
- },
+ set selection(selection) {
+ this.$.content.selection = selection;
+ this.$.relatedEvents.setRelatedEvents(selection);
+ if (this.$.relatedEvents.hasRelatedEvents()) {
+ this.$.relatedEvents.style.display = '';
+ } else {
+ this.$.relatedEvents.style.display = 'none';
+ }
+ },
- get relatedEventsToHighlight() {
- if (!this.$.content.selection)
- return undefined;
- var selection = new tr.model.EventSet();
- this.$.content.selection.forEach(function(asyncEvent) {
- if (!asyncEvent.associatedEvents)
- return;
- asyncEvent.associatedEvents.forEach(function(event) {
- selection.push(event);
- });
- });
- if (selection.length)
- return selection;
+ get relatedEventsToHighlight() {
+ if (!this.$.content.selection)
return undefined;
- }
- });
- </script>
-</polymer-element>
+ var selection = new tr.model.EventSet();
+ this.$.content.selection.forEach(function(asyncEvent) {
+ if (!asyncEvent.associatedEvents)
+ return;
+ asyncEvent.associatedEvents.forEach(function(event) {
+ selection.push(event);
+ });
+ });
+ if (selection.length)
+ return selection;
+ return undefined;
+ }
+});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-async-slice-sub-view',
+ tr.model.AsyncSlice,
+ {
+ multi: true,
+ title: 'Async Slices',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html
index f4f5215a004..ee061a58271 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
-<polymer-element name="tr-ui-a-multi-cpu-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-cpu-slice-sub-view'>
<template>
<style>
:host {
@@ -21,22 +20,32 @@ found in the LICENSE file.
</style>
<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-multi-cpu-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- ready: function() {
- this.$.content.eventsHaveSubRows = false;
- },
+ ready: function() {
+ this.$.content.eventsHaveSubRows = false;
+ },
- get selection() {
- return this.$.content.selection;
- },
+ get selection() {
+ return this.$.content.selection;
+ },
- set selection(selection) {
- this.$.content.setSelectionWithoutErrorChecks(selection);
- }
- });
- </script>
-</polymer-element>
+ set selection(selection) {
+ this.$.content.setSelectionWithoutErrorChecks(selection);
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-cpu-slice-sub-view',
+ tr.model.CpuSlice,
+ {
+ multi: true,
+ title: 'CPU Slices',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html
deleted file mode 100644
index 101137cdcb6..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html
+++ /dev/null
@@ -1,333 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/base.html">
-<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/model/event_set.html">
-<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
-<link rel="import" href="/tracing/ui/analysis/multi_event_summary.html">
-<link rel="import" href="/tracing/ui/base/table.html">
-<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-
-<polymer-element name='tr-ui-a-multi-event-details-table'>
- <template>
- <style>
- :host {
- display: flex;
- flex-direction: column;
- }
- #table {
- flex: 1 1 auto;
- align-self: stretch;
- }
-
- #titletable {
- font-weight: bold;
- }
-
- #title-info {
- font-size: 12px;
- }
- </style>
- <tr-ui-b-table id="titletable">
- </tr-ui-b-table>
- <tr-ui-b-table id="table">
- </tr-ui-b-table>
- </template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.selection_ = undefined;
- this.eventsHaveDuration_ = true;
- this.eventsHaveSubRows_ = true;
- },
-
- ready: function() {
- this.initTitleTable_();
- },
-
- get eventsHaveDuration() {
- return this.eventsHaveDuration_;
- },
-
- set eventsHaveDuration(eventsHaveDuration) {
- this.eventsHaveDuration_ = eventsHaveDuration;
- this.updateContents_();
- },
-
- get eventsHaveSubRows() {
- return this.eventsHaveSubRows_;
- },
-
- set eventsHaveSubRows(eventsHaveSubRows) {
- this.eventsHaveSubRows_ = eventsHaveSubRows;
- this.updateContents_();
- },
-
- get selection() {
- return this.selection_;
- },
-
- set selection(selection) {
- this.selection_ = selection;
- this.updateContents_();
- },
-
- updateContents_: function() {
- var selection = this.selection_;
-
- this.updateTitleTable_();
-
- if (this.selection_ === undefined) {
- this.$.table.tableRows = [];
- this.$.table.tableFooterRows = [];
- this.$.table.rebuild();
- return;
- }
-
- var summary = new tr.ui.analysis.MultiEventSummary(
- 'Totals', this.selection_);
- this.updateColumns_(summary);
- this.updateRows_(summary);
- this.$.table.rebuild();
- },
-
- initTitleTable_: function() {
- var table = this.$.titletable;
-
- table.showHeader = false;
- table.tableColumns = [
- {
- title: 'Title',
- value: function(row) { return row.title; },
- width: '350px'
- },
- {
- title: 'Value',
- width: '100%',
- value: function(row) {
- return row.value;
- }
- }
- ];
- },
-
- getSelectionTitle_: function() {
- if (!this.selection || !this.selection.length)
- return '<No selection>';
-
- var firstTitle = tr.b.getFirstElement(this.selection).title;
- if (!tr.b.every(this.selection, (event) => event.title === firstTitle))
- return '<Different titles>';
-
- return firstTitle;
- },
-
- updateTitleTable_: function() {
- this.$.titletable.tableRows = [{
- title: 'Title',
- value: this.getSelectionTitle_()
- }];
- },
-
- updateColumns_: function(summary) {
- var hasCpuData;
- if (summary.cpuDuration !== undefined)
- hasCpuData = true;
- if (summary.cpuSelfTime !== undefined)
- hasCpuData = true;
-
- var colWidthPercentage;
- if (hasCpuData)
- colWidthPercentage = '20%';
- else
- colWidthPercentage = '33.3333%';
-
- var ownerDocument = this.ownerDocument;
- var columns = [];
-
- columns.push({
- title: 'Start',
- value: function(row) {
- if (row.__proto__ === tr.ui.analysis.MultiEventSummary.prototype) {
- return row.title;
- }
-
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return new tr.model.EventSet(row.event);
- });
- linkEl.appendChild(tr.v.ui.createScalarSpan(row.start, {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: ownerDocument
- }));
- return linkEl;
- },
- width: '350px',
- cmp: function(rowA, rowB) {
- return rowA.start - rowB.start;
- }
- });
-
- if (this.eventsHaveDuration_) {
- columns.push({
- title: 'Wall Duration (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.duration, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: ownerDocument
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.duration - rowB.duration;
- }
- });
- }
-
- if (this.eventsHaveDuration_ && hasCpuData) {
- columns.push({
- title: 'CPU Duration (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.cpuDuration, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: ownerDocument
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.cpuDuration - rowB.cpuDuration;
- }
- });
- }
-
- if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) {
- columns.push({
- title: 'Self time (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.selfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: ownerDocument
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.selfTime - rowB.selfTime;
- }
- });
- }
-
- if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) {
- columns.push({
- title: 'CPU Self Time (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.cpuSelfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: ownerDocument
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.cpuSelfTime - rowB.cpuSelfTime;
- }
- });
- }
-
- var argKeys = tr.b.dictionaryKeys(summary.totalledArgs);
- argKeys.sort();
-
- var otherKeys = summary.untotallableArgs.slice(0);
- otherKeys.sort();
-
- argKeys.push.apply(argKeys, otherKeys);
- var keysWithColumns = argKeys.slice(0, 4);
- var keysInOtherColumn = argKeys.slice(4);
-
- keysWithColumns.forEach(function(argKey) {
-
- var hasTotal = summary.totalledArgs[argKey];
- var colDesc = {
- title: 'Arg: ' + argKey,
- value: function(row) {
- if (row.__proto__ !== tr.ui.analysis.MultiEventSummary.prototype) {
- var argView =
- document.createElement('tr-ui-a-generic-object-view');
- argView.object = row.args[argKey];
- return argView;
- }
- if (hasTotal)
- return row.totalledArgs[argKey];
- return '';
- },
- width: '<upated further down>'
- };
- if (hasTotal) {
- colDesc.cmp = function(rowA, rowB) {
- return rowA.args[argKey] - rowB.args[argKey];
- };
- }
- columns.push(colDesc);
- });
-
- if (keysInOtherColumn.length) {
- columns.push({
- title: 'Other Args',
- value: function(row) {
- if (row.__proto__ === tr.ui.analysis.MultiEventSummary.prototype)
- return '';
- var argView =
- document.createElement('tr-ui-a-generic-object-view');
- var obj = {};
- for (var i = 0; i < keysInOtherColumn.length; i++)
- obj[keysInOtherColumn[i]] = row.args[keysInOtherColumn[i]];
- argView.object = obj;
- return argView;
- },
- width: '<upated further down>'
- });
- }
-
- var colWidthPercentage;
- if (columns.length == 1)
- colWidthPercentage = '100%';
- else
- colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
-
- for (var i = 1; i < columns.length; i++)
- columns[i].width = colWidthPercentage;
-
- this.$.table.tableColumns = columns;
- },
-
- updateRows_: function(summary) {
- this.$.table.sortColumnIndex = 0;
- function Row(event) {
- this.event = event;
- }
- Row.prototype = {
- get start() { return this.event.start; },
- get duration() { return this.event.duration; },
- get cpuDuration() { return this.event.cpuDuration; },
- get selfTime() { return this.event.selfTime; },
- get cpuSelfTime() { return this.event.cpuSelfTime; },
- get args() { return this.event.args; }
- };
-
- this.$.table.tableRows = this.selection_.map(function(event) {
- return new Row(event);
- });
- this.$.table.footerRows = [summary];
- }
- });
-</script>
-</polymer-element>
-
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html
deleted file mode 100644
index 0bf2d13e081..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html
+++ /dev/null
@@ -1,171 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/model/event_set.html">
-<link rel="import" href="/tracing/model/model.html">
-<link rel="import" href="/tracing/ui/analysis/multi_event_details_table.html">
-<link rel="import" href="/tracing/ui/base/deep_utils.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- var Model = tr.Model;
- var Thread = tr.model.Thread;
- var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.TestUtils.newSliceEx;
-
- test('sortingOfFirstColumn', function() {
- var model = new Model();
- var thread = model.getOrCreateProcess(1).getOrCreateThread(2);
- var tsg = thread.sliceGroup;
- var sA = tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2,
- cpuStart: 1, cpuEnd: 1.75}));
- var sB = tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3,
- cpuStart: 0, cpuEnd: 3}));
- var sC = tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5,
- cpuStart: 3, cpuEnd: 3.75}));
- tsg.createSubSlices();
-
- var threadTrack = {};
- threadTrack.thread = thread;
-
- var selection = new EventSet(tsg.slices);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
-
- var table = viewEl.$.table;
- var cmpResult = table.tableColumns[0].cmp(sA, sB);
- assert.equal(cmpResult, 1);
- });
-
- test('withCpuTime', function() {
- var model = new Model();
- var thread = model.getOrCreateProcess(1).getOrCreateThread(2);
- var tsg = thread.sliceGroup;
- tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3,
- cpuStart: 0, cpuEnd: 3}));
- tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2,
- cpuStart: 1, cpuEnd: 1.75}));
- tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5,
- cpuStart: 3, cpuEnd: 3.75}));
- tsg.createSubSlices();
-
- var threadTrack = {};
- threadTrack.thread = thread;
-
- var selection = new EventSet(tsg.slices);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
- });
-
- test('withoutCpuTime', function() {
- var model = new Model();
- var thread = model.getOrCreateProcess(1).getOrCreateThread(2);
- var tsg = thread.sliceGroup;
- tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3}));
- tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2}));
- tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5}));
- tsg.createSubSlices();
-
- var threadTrack = {};
- threadTrack.thread = thread;
-
- var selection = new EventSet(tsg.slices);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
- });
-
-
- test('withFewerThanFourArgs', function() {
- var model = new Model();
- var thread = model.getOrCreateProcess(1).getOrCreateThread(2);
- var tsg = thread.sliceGroup;
- tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3,
- args: {value1: 3, value2: 'x', value3: 1}}));
- tsg.pushSlice(newSliceEx({title: 'b', start: 1, end: 2,
- args: {value1: 3.1, value2: 'y', value3: 2}}));
- tsg.pushSlice(newSliceEx({title: 'b', start: 4, end: 5,
- args: {value1: 3.2, value2: 'z', value3: 'x'}}));
- tsg.createSubSlices();
-
- var threadTrack = {};
- threadTrack.thread = thread;
-
- var selection = new EventSet(tsg.slices);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
- });
-
- test('withExtraArgs', function() {
- var model = new Model();
- var thread = model.getOrCreateProcess(1).getOrCreateThread(2);
- var tsg = thread.sliceGroup;
- tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3,
- args: {value1: 3, value2: 'x', value3: 1,
- value4: 4, value5: 5, value6: 6}}));
- tsg.pushSlice(newSliceEx({title: 'b', start: 1, end: 2,
- args: {value1: 3.1, value2: 'y', value3: 2,
- value4: 4, value5: 5, value6: 6}}));
- tsg.pushSlice(newSliceEx({title: 'b', start: 4, end: 5,
- args: {value1: 3.2, value2: 'z', value3: 'x',
- value4: 4, value5: 'whoops', value6: 6}}));
- tsg.createSubSlices();
-
- var threadTrack = {};
- threadTrack.thread = thread;
-
- var selection = new EventSet(tsg.slices);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
- });
-
- test('noDuration', function() {
- var model = new Model();
-
- var fe1 = new tr.model.FlowEvent('cat', 1234, 'title', 7, 10, {});
- var fe2 = new tr.model.FlowEvent('cat', 1234, 'title', 8, 20, {});
-
- // Make reading some properties an explosion, as a way to ensure that they
- // aren't read.
- var failProp = {
- get: function() {
- throw new Error('Should not be called');
- }
- };
- Object.defineProperty(fe1, 'duration', failProp);
- Object.defineProperty(fe2, 'duration', failProp);
-
- Object.defineProperty(fe1, 'subRows', failProp);
- Object.defineProperty(fe2, 'subRows', failProp);
-
- Object.defineProperty(fe1, 'selfTime', failProp);
- Object.defineProperty(fe2, 'selfTime', failProp);
-
- model.flowEvents.push(fe1);
- model.flowEvents.push(fe2);
-
- var selection = new EventSet([fe1, fe2]);
-
- var viewEl = document.createElement('tr-ui-a-multi-event-details-table');
- viewEl.eventsHaveDuration = false;
- viewEl.selection = selection;
- this.addHTMLOutput(viewEl);
- });
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html
index c6333dce9a6..c134f16c57c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html
@@ -7,14 +7,15 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
-<link rel="import" href="/tracing/ui/analysis/selection_summary_table.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_summary_table.html">
-<link rel="import" href="/tracing/ui/analysis/multi_event_details_table.html">
-<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/analysis/selection_summary_table.html">
+<link rel="import" href="/tracing/ui/base/radio_picker.html">
<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/value/diagnostics/scalar.html">
+<link rel="import" href="/tracing/value/histogram.html">
-<polymer-element name="tr-ui-a-multi-event-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-event-sub-view'>
<template>
<style>
:host {
@@ -31,6 +32,10 @@ found in the LICENSE file.
flex: 0 0 auto;
align-self: stretch;
}
+ #histogramContainer {
+ display: flex;
+ }
+
tr-ui-a-multi-event-summary-table {
border-bottom: 1px solid #aaa;
}
@@ -44,18 +49,69 @@ found in the LICENSE file.
border-bottom: 1px solid #aaa;
}
</style>
- <div id="content"></div>
+ <div id="content">
+ <tr-ui-a-multi-event-summary-table id="eventSummaryTable">
+ </tr-ui-a-multi-event-summary-table>
+ <tr-ui-a-selection-summary-table id="selectionSummaryTable">
+ </tr-ui-a-selection-summary-table>
+ <tr-ui-b-radio-picker id="radioPicker">
+ </tr-ui-b-radio-picker>
+ <div id="histogramContainer">
+ <tr-v-ui-histogram-span id="histogramSpan">
+ </tr-v-ui-histogram-span>
+ </div>
+ </div>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+ var EVENT_FIELD = [
+ {key: 'start', label: 'Start'},
+ {key: 'cpuDuration', label: 'CPU Duration'},
+ {key: 'duration', label: 'Duration'},
+ {key: 'cpuSelfTime', label: 'CPU Self Time'},
+ {key: 'selfTime', label: 'Self Time'}
+ ];
+
+ function buildDiagnostics_(slice, selectedKey) {
+ var diagnostics = {};
+ for (var item of EVENT_FIELD) {
+ var fieldName = item.key;
+ if (fieldName === selectedKey || slice[fieldName] === undefined)
+ continue;
+ diagnostics[fieldName] = new tr.v.d.Scalar(new tr.v.ScalarNumeric(
+ tr.b.Unit.byName.timeDurationInMs, slice[fieldName]));
+ }
+ diagnostics['args'] = new tr.v.d.Generic(slice.args);
+ diagnostics['event'] = new tr.v.d.RelatedEventSet(slice);
+ return diagnostics;
+ }
Polymer({
+ is: 'tr-ui-a-multi-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
created: function() {
this.currentSelection_ = undefined;
this.eventsHaveDuration_ = true;
this.eventsHaveSubRows_ = true;
},
+ ready: function() {
+ this.$.radioPicker.style.display = 'none';
+ this.$.radioPicker.items = EVENT_FIELD;
+ this.$.radioPicker.select('cpuSelfTime');
+ this.$.radioPicker.addEventListener('change', function(e) {
+ this.$.histogramSpan.histogram =
+ this.buildHistogram_(e.target.selectedKey);
+ }.bind(this));
+
+ this.$.histogramSpan.chartWidth = 400;
+ this.$.histogramContainer.style.display = 'none';
+ },
+
set selection(selection) {
if (selection.length <= 1)
throw new Error('Only supports multiple items');
@@ -89,40 +145,61 @@ found in the LICENSE file.
this.updateContents_();
},
+ buildHistogram_: function(selectedKey) {
+ var leftBoundary = Number.MAX_VALUE;
+ var rightBoundary = tr.b.Statistics.percentile(
+ this.currentSelection_, 0.95,
+ function(value) {
+ leftBoundary = Math.min(leftBoundary, value[selectedKey]);
+ return value[selectedKey];
+ });
+
+ if (leftBoundary === rightBoundary) rightBoundary += 1;
+ var histogram = new tr.v.Histogram(
+ '',
+ tr.b.Unit.byName.timeDurationInMs,
+ tr.v.HistogramBinBoundaries.createLinear(
+ leftBoundary, rightBoundary,
+ Math.ceil(Math.sqrt(this.currentSelection_.length))));
+ histogram.customizeSummaryOptions({sum: false});
+ for (var slice of this.currentSelection_) {
+ histogram.addSample(slice[selectedKey],
+ buildDiagnostics_(slice, selectedKey));
+ }
+
+ return histogram;
+ },
+
updateContents_: function() {
var selection = this.currentSelection_;
- this.$.content.textContent = '';
if (!selection)
return;
var eventsByTitle = selection.getEventsOrganizedByTitle();
var numTitles = tr.b.dictionaryLength(eventsByTitle);
- var summaryTableEl = document.createElement(
- 'tr-ui-a-multi-event-summary-table');
- summaryTableEl.configure({
+ this.$.eventSummaryTable.configure({
showTotals: numTitles > 1,
eventsByTitle: eventsByTitle,
eventsHaveDuration: this.eventsHaveDuration_,
eventsHaveSubRows: this.eventsHaveSubRows_
});
- this.$.content.appendChild(summaryTableEl);
- var selectionSummaryTableEl = document.createElement(
- 'tr-ui-a-selection-summary-table');
- selectionSummaryTableEl.selection = this.currentSelection_;
- this.$.content.appendChild(selectionSummaryTableEl);
+ this.$.selectionSummaryTable.selection = this.currentSelection_;
if (numTitles === 1) {
- var detailsTableEl = document.createElement(
- 'tr-ui-a-multi-event-details-table');
- detailsTableEl.eventsHaveDuration = this.eventsHaveDuration_;
- detailsTableEl.eventsHaveSubRows = this.eventsHaveSubRows_;
- detailsTableEl.selection = selection;
- this.$.content.appendChild(detailsTableEl);
+ this.$.radioPicker.style.display = 'block';
+ this.$.histogramSpan.histogram =
+ this.buildHistogram_(this.$.radioPicker.selectedKey);
+ this.$.histogramContainer.style.display = 'flex';
+ } else {
+ this.$.radioPicker.style.display = 'none';
+ this.$.histogramContainer.style.display = 'none';
}
}
});
- </script>
-</polymer-element>
+
+ return {};
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
index 5c26a864b78..c47543d1dac 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
@@ -19,7 +19,6 @@ tr.b.unittest.testSuite(function() {
var Thread = tr.model.Thread;
var EventSet = tr.model.EventSet;
var newSliceEx = tr.c.TestUtils.newSliceEx;
- var Slice = tr.model.Slice;
test('differentTitles', function() {
var model = new Model();
@@ -46,19 +45,16 @@ tr.b.unittest.testSuite(function() {
var summaryTableEl = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-multi-event-summary-table');
- assert.isDefined(summaryTableEl);
-
assert.isTrue(summaryTableEl.showTotals);
assert.equal(tr.b.dictionaryLength(summaryTableEl.eventsByTitle), 2);
var selectionSummaryTableEl = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-selection-summary-table');
- assert.isDefined(selectionSummaryTableEl);
assert.equal(selectionSummaryTableEl.selection, selection);
- var detailsTableEl = tr.b.findDeepElementMatching(
- viewEl, 'tr-ui-a-multi-event-details-table');
- assert.isUndefined(detailsTableEl);
+ var radioPickerEl =
+ tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-radio-picker');
+ assert.equal(radioPickerEl.style.display, 'none');
});
test('sameTitles', function() {
@@ -83,20 +79,16 @@ tr.b.unittest.testSuite(function() {
var summaryTableEl = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-multi-event-summary-table');
- assert.isDefined(summaryTableEl);
-
assert.isFalse(summaryTableEl.showTotals);
assert.equal(tr.b.dictionaryLength(summaryTableEl.eventsByTitle), 1);
var selectionSummaryTableEl = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-selection-summary-table');
- assert.isDefined(selectionSummaryTableEl);
assert.equal(selectionSummaryTableEl.selection, selection);
- var detailsTableEl = tr.b.findDeepElementMatching(
- viewEl, 'tr-ui-a-multi-event-details-table');
- assert.isDefined(detailsTableEl);
- assert.equal(detailsTableEl.selection, selection);
+ var radioPickerEl =
+ tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-radio-picker');
+ assert.equal(radioPickerEl.style.display, 'block');
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html
index 64cd636efcc..9b03bf7e090 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html
@@ -29,11 +29,11 @@ tr.exportTo('tr.ui.analysis', function() {
this.untotallableArgs_ = [];
this.totalledArgs_ = undefined;
- };
+ }
MultiEventSummary.prototype = {
set title(title) {
- if (title == 'Totals')
+ if (title === 'Totals')
this.totalsRow = true;
this.title_ = title;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html
index 06ec9cbc17c..290ce0cfcb4 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html
@@ -7,16 +7,16 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_summary.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-</script>
-<polymer-element name='tr-ui-a-multi-event-summary-table'>
+<dom-module id='tr-ui-a-multi-event-summary-table'>
<template>
<style>
:host {
@@ -25,292 +25,327 @@ found in the LICENSE file.
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table">
</tr-ui-b-table>
</div>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.showTotals_ = false;
- this.eventsHaveDuration_ = true;
- this.eventsHaveSubRows_ = true;
- this.eventsByTitle_ = undefined;
- },
-
- updateTableColumns_: function(rows, maxValues) {
- var hasCpuData = false;
- var hasAlerts = false;
- rows.forEach(function(row) {
- if (row.cpuDuration !== undefined)
- hasCpuData = true;
- if (row.cpuSelfTime !== undefined)
- hasCpuData = true;
- if (row.numAlerts)
- hasAlerts = true;
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-multi-event-summary-table',
+
+ ready: function() {
+ this.showTotals_ = false;
+ this.eventsHaveDuration_ = true;
+ this.eventsHaveSubRows_ = true;
+ this.eventsByTitle_ = undefined;
+ },
+
+ updateTableColumns_: function(rows, maxValues) {
+ var hasCpuData = false;
+ var hasAlerts = false;
+ rows.forEach(function(row) {
+ if (row.cpuDuration !== undefined)
+ hasCpuData = true;
+ if (row.cpuSelfTime !== undefined)
+ hasCpuData = true;
+ if (row.numAlerts)
+ hasAlerts = true;
+ });
+
+ var ownerDocument = this.ownerDocument;
+
+ var columns = [];
+
+ columns.push({
+ title: 'Name',
+ value: function(row) {
+ if (row.title === 'Totals')
+ return 'Totals';
+
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(function() {
+ return new tr.model.EventSet(row.events);
+ }, row.title);
+ return linkEl;
+ },
+ width: '350px',
+ cmp: function(rowA, rowB) {
+ return rowA.title.localeCompare(rowB.title);
+ }
+ });
+ if (this.eventsHaveDuration_) {
+ columns.push({
+ title: 'Wall Duration',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.duration, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ customContextRange: row.totalsRow ? undefined :
+ tr.b.Range.fromExplicitRange(0, maxValues.duration),
+ ownerDocument: ownerDocument,
+ rightAlign: true
+ });
+ },
+ width: '<upated further down>',
+ cmp: function(rowA, rowB) {
+ return rowA.duration - rowB.duration;
+ }
});
+ }
- var ownerDocument = this.ownerDocument;
+ if (this.eventsHaveDuration_ && hasCpuData) {
+ columns.push({
+ title: 'CPU Duration',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.cpuDuration, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ customContextRange: row.totalsRow ? undefined :
+ tr.b.Range.fromExplicitRange(0, maxValues.cpuDuration),
+ ownerDocument: ownerDocument,
+ rightAlign: true
+ });
+ },
+ width: '<upated further down>',
+ cmp: function(rowA, rowB) {
+ return rowA.cpuDuration - rowB.cpuDuration;
+ }
+ });
+ }
- var columns = [];
+ if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) {
+ columns.push({
+ title: 'Self time',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.selfTime, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ customContextRange: row.totalsRow ? undefined :
+ tr.b.Range.fromExplicitRange(0, maxValues.selfTime),
+ ownerDocument: ownerDocument,
+ rightAlign: true
+ });
+ },
+ width: '<upated further down>',
+ cmp: function(rowA, rowB) {
+ return rowA.selfTime - rowB.selfTime;
+ }
+ });
+ }
+ if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) {
columns.push({
- title: 'Name',
+ title: 'CPU Self Time',
value: function(row) {
- if (row.title === 'Totals')
- return 'Totals';
-
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return new tr.model.EventSet(row.events);
- }, row.title);
- return linkEl;
+ return tr.v.ui.createScalarSpan(row.cpuSelfTime, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ customContextRange: row.totalsRow ? undefined :
+ tr.b.Range.fromExplicitRange(0, maxValues.cpuSelfTime),
+ ownerDocument: ownerDocument,
+ rightAlign: true
+ });
},
- width: '350px',
+ width: '<upated further down>',
cmp: function(rowA, rowB) {
- return rowA.title.localeCompare(rowB.title);
+ return rowA.cpuSelfTime - rowB.cpuSelfTime;
}
});
- if (this.eventsHaveDuration_) {
- columns.push({
- title: 'Wall Duration',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.duration, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- total: row.totalsRow ? undefined : maxValues.duration,
- ownerDocument: ownerDocument,
- rightAlign: true
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.duration - rowB.duration;
- }
- });
- }
+ }
- if (this.eventsHaveDuration_ && hasCpuData) {
- columns.push({
- title: 'CPU Duration',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.cpuDuration, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- total: row.totalsRow ? undefined : maxValues.cpuDuration,
- ownerDocument: ownerDocument,
- rightAlign: true
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.cpuDuration - rowB.cpuDuration;
+ if (this.eventsHaveDuration_) {
+ columns.push({
+ title: 'Average ' + (hasCpuData ? 'CPU' : 'Wall') + ' Duration',
+ value: function(row) {
+ var totalDuration = hasCpuData ? row.cpuDuration : row.duration;
+ return tr.v.ui.createScalarSpan(totalDuration / row.numEvents, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ customContextRange: row.totalsRow ? undefined :
+ tr.b.Range.fromExplicitRange(0, maxValues.duration),
+ ownerDocument: ownerDocument,
+ rightAlign: true
+ });
+ },
+ width: '<upated further down>',
+ cmp: function(rowA, rowB) {
+ if (hasCpuData) {
+ return rowA.cpuDuration / rowA.numEvents -
+ rowB.cpuDuration / rowB.numEvents;
+ } else {
+ return rowA.duration / rowA.numEvents -
+ rowB.duration / rowB.numEvents;
}
- });
- }
+ }
+ });
+ }
- if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) {
- columns.push({
- title: 'Self time',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.selfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- total: row.totalsRow ? undefined : maxValues.selfTime,
- ownerDocument: ownerDocument,
- rightAlign: true
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.selfTime - rowB.selfTime;
- }
- });
+ columns.push({
+ title: 'Occurrences',
+ value: function(row) {
+ return row.numEvents;
+ },
+ width: '<upated further down>',
+ cmp: function(rowA, rowB) {
+ return rowA.numEvents - rowB.numEvents;
}
+ });
- if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) {
- columns.push({
- title: 'CPU Self Time',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.cpuSelfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- total: row.totalsRow ? undefined : maxValues.cpuSelfTime,
- ownerDocument: ownerDocument,
- rightAlign: true
- });
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.cpuSelfTime - rowB.cpuSelfTime;
- }
- });
- }
+ var alertsColumnIndex;
+ if (hasAlerts) {
columns.push({
- title: 'Occurrences',
+ title: 'Num Alerts',
value: function(row) {
- return row.numEvents;
+ return row.numAlerts;
},
width: '<upated further down>',
cmp: function(rowA, rowB) {
- return rowA.numEvents - rowB.numEvents;
+ return rowA.numAlerts - rowB.numAlerts;
}
});
+ alertsColumnIndex = columns.length - 1;
+ }
+ var colWidthPercentage;
+ if (columns.length === 1)
+ colWidthPercentage = '100%';
+ else
+ colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
- var alertsColumnIndex;
- if (hasAlerts) {
- columns.push({
- title: 'Num Alerts',
- value: function(row) {
- return row.numAlerts;
- },
- width: '<upated further down>',
- cmp: function(rowA, rowB) {
- return rowA.numAlerts - rowB.numAlerts;
- }
- });
- alertsColumnIndex = columns.length - 1;
- }
- var colWidthPercentage;
- if (columns.length == 1)
- colWidthPercentage = '100%';
- else
- colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
+ for (var i = 1; i < columns.length; i++)
+ columns[i].width = colWidthPercentage;
- for (var i = 1; i < columns.length; i++)
- columns[i].width = colWidthPercentage;
+ this.$.table.tableColumns = columns;
- this.$.table.tableColumns = columns;
+ if (hasAlerts) {
+ this.$.table.sortColumnIndex = alertsColumnIndex;
+ this.$.table.sortDescending = true;
+ }
+ },
- if (hasAlerts) {
- this.$.table.sortColumnIndex = alertsColumnIndex;
- this.$.table.sortDescending = true;
- }
- },
-
- configure: function(config) {
- if (config.eventsByTitle === undefined)
- throw new Error('Required: eventsByTitle');
-
- if (config.showTotals !== undefined)
- this.showTotals_ = config.showTotals;
- else
- this.showTotals_ = true;
-
- if (config.eventsHaveDuration !== undefined)
- this.eventsHaveDuration_ = config.eventsHaveDuration;
- else
- this.eventsHaveDuration_ = true;
-
- if (config.eventsHaveSubRows !== undefined)
- this.eventsHaveSubRows_ = config.eventsHaveSubRows;
- else
- this.eventsHaveSubRows_ = true;
-
- this.eventsByTitle_ = config.eventsByTitle;
- this.updateContents_();
- },
-
- get showTotals() {
- return this.showTotals_;
- },
-
- set showTotals(showTotals) {
- this.showTotals_ = showTotals;
- this.updateContents_();
- },
-
- get eventsHaveDuration() {
- return this.eventsHaveDuration_;
- },
-
- set eventsHaveDuration(eventsHaveDuration) {
- this.eventsHaveDuration_ = eventsHaveDuration;
- this.updateContents_();
- },
-
- get eventsHaveSubRows() {
- return this.eventsHaveSubRows_;
- },
-
- set eventsHaveSubRows(eventsHaveSubRows) {
- this.eventsHaveSubRows_ = eventsHaveSubRows;
- this.updateContents_();
- },
-
- get eventsByTitle() {
- return this.eventsByTitle_;
- },
-
- set eventsByTitle(eventsByTitle) {
- this.eventsByTitle_ = eventsByTitle;
- this.updateContents_();
- },
-
- get selectionBounds() {
- return this.selectionBounds_;
- },
-
- set selectionBounds(selectionBounds) {
- this.selectionBounds_ = selectionBounds;
- this.updateContents_();
- },
-
- updateContents_: function() {
- var eventsByTitle;
- if (this.eventsByTitle_ !== undefined)
- eventsByTitle = this.eventsByTitle_;
- else
- eventsByTitle = [];
-
- var allEvents = [];
- var rows = [];
- tr.b.iterItems(
- eventsByTitle,
- function(title, eventsOfSingleTitle) {
- allEvents.push.apply(allEvents, eventsOfSingleTitle);
- var row = new tr.ui.analysis.MultiEventSummary(
- title, eventsOfSingleTitle);
- rows.push(row);
- });
+ configure: function(config) {
+ if (config.eventsByTitle === undefined)
+ throw new Error('Required: eventsByTitle');
- this.updateTableColumns_(rows);
- this.$.table.tableRows = rows;
+ if (config.showTotals !== undefined)
+ this.showTotals_ = config.showTotals;
+ else
+ this.showTotals_ = true;
- var maxValues = {
- duration: undefined,
- selfTime: undefined,
- cpuSelfTime: undefined,
- cpuDuration: undefined
- };
+ if (config.eventsHaveDuration !== undefined)
+ this.eventsHaveDuration_ = config.eventsHaveDuration;
+ else
+ this.eventsHaveDuration_ = true;
- if (this.eventsHaveDuration) {
- for (var column in maxValues) {
- maxValues[column] = tr.b.Statistics.max(rows, function(event) {
- return event[column];
- });
- }
- }
+ if (config.eventsHaveSubRows !== undefined)
+ this.eventsHaveSubRows_ = config.eventsHaveSubRows;
+ else
+ this.eventsHaveSubRows_ = true;
+
+ this.eventsByTitle_ = config.eventsByTitle;
+ this.updateContents_();
+ },
+
+ get showTotals() {
+ return this.showTotals_;
+ },
+
+ set showTotals(showTotals) {
+ this.showTotals_ = showTotals;
+ this.updateContents_();
+ },
+
+ get eventsHaveDuration() {
+ return this.eventsHaveDuration_;
+ },
+
+ set eventsHaveDuration(eventsHaveDuration) {
+ this.eventsHaveDuration_ = eventsHaveDuration;
+ this.updateContents_();
+ },
+
+ get eventsHaveSubRows() {
+ return this.eventsHaveSubRows_;
+ },
+
+ set eventsHaveSubRows(eventsHaveSubRows) {
+ this.eventsHaveSubRows_ = eventsHaveSubRows;
+ this.updateContents_();
+ },
+
+ get eventsByTitle() {
+ return this.eventsByTitle_;
+ },
+
+ set eventsByTitle(eventsByTitle) {
+ this.eventsByTitle_ = eventsByTitle;
+ this.updateContents_();
+ },
+
+ get selectionBounds() {
+ return this.selectionBounds_;
+ },
+
+ set selectionBounds(selectionBounds) {
+ this.selectionBounds_ = selectionBounds;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var eventsByTitle;
+ if (this.eventsByTitle_ !== undefined)
+ eventsByTitle = this.eventsByTitle_;
+ else
+ eventsByTitle = [];
+
+ var allEvents = new tr.model.EventSet();
+ var rows = [];
+ tr.b.iterItems(
+ eventsByTitle,
+ function(title, eventsOfSingleTitle) {
+ for (var event of allEvents)
+ allEvents.push(event);
+ var row = new tr.ui.analysis.MultiEventSummary(
+ title, eventsOfSingleTitle);
+ rows.push(row);
+ });
+
+ this.updateTableColumns_(rows);
+ this.$.table.tableRows = rows;
- var footerRows = [];
+ var maxValues = {
+ duration: undefined,
+ selfTime: undefined,
+ cpuSelfTime: undefined,
+ cpuDuration: undefined
+ };
- if (this.showTotals_) {
- var multiEventSummary = new tr.ui.analysis.MultiEventSummary(
- 'Totals', allEvents);
- footerRows.push(multiEventSummary);
+ if (this.eventsHaveDuration) {
+ for (var column in maxValues) {
+ maxValues[column] = tr.b.Statistics.max(rows, function(event) {
+ return event[column];
+ });
}
+ }
+ var footerRows = [];
- this.updateTableColumns_(rows, maxValues);
- this.$.table.tableRows = rows;
+ if (this.showTotals_) {
+ var multiEventSummary = new tr.ui.analysis.MultiEventSummary(
+ 'Totals', allEvents);
+ footerRows.push(multiEventSummary);
+ }
- // TODO(selection bounds).
- // TODO(sorting)
+ this.updateTableColumns_(rows, maxValues);
+ this.$.table.tableRows = rows;
- this.$.table.footerRows = footerRows;
- this.$.table.rebuild();
- }
- });
- </script>
-</polymer-element>
+ // TODO(selection bounds).
+
+ // TODO(sorting)
+
+ this.$.table.footerRows = footerRows;
+ this.$.table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
index ebef452ab9e..97898aeed6a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
@@ -68,22 +68,20 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(viewEl);
});
- test('noDurationNoSubRows', function() {
+ test('noSelfTimeNoSubRows', function() {
var model = new Model();
var fe1 = new tr.model.FlowEvent('cat', 1234, 'title', 7, 10, {});
var fe2 = new tr.model.FlowEvent('cat', 1234, 'title', 8, 20, {});
// Make reading some properties an explosion, as a way to ensure that they
- // aren't read.
+ // aren't read. Note that 'duration' is read since it is used by the
+ // EventSet to get the range.
var failProp = {
get: function() {
throw new Error('Should not be called');
}
};
- Object.defineProperty(fe1, 'duration', failProp);
- Object.defineProperty(fe2, 'duration', failProp);
-
Object.defineProperty(fe1, 'subRows', failProp);
Object.defineProperty(fe2, 'subRows', failProp);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html
index ec185d1844b..14946562497 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
-<polymer-element name="tr-ui-a-multi-flow-event-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-flow-event-sub-view'>
<template>
<style>
:host {
@@ -18,23 +17,33 @@ found in the LICENSE file.
</style>
<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-multi-flow-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- ready: function() {
- this.$.content.eventsHaveDuration = false;
- this.$.content.eventsHaveSubRows = false;
- },
+ ready: function() {
+ this.$.content.eventsHaveDuration = false;
+ this.$.content.eventsHaveSubRows = false;
+ },
- set selection(selection) {
- this.$.content.selection = selection;
- },
+ set selection(selection) {
+ this.$.content.selection = selection;
+ },
- get selection() {
- return this.$.content.selection;
- }
- });
- </script>
-</polymer-element>
+ get selection() {
+ return this.$.content.selection;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-flow-event-sub-view',
+ tr.model.FlowEvent,
+ {
+ multi: true,
+ title: 'Flow Events',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html
index 1ecf2d02e35..dd526e655b0 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html
@@ -6,46 +6,53 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/model/event_set.html">
-<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
+<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
+
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-multi-frame-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ set selection(selection) {
+ Polymer.dom(this).textContent = '';
+ var realView = document.createElement('tr-ui-a-multi-event-sub-view');
+ realView.eventsHaveDuration = false;
+ realView.eventsHaveSubRows = false;
+
+ Polymer.dom(this).appendChild(realView);
+ realView.setSelectionWithoutErrorChecks(selection);
+
+ this.currentSelection_ = selection;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
-<polymer-element name="tr-ui-a-multi-frame-sub-view"
- extends="tr-ui-a-sub-view">
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- set selection(selection) {
- this.textContent = '';
- var realView = document.createElement('tr-ui-a-multi-event-sub-view');
- realView.eventsHaveDuration = false;
- realView.eventsHaveSubRows = false;
-
- this.appendChild(realView);
- realView.setSelectionWithoutErrorChecks(selection);
-
- this.currentSelection_ = selection;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- var selection = new tr.model.EventSet();
- this.currentSelection_.forEach(function(frameEvent) {
- frameEvent.associatedEvents.forEach(function(event) {
- selection.push(event);
- });
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ var selection = new tr.model.EventSet();
+ this.currentSelection_.forEach(function(frameEvent) {
+ frameEvent.associatedEvents.forEach(function(event) {
+ selection.push(event);
});
- return selection;
- }
- });
- </script>
-</polymer-element>
+ });
+ return selection;
+ }
+});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-frame-sub-view',
+ tr.model.Frame,
+ {
+ multi: true,
+ title: 'Frames',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html
index 7d6adb91c4e..9701827e709 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
-<polymer-element name="tr-ui-a-multi-instant-event-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-instant-event-sub-view'>
<template>
<style>
:host {
@@ -18,30 +17,32 @@ found in the LICENSE file.
</style>
<div id='content'></div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- set selection(selection) {
- this.$.content.textContent = '';
- var realView = document.createElement('tr-ui-a-multi-event-sub-view');
- realView.eventsHaveDuration = false;
- realView.eventsHaveSubRows = false;
-
- this.$.content.appendChild(realView);
- realView.setSelectionWithoutErrorChecks(selection);
-
- this.currentSelection_ = selection;
- },
-
- get selection() {
- return this.currentSelection_;
- }
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-multi-instant-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ set selection(selection) {
+ Polymer.dom(this.$.content).textContent = '';
+ var realView = document.createElement('tr-ui-a-multi-event-sub-view');
+ realView.eventsHaveDuration = false;
+ realView.eventsHaveSubRows = false;
+
+ Polymer.dom(this.$.content).appendChild(realView);
+ realView.setSelectionWithoutErrorChecks(selection);
+
+ this.currentSelection_ = selection;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html
index 8241ab16aa2..d95ab8ba29b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html
@@ -5,89 +5,107 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-multi-object-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-object-sub-view'>
<template>
<style>
:host {
display: flex;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="content"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
+Polymer({
+ is: 'tr-ui-a-multi-object-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- ready: function() {
- this.$.content.showHeader = false;
- },
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
- get selection() {
- return this.currentSelection_;
- },
+ ready: function() {
+ this.$.content.showHeader = false;
+ },
- set selection(selection) {
- this.currentSelection_ = selection;
+ get selection() {
+ return this.currentSelection_;
+ },
- var objectEvents = tr.b.asArray(selection).sort(
- tr.b.Range.compareByMinTimes);
+ set selection(selection) {
+ this.currentSelection_ = selection;
- var timeSpanConfig = {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: this.ownerDocument
- };
- var table = this.$.content;
- table.tableColumns = [
- {
- title: 'First',
- value: function(event) {
- if (event instanceof tr.model.ObjectSnapshot)
- return tr.v.ui.createScalarSpan(event.ts, timeSpanConfig);
+ var objectEvents = tr.b.asArray(selection).sort(
+ tr.b.Range.compareByMinTimes);
- var spanEl = document.createElement('span');
- spanEl.appendChild(tr.v.ui.createScalarSpan(
- event.creationTs, timeSpanConfig));
- spanEl.appendChild(tr.ui.b.createSpan({
- textContent: '-',
- marginLeft: '4px',
- marginRight: '4px'
- }));
- if (event.deletionTs != Number.MAX_VALUE) {
- spanEl.appendChild(tr.v.ui.createScalarSpan(
- event.deletionTs, timeSpanConfig));
- }
- return spanEl;
- },
- width: '200px'
+ var timeSpanConfig = {
+ unit: tr.b.Unit.byName.timeStampInMs,
+ ownerDocument: this.ownerDocument
+ };
+ var table = this.$.content;
+ table.tableColumns = [
+ {
+ title: 'First',
+ value: function(event) {
+ if (event instanceof tr.model.ObjectSnapshot)
+ return tr.v.ui.createScalarSpan(event.ts, timeSpanConfig);
+
+ var spanEl = document.createElement('span');
+ Polymer.dom(spanEl).appendChild(tr.v.ui.createScalarSpan(
+ event.creationTs, timeSpanConfig));
+ Polymer.dom(spanEl).appendChild(tr.ui.b.createSpan({
+ textContent: '-',
+ marginLeft: '4px',
+ marginRight: '4px'
+ }));
+ if (event.deletionTs !== Number.MAX_VALUE) {
+ Polymer.dom(spanEl).appendChild(tr.v.ui.createScalarSpan(
+ event.deletionTs, timeSpanConfig));
+ }
+ return spanEl;
},
- {
- title: 'Second',
- value: function(event) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return new tr.model.EventSet(event);
- }, event.userFriendlyName);
- return linkEl;
- },
- width: '100%'
- }
- ];
- table.tableRows = objectEvents;
- table.rebuild();
- }
- });
- </script>
-</polymer-element>
+ width: '200px'
+ },
+ {
+ title: 'Second',
+ value: function(event) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(function() {
+ return new tr.model.EventSet(event);
+ }, event.userFriendlyName);
+ return linkEl;
+ },
+ width: '100%'
+ }
+ ];
+ table.tableRows = objectEvents;
+ table.rebuild();
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-object-sub-view',
+ tr.model.ObjectInstance,
+ {
+ multi: true,
+ title: 'Object Instances',
+ });
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-object-sub-view',
+ tr.model.ObjectSnapshot,
+ {
+ multi: true,
+ title: 'Object Snapshots',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html
index 2fc86530efb..2c7b8773f19 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html
@@ -10,8 +10,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/frame_power_usage_chart.html">
<link rel="import" href="/tracing/ui/analysis/power_sample_summary_table.html">
-<polymer-element name="tr-ui-a-multi-power-sample-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-power-sample-sub-view'>
<template>
<style>
:host {
@@ -34,14 +33,17 @@ found in the LICENSE file.
<tr-ui-a-frame-power-usage-chart id="chart">
</tr-ui-a-frame-power-usage-chart>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
// TODO(charliea): Add a dropdown that allows the user to select which type of
// power sample analysis view they want (e.g. table of samples, graph).
-Polymer('tr-ui-a-multi-power-sample-sub-view', {
+Polymer({
+ is: 'tr-ui-a-multi-power-sample-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
ready: function() {
this.currentSelection_ = undefined;
},
@@ -64,4 +66,12 @@ Polymer('tr-ui-a-multi-power-sample-sub-view', {
this.$.chart.setData(this.selection, vSyncTimestamps);
}
});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-power-sample-sub-view',
+ tr.model.PowerSample,
+ {
+ multi: true,
+ title: 'Power Samples',
+ });
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html
index ab570d12da7..4b515be4459 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html
@@ -6,13 +6,13 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/multi_dimensional_view.html">
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-multi-sample-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-sample-sub-view'>
<template>
<style>
:host { display: block; }
@@ -32,6 +32,9 @@ found in the LICENSE file.
margin: 1px;
margin-right: 2px;
}
+ tr-ui-b-table {
+ font-size: 12px;
+ }
</style>
<div id="control">
Sample View Option
@@ -39,230 +42,245 @@ found in the LICENSE file.
<tr-ui-b-table id="table">
</tr-ui-b-table>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
-
- (function() {
- var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder;
- var SAMPLE_TYPE = {
- COMPILER: 'compiler',
- EXTERNAL: 'external',
- GC: 'gc',
- NATIVEV8: '[native v8]',
- OTHER: 'other',
- UNKNOWN: 'unknown'
- };
+(function() {
+ var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder;
+ var SAMPLE_TYPE = {
+ COMPILER: 'compiler',
+ EXTERNAL: 'external',
+ GC: 'gc',
+ NATIVEV8: '[native v8]',
+ OTHER: 'other',
+ UNKNOWN: 'unknown'
+ };
- Polymer({
- created: function() {
- this.viewOption_ = undefined;
- this.selection_ = undefined;
- },
+ Polymer({
+ is: 'tr-ui-a-multi-sample-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- ready: function() {
- var viewSelector = tr.ui.b.createSelector(
- this, 'viewOption', 'tracing.ui.analysis.multi_sample_sub_view',
- MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW,
- [
- {
- label: 'Top-down (Tree)',
- value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW
- },
- {
- label: 'Top-down (Heavy)',
- value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW
- },
- {
- label: 'Bottom-up (Heavy)',
- value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW
- }
- ]);
- this.$.control.appendChild(viewSelector);
- this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
- },
+ created: function() {
+ this.viewOption_ = undefined;
+ this.selection_ = undefined;
+ },
- get selection() {
- return this.selection_;
- },
-
- set selection(selection) {
- this.selection_ = selection;
- this.updateContents_();
- },
+ ready: function() {
+ var viewSelector = tr.ui.b.createSelector(
+ this, 'viewOption', 'tracing.ui.analysis.multi_sample_sub_view',
+ MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW,
+ [
+ {
+ label: 'Top-down (Tree)',
+ value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW
+ },
+ {
+ label: 'Top-down (Heavy)',
+ value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW
+ },
+ {
+ label: 'Bottom-up (Heavy)',
+ value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW
+ }
+ ]);
+ Polymer.dom(this.$.control).appendChild(viewSelector);
+ this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ },
- get viewOption() {
- return this.viewOption_;
- },
+ get selection() {
+ return this.selection_;
+ },
- set viewOption(viewOption) {
- this.viewOption_ = viewOption;
- this.updateContents_();
- },
+ set selection(selection) {
+ this.selection_ = selection;
+ this.updateContents_();
+ },
- createSamplingSummary_: function(selection, viewOption) {
- var builder = new MultiDimensionalViewBuilder(
- 1 /* dimensions */, 1 /* valueCount */);
- var samples = selection.getEventsOrganizedByBaseType().sample;
+ get viewOption() {
+ return this.viewOption_;
+ },
- samples.forEach(function(sample) {
- builder.addPath([sample.getUserFriendlyStackTrace().reverse()],
- [1], MultiDimensionalViewBuilder.ValueKind.SELF);
- });
+ set viewOption(viewOption) {
+ this.viewOption_ = viewOption;
+ this.updateContents_();
+ },
- return builder.buildView(viewOption);
- },
+ createSamplingSummary_: function(selection, viewOption) {
+ var builder = new MultiDimensionalViewBuilder(
+ 1 /* dimensions */, 1 /* valueCount */);
+ var samples = selection.filter(function(event) {
+ return event instanceof tr.model.Sample;
+ });
- // Constructs function name and file name of sample
- // if it is compiler, external, gc, other, or unknown.
- processTypedSampleRow_: function(row) {
- var title = row.title[0];
- switch (title) {
- case SAMPLE_TYPE.COMPILER:
- case SAMPLE_TYPE.EXTERNAL:
- case SAMPLE_TYPE.GC:
- case SAMPLE_TYPE.OTHER:
- row.functionName = title;
- row.fileName = 'N/A';
- return true;
- case SAMPLE_TYPE.UNKNOWN:
- row.functionName = SAMPLE_TYPE.UNKNOWN;
- row.fileName = SAMPLE_TYPE.UNKNOWN;
- return true;
- default:
- return false;
- }
- },
+ samples.forEach(function(sample) {
+ builder.addPath([sample.getUserFriendlyStackTrace().reverse()],
+ [1], MultiDimensionalViewBuilder.ValueKind.SELF);
+ });
- // Constructs function name and file name of native v8 sample.
- processNativeV8SampleRow_: function(row) {
- var title = row.title[0];
- if (!title.includes(SAMPLE_TYPE.NATIVEV8))
- return false;
- var arr = title.split(SAMPLE_TYPE.NATIVEV8);
- row.functionName = arr[0].trim();
- if (row.functionName === '')
- row.functionName = '(anonymous function)';
- row.fileName = SAMPLE_TYPE.NATIVEV8;
- var fileNameSuffix = arr[1].trim();
- if (fileNameSuffix !== '')
- row.fileName += ' ' + fileNameSuffix;
- return true;
- },
+ return builder.buildView(viewOption);
+ },
- // Constructs function name and file name for sample.
- processGeneralSampleRow_: function(row) {
- var title = row.title[0];
- var idx = title.lastIndexOf(' ');
- if (idx === -1) {
+ // Constructs function name and file name of sample
+ // if it is compiler, external, gc, other, or unknown.
+ processTypedSampleRow_: function(row) {
+ var title = row.title[0];
+ switch (title) {
+ case SAMPLE_TYPE.COMPILER:
+ case SAMPLE_TYPE.EXTERNAL:
+ case SAMPLE_TYPE.GC:
+ case SAMPLE_TYPE.OTHER:
row.functionName = title;
- row.fileName = 'unknown';
- return;
- }
- var prefix = title.substr(0, idx);
- var suffix = title.substr(idx + 1);
- if (suffix.startsWith('v8/')) {
- row.functionName = suffix;
- row.fileName = 'unknown';
- } else if (suffix === '') {
- row.functionName = prefix;
- row.fileName = 'unknown';
- } else if (prefix === '') {
- row.functionName = '(anonymous function)';
- row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1);
- } else {
- row.functionName = prefix;
- row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1);
- }
- },
+ row.fileName = 'N/A';
+ return true;
+ case SAMPLE_TYPE.UNKNOWN:
+ row.functionName = SAMPLE_TYPE.UNKNOWN;
+ row.fileName = SAMPLE_TYPE.UNKNOWN;
+ return true;
+ default:
+ return false;
+ }
+ },
- processSampleRows_: function(rows) {
- rows.forEach(function(row) {
- if (!this.processTypedSampleRow_(row) &&
- !this.processNativeV8SampleRow_(row))
- this.processGeneralSampleRow_(row);
- this.processSampleRows_(row.subRows);
- }, this);
- },
+ // Constructs function name and file name of native v8 sample.
+ processNativeV8SampleRow_: function(row) {
+ var title = row.title[0];
+ if (!title.includes(SAMPLE_TYPE.NATIVEV8))
+ return false;
+ var arr = title.split(SAMPLE_TYPE.NATIVEV8);
+ row.functionName = arr[0].trim();
+ if (row.functionName === '')
+ row.functionName = '(anonymous function)';
+ row.fileName = SAMPLE_TYPE.NATIVEV8;
+ var fileNameSuffix = arr[1].trim();
+ if (fileNameSuffix !== '')
+ row.fileName += ' ' + fileNameSuffix;
+ return true;
+ },
- updateContents_: function() {
- if (this.selection === undefined) {
- this.$.table.tableColumns = [];
- this.$.table.tableRows = [];
- this.$.table.rebuild();
- return;
- }
+ // Constructs function name and file name for sample.
+ processGeneralSampleRow_: function(row) {
+ var title = row.title[0];
+ var idx = title.lastIndexOf(' ');
+ if (idx === -1) {
+ row.functionName = title;
+ row.fileName = 'unknown';
+ return;
+ }
+ var prefix = title.substr(0, idx);
+ var suffix = title.substr(idx + 1);
+ if (suffix.startsWith('v8/')) {
+ row.functionName = suffix;
+ row.fileName = 'unknown';
+ } else if (suffix === '') {
+ row.functionName = prefix;
+ row.fileName = 'unknown';
+ } else if (prefix === '') {
+ row.functionName = '(anonymous function)';
+ row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1);
+ } else {
+ row.functionName = prefix;
+ row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1);
+ }
+ },
- var samplingData = this.createSamplingSummary_(
- this.selection, this.viewOption);
- var total = samplingData.values[0].total;
- var columns = [
- this.createPercentColumn_('Total', total),
- this.createSamplesColumn_('Total'),
- this.createPercentColumn_('Self', total),
- this.createSamplesColumn_('Self'),
- {
- title: 'Function Name',
- value: function(row) { return row.functionName; },
- width: '150px',
- cmp: function(a, b) {
- return a.functionName.localeCompare(b.functionName);
- },
- showExpandButtons: true
- },
- {
- title: 'Location',
- value: function(row) { return row.fileName; },
- width: '250px',
- cmp: function(a, b) {
- return a.fileName.localeCompare(b.fileName);
- }
- }
- ];
+ processSampleRows_: function(rows) {
+ rows.forEach(function(row) {
+ if (!this.processTypedSampleRow_(row) &&
+ !this.processNativeV8SampleRow_(row))
+ this.processGeneralSampleRow_(row);
+ this.processSampleRows_(row.subRows);
+ }, this);
+ },
- this.processSampleRows_(samplingData.subRows);
- this.$.table.tableColumns = columns;
- this.$.table.sortColumnIndex = 1 /* Total samples */;
- this.$.table.sortDescending = true;
- this.$.table.tableRows = samplingData.subRows;
+ updateContents_: function() {
+ if (this.selection === undefined) {
+ this.$.table.tableColumns = [];
+ this.$.table.tableRows = [];
this.$.table.rebuild();
- },
-
- createPercentColumn_: function(title, samplingDataTotal) {
- var field = title.toLowerCase();
- return {
- title: title + ' percent',
- value: function(row) {
- var percent = row.values[0][field] / samplingDataTotal;
-
- var span = document.createElement('tr-v-ui-scalar-span');
- span.value = (percent * 100).toFixed(2);
- span.percentage = percent;
- span.unit = tr.v.Unit.byName.unitlessNumber;
- return span;
+ return;
+ }
- }.bind(this),
- width: '60px',
+ var samplingData = this.createSamplingSummary_(
+ this.selection, this.viewOption);
+ var total = samplingData.values[0].total;
+ var columns = [
+ this.createPercentColumn_('Total', total),
+ this.createSamplesColumn_('Total'),
+ this.createPercentColumn_('Self', total),
+ this.createSamplesColumn_('Self'),
+ {
+ title: 'Function Name',
+ value: function(row) { return row.functionName; },
+ width: '150px',
cmp: function(a, b) {
- return a.values[0][field] - b.values[0][field];
- }
- };
- },
-
- createSamplesColumn_: function(title) {
- var field = title.toLowerCase();
- return {
- title: title + ' samples',
- value: function(row) {
- return row.values[0][field];
+ return a.functionName.localeCompare(b.functionName);
},
- width: '60px',
+ showExpandButtons: true
+ },
+ {
+ title: 'Location',
+ value: function(row) { return row.fileName; },
+ width: '250px',
cmp: function(a, b) {
- return a.values[0][field] - b.values[0][field];
+ return a.fileName.localeCompare(b.fileName);
}
- };
- }
+ }
+ ];
+
+ this.processSampleRows_(samplingData.subRows);
+ this.$.table.tableColumns = columns;
+ this.$.table.sortColumnIndex = 1 /* Total samples */;
+ this.$.table.sortDescending = true;
+ this.$.table.tableRows = samplingData.subRows;
+ this.$.table.rebuild();
+ },
+
+ createPercentColumn_: function(title, samplingDataTotal) {
+ var field = title.toLowerCase();
+ return {
+ title: title + ' percent',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(
+ row.values[0][field] / samplingDataTotal, {
+ customContextRange: tr.b.Range.PERCENT_RANGE,
+ unit: tr.b.Unit.byName.normalizedPercentage,
+ context: { minimumFractionDigits: 2, maximumFractionDigits: 2 },
+ rightAlign: true
+ });
+ },
+ width: '60px',
+ cmp: function(a, b) {
+ return a.values[0][field] - b.values[0][field];
+ }
+ };
+ },
+
+ createSamplesColumn_: function(title) {
+ var field = title.toLowerCase();
+ return {
+ title: title + ' samples',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.values[0][field], {
+ unit: tr.b.Unit.byName.unitlessNumber,
+ context: { maximumFractionDigits: 0 },
+ rightAlign: true
+ });
+ },
+ width: '60px',
+ cmp: function(a, b) {
+ return a.values[0][field] - b.values[0][field];
+ }
+ };
+ }
+ });
+
+ tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-sample-sub-view',
+ tr.model.Sample,
+ {
+ multi: true,
+ title: 'Samples',
});
- })();
- </script>
-</polymer-element>
+})();
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html
index 54c1c324ab2..08e41c64d37 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html
@@ -9,8 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/related_events.html">
-<polymer-element name="tr-ui-a-multi-thread-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-thread-slice-sub-view'>
<template>
<style>
:host {
@@ -27,68 +26,78 @@ found in the LICENSE file.
</style>
<div id="content"></div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.selection_ = undefined;
- },
-
- get selection() {
- return this.selection_;
- },
-
- set selection(selection) {
- this.selection_ = selection;
-
- // TODO(nduca): This is a gross hack for cc Frame Viewer, but its only
- // the frame viewer that needs this feature, so ~shrug~.
- // We check for its presence so that we do not have a hard dependency
- // on frame viewer.
- if (tr.isExported('tr.ui.e.chrome.cc.RasterTaskSelection')) {
- if (tr.ui.e.chrome.cc.RasterTaskSelection.supports(selection)) {
- var ltvSelection = new tr.ui.e.chrome.cc.RasterTaskSelection(
- selection);
-
- var ltv = new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView();
- ltv.objectSnapshot = ltvSelection.containingSnapshot;
- ltv.selection = ltvSelection;
- ltv.extraHighlightsByLayerId = ltvSelection.extraHighlightsByLayerId;
-
- this.$.content.textContent = '';
- this.$.content.appendChild(ltv);
-
- this.requiresTallView_ = true;
- return;
- }
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-multi-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.selection_ = undefined;
+ },
+
+ get selection() {
+ return this.selection_;
+ },
+
+ set selection(selection) {
+ this.selection_ = selection;
+
+ // TODO(nduca): This is a gross hack for cc Frame Viewer, but its only
+ // the frame viewer that needs this feature, so ~shrug~.
+ // We check for its presence so that we do not have a hard dependency
+ // on frame viewer.
+ if (tr.isExported('tr.ui.e.chrome.cc.RasterTaskSelection')) {
+ if (tr.ui.e.chrome.cc.RasterTaskSelection.supports(selection)) {
+ var ltvSelection = new tr.ui.e.chrome.cc.RasterTaskSelection(
+ selection);
+
+ var ltv = new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView();
+ ltv.objectSnapshot = ltvSelection.containingSnapshot;
+ ltv.selection = ltvSelection;
+ ltv.extraHighlightsByLayerId = ltvSelection.extraHighlightsByLayerId;
+
+ Polymer.dom(this.$.content).textContent = '';
+ Polymer.dom(this.$.content).appendChild(ltv);
+
+ this.requiresTallView_ = true;
+ return;
}
+ }
- this.$.content.textContent = '';
-
- var mesv = document.createElement('tr-ui-a-multi-event-sub-view');
- mesv.selection = selection;
- this.$.content.appendChild(mesv);
-
- var relatedEvents = document.createElement('tr-ui-a-related-events');
- relatedEvents.setRelatedEvents(selection);
+ Polymer.dom(this.$.content).textContent = '';
- if (relatedEvents.hasRelatedEvents()) {
- this.$.content.appendChild(relatedEvents);
- }
- },
+ var mesv = document.createElement('tr-ui-a-multi-event-sub-view');
+ mesv.selection = selection;
+ Polymer.dom(this.$.content).appendChild(mesv);
- get requiresTallView() {
- if (this.$.content.children.length === 0)
- return false;
- var childTagName = this.$.content.children[0].tagName;
- if (childTagName === 'TR-UI-A-MULTI-EVENT-SUB-VIEW')
- return false;
+ var relatedEvents = document.createElement('tr-ui-a-related-events');
+ relatedEvents.setRelatedEvents(selection);
- // Using raster task view.
- return true;
+ if (relatedEvents.hasRelatedEvents()) {
+ Polymer.dom(this.$.content).appendChild(relatedEvents);
}
- });
- </script>
-</polymer-element>
+ },
+
+ get requiresTallView() {
+ if (this.$.content.children.length === 0)
+ return false;
+ var childTagName = this.$.content.children[0].tagName;
+ if (childTagName === 'TR-UI-A-MULTI-EVENT-SUB-VIEW')
+ return false;
+
+ // Using raster task view.
+ return true;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-thread-slice-sub-view',
+ tr.model.ThreadSlice,
+ {
+ multi: true,
+ title: 'Slices',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html
index 6fba8d2e857..31bd29e3567 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html">
-<polymer-element name="tr-ui-a-multi-thread-time-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-thread-time-slice-sub-view'>
<template>
<style>
:host {
@@ -21,22 +20,32 @@ found in the LICENSE file.
</style>
<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-multi-thread-time-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- ready: function() {
- this.$.content.eventsHaveSubRows = false;
- },
+ ready: function() {
+ this.$.content.eventsHaveSubRows = false;
+ },
- get selection() {
- return this.$.content.selection;
- },
+ get selection() {
+ return this.$.content.selection;
+ },
- set selection(selection) {
- this.$.content.setSelectionWithoutErrorChecks(selection);
- }
+ set selection(selection) {
+ this.$.content.setSelectionWithoutErrorChecks(selection);
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-thread-time-slice-sub-view',
+ tr.model.ThreadTimeSlice,
+ {
+ multi: true,
+ title: 'Thread Timeslices',
});
- </script>
-</polymer-element>
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html
index 34b70762345..0caf158532c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html
@@ -11,8 +11,7 @@ found in the LICENSE file.
<link rel="import"
href="/tracing/ui/analysis/user_expectation_related_samples_table.html">
-<polymer-element name="tr-ui-a-multi-user-expectation-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-multi-user-expectation-sub-view'>
<template>
<style>
:host {
@@ -29,42 +28,52 @@ found in the LICENSE file.
<tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table>
</div>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
+Polymer({
+ is: 'tr-ui-a-multi-interaction-record-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- set selection(selection) {
- this.currentSelection_ = selection;
- this.$.realView.setSelectionWithoutErrorChecks(selection);
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
- this.currentSelection_ = selection;
+ set selection(selection) {
+ this.currentSelection_ = selection;
+ this.$.realView.setSelectionWithoutErrorChecks(selection);
- this.$.relatedSamples.selection = selection;
- if (this.$.relatedSamples.hasRelatedSamples())
- this.$.events.style.display = '';
- else
- this.$.events.style.display = 'none';
- },
+ this.currentSelection_ = selection;
- get selection() {
- return this.currentSelection_;
- },
+ this.$.relatedSamples.selection = selection;
+ if (this.$.relatedSamples.hasRelatedSamples())
+ this.$.events.style.display = '';
+ else
+ this.$.events.style.display = 'none';
+ },
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- var selection = new tr.model.EventSet();
- this.currentSelection_.forEach(function(ir) {
- ir.associatedEvents.forEach(function(event) {
- selection.push(event);
- });
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ var selection = new tr.model.EventSet();
+ this.currentSelection_.forEach(function(ir) {
+ ir.associatedEvents.forEach(function(event) {
+ selection.push(event);
});
- return selection;
- }
- });
- </script>
-</polymer-element>
+ });
+ return selection;
+ }
+});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-user-expectation-sub-view',
+ tr.model.um.UserExpectation,
+ {
+ multi: true,
+ title: 'User Expectations',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html
index f94aa245f6e..e07e2e4ea95 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html
@@ -15,7 +15,7 @@ tr.exportTo('tr.ui.analysis', function() {
var ObjectInstanceView = tr.ui.b.define('object-instance-view');
ObjectInstanceView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.objectInstance_ = undefined;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html
index a50747beefa..4363e9fb466 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html
@@ -15,7 +15,7 @@ tr.exportTo('tr.ui.analysis', function() {
var ObjectSnapshotView = tr.ui.b.define('object-snapshot-view');
ObjectSnapshotView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.objectSnapshot_ = undefined;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html
index ab314e42589..6325bd8a691 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html
@@ -6,124 +6,132 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/base/table.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-power-sample-summary-table">
+<dom-module id='tr-ui-a-power-sample-summary-table'>
<template>
+ <style>
+ tr-ui-b-table {
+ font-size: 12px;
+ }
+ </style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.$.table.tableColumns = [
- {
- title: 'Min power',
- width: '100px',
- value: function(row) {
- return tr.v.Unit.byName.powerInWatts.format(row.min);
- }
- },
- {
- title: 'Max power',
- width: '100px',
- value: function(row) {
- return tr.v.Unit.byName.powerInWatts.format(row.max);
- }
- },
- {
- title: 'Time-weighted average',
- width: '100px',
- value: function(row) {
- return tr.v.Unit.byName.powerInWatts.format(
- row.timeWeightedAverage);
- }
- },
- {
- title: 'Energy consumed',
- width: '100px',
- value: function(row) {
- return tr.v.Unit.byName.energyInJoules.format(row.energyConsumed);
- }
- },
- {
- title: 'Sample count',
- width: '100%',
- value: function(row) { return row.sampleCount; }
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-power-sample-summary-table',
+
+ ready: function() {
+ this.$.table.tableColumns = [
+ {
+ title: 'Min power',
+ width: '100px',
+ value: function(row) {
+ return tr.b.Unit.byName.powerInWatts.format(row.min);
+ }
+ },
+ {
+ title: 'Max power',
+ width: '100px',
+ value: function(row) {
+ return tr.b.Unit.byName.powerInWatts.format(row.max);
+ }
+ },
+ {
+ title: 'Time-weighted average',
+ width: '100px',
+ value: function(row) {
+ return tr.b.Unit.byName.powerInWatts.format(
+ row.timeWeightedAverageInW);
+ }
+ },
+ {
+ title: 'Energy consumed',
+ width: '100px',
+ value: function(row) {
+ return tr.b.Unit.byName.energyInJoules.format(row.energyConsumedInJ);
}
- ];
- this.samples = new tr.model.EventSet();
- },
-
- get samples() {
- return this.samples_;
- },
-
- set samples(samples) {
- if (samples === this.samples)
- return;
-
- this.samples_ =
- (samples === undefined) ? new tr.model.EventSet() : samples;
- this.updateContents_();
- },
-
- updateContents_: function() {
- if (this.samples.length === 0) {
- this.$.table.tableRows = [];
- } else {
- this.$.table.tableRows = [{
- min: this.getMin(),
- max: this.getMax(),
- timeWeightedAverage: this.getTimeWeightedAverage(),
- energyConsumed: this.getEnergyConsumed(),
- sampleCount: this.samples.length
- }];
+ },
+ {
+ title: 'Sample count',
+ width: '100%',
+ value: function(row) { return row.sampleCount; }
}
-
- this.$.table.rebuild();
- },
-
- getMin: function() {
- return Math.min.apply(null, this.samples.map(function(sample) {
- return sample.power;
- }));
- },
-
- getMax: function() {
- return Math.max.apply(null, this.samples.map(function(sample) {
- return sample.power;
- }));
- },
-
- /**
- * Returns a time-weighted average of the power consumption (Watts)
- * in between the first sample (inclusive) and last sample (exclusive).
- */
- getTimeWeightedAverage: function() {
- var energyConsumed = this.getEnergyConsumed();
-
- if (energyConsumed === 'N/A')
- return 'N/A';
-
- // Divide by 1000 to convert milliseconds to seconds.
- var durationInSeconds = this.samples.bounds.duration / 1000;
-
- // Convert energy to power in milliwatts by dividing by time in seconds.
- return this.getEnergyConsumed() / durationInSeconds;
- },
-
- getEnergyConsumed: function() {
- if (this.samples.length < 2)
- return 'N/A';
-
- var bounds = this.samples.bounds;
- var series = tr.b.getFirstElement(this.samples).series;
- return series.getEnergyConsumed(bounds.min, bounds.max);
+ ];
+ this.samples = new tr.model.EventSet();
+ },
+
+ get samples() {
+ return this.samples_;
+ },
+
+ set samples(samples) {
+ if (samples === this.samples)
+ return;
+
+ this.samples_ =
+ (samples === undefined) ? new tr.model.EventSet() : samples;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ if (this.samples.length === 0) {
+ this.$.table.tableRows = [];
+ } else {
+ this.$.table.tableRows = [{
+ min: this.getMin(),
+ max: this.getMax(),
+ timeWeightedAverageInW: this.getTimeWeightedAverageInW(),
+ energyConsumedInJ: this.getEnergyConsumedInJ(),
+ sampleCount: this.samples.length
+ }];
}
- });
- </script>
-</polymer-element>
+
+ this.$.table.rebuild();
+ },
+
+ getMin: function() {
+ return Math.min.apply(null, this.samples.map(function(sample) {
+ return sample.powerInW;
+ }));
+ },
+
+ getMax: function() {
+ return Math.max.apply(null, this.samples.map(function(sample) {
+ return sample.powerInW;
+ }));
+ },
+
+ /**
+ * Returns a time-weighted average of the power consumption (Watts)
+ * in between the first sample (inclusive) and last sample (exclusive).
+ */
+ getTimeWeightedAverageInW: function() {
+ var energyConsumedInJ = this.getEnergyConsumedInJ();
+
+ if (energyConsumedInJ === 'N/A')
+ return 'N/A';
+
+ var durationInS = tr.b.convertUnit(this.samples.bounds.duration,
+ tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
+
+ return energyConsumedInJ / durationInS;
+ },
+
+
+ getEnergyConsumedInJ: function() {
+ if (this.samples.length < 2)
+ return 'N/A';
+
+ var bounds = this.samples.bounds;
+ var series = tr.b.getFirstElement(this.samples).series;
+ return series.getEnergyConsumedInJ(bounds.min, bounds.max);
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html
index 82cc98dc1fb..151a36459ea 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html
@@ -58,8 +58,8 @@ tr.b.unittest.testSuite(function() {
assert.lengthOf(table.$.table.tableRows, 1);
assert.equal(table.$.table.tableRows[0].min, 1);
assert.equal(table.$.table.tableRows[0].max, 1);
- assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 'N/A');
- assert.equal(table.$.table.tableRows[0].energyConsumed, 'N/A');
+ assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 'N/A');
+ assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 'N/A');
assert.equal(table.$.table.tableRows[0].sampleCount, 1);
});
@@ -75,8 +75,8 @@ tr.b.unittest.testSuite(function() {
assert.lengthOf(table.$.table.tableRows, 1);
assert.equal(table.$.table.tableRows[0].min, 1);
assert.equal(table.$.table.tableRows[0].max, 2);
- assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 1);
- assert.equal(table.$.table.tableRows[0].energyConsumed, 1);
+ assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 1);
+ assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 1);
assert.equal(table.$.table.tableRows[0].sampleCount, 2);
});
@@ -93,8 +93,8 @@ tr.b.unittest.testSuite(function() {
assert.lengthOf(table.$.table.tableRows, 1);
assert.equal(table.$.table.tableRows[0].min, 1);
assert.equal(table.$.table.tableRows[0].max, 3);
- assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 1.5);
- assert.equal(table.$.table.tableRows[0].energyConsumed, 3);
+ assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 1.5);
+ assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 3);
assert.equal(table.$.table.tableRows[0].sampleCount, 3);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html
new file mode 100644
index 00000000000..65cf075a003
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/raf.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.analysis', function() {
+
+ var RebuildableBehavior = {
+ rebuild: function() {
+ /**
+ * Rebuild the pane if necessary.
+ *
+ * This method is not intended to be overriden by subclasses. Please
+ * override scheduleRebuild_() instead.
+ */
+ if (!this.paneDirty_) {
+ // Avoid rebuilding unnecessarily as it breaks things like table
+ // selection.
+ return;
+ }
+
+ this.paneDirty_ = false;
+ this.onRebuild_();
+ },
+
+ /**
+ * Mark the UI state of the pane as dirty and schedule a rebuild.
+ *
+ * This method is intended to be called by subclasses.
+ */
+ scheduleRebuild_: function() {
+ if (this.paneDirty_)
+ return;
+ this.paneDirty_ = true;
+ tr.b.requestAnimationFrame(this.rebuild.bind(this));
+ },
+
+ /**
+ * Called when the pane is dirty and a rebuild is triggered.
+ *
+ * This method is intended to be overriden by subclasses (instead of
+ * directly overriding rebuild()).
+ */
+ onRebuild_: function() {
+ }
+ };
+
+ return {
+ RebuildableBehavior: RebuildableBehavior
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html
new file mode 100644
index 00000000000..4b7ed3a164f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ Polymer({
+ is: 'tr-ui-analysis-rebuildable-test-element',
+ behaviors: [tr.ui.analysis.RebuildableBehavior]
+ });
+
+ test('rebuild', function() {
+ var el = document.createElement('tr-ui-analysis-rebuildable-test-element');
+ var didFireOnRebuild;
+ el.onRebuild_ = function() {
+ assert.strictEqual(this, el);
+ didFireOnRebuild = true;
+ };
+
+ function checkManualRebuild(expectedDidFireOnRebuild) {
+ didFireOnRebuild = false;
+ el.rebuild();
+ assert.strictEqual(didFireOnRebuild, expectedDidFireOnRebuild);
+ }
+
+ function checkRAFRebuild(expectedDidFireOnRebuild) {
+ didFireOnRebuild = false;
+ tr.b.forcePendingRAFTasksToRun();
+ assert.strictEqual(didFireOnRebuild, expectedDidFireOnRebuild);
+ }
+
+ // No rebuilds should occur when not scheduled.
+ checkManualRebuild(false);
+ checkRAFRebuild(false);
+
+ // Single rebuild should occur when scheduled once.
+ el.scheduleRebuild_();
+ checkManualRebuild(true);
+ checkManualRebuild(false);
+
+ el.scheduleRebuild_();
+ checkRAFRebuild(true);
+ checkRAFRebuild(false);
+
+ // Only a single rebuild should occur even when scheduled multiple times.
+ el.scheduleRebuild_();
+ el.scheduleRebuild_();
+ checkManualRebuild(true);
+ checkRAFRebuild(false);
+ checkManualRebuild(false);
+
+ el.scheduleRebuild_();
+ el.scheduleRebuild_();
+ checkRAFRebuild(true);
+ checkRAFRebuild(false);
+ checkManualRebuild(false);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html
index faec4d0471e..142887260ad 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name="tr-ui-a-related-events">
+<dom-module id='tr-ui-a-related-events'>
<template>
<style>
:host {
@@ -23,241 +23,302 @@ found in the LICENSE file.
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+function* getEventInFlowEvents(event) {
+ if (!event.inFlowEvents)
+ return;
+ yield * event.inFlowEvents;
+}
- Polymer({
- ready: function() {
- this.eventGroups_ = [];
- this.cancelFunctions_ = [];
+function* getEventOutFlowEvents(event) {
+ if (!event.outFlowEvents)
+ return;
+ yield * event.outFlowEvents;
+}
- this.$.table.tableColumns = [
- {
- title: 'Event(s)',
- value: function(row) {
- var typeEl = document.createElement('span');
- typeEl.innerText = row.type;
- if (row.tooltip)
- typeEl.title = row.tooltip;
- return typeEl;
- },
- width: '150px'
+function* getEventAncestors(event) {
+ if (!event.enumerateAllAncestors)
+ return;
+ yield * event.enumerateAllAncestors();
+}
+
+function* getEventDescendents(event) {
+ if (!event.enumerateAllDescendents)
+ return;
+ yield * event.enumerateAllDescendents();
+}
+
+Polymer({
+ is: 'tr-ui-a-related-events',
+
+ ready: function() {
+ this.eventGroups_ = [];
+ this.cancelFunctions_ = [];
+
+ this.$.table.tableColumns = [
+ {
+ title: 'Event(s)',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.type;
+ if (row.tooltip)
+ typeEl.title = row.tooltip;
+ return typeEl;
},
- {
- title: 'Link',
- width: '100%',
- value: function(row) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- if (row.name)
- linkEl.setSelectionAndContent(row.selection, row.name);
- else
- linkEl.selection = row.selection;
- return linkEl;
- }
+ width: '150px'
+ },
+ {
+ title: 'Link',
+ width: '100%',
+ value: function(row) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ if (row.name)
+ linkEl.setSelectionAndContent(row.selection, row.name);
+ else
+ linkEl.selection = row.selection;
+ return linkEl;
}
- ];
- },
+ }
+ ];
+ },
- hasRelatedEvents: function() {
- return (this.eventGroups_ && this.eventGroups_.length > 0);
- },
+ hasRelatedEvents: function() {
+ return (this.eventGroups_ && this.eventGroups_.length > 0);
+ },
- setRelatedEvents: function(eventSet) {
- this.cancelAllTasks_();
- this.eventGroups_ = [];
- this.addConnectedFlows_(eventSet);
- this.addConnectedEvents_(eventSet);
- this.addOverlappingSamples_(eventSet);
- this.updateContents_();
- },
+ setRelatedEvents: function(eventSet) {
+ this.cancelAllTasks_();
+ this.eventGroups_ = [];
+ this.addRuntimeCallStats_(eventSet);
+ this.addV8GCObjectStats_(eventSet);
+ this.addV8Slices_(eventSet);
+ this.addConnectedFlows_(eventSet);
+ this.addConnectedEvents_(eventSet);
+ this.addOverlappingSamples_(eventSet);
+ this.updateContents_();
+ },
- addConnectedFlows_: function(eventSet) {
- var classifier = new tr.ui.analysis.FlowClassifier();
- eventSet.forEach(function(slice) {
- if (slice.inFlowEvents) {
- slice.inFlowEvents.forEach(function(flow) {
- classifier.addInFlow(flow);
- });
- }
- if (slice.outFlowEvents) {
- slice.outFlowEvents.forEach(function(flow) {
- classifier.addOutFlow(flow);
- });
- }
+ addConnectedFlows_: function(eventSet) {
+ var classifier = new tr.ui.analysis.FlowClassifier();
+ eventSet.forEach(function(slice) {
+ if (slice.inFlowEvents) {
+ slice.inFlowEvents.forEach(function(flow) {
+ classifier.addInFlow(flow);
+ });
+ }
+ if (slice.outFlowEvents) {
+ slice.outFlowEvents.forEach(function(flow) {
+ classifier.addOutFlow(flow);
+ });
+ }
+ });
+ if (!classifier.hasEvents())
+ return;
+
+ var addToEventGroups = function(type, flowEvent) {
+ this.eventGroups_.push({
+ type: type,
+ selection: new tr.model.EventSet(flowEvent),
+ name: flowEvent.title
});
- if (!classifier.hasEvents())
- return;
+ };
- var addToEventGroups = function(type, flowEvent) {
- this.eventGroups_.push({
- type: type,
- selection: new tr.model.EventSet(flowEvent),
- name: flowEvent.title
- });
- };
+ classifier.inFlowEvents.forEach(
+ addToEventGroups.bind(this, 'Incoming flow'));
+ classifier.outFlowEvents.forEach(
+ addToEventGroups.bind(this, 'Outgoing flow'));
+ classifier.internalFlowEvents.forEach(
+ addToEventGroups.bind(this, 'Internal flow'));
+ },
- classifier.inFlowEvents.forEach(
- addToEventGroups.bind(this, 'Incoming flow'));
- classifier.outFlowEvents.forEach(
- addToEventGroups.bind(this, 'Outgoing flow'));
- classifier.internalFlowEvents.forEach(
- addToEventGroups.bind(this, 'Internal flow'));
- },
+ cancelAllTasks_: function() {
+ this.cancelFunctions_.forEach(function(cancelFunction) {
+ cancelFunction();
+ });
+ this.cancelFunctions_ = [];
+ },
- cancelAllTasks_: function() {
- this.cancelFunctions_.forEach(function(cancelFunction) {
- cancelFunction();
- });
- this.cancelFunctions_ = [];
- },
+ addConnectedEvents_: function(eventSet) {
+ this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
+ 'Preceding events',
+ 'Add all events that have led to the selected one(s), connected by ' +
+ 'flow arrows or by call stack.',
+ eventSet,
+ function*(event) {
+ yield * getEventInFlowEvents(event);
+ yield * getEventAncestors(event);
+ if (event.startSlice)
+ yield event.startSlice;
+ }.bind(this)));
+ this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
+ 'Following events',
+ 'Add all events that have been caused by the selected one(s), ' +
+ 'connected by flow arrows or by call stack.',
+ eventSet,
+ function*(event) {
+ yield * getEventOutFlowEvents(event);
+ yield * getEventDescendents(event);
+ if (event.endSlice)
+ yield event.endSlice;
+ }.bind(this)));
+ this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
+ 'All connected events',
+ 'Add all events connected to the selected one(s) by flow arrows or ' +
+ 'by call stack.',
+ eventSet,
+ function*(event) {
+ yield * getEventInFlowEvents(event);
+ yield * getEventOutFlowEvents(event);
+ yield * getEventAncestors(event);
+ yield * getEventDescendents(event);
+ if (event.startSlice)
+ yield event.startSlice;
+ if (event.endSlice)
+ yield event.endSlice;
+ }.bind(this)));
+ },
- addConnectedEvents_: function(eventSet) {
- this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
- 'Preceding events',
- 'Add all events that have led to the selected one(s), connected by ' +
- 'flow arrows or by call stack.',
- eventSet,
- function(event, events) {
- this.addInFlowEvents_(event, events);
- this.addAncestors_(event, events);
- if (event.startSlice)
- events.push(event.startSlice);
- }.bind(this)));
- this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
- 'Following events',
- 'Add all events that have been caused by the selected one(s), ' +
- 'connected by flow arrows or by call stack.',
- eventSet,
- function(event, events) {
- this.addOutFlowEvents_(event, events);
- this.addDescendents_(event, events);
- if (event.endSlice)
- events.push(event.endSlice);
- }.bind(this)));
- this.cancelFunctions_.push(this.createEventsLinkIfNeeded_(
- 'All connected events',
- 'Add all events connected to the selected one(s) by flow arrows or ' +
- 'by call stack.',
- eventSet,
- function(event, events) {
- this.addInFlowEvents_(event, events);
- this.addOutFlowEvents_(event, events);
- this.addAncestors_(event, events);
- this.addDescendents_(event, events);
- if (event.startSlice)
- events.push(event.startSlice);
- if (event.endSlice)
- events.push(event.endSlice);
- }.bind(this)));
- },
+ createEventsLinkIfNeeded_: function(title, tooltip, events, connectedFn) {
+ events = new tr.model.EventSet(events);
+ var eventsToProcess = new Set(events);
+ // for (var event of events)
+ // eventsToProcess.add(event);
+ var wasChanged = false;
+ var task;
+ var isCanceled = false;
+ function addEventsUntilTimeout() {
+ if (isCanceled)
+ return;
+ // Let's grant ourselves a budget of 8 ms. If time runs out, then
+ // create another task to do the rest.
+ var timeout = window.performance.now() + 8;
+ // TODO(alexandermont): Don't check window.performance.now
+ // every iteration.
+ while (eventsToProcess.size > 0 &&
+ window.performance.now() <= timeout) {
+ // Get the next event.
+ var nextEvent = tr.b.getFirstElement(eventsToProcess);
+ eventsToProcess.delete(nextEvent);
- createEventsLinkIfNeeded_: function(title, tooltip, events, addFunction) {
- events = new tr.model.EventSet(events);
- var lengthBefore = events.length;
- var task;
- var isCanceled = false;
- function addEventsUntilTimeout(startingIndex) {
- if (isCanceled)
- return;
- var startingTime = window.performance.now();
- while (startingIndex < events.length) {
- addFunction(events[startingIndex], events);
- startingIndex++;
- // Let's grant ourselves a budget of 8ms.
- if (window.performance.now() - startingTime > 8) {
- var newTask = new tr.b.Task(
- addEventsUntilTimeout.bind(this, startingIndex), this);
- task.after(newTask);
- task = newTask;
- return;
+ // Add the connected events to the list.
+ for (var eventToAdd of connectedFn(nextEvent)) {
+ if (!events.contains(eventToAdd)) {
+ events.push(eventToAdd);
+ eventsToProcess.add(eventToAdd);
+ wasChanged = true;
}
}
- // Went through all events, add the link.
- if (lengthBefore === events.length)
+ }
+ if (eventsToProcess.size > 0) {
+ // There are still events to process, but we ran out of time. Post
+ // more work for later.
+ var newTask = new tr.b.Task(
+ addEventsUntilTimeout.bind(this), this);
+ task.after(newTask);
+ task = newTask;
return;
- this.eventGroups_.push({
- type: title,
- tooltip: tooltip,
- selection: events
- });
- this.updateContents_();
- };
- function cancelTask() {
- isCanceled = true;
}
- task = new tr.b.Task(addEventsUntilTimeout.bind(this, 0), this);
- tr.b.Task.RunWhenIdle(task);
- return cancelTask;
- },
-
- addInFlowEvents_: function(event, eventSet) {
- if (!event.inFlowEvents)
+ // Went through all events, add the link.
+ if (!wasChanged)
return;
- event.inFlowEvents.forEach(function(e) {
- eventSet.push(e);
+ this.eventGroups_.push({
+ type: title,
+ tooltip: tooltip,
+ selection: events
});
- },
+ this.updateContents_();
+ }
+ function cancelTask() {
+ isCanceled = true;
+ }
+ task = new tr.b.Task(addEventsUntilTimeout.bind(this), this);
+ tr.b.Task.RunWhenIdle(task);
+ return cancelTask;
+ },
- addOutFlowEvents_: function(event, eventSet) {
- if (!event.outFlowEvents)
- return;
- event.outFlowEvents.forEach(function(e) {
- eventSet.push(e);
+ addOverlappingSamples_: function(eventSet) {
+ var samples = new tr.model.EventSet;
+ for (var slice of eventSet) {
+ if (!slice.parentContainer || !slice.parentContainer.samples)
+ continue;
+ var candidates = slice.parentContainer.samples;
+ var range = tr.b.Range.fromExplicitRange(
+ slice.start, slice.start + slice.duration);
+ var filteredSamples = range.filterArray(
+ candidates, function(value) {return value.start;});
+ for (var sample of filteredSamples)
+ samples.push(sample);
+ }
+ if (samples.length > 0) {
+ this.eventGroups_.push({
+ type: 'Overlapping samples',
+ tooltip: 'All samples overlapping the selected slice(s).',
+ selection: samples
});
- },
+ }
+ },
- addAncestors_: function(event, eventSet) {
- if (!event.iterateAllAncestors)
- return;
- event.iterateAllAncestors(function(e) {
- eventSet.push(e);
+ addV8Slices_: function(eventSet) {
+ var v8Slices = new tr.model.EventSet;
+ for (var slice of eventSet) {
+ if (slice.category === 'v8')
+ v8Slices.push(slice);
+ }
+ if (v8Slices.length > 0) {
+ this.eventGroups_.push({
+ type: 'V8 Slices',
+ tooltip: 'All V8 slices in the selected slice(s).',
+ selection: v8Slices
});
- },
+ }
+ },
- addDescendents_: function(event, eventSet) {
- if (!event.iterateAllDescendents)
- return;
- event.iterateAllDescendents(function(e) {
- eventSet.push(e);
+ addRuntimeCallStats_: function(eventSet) {
+ var slices = new tr.model.EventSet;
+ for (var slice of eventSet) {
+ if (slice.category === 'v8' && slice.runtimeCallStats)
+ slices.push(slice);
+ }
+ if (slices.length > 0) {
+ this.eventGroups_.push({
+ type: 'Runtime call stats table',
+ // eslint-disable-next-line
+ tooltip: 'All V8 slices containing runtime call stats table in the selected slice(s).',
+ selection: slices
});
- },
-
- addOverlappingSamples_: function(eventSet) {
- var samples = new tr.model.EventSet;
- eventSet.forEach(function(slice) {
- if (!slice.parentContainer || !slice.parentContainer.samples)
- return;
- var candidates = slice.parentContainer.samples;
- var range = tr.b.Range.fromExplicitRange(
- slice.start, slice.start + slice.duration);
- var filteredSamples = range.filterArray(
- candidates, function(value) {return value.start;});
- filteredSamples.forEach(function(sample) {
- samples.push(sample);
- });
- }.bind(this));
- if (samples.length > 0) {
- this.eventGroups_.push({
- type: 'Overlapping samples',
- tooltip: 'All samples overlapping the selected slice(s).',
- selection: samples
- });
- }
- },
+ }
+ },
- updateContents_: function() {
- var table = this.$.table;
- if (this.eventGroups_ === undefined)
- table.tableRows = [];
- else
- table.tableRows = this.eventGroups_.slice();
- table.rebuild();
+ addV8GCObjectStats_: function(eventSet) {
+ var slices = new tr.model.EventSet;
+ for (var slice of eventSet) {
+ if (slice.title === 'V8.GC_Objects_Stats')
+ slices.push(slice);
}
- });
- </script>
-</polymer-element>
+ if (slices.length > 0) {
+ this.eventGroups_.push({
+ type: 'V8 GC stats table',
+ tooltip: 'All V8 GC statistics slices in the selected set.',
+ selection: slices
+ });
+ }
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+ if (this.eventGroups_ === undefined)
+ table.tableRows = [];
+ else
+ table.tableRows = this.eventGroups_.slice();
+ table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html
index cc3c00e410c..f4f2b62af06 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html
@@ -6,11 +6,11 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/base.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name='tr-ui-a-selection-summary-table'>
+<dom-module id='tr-ui-a-selection-summary-table'>
<template>
<style>
:host {
@@ -19,76 +19,78 @@ found in the LICENSE file.
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table">
</tr-ui-b-table>
</div>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.selection_ = new tr.b.Range();
- },
+Polymer({
+ is: 'tr-ui-a-selection-summary-table',
+ created: function() {
+ this.selection_ = new tr.b.Range();
+ },
- ready: function() {
- this.$.table.showHeader = false;
- this.$.table.tableColumns = [
- {
- title: 'Name',
- value: function(row) { return row.title; },
- width: '350px'
- },
- {
- title: 'Value',
- width: '100%',
- value: function(row) {
- return row.value;
- }
+ ready: function() {
+ this.$.table.showHeader = false;
+ this.$.table.tableColumns = [
+ {
+ title: 'Name',
+ value: function(row) { return row.title; },
+ width: '350px'
+ },
+ {
+ title: 'Value',
+ width: '100%',
+ value: function(row) {
+ return row.value;
}
- ];
- },
+ }
+ ];
+ },
- get selection() {
- return this.selection_;
- },
+ get selection() {
+ return this.selection_;
+ },
- set selection(selection) {
- this.selection_ = selection;
- this.updateContents_();
- },
+ set selection(selection) {
+ this.selection_ = selection;
+ this.updateContents_();
+ },
- updateContents_: function() {
- var selection = this.selection_;
- var rows = [];
- var hasRange;
- if (this.selection_ && (!selection.bounds.isEmpty))
- hasRange = true;
- else
- hasRange = false;
+ updateContents_: function() {
+ var selection = this.selection_;
+ var rows = [];
+ var hasRange;
+ if (this.selection_ && (!selection.bounds.isEmpty))
+ hasRange = true;
+ else
+ hasRange = false;
- rows.push({
- title: 'Selection start',
- value: hasRange ? tr.v.ui.createScalarSpan(
- selection.bounds.min, {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: this.ownerDocument
- }) : '<empty>'
- });
- rows.push({
- title: 'Selection extent',
- value: hasRange ? tr.v.ui.createScalarSpan(
- selection.bounds.range, {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: this.ownerDocument
- }) : '<empty>'
- });
+ rows.push({
+ title: 'Selection start',
+ value: hasRange ? tr.v.ui.createScalarSpan(
+ selection.bounds.min, {
+ unit: tr.b.Unit.byName.timeStampInMs,
+ ownerDocument: this.ownerDocument
+ }) : '<empty>'
+ });
+ rows.push({
+ title: 'Selection extent',
+ value: hasRange ? tr.v.ui.createScalarSpan(
+ selection.bounds.range, {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ ownerDocument: this.ownerDocument
+ }) : '<empty>'
+ });
- this.$.table.tableRows = rows;
- this.$.table.rebuild();
- }
- });
- </script>
-</polymer-element>
+ this.$.table.tableRows = rows;
+ this.$.table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
index 5c1f1691efd..d8332b5a17e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
@@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/ui/analysis/selection_summary_table.html">
<link rel="import" href="/tracing/ui/base/deep_utils.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -66,10 +66,10 @@ tr.b.unittest.testSuite(function() {
summaryTable, 'tr-ui-b-table');
assert.equal(tableEl.tableRows[0].value.value, 0);
assert.strictEqual(tableEl.tableRows[0].value.unit,
- tr.v.Unit.byName.timeStampInMs);
+ tr.b.Unit.byName.timeStampInMs);
assert.equal(tableEl.tableRows[1].value.value, 3);
assert.strictEqual(tableEl.tableRows[1].value.unit,
- tr.v.Unit.byName.timeDurationInMs);
+ tr.b.Unit.byName.timeDurationInMs);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html
deleted file mode 100644
index 89d8ade4c5b..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2015 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
-<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-
-<polymer-element name="tr-ui-a-single-alert-sub-view"
- extends="tr-ui-a-sub-view">
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- set selection(selection) {
- this.currentSelection_ = selection;
-
- this.textContent = '';
- var realView = document.createElement('tr-ui-a-single-event-sub-view');
- realView.addExtraRowsCallback = function(rows) {
- // Alert description.
- var alert = this.currentSelection_[0];
-
- var descriptionEl = tr.ui.b.createSpan({
- textContent: alert.info.description
- });
- rows.push({
- name: 'Description',
- value: descriptionEl
- });
-
- // Associated events...
- if (alert.associatedEvents.length) {
- var eventSubRows = [];
- alert.associatedEvents.forEach(function(event, i) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return event;
- }, event.userFriendlyName);
- eventSubRows.push({
- name: i,
- value: linkEl
- });
- });
-
- rows.push({
- name: 'Alerts', value: '',
- isExpanded: true, subRows: eventSubRows
- });
- }
- }.bind(this);
-
- this.appendChild(realView);
- realView.setSelectionWithoutErrorChecks(selection);
- }
- });
- </script>
-</polymer-element>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html
index 26a47706165..b2238040827 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html
@@ -10,8 +10,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/related_events.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-<polymer-element name="tr-ui-a-single-async-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-async-slice-sub-view'>
<template>
<style>
:host {
@@ -28,44 +27,53 @@ found in the LICENSE file.
<tr-ui-a-related-events id="relatedEvents"></tr-ui-a-related-events>
</div>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-single-async-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- get selection() {
- return this.$.content.selection;
- },
+ get selection() {
+ return this.$.content.selection;
+ },
- set selection(selection) {
- if (selection.length !== 1)
- throw new Error('Only supports single slices');
- this.$.content.setSelectionWithoutErrorChecks(selection);
- this.$.relatedEvents.setRelatedEvents(selection);
- if (this.$.relatedEvents.hasRelatedEvents()) {
- this.$.relatedEvents.style.display = '';
- } else {
- this.$.relatedEvents.style.display = 'none';
- }
- },
+ set selection(selection) {
+ if (selection.length !== 1)
+ throw new Error('Only supports single slices');
+ this.$.content.setSelectionWithoutErrorChecks(selection);
+ this.$.relatedEvents.setRelatedEvents(selection);
+ if (this.$.relatedEvents.hasRelatedEvents()) {
+ this.$.relatedEvents.style.display = '';
+ } else {
+ this.$.relatedEvents.style.display = 'none';
+ }
+ },
- getEventRows_: function(event) {
- // TODO(nduca): Figure out if there is a cleaner way to do this.
- var rows = this.__proto__.__proto__.getEventRows_(event);
+ getEventRows_: function(event) {
+ // TODO(nduca): Figure out if there is a cleaner way to do this.
+ var rows = this.__proto__.__proto__.getEventRows_(event);
- // Put the ID up top.
- rows.splice(0, 0, {
- name: 'ID',
- value: event.id
- });
- return rows;
- },
+ // Put the ID up top.
+ rows.splice(0, 0, {
+ name: 'ID',
+ value: event.id
+ });
+ return rows;
+ },
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
- }
- });
- </script>
-</polymer-element>
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
+ }
+});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-async-slice-sub-view',
+ tr.model.AsyncSlice,
+ {
+ multi: false,
+ title: 'Async Slice',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html
index 42081c5baf1..a4f98dd255f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html
@@ -6,15 +6,14 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-single-cpu-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-cpu-slice-sub-view'>
<template>
<style>
table {
@@ -79,61 +78,72 @@ found in the LICENSE file.
</tr>
</table>
</template>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-cpu-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ var cpuSlice = tr.b.getOnlyElement(selection);
+ if (!(cpuSlice instanceof tr.model.CpuSlice))
+ throw new Error('Only supports thread time slices');
+
+ this.currentSelection_ = selection;
+
+ var thread = cpuSlice.threadThatWasRunning;
+
+ var root = Polymer.dom(this.root);
+ if (thread) {
+ Polymer.dom(root.querySelector('#process-name')).textContent =
+ thread.parent.userFriendlyName;
+ Polymer.dom(root.querySelector('#thread-name')).textContent =
+ thread.userFriendlyName;
+ } else {
+ root.querySelector('#process-name').parentElement.style.display =
+ 'none';
+ Polymer.dom(root.querySelector('#thread-name')).textContent =
+ cpuSlice.title;
+ }
- <script>
- 'use strict';
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- var cpuSlice = tr.b.getOnlyElement(selection);
- if (!(cpuSlice instanceof tr.model.CpuSlice))
- throw new Error('Only supports thread time slices');
-
- this.currentSelection_ = selection;
-
- var thread = cpuSlice.threadThatWasRunning;
-
- var shadowRoot = this.shadowRoot;
- if (thread) {
- shadowRoot.querySelector('#process-name').textContent =
- thread.parent.userFriendlyName;
- shadowRoot.querySelector('#thread-name').textContent =
- thread.userFriendlyName;
- } else {
- shadowRoot.querySelector('#process-name').parentElement.style.display =
- 'none';
- shadowRoot.querySelector('#thread-name').textContent = cpuSlice.title;
- }
-
- shadowRoot.querySelector('#start').setValueAndUnit(
- cpuSlice.start, tr.v.Unit.byName.timeStampInMs);
- shadowRoot.querySelector('#duration').setValueAndUnit(
- cpuSlice.duration, tr.v.Unit.byName.timeDurationInMs);
-
- var runningThreadEl = shadowRoot.querySelector('#running-thread');
-
- var timeSlice = cpuSlice.getAssociatedTimeslice();
- if (!timeSlice) {
- runningThreadEl.parentElement.style.display = 'none';
- } else {
- var threadLink = document.createElement('tr-ui-a-analysis-link');
- threadLink.selection = new tr.model.EventSet(timeSlice);
- threadLink.textContent = 'Click to select';
- runningThreadEl.parentElement.style.display = '';
- runningThreadEl.textContent = '';
- runningThreadEl.appendChild(threadLink);
- }
-
- shadowRoot.querySelector('#args').object = cpuSlice.args;
-
+ root.querySelector('#start').setValueAndUnit(
+ cpuSlice.start, tr.b.Unit.byName.timeStampInMs);
+ root.querySelector('#duration').setValueAndUnit(
+ cpuSlice.duration, tr.b.Unit.byName.timeDurationInMs);
+
+ var runningThreadEl = root.querySelector('#running-thread');
+
+ var timeSlice = cpuSlice.getAssociatedTimeslice();
+ if (!timeSlice) {
+ runningThreadEl.parentElement.style.display = 'none';
+ } else {
+ var threadLink = document.createElement('tr-ui-a-analysis-link');
+ threadLink.selection = new tr.model.EventSet(timeSlice);
+ Polymer.dom(threadLink).textContent = 'Click to select';
+ runningThreadEl.parentElement.style.display = '';
+ Polymer.dom(runningThreadEl).textContent = '';
+ Polymer.dom(runningThreadEl).appendChild(threadLink);
}
- });
- </script>
-</polymer-element>
+
+ root.querySelector('#args').object = cpuSlice.args;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-cpu-slice-sub-view',
+ tr.model.CpuSlice,
+ {
+ multi: false,
+ title: 'CPU Slice',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
index ea75afe6dcf..e3170dccb51 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
@@ -56,7 +56,7 @@ tr.b.unittest.testSuite(function() {
new tr.model.EventSet(thread.timeSlices[0])));
didSelectionChangeHappen = true;
});
- view.shadowRoot.querySelector('tr-ui-a-analysis-link').click();
+ Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click();
assert.isTrue(didSelectionChangeHappen);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html
index 74a82c95348..55a5b0d1927 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html
@@ -7,6 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
@@ -14,10 +15,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-single-event-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-event-sub-view'>
<template>
<style>
:host {
@@ -27,200 +26,257 @@ found in the LICENSE file.
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table">
</tr-ui-b-table>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.currentSelection_ = undefined;
- this.$.table.tableColumns = [
- {
- title: 'Label',
- value: function(row) { return row.name; },
- width: '150px'
- },
- {
- title: 'Value',
- width: '100%',
- value: function(row) { return row.value; }
- }
- ];
- this.$.table.showHeader = false;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- if (selection.length !== 1)
- throw new Error('Only supports single slices');
- this.setSelectionWithoutErrorChecks(selection);
- },
-
- setSelectionWithoutErrorChecks: function(selection) {
- this.currentSelection_ = selection;
- this.updateContents_();
- },
-
- getEventRows_: function(event) {
- var rows = [];
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ properties: {
+ isFlow: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ ready: function() {
+ this.currentSelection_ = undefined;
+ this.$.table.tableColumns = [
+ {
+ title: 'Label',
+ value: function(row) { return row.name; },
+ width: '150px'
+ },
+ {
+ title: 'Value',
+ width: '100%',
+ value: function(row) { return row.value; }
+ }
+ ];
+ this.$.table.showHeader = false;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ if (selection.length !== 1)
+ throw new Error('Only supports single slices');
+ this.setSelectionWithoutErrorChecks(selection);
+ },
+
+ setSelectionWithoutErrorChecks: function(selection) {
+ this.currentSelection_ = selection;
+ this.updateContents_();
+ },
+
+ getFlowEventRows_: function(event) {
+ // TODO(nduca): Figure out if there is a cleaner way to do this.
+
+ var rows = this.getEventRowsHelper_(event);
+ // var rows = this.__proto__.__proto__.getEventRows_(event);
+
+ // Put the ID up top.
+ rows.splice(0, 0, {
+ name: 'ID',
+ value: event.id
+ });
+
+ function createLinkTo(slice) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(function() {
+ return new tr.model.EventSet(slice);
+ });
+ Polymer.dom(linkEl).textContent = slice.userFriendlyName;
+ return linkEl;
+ }
- if (event.error)
- rows.push({ name: 'Error', value: event.error });
+ rows.push({
+ name: 'From',
+ value: createLinkTo(event.startSlice)
+ });
+ rows.push({
+ name: 'To',
+ value: createLinkTo(event.endSlice)
+ });
+ return rows;
+ },
+
+ getEventRowsHelper_: function(event) {
+ var rows = [];
+
+ if (event.error)
+ rows.push({ name: 'Error', value: event.error });
+
+ if (event.title)
+ rows.push({ name: 'Title', value: event.title });
+
+ if (event.category)
+ rows.push({ name: 'Category', value: event.category });
+
+ if (event.model !== undefined) {
+ var ufc = event.model.getUserFriendlyCategoryFromEvent(event);
+ if (ufc !== undefined)
+ rows.push({ name: 'User Friendly Category', value: ufc });
+ }
- if (event.title)
- rows.push({ name: 'Title', value: event.title });
+ if (event.name)
+ rows.push({ name: 'Name', value: event.name });
- if (event.category)
- rows.push({ name: 'Category', value: event.category });
+ rows.push({
+ name: 'Start',
+ value: tr.v.ui.createScalarSpan(event.start, {
+ unit: tr.b.Unit.byName.timeStampInMs
+ })
+ });
- if (event.model !== undefined) {
- var ufc = event.model.getUserFriendlyCategoryFromEvent(event);
- if (ufc !== undefined)
- rows.push({ name: 'User Friendly Category', value: ufc });
- }
-
- if (event.name)
- rows.push({ name: 'Name', value: event.name });
+ if (event.duration) {
+ rows.push({
+ name: 'Wall Duration',
+ value: tr.v.ui.createScalarSpan(event.duration, {
+ unit: tr.b.Unit.byName.timeDurationInMs
+ })
+ });
+ }
+ if (event.cpuDuration) {
rows.push({
- name: 'Start',
- value: tr.v.ui.createScalarSpan(event.start, {
- unit: tr.v.Unit.byName.timeStampInMs
+ name: 'CPU Duration',
+ value: tr.v.ui.createScalarSpan(event.cpuDuration, {
+ unit: tr.b.Unit.byName.timeDurationInMs
})
});
+ }
- if (event.duration) {
+ if (event.subSlices !== undefined && event.subSlices.length !== 0) {
+ if (event.selfTime) {
rows.push({
- name: 'Wall Duration',
- value: tr.v.ui.createScalarSpan(event.duration, {
- unit: tr.v.Unit.byName.timeDurationInMs
+ name: 'Self Time',
+ value: tr.v.ui.createScalarSpan(event.selfTime, {
+ unit: tr.b.Unit.byName.timeDurationInMs
})
});
}
- if (event.cpuDuration) {
- rows.push({
- name: 'CPU Duration',
- value: tr.v.ui.createScalarSpan(event.cpuDuration, {
- unit: tr.v.Unit.byName.timeDurationInMs
- })
+ if (event.cpuSelfTime) {
+ var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, {
+ unit: tr.b.Unit.byName.timeDurationInMs
});
- }
-
- if (event.subSlices !== undefined && event.subSlices.length !== 0) {
- if (event.selfTime) {
- rows.push({
- name: 'Self Time',
- value: tr.v.ui.createScalarSpan(event.selfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs
- })
- });
- }
-
- if (event.cpuSelfTime) {
- var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, {
- unit: tr.v.Unit.byName.timeDurationInMs
- });
- if (event.cpuSelfTime > event.selfTime) {
- cpuSelfTimeEl.warning =
- ' Note that CPU Self Time is larger than Self Time. ' +
- 'This is a known limitation of this system, which occurs ' +
- 'due to several subslices, rounding issues, and imprecise ' +
- 'time at which we get cpu- and real-time.';
- }
- rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl });
+ if (event.cpuSelfTime > event.selfTime) {
+ cpuSelfTimeEl.warning =
+ ' Note that CPU Self Time is larger than Self Time. ' +
+ 'This is a known limitation of this system, which occurs ' +
+ 'due to several subslices, rounding issues, and imprecise ' +
+ 'time at which we get cpu- and real-time.';
}
+ rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl });
}
+ }
- if (event.durationInUserTime) {
- rows.push({
- name: 'Duration (U)',
- value: tr.v.ui.createScalarSpan(event.durationInUserTime, {
- unit: tr.v.Unit.byName.timeDurationInMs
- })
- });
- }
+ if (event.durationInUserTime) {
+ rows.push({
+ name: 'Duration (U)',
+ value: tr.v.ui.createScalarSpan(event.durationInUserTime, {
+ unit: tr.b.Unit.byName.timeDurationInMs
+ })
+ });
+ }
- function createStackFrameEl(sf) {
- var sfEl = document.createElement('tr-ui-a-stack-frame');
- sfEl.stackFrame = sf;
- return sfEl;
- }
- if (event.startStackFrame && event.endStackFrame) {
- if (event.startStackFrame === event.endStackFrame) {
- rows.push({name: 'Start+End Stack Trace',
- value: createStackFrameEl(event.startStackFrame)});
-
- } else {
- rows.push({ name: 'Start Stack Trace',
- value: createStackFrameEl(event.startStackFrame)});
- rows.push({ name: 'End Stack Trace',
- value: createStackFrameEl(event.endStackFrame)});
- }
- } else if (event.startStackFrame) {
- rows.push({ name: 'Start Stack Trace',
+ function createStackFrameEl(sf) {
+ var sfEl = document.createElement('tr-ui-a-stack-frame');
+ sfEl.stackFrame = sf;
+ return sfEl;
+ }
+ if (event.startStackFrame && event.endStackFrame) {
+ if (event.startStackFrame === event.endStackFrame) {
+ rows.push({name: 'Start+End Stack Trace',
value: createStackFrameEl(event.startStackFrame)});
- } else if (event.endStackFrame) {
+ } else {
+ rows.push({ name: 'Start Stack Trace',
+ value: createStackFrameEl(event.startStackFrame)});
rows.push({ name: 'End Stack Trace',
value: createStackFrameEl(event.endStackFrame)});
}
+ } else if (event.startStackFrame) {
+ rows.push({ name: 'Start Stack Trace',
+ value: createStackFrameEl(event.startStackFrame)});
- if (event.info) {
- var descriptionEl = tr.ui.b.createDiv({
- textContent: event.info.description,
- maxWidth: '300px'
- });
- rows.push({
- name: 'Description',
- value: descriptionEl
- });
+ } else if (event.endStackFrame) {
+ rows.push({ name: 'End Stack Trace',
+ value: createStackFrameEl(event.endStackFrame)});
+ }
+ if (event.info) {
+ var descriptionEl = tr.ui.b.createDiv({
+ textContent: event.info.description,
+ maxWidth: '300px'
+ });
+ rows.push({
+ name: 'Description',
+ value: descriptionEl
+ });
- if (event.info.docLinks) {
- event.info.docLinks.forEach(function(linkObject) {
- var linkEl = document.createElement('a');
- linkEl.target = '_blank';
- linkEl.href = linkObject.href;
- linkEl.textContent = linkObject.textContent;
- rows.push({
- name: linkObject.label,
- value: linkEl
- });
- });
- }
- }
- if (event.associatedAlerts.length) {
- var alertSubRows = [];
- event.associatedAlerts.forEach(function(alert) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return new tr.model.EventSet(alert);
- }, alert.info.description);
- alertSubRows.push({
- name: alert.title,
+ if (event.info.docLinks) {
+ event.info.docLinks.forEach(function(linkObject) {
+ var linkEl = document.createElement('a');
+ linkEl.target = '_blank';
+ linkEl.href = linkObject.href;
+ Polymer.dom(linkEl).textContent = Polymer.dom(linkObject).textContent;
+ rows.push({
+ name: linkObject.label,
value: linkEl
});
});
+ }
+ }
- rows.push({
- name: 'Alerts', value: '',
- isExpanded: true, subRows: alertSubRows
+ if (event.associatedAlerts.length) {
+ var alertSubRows = [];
+ event.associatedAlerts.forEach(function(alert) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(function() {
+ return new tr.model.EventSet(alert);
+ }, alert.info.description);
+ alertSubRows.push({
+ name: alert.title,
+ value: linkEl
});
- }
- return rows;
- },
+ });
+
+ rows.push({
+ name: 'Alerts', value: '',
+ isExpanded: true, subRows: alertSubRows
+ });
+ }
+ return rows;
+ },
+
+ getEventRows_: function(event) {
+
+ if (this.isFlow)
+ return this.getFlowEventRows_(event);
- addArgsToRows_: function(rows, args) {
- var n = 0;
+ return this.getEventRowsHelper_(event);
+ },
+
+ addArgsToRows_: function(rows, args) {
+ var n = 0;
+ for (var argName in args) {
+ n += 1;
+ }
+ if (n > 0) {
+ var subRows = [];
for (var argName in args) {
n += 1;
}
@@ -239,48 +295,48 @@ found in the LICENSE file.
subRows: subRows
});
}
- },
-
- addContextsToRows_: function(rows, contexts) {
- if (contexts.length) {
- var subRows = contexts.map(function(context) {
- var contextView =
- document.createElement('tr-ui-a-generic-object-view');
- contextView.object = context;
- return {name: 'Context', value: contextView};
- });
- rows.push({
- name: 'Contexts',
- value: '',
- isExpanded: true,
- subRows: subRows
- });
- }
- },
+ }
+ },
+
+ addContextsToRows_: function(rows, contexts) {
+ if (contexts.length) {
+ var subRows = contexts.map(function(context) {
+ var contextView =
+ document.createElement('tr-ui-a-generic-object-view');
+ contextView.object = context;
+ return {name: 'Context', value: contextView};
+ });
+ rows.push({
+ name: 'Contexts',
+ value: '',
+ isExpanded: true,
+ subRows: subRows
+ });
+ }
+ },
- updateContents_: function() {
- if (this.currentSelection_ === undefined) {
- this.$.table.rows = [];
- this.$.table.rebuild();
- return;
- }
+ updateContents_: function() {
+ if (this.currentSelection_ === undefined) {
+ this.$.table.rows = [];
+ this.$.table.rebuild();
+ return;
+ }
- var event = tr.b.getOnlyElement(this.currentSelection_);
+ var event = tr.b.getOnlyElement(this.currentSelection_);
- var rows = this.getEventRows_(event);
- if (event.argsStripped)
- rows.push({ name: 'Args', value: 'Stripped' });
- else
- this.addArgsToRows_(rows, event.args);
- this.addContextsToRows_(rows, event.contexts);
+ var rows = this.getEventRows_(event);
+ if (event.argsStripped)
+ rows.push({ name: 'Args', value: 'Stripped' });
+ else
+ this.addArgsToRows_(rows, event.args);
+ this.addContextsToRows_(rows, event.contexts);
- var event = new tr.b.Event('customize-rows');
- event.rows = rows;
- this.dispatchEvent(event);
+ var customizeRowsEvent = new tr.b.Event('customize-rows');
+ customizeRowsEvent.rows = rows;
+ this.dispatchEvent(customizeRowsEvent);
- this.$.table.tableRows = rows;
- this.$.table.rebuild();
- }
- });
- </script>
-</polymer-element>
+ this.$.table.tableRows = rows;
+ this.$.table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
index b52ebaa16bc..0a3d481a2d7 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
@@ -58,7 +58,7 @@ tr.b.unittest.testSuite(function() {
t53.sliceGroup.pushSlice(slice);
});
- };
+ }
test('instantiate_withSingleSlice', function() {
var selection = createSelectionWithSingleSlice();
@@ -125,7 +125,7 @@ tr.b.unittest.testSuite(function() {
var e = tr.b.findDeepElementWithTextContent(
analysisEl, /Start Stack Trace/);
assert.isDefined(e);
- assert.isDefined(e.nextSibling.children[0].stackFrame);
+ assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame);
});
test('instantiate_withSingleEndStackFrame', function() {
@@ -139,8 +139,8 @@ tr.b.unittest.testSuite(function() {
var e = tr.b.findDeepElementWithTextContent(
analysisEl, /End Stack Trace/);
assert.isDefined(e);
- assert.isDefined(e.nextSibling.children[0].stackFrame);
- assert.equal(e.nextSibling.children[0].stackFrame.title, 'b2');
+ assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame);
+ assert.equal(Polymer.dom(e).nextSibling.children[0].stackFrame.title, 'b2');
});
test('instantiate_withDifferentStartAndEndStackFrames', function() {
@@ -155,14 +155,16 @@ tr.b.unittest.testSuite(function() {
var eA = tr.b.findDeepElementWithTextContent(
analysisEl, /Start Stack Trace/);
assert.isDefined(eA);
- assert.isDefined(eA.nextSibling.children[0].stackFrame);
- assert.equal(eA.nextSibling.children[0].stackFrame.title, 'a2');
+ assert.isDefined(Polymer.dom(eA).nextSibling.children[0].stackFrame);
+ assert.equal(
+ Polymer.dom(eA).nextSibling.children[0].stackFrame.title, 'a2');
var eB = tr.b.findDeepElementWithTextContent(
analysisEl, /End Stack Trace/);
assert.isDefined(eB);
- assert.isDefined(eB.nextSibling.children[0].stackFrame);
- assert.equal(eB.nextSibling.children[0].stackFrame.title, 'b2');
+ assert.isDefined(Polymer.dom(eB).nextSibling.children[0].stackFrame);
+ assert.equal(
+ Polymer.dom(eB).nextSibling.children[0].stackFrame.title, 'b2');
});
test('instantiate_withSameStartAndEndStackFrames', function() {
@@ -177,8 +179,8 @@ tr.b.unittest.testSuite(function() {
var e = tr.b.findDeepElementWithTextContent(
analysisEl, /Start\+End Stack Trace/);
assert.isDefined(e);
- assert.isDefined(e.nextSibling.children[0].stackFrame);
- assert.equal(e.nextSibling.children[0].stackFrame.title, 'a2');
+ assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame);
+ assert.equal(Polymer.dom(e).nextSibling.children[0].stackFrame.title, 'a2');
});
test('analyzeSelectionWithSingleSlice', function() {
@@ -193,10 +195,10 @@ tr.b.unittest.testSuite(function() {
assert.equal(table.tableRows[0].value, 'b');
assert.equal(table.tableRows[1].value.value, 0);
assert.strictEqual(table.tableRows[1].value.unit,
- tr.v.Unit.byName.timeStampInMs);
+ tr.b.Unit.byName.timeStampInMs);
assert.equal(table.tableRows[2].value.value, 0.002);
assert.strictEqual(table.tableRows[2].value.unit,
- tr.v.Unit.byName.timeDurationInMs);
+ tr.b.Unit.byName.timeDurationInMs);
});
test('analyzeSelectionWithSingleSliceCategory', function() {
@@ -213,10 +215,10 @@ tr.b.unittest.testSuite(function() {
assert.equal(table.tableRows[1].value, 'foo');
assert.equal(table.tableRows[2].value.value, 0);
assert.strictEqual(table.tableRows[2].value.unit,
- tr.v.Unit.byName.timeStampInMs);
+ tr.b.Unit.byName.timeStampInMs);
assert.equal(table.tableRows[3].value.value, 0.002);
assert.strictEqual(table.tableRows[3].value.unit,
- tr.v.Unit.byName.timeDurationInMs);
+ tr.b.Unit.byName.timeDurationInMs);
});
test('instantiate_withSingleSliceContainingIDRef', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html
index 899f9f2096e..ae6497b7c69 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html
@@ -5,46 +5,78 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/model/event_set.html">
-<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
+<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-<polymer-element name="tr-ui-a-single-flow-event-sub-view"
- extends="tr-ui-a-single-event-sub-view">
- <script>
- 'use strict';
-
- Polymer({
- getEventRows_: function(event) {
- // TODO(nduca): Figure out if there is a cleaner way to do this.
- var rows = this.__proto__.__proto__.getEventRows_(event);
-
- // Put the ID up top.
- rows.splice(0, 0, {
- name: 'ID',
- value: event.id
- });
-
- function createLinkTo(slice) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(function() {
- return new tr.model.EventSet(slice);
- });
- linkEl.textContent = slice.userFriendlyName;
- return linkEl;
- }
-
- rows.push({
- name: 'From',
- value: createLinkTo(event.startSlice)
- });
- rows.push({
- name: 'To',
- value: createLinkTo(event.endSlice)
- });
- return rows;
+<dom-module id="tr-ui-a-single-flow-event-sub-view">
+ <template>
+ <style>
+ :host {
+ display: block;
}
- });
- </script>
-</polymer-element>
+ </style>
+ <tr-ui-a-single-event-sub-view id="singleEventSubView">
+ </tr-ui-a-single-event-sub-view>
+ </template>
+</dom-module>
+<script>
+'use strict';
+
+function createAnalysisLinkTo(event) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(
+ new tr.model.EventSet(event), event.userFriendlyName);
+ return linkEl;
+}
+
+Polymer({
+ is: 'tr-ui-a-single-flow-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ listeners: {
+ 'singleEventSubView.customize-rows': 'onCustomizeRows_'
+ },
+
+ set selection(selection) {
+ this.currentSelection_ = selection;
+ this.$.singleEventSubView.setSelectionWithoutErrorChecks(selection);
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ /**
+ * Event handler for an event that's fired after the single event sub view has
+ * finished row construction. This hook gives us the opportunity to customize
+ * the rows present in the sub view.
+ */
+ onCustomizeRows_: function(e) {
+ var event = tr.b.getOnlyElement(this.currentSelection_);
+ var rows = e.rows;
+
+ rows.unshift({
+ name: 'ID',
+ value: event.id
+ });
+ rows.push({
+ name: 'From',
+ value: createAnalysisLinkTo(event.startSlice)
+ });
+ rows.push({
+ name: 'To',
+ value: createAnalysisLinkTo(event.endSlice)
+ });
+ }
+});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-flow-event-sub-view',
+ tr.model.FlowEvent,
+ {
+ multi: false,
+ title: 'Flow Event',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
index bbd348a1b20..b4125fae2ac 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
@@ -44,7 +44,8 @@ tr.b.unittest.testSuite(function() {
selection.push(model.fe);
assert.equal(selection.length, 1);
- var subView = document.createElement('tr-ui-a-single-flow-event-sub-view');
+ var subView = document.createElement('tr-ui-a-single-event-sub-view');
+ subView.isFlow = true;
subView.selection = selection;
this.addHTMLOutput(subView);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html
index f58168d1c87..8edcaa5203a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html
@@ -9,8 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/alert_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
-<polymer-element name="tr-ui-a-single-frame-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-frame-sub-view'>
<template>
<style>
:host {
@@ -25,28 +24,39 @@ found in the LICENSE file.
<tr-ui-a-alert-sub-view id="asv">
</tr-ui-a-alert-sub-view>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.currentSelection_ = undefined;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- this.currentSelection_ = selection;
- this.$.asv.selection = tr.b.getOnlyElement(selection).associatedAlerts;
- },
-
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
- }
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-frame-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ ready: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ this.currentSelection_ = selection;
+ this.$.asv.selection = tr.b.getOnlyElement(selection).associatedAlerts;
+ },
+
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-frame-sub-view',
+ tr.model.Frame,
+ {
+ multi: false,
+ title: 'Frame',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html
index c8ab4aa7389..84972063550 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-<polymer-element name="tr-ui-a-single-instant-event-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-instant-event-sub-view'>
<template>
<style>
:host {
@@ -18,28 +17,47 @@ found in the LICENSE file.
</style>
<div id='content'></div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- set selection(selection) {
- this.$.content.textContent = '';
- var realView = document.createElement('tr-ui-a-single-event-sub-view');
- realView.setSelectionWithoutErrorChecks(selection);
-
- this.$.content.appendChild(realView);
-
- this.currentSelection_ = selection;
- },
-
- get selection() {
- return this.currentSelection_;
- }
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-instant-event-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ set selection(selection) {
+ Polymer.dom(this.$.content).textContent = '';
+ var realView = document.createElement('tr-ui-a-single-event-sub-view');
+ realView.setSelectionWithoutErrorChecks(selection);
+
+ Polymer.dom(this.$.content).appendChild(realView);
+
+ this.currentSelection_ = selection;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-instant-event-sub-view',
+ tr.model.InstantEvent,
+ {
+ multi: false,
+ title: 'Instant Event',
+ });
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-multi-instant-event-sub-view',
+ tr.model.InstantEvent,
+ {
+ multi: true,
+ title: 'Instant Events',
+ });
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html
index ca5cd4a730d..c450bbcc9e9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html
@@ -13,8 +13,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/object_instance_view.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-<polymer-element name="tr-ui-a-single-object-instance-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-object-instance-sub-view'>
<template>
<style>
:host {
@@ -47,70 +46,81 @@ found in the LICENSE file.
</style>
<div id='content'></div>
</template>
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- get requiresTallView() {
- if (this.$.content.children.length === 0)
- return false;
- if (this.$.content.children[0] instanceof
- tr.ui.analysis.ObjectInstanceView)
- return this.$.content.children[0].requiresTallView;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- var instance = tr.b.getOnlyElement(selection);
- if (!(instance instanceof tr.model.ObjectInstance))
- throw new Error('Only supports object instances');
-
- this.$.content.textContent = '';
- this.currentSelection_ = selection;
-
- var typeInfo = tr.ui.analysis.ObjectInstanceView.getTypeInfo(
- instance.category, instance.typeName);
- if (typeInfo) {
- var customView = new typeInfo.constructor();
- this.$.content.appendChild(customView);
- customView.modelEvent = instance;
- } else {
- this.appendGenericAnalysis_(instance);
- }
- },
-
- appendGenericAnalysis_: function(instance) {
- var html = '';
- html += '<div class="title">' +
- instance.typeName + ' ' +
- instance.id + '</div>\n';
- html += '<table>';
- html += '<tr>';
- html += '<tr><td>creationTs:</td><td>' +
- instance.creationTs + '</td></tr>\n';
- if (instance.deletionTs != Number.MAX_VALUE) {
- html += '<tr><td>deletionTs:</td><td>' +
- instance.deletionTs + '</td></tr>\n';
- } else {
- html += '<tr><td>deletionTs:</td><td>not deleted</td></tr>\n';
- }
- html += '<tr><td>snapshots:</td><td id="snapshots"></td></tr>\n';
- html += '</table>';
- this.$.content.innerHTML = html;
- var snapshotsEl = this.$.content.querySelector('#snapshots');
- instance.snapshots.forEach(function(snapshot) {
- var snapshotLink = document.createElement('tr-ui-a-analysis-link');
- snapshotLink.selection = new tr.model.EventSet(snapshot);
- snapshotsEl.appendChild(snapshotLink);
- });
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-object-instance-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get requiresTallView() {
+ if (this.$.content.children.length === 0)
+ return false;
+ if (this.$.content.children[0] instanceof
+ tr.ui.analysis.ObjectInstanceView)
+ return this.$.content.children[0].requiresTallView;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ var instance = tr.b.getOnlyElement(selection);
+ if (!(instance instanceof tr.model.ObjectInstance))
+ throw new Error('Only supports object instances');
+
+ Polymer.dom(this.$.content).textContent = '';
+ this.currentSelection_ = selection;
+
+ var typeInfo = tr.ui.analysis.ObjectInstanceView.getTypeInfo(
+ instance.category, instance.typeName);
+ if (typeInfo) {
+ var customView = new typeInfo.constructor();
+ Polymer.dom(this.$.content).appendChild(customView);
+ customView.modelEvent = instance;
+ } else {
+ this.appendGenericAnalysis_(instance);
}
- });
- </script>
-</polymer-element>
+ },
+
+ appendGenericAnalysis_: function(instance) {
+ var html = '';
+ html += '<div class="title">' +
+ instance.typeName + ' ' +
+ instance.id + '</div>\n';
+ html += '<table>';
+ html += '<tr>';
+ html += '<tr><td>creationTs:</td><td>' +
+ instance.creationTs + '</td></tr>\n';
+ if (instance.deletionTs !== Number.MAX_VALUE) {
+ html += '<tr><td>deletionTs:</td><td>' +
+ instance.deletionTs + '</td></tr>\n';
+ } else {
+ html += '<tr><td>deletionTs:</td><td>not deleted</td></tr>\n';
+ }
+ html += '<tr><td>snapshots:</td><td id="snapshots"></td></tr>\n';
+ html += '</table>';
+ Polymer.dom(this.$.content).innerHTML = html;
+ var snapshotsEl = Polymer.dom(this.$.content).querySelector('#snapshots');
+ instance.snapshots.forEach(function(snapshot) {
+ var snapshotLink = document.createElement('tr-ui-a-analysis-link');
+ snapshotLink.selection = new tr.model.EventSet(snapshot);
+ Polymer.dom(snapshotsEl).appendChild(snapshotLink);
+ });
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-object-instance-sub-view',
+ tr.model.ObjectInstance,
+ {
+ multi: false,
+ title: 'Object Instance',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html
index d156203b904..e3b39130326 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
@@ -14,10 +15,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-single-object-snapshot-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-object-snapshot-sub-view'>
<template>
<style>
#args {
@@ -46,83 +45,94 @@ found in the LICENSE file.
</style>
<content></content>
</template>
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- get requiresTallView() {
- if (this.children.length === 0)
- return false;
- if (this.children[0] instanceof tr.ui.analysis.ObjectSnapshotView)
- return this.children[0].requiresTallView;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- var snapshot = tr.b.getOnlyElement(selection);
- if (!(snapshot instanceof tr.model.ObjectSnapshot))
- throw new Error('Only supports object instances');
-
- this.textContent = '';
- this.currentSelection_ = selection;
-
- var typeInfo = tr.ui.analysis.ObjectSnapshotView.getTypeInfo(
- snapshot.objectInstance.category, snapshot.objectInstance.typeName);
- if (typeInfo) {
- var customView = new typeInfo.constructor();
- this.appendChild(customView);
- customView.modelEvent = snapshot;
- } else {
- this.appendGenericAnalysis_(snapshot);
- }
- },
-
- appendGenericAnalysis_: function(snapshot) {
- var instance = snapshot.objectInstance;
-
- this.textContent = '';
-
- var titleEl = document.createElement('div');
- titleEl.classList.add('title');
- titleEl.appendChild(document.createTextNode('Snapshot of '));
- this.appendChild(titleEl);
-
- var instanceLinkEl = document.createElement('tr-ui-a-analysis-link');
- instanceLinkEl.selection = new tr.model.EventSet(instance);
- titleEl.appendChild(instanceLinkEl);
-
- titleEl.appendChild(document.createTextNode(' @ '));
-
- titleEl.appendChild(tr.v.ui.createScalarSpan(snapshot.ts, {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: this.ownerDocument
- }));
-
- var tableEl = document.createElement('table');
- this.appendChild(tableEl);
-
- var rowEl = document.createElement('tr');
- tableEl.appendChild(rowEl);
-
- var labelEl = document.createElement('td');
- labelEl.textContent = 'args:';
- rowEl.appendChild(labelEl);
-
- var argsEl = document.createElement('td');
- argsEl.id = 'args';
- rowEl.appendChild(argsEl);
-
- var objectViewEl = document.createElement('tr-ui-a-generic-object-view');
- objectViewEl.object = snapshot.args;
- argsEl.appendChild(objectViewEl);
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-object-snapshot-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get requiresTallView() {
+ if (this.children.length === 0)
+ return false;
+ if (this.children[0] instanceof tr.ui.analysis.ObjectSnapshotView)
+ return this.children[0].requiresTallView;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ var snapshot = tr.b.getOnlyElement(selection);
+ if (!(snapshot instanceof tr.model.ObjectSnapshot))
+ throw new Error('Only supports object instances');
+
+ Polymer.dom(this).textContent = '';
+ this.currentSelection_ = selection;
+
+ var typeInfo = tr.ui.analysis.ObjectSnapshotView.getTypeInfo(
+ snapshot.objectInstance.category, snapshot.objectInstance.typeName);
+ if (typeInfo) {
+ var customView = new typeInfo.constructor();
+ Polymer.dom(this).appendChild(customView);
+ customView.modelEvent = snapshot;
+ } else {
+ this.appendGenericAnalysis_(snapshot);
}
- });
- </script>
-</polymer-element>
+ },
+
+ appendGenericAnalysis_: function(snapshot) {
+ var instance = snapshot.objectInstance;
+
+ Polymer.dom(this).textContent = '';
+
+ var titleEl = document.createElement('div');
+ Polymer.dom(titleEl).classList.add('title');
+ Polymer.dom(titleEl).appendChild(document.createTextNode('Snapshot of '));
+ Polymer.dom(this).appendChild(titleEl);
+
+ var instanceLinkEl = document.createElement('tr-ui-a-analysis-link');
+ instanceLinkEl.selection = new tr.model.EventSet(instance);
+ Polymer.dom(titleEl).appendChild(instanceLinkEl);
+
+ Polymer.dom(titleEl).appendChild(document.createTextNode(' @ '));
+
+ Polymer.dom(titleEl).appendChild(tr.v.ui.createScalarSpan(snapshot.ts, {
+ unit: tr.b.Unit.byName.timeStampInMs,
+ ownerDocument: this.ownerDocument
+ }));
+
+ var tableEl = document.createElement('table');
+ Polymer.dom(this).appendChild(tableEl);
+
+ var rowEl = document.createElement('tr');
+ Polymer.dom(tableEl).appendChild(rowEl);
+
+ var labelEl = document.createElement('td');
+ Polymer.dom(labelEl).textContent = 'args:';
+ Polymer.dom(rowEl).appendChild(labelEl);
+
+ var argsEl = document.createElement('td');
+ argsEl.id = 'args';
+ Polymer.dom(rowEl).appendChild(argsEl);
+
+ var objectViewEl = document.createElement('tr-ui-a-generic-object-view');
+ objectViewEl.object = snapshot.args;
+ Polymer.dom(argsEl).appendChild(objectViewEl);
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-object-snapshot-sub-view',
+ tr.model.ObjectSnapshot,
+ {
+ multi: false,
+ title: 'Object Snapshot',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html
index 96043122244..9be2ec3fac3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html
@@ -5,27 +5,31 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-power-sample-table">
+<dom-module id='tr-ui-a-power-sample-table'>
<template>
<style>
:host {
display: flex;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
-Polymer('tr-ui-a-power-sample-table', {
+Polymer({
+ is: 'tr-ui-a-power-sample-table',
+
ready: function() {
this.$.table.tableColumns = [
{
@@ -33,7 +37,7 @@ Polymer('tr-ui-a-power-sample-table', {
width: '100px',
value: function(row) {
return tr.v.ui.createScalarSpan(row.start, {
- unit: tr.v.Unit.byName.timeStampInMs
+ unit: tr.b.Unit.byName.timeStampInMs
});
}
},
@@ -41,8 +45,8 @@ Polymer('tr-ui-a-power-sample-table', {
title: 'Power',
width: '100%',
value: function(row) {
- return tr.v.ui.createScalarSpan(row.power, {
- unit: tr.v.Unit.byName.powerInWatts
+ return tr.v.ui.createScalarSpan(row.powerInW, {
+ unit: tr.b.Unit.byName.powerInWatts
});
}
}
@@ -60,7 +64,7 @@ Polymer('tr-ui-a-power-sample-table', {
},
updateContents_: function() {
- if (this.sample == undefined)
+ if (this.sample === undefined)
this.$.table.tableRows = [];
else
this.$.table.tableRows = [this.sample];
@@ -69,8 +73,7 @@ Polymer('tr-ui-a-power-sample-table', {
});
</script>
-<polymer-element name="tr-ui-a-single-power-sample-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-power-sample-sub-view'>
<template>
<style>
:host { display: block; }
@@ -78,30 +81,40 @@ Polymer('tr-ui-a-power-sample-table', {
<tr-ui-a-power-sample-table id="samplesTable">
</tr-ui-a-power-sample-table>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-single-power-sample-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- ready: function() {
- this.currentSelection_ = undefined;
+ ready: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
- },
+ set selection(selection) {
+ this.currentSelection_ = selection;
+ this.updateContents_();
+ },
- get selection() {
- return this.currentSelection_;
- },
+ updateContents_: function() {
+ if (this.selection.length !== 1)
+ throw 'Cannot pass multiple samples to sample table.';
+ this.$.samplesTable.sample = tr.b.getOnlyElement(this.selection);
+ }
+});
- set selection(selection) {
- this.currentSelection_ = selection;
- this.updateContents_();
- },
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-power-sample-sub-view',
+ tr.model.PowerSample,
+ {
+ multi: false,
+ title: 'Power Sample',
+ });
- updateContents_: function() {
- if (this.selection.length != 1)
- throw 'Cannot pass multiple samples to sample table.';
- this.$.samplesTable.sample = this.selection[0];
- }
- });
- </script>
-</polymer-element>
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html
index 29f7b2e064a..bcd0919e460 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html
@@ -5,85 +5,95 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/stack_frame.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-single-sample-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-sample-sub-view'>
<template>
<style>
:host {
display: flex;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="content"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
+Polymer({
+ is: 'tr-ui-a-single-sample-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- ready: function() {
- this.$.content.tableColumns = [
- {
- title: 'FirstColumn',
- value: function(row) { return row.title; },
- width: '250px'
- },
- {
- title: 'SecondColumn',
- value: function(row) { return row.value; },
- width: '100%'
- }
- ];
- this.$.content.showHeader = false;
- },
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
- get selection() {
- return this.currentSelection_;
- },
+ ready: function() {
+ this.$.content.tableColumns = [
+ {
+ title: 'FirstColumn',
+ value: function(row) { return row.title; },
+ width: '250px'
+ },
+ {
+ title: 'SecondColumn',
+ value: function(row) { return row.value; },
+ width: '100%'
+ }
+ ];
+ this.$.content.showHeader = false;
+ },
- set selection(selection) {
- this.currentSelection_ = selection;
+ get selection() {
+ return this.currentSelection_;
+ },
- if (this.currentSelection_ === undefined) {
- this.$.content.tableRows = [];
- return;
- }
+ set selection(selection) {
+ this.currentSelection_ = selection;
- var sample = this.currentSelection_[0];
- var table = this.$.content;
+ if (this.currentSelection_ === undefined) {
+ this.$.content.tableRows = [];
+ return;
+ }
- var rows = [];
+ var sample = tr.b.getOnlyElement(this.currentSelection_);
+ var table = this.$.content;
+ var rows = [];
- rows.push({
- title: 'Title',
- value: sample.title
- });
+ rows.push({
+ title: 'Title',
+ value: sample.title
+ });
- rows.push({
- title: 'Sample time',
- value: tr.v.ui.createScalarSpan(sample.start, {
- unit: tr.v.Unit.byName.timeStampInMs,
- ownerDocument: this.ownerDocument
- })
- });
+ rows.push({
+ title: 'Sample time',
+ value: tr.v.ui.createScalarSpan(sample.start, {
+ unit: tr.b.Unit.byName.timeStampInMs,
+ ownerDocument: this.ownerDocument
+ })
+ });
- var sfEl = document.createElement('tr-ui-a-stack-frame');
- sfEl.stackFrame = sample.leafStackFrame;
- rows.push({
- title: 'Stack trace',
- value: sfEl
- });
- table.tableRows = rows;
- table.rebuild();
- }
- });
- </script>
-</polymer-element>
+ var sfEl = document.createElement('tr-ui-a-stack-frame');
+ sfEl.stackFrame = sample.leafStackFrame;
+ rows.push({
+ title: 'Stack trace',
+ value: sfEl
+ });
+ table.tableRows = rows;
+ table.rebuild();
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-sample-sub-view',
+ tr.model.Sample,
+ {
+ multi: false,
+ title: 'Sample',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
index d31abfaff08..802bc99aa34 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
@@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/ui/analysis/single_sample_sub_view.html">
<link rel="import" href="/tracing/ui/base/deep_utils.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
@@ -53,7 +53,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(rows[0].value, 'X');
assert.equal(rows[1].value.value, 0.184);
- assert.strictEqual(rows[1].value.unit, tr.v.Unit.byName.timeStampInMs);
+ assert.strictEqual(rows[1].value.unit, tr.b.Unit.byName.timeStampInMs);
assert.equal(rows[2].value.stackFrame, t53.samples[0].leafStackFrame);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html
index 2eeb8819785..d934bedd3b6 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html
@@ -6,11 +6,10 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
-<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/related_events.html">
+<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
-<polymer-element name="tr-ui-a-single-thread-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-thread-slice-sub-view'>
<template>
<style>
:host {
@@ -29,23 +28,33 @@ found in the LICENSE file.
</tr-ui-a-related-events>
</div>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-a-single-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- Polymer({
- get selection() {
- return this.$.content.selection;
- },
+ get selection() {
+ return this.$.content.selection;
+ },
- set selection(selection) {
- this.$.content.selection = selection;
- this.$.relatedEvents.setRelatedEvents(selection);
- if (this.$.relatedEvents.hasRelatedEvents())
- this.$.relatedEvents.style.display = '';
- else
- this.$.relatedEvents.style.display = 'none';
- }
- });
- </script>
-</polymer-element>
+ set selection(selection) {
+ this.$.content.selection = selection;
+ this.$.relatedEvents.setRelatedEvents(selection);
+ if (this.$.relatedEvents.hasRelatedEvents())
+ this.$.relatedEvents.style.display = '';
+ else
+ this.$.relatedEvents.style.display = 'none';
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-thread-slice-sub-view',
+ tr.model.ThreadSlice,
+ {
+ multi: false,
+ title: 'Slice',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html
index 8d82ca6ee04..11574b892bf 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html
@@ -8,6 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/color_scheme.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/model.html">
@@ -15,10 +16,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-a-single-thread-time-slice-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-thread-time-slice-sub-view'>
<template>
<style>
table {
@@ -89,86 +88,99 @@ found in the LICENSE file.
</tr>
</table>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
-
- get selection() {
- return this.currentSelection_;
- },
-
- set selection(selection) {
- var timeSlice = tr.b.getOnlyElement(selection);
-
- if (!(timeSlice instanceof tr.model.ThreadTimeSlice))
- throw new Error('Only supports thread time slices');
-
- this.currentSelection_ = selection;
-
- var thread = timeSlice.thread;
-
- var shadowRoot = this.shadowRoot;
- shadowRoot.querySelector('#state').textContent = timeSlice.title;
- var stateColor = tr.b.ColorScheme.colorsAsStrings[timeSlice.colorId];
- shadowRoot.querySelector('#state').style.backgroundColor = stateColor;
-
- shadowRoot.querySelector('#process-name').textContent =
- thread.parent.userFriendlyName;
- shadowRoot.querySelector('#thread-name').textContent =
- thread.userFriendlyName;
-
- shadowRoot.querySelector('#start').setValueAndUnit(
- timeSlice.start, tr.v.Unit.byName.timeStampInMs);
- shadowRoot.querySelector('#duration').setValueAndUnit(
- timeSlice.duration, tr.v.Unit.byName.timeDurationInMs);
-
- var onCpuEl = shadowRoot.querySelector('#on-cpu');
- onCpuEl.textContent = '';
- var runningInsteadEl = shadowRoot.querySelector('#running-instead');
- if (timeSlice.cpuOnWhichThreadWasRunning) {
- runningInsteadEl.parentElement.removeChild(runningInsteadEl);
-
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-single-thread-time-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
+
+ get selection() {
+ return this.currentSelection_;
+ },
+
+ set selection(selection) {
+ var timeSlice = tr.b.getOnlyElement(selection);
+
+ if (!(timeSlice instanceof tr.model.ThreadTimeSlice))
+ throw new Error('Only supports thread time slices');
+
+ this.currentSelection_ = selection;
+
+ var thread = timeSlice.thread;
+
+ var root = Polymer.dom(this.root);
+ Polymer.dom(root.querySelector('#state')).textContent =
+ timeSlice.title;
+ var stateColor = tr.b.ColorScheme.colorsAsStrings[timeSlice.colorId];
+ root.querySelector('#state').style.backgroundColor = stateColor;
+
+ Polymer.dom(root.querySelector('#process-name')).textContent =
+ thread.parent.userFriendlyName;
+ Polymer.dom(root.querySelector('#thread-name')).textContent =
+ thread.userFriendlyName;
+
+ root.querySelector('#start').setValueAndUnit(
+ timeSlice.start, tr.b.Unit.byName.timeStampInMs);
+ root.querySelector('#duration').setValueAndUnit(
+ timeSlice.duration, tr.b.Unit.byName.timeDurationInMs);
+
+ var onCpuEl = root.querySelector('#on-cpu');
+ Polymer.dom(onCpuEl).textContent = '';
+ var runningInsteadEl = root.querySelector('#running-instead');
+ if (timeSlice.cpuOnWhichThreadWasRunning) {
+ Polymer.dom(runningInsteadEl.parentElement).removeChild(runningInsteadEl);
+
+ var cpuLink = document.createElement('tr-ui-a-analysis-link');
+ cpuLink.selection = new tr.model.EventSet(
+ timeSlice.getAssociatedCpuSlice());
+ Polymer.dom(cpuLink).textContent =
+ timeSlice.cpuOnWhichThreadWasRunning.userFriendlyName;
+ Polymer.dom(onCpuEl).appendChild(cpuLink);
+ } else {
+ Polymer.dom(onCpuEl.parentElement).removeChild(onCpuEl);
+
+ var cpuSliceThatTookCpu = timeSlice.getCpuSliceThatTookCpu();
+ if (cpuSliceThatTookCpu) {
var cpuLink = document.createElement('tr-ui-a-analysis-link');
- cpuLink.selection = new tr.model.EventSet(
- timeSlice.getAssociatedCpuSlice());
- cpuLink.textContent =
- timeSlice.cpuOnWhichThreadWasRunning.userFriendlyName;
- onCpuEl.appendChild(cpuLink);
+ cpuLink.selection = new tr.model.EventSet(cpuSliceThatTookCpu);
+ if (cpuSliceThatTookCpu.thread)
+ Polymer.dom(cpuLink).textContent =
+ cpuSliceThatTookCpu.thread.userFriendlyName;
+ else
+ Polymer.dom(cpuLink).textContent = cpuSliceThatTookCpu.title;
+ Polymer.dom(runningInsteadEl).appendChild(cpuLink);
} else {
- onCpuEl.parentElement.removeChild(onCpuEl);
-
- var cpuSliceThatTookCpu = timeSlice.getCpuSliceThatTookCpu();
- if (cpuSliceThatTookCpu) {
- var cpuLink = document.createElement('tr-ui-a-analysis-link');
- cpuLink.selection = new tr.model.EventSet(cpuSliceThatTookCpu);
- if (cpuSliceThatTookCpu.thread)
- cpuLink.textContent = cpuSliceThatTookCpu.thread.userFriendlyName;
- else
- cpuLink.textContent = cpuSliceThatTookCpu.title;
- runningInsteadEl.appendChild(cpuLink);
- } else {
- runningInsteadEl.parentElement.removeChild(runningInsteadEl);
- }
+ Polymer.dom(runningInsteadEl.parentElement).removeChild(
+ runningInsteadEl);
}
+ }
- var argsEl = shadowRoot.querySelector('#args');
- if (tr.b.dictionaryKeys(timeSlice.args).length > 0) {
- var argsView =
- document.createElement('tr-ui-a-generic-object-view');
- argsView.object = timeSlice.args;
-
- argsEl.parentElement.style.display = '';
- argsEl.textContent = '';
- argsEl.appendChild(argsView);
- } else {
- argsEl.parentElement.style.display = 'none';
- }
+ var argsEl = root.querySelector('#args');
+ if (tr.b.dictionaryKeys(timeSlice.args).length > 0) {
+ var argsView =
+ document.createElement('tr-ui-a-generic-object-view');
+ argsView.object = timeSlice.args;
+
+ argsEl.parentElement.style.display = '';
+ Polymer.dom(argsEl).textContent = '';
+ Polymer.dom(argsEl).appendChild(argsView);
+ } else {
+ argsEl.parentElement.style.display = 'none';
}
- });
- </script>
-</polymer-element>
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-thread-time-slice-sub-view',
+ tr.model.ThreadTimeSlice,
+ {
+ multi: false,
+ title: 'Thread Timeslice',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
index 5ab48cbe2cf..f2b0faff015 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
@@ -56,7 +56,7 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(e.selection.equals(new tr.model.EventSet(binderSlice)));
didSelectionChangeHappen = true;
});
- view.shadowRoot.querySelector('tr-ui-a-analysis-link').click();
+ Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click();
assert.isTrue(didSelectionChangeHappen);
});
@@ -85,7 +85,7 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(e.selection.equals(new tr.model.EventSet(launcherSlice)));
didSelectionChangeHappen = true;
});
- view.shadowRoot.querySelector('tr-ui-a-analysis-link').click();
+ Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click();
assert.isTrue(didSelectionChangeHappen);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html
index 0c2ba50450a..4c332b0f761 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html
@@ -6,16 +6,15 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html">
<link rel="import"
href="/tracing/ui/analysis/user_expectation_related_samples_table.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
<link rel="import" href="/tracing/value/value_set.html">
-<polymer-element name="tr-ui-a-single-user-expectation-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-single-user-expectation-sub-view'>
<template>
<style>
:host {
@@ -32,50 +31,61 @@ found in the LICENSE file.
<tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table>
</div>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.currentSelection_ = undefined;
- },
+Polymer({
+ is: 'tr-ui-a-single-user-expectation-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
- get selection() {
- return this.currentSelection_;
- },
+ created: function() {
+ this.currentSelection_ = undefined;
+ },
- set selection(selection) {
- this.$.realView.addEventListener('customize-rows',
- this.onCustomizeRows_.bind(this));
+ get selection() {
+ return this.currentSelection_;
+ },
- this.currentSelection_ = selection;
- this.$.realView.setSelectionWithoutErrorChecks(selection);
+ set selection(selection) {
+ this.$.realView.addEventListener('customize-rows',
+ this.onCustomizeRows_.bind(this));
- this.$.relatedSamples.selection = selection;
- if (this.$.relatedSamples.hasRelatedSamples())
- this.$.events.style.display = '';
- else
- this.$.events.style.display = 'none';
- },
+ this.currentSelection_ = selection;
+ this.$.realView.setSelectionWithoutErrorChecks(selection);
- get relatedEventsToHighlight() {
- if (!this.currentSelection_)
- return undefined;
- return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
- },
+ this.$.relatedSamples.selection = selection;
+ if (this.$.relatedSamples.hasRelatedSamples())
+ this.$.events.style.display = '';
+ else
+ this.$.events.style.display = 'none';
+ },
- onCustomizeRows_: function(event) {
- var ue = tr.b.getOnlyElement(this.selection);
+ get relatedEventsToHighlight() {
+ if (!this.currentSelection_)
+ return undefined;
+ return tr.b.getOnlyElement(this.currentSelection_).associatedEvents;
+ },
- if (ue.rawCpuMs) {
- event.rows.push({
- name: 'Total CPU',
- value: tr.v.ui.createScalarSpan(ue.totalCpuMs, {
- unit: tr.v.Unit.byName.timeDurationInMs
- })
- });
- }
+ onCustomizeRows_: function(event) {
+ var ue = tr.b.getOnlyElement(this.selection);
+
+ if (ue.rawCpuMs) {
+ event.rows.push({
+ name: 'Total CPU',
+ value: tr.v.ui.createScalarSpan(ue.totalCpuMs, {
+ unit: tr.b.Unit.byName.timeDurationInMs
+ })
+ });
}
- });
- </script>
-</polymer-element>
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-single-user-expectation-sub-view',
+ tr.model.um.UserExpectation,
+ {
+ multi: false,
+ title: 'User Expectation',
+ });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html
index aeca20ee40d..27533e3131c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html
@@ -6,73 +6,76 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name="tr-ui-a-stack-frame">
+<dom-module id='tr-ui-a-stack-frame'>
<template>
<style>
:host {
display: flex;
flex-direction: row;
align-items: center;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- ready: function() {
- this.stackFrame_ = undefined;
- this.$.table.tableColumns = [];
- this.$.table.showHeader = true;
- },
+Polymer({
+ is: 'tr-ui-a-stack-frame',
- get stackFrame() {
- return this.stackFrame_;
- },
+ ready: function() {
+ this.stackFrame_ = undefined;
+ this.$.table.tableColumns = [];
+ this.$.table.showHeader = true;
+ },
- set stackFrame(stackFrame) {
- var table = this.$.table;
+ get stackFrame() {
+ return this.stackFrame_;
+ },
- this.stackFrame_ = stackFrame;
- if (stackFrame === undefined) {
- table.tableColumns = [];
- table.tableRows = [];
- table.rebuild();
- return;
- }
+ set stackFrame(stackFrame) {
+ var table = this.$.table;
- var hasName = false;
- var hasTitle = false;
-
- table.tableRows = stackFrame.stackTrace;
- table.tableRows.forEach(function(row) {
- hasName |= row.name !== undefined;
- hasTitle |= row.title !== undefined;
- });
+ this.stackFrame_ = stackFrame;
+ if (stackFrame === undefined) {
+ table.tableColumns = [];
+ table.tableRows = [];
+ table.rebuild();
+ return;
+ }
- var cols = [];
- if (hasName) {
- cols.push({
- title: 'Name',
- value: function(row) { return row.name; }
- });
- }
+ var hasName = false;
+ var hasTitle = false;
- if (hasTitle) {
- cols.push({
- title: 'Title',
- value: function(row) { return row.title; }
- });
- }
+ table.tableRows = stackFrame.stackTrace;
+ table.tableRows.forEach(function(row) {
+ hasName |= row.name !== undefined;
+ hasTitle |= row.title !== undefined;
+ });
- table.tableColumns = cols;
- table.rebuild();
- },
+ var cols = [];
+ if (hasName) {
+ cols.push({
+ title: 'Name',
+ value: function(row) { return row.name; }
+ });
+ }
- tableForTesting: function() {
- return this.$.table;
+ if (hasTitle) {
+ cols.push({
+ title: 'Title',
+ value: function(row) { return row.title; }
+ });
}
- });
- </script>
-</polymer-element>
+
+ table.tableColumns = cols;
+ table.rebuild();
+ },
+
+ tableForTesting: function() {
+ return this.$.table;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html
index ba5deb30330..a6446b64c4c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html
@@ -5,55 +5,18 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/base.html">
+<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html">
<!--
@fileoverview Analysis view stacked pane. See the stacked pane view element
(tr-ui-a-stacked-pane-view) documentation for more details.
-->
-<polymer-element name="tr-ui-a-stacked-pane">
- <script>
- 'use strict';
+<script>
+'use strict';
- Polymer({
- rebuild: function() {
- /**
- * Rebuild the pane if necessary.
- *
- * This method is not intended to be overriden by subclasses. Please
- * override scheduleRebuildPane_() instead.
- */
- if (!this.paneDirty_) {
- // Avoid rebuilding unnecessarily as it breaks things like table
- // selection.
- return;
- }
-
- this.paneDirty_ = false;
- this.rebuildPane_();
- },
-
- /**
- * Mark the UI state of the pane as dirty and schedule a rebuild.
- *
- * This method is intended to be called by subclasses.
- */
- scheduleRebuildPane_: function() {
- if (this.paneDirty_)
- return;
- this.paneDirty_ = true;
- setTimeout(this.rebuild.bind(this), 0);
- },
-
- /**
- * Called when the pane is dirty and a rebuild is triggered.
- *
- * This method is intended to be overriden by subclasses (instead of
- * directly overriding rebuild()).
- */
- rebuildPane_: function() {
- },
+tr.exportTo('tr.ui.analysis', function() {
+ var StackedPaneImpl = {
/**
* Request changing the child pane of this pane in the associated stacked
* pane view. If the assigned builder is undefined, request removing the
@@ -76,14 +39,24 @@ found in the LICENSE file.
/**
* Called right after the pane is appended to a pane view.
*
- * This method triggers an immediate rebuild by default (if necessary).
- * Subclasses are free to change this behavior (e.g. if a pane has lots of
- * data to display, it might decide to defer rebuilding in order not to
- * cause jank).
+ * This method triggers an immediate rebuild by default. Subclasses are
+ * free to change this behavior (e.g. if a pane has lots of data to display,
+ * it might decide to defer rebuilding in order not to cause jank).
*/
appended: function() {
this.rebuild();
}
- });
- </script>
-</polymer-element>
+ };
+
+ var StackedPane = [tr.ui.analysis.RebuildableBehavior, StackedPaneImpl];
+
+ return {
+ StackedPane: StackedPane
+ };
+});
+
+Polymer({
+ is: 'tr-ui-a-stacked-pane',
+ behaviors: [tr.ui.analysis.StackedPane]
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html
index f76feea8122..a4c8d5213dc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html
@@ -11,35 +11,6 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- test('rebuild', function() {
- var pane = document.createElement('tr-ui-a-stacked-pane');
- var didFireBuildPane;
- pane.rebuildPane_ = function() {
- didFireBuildPane = true;
- };
-
- function checkRebuild(expectedDidFireBuildPane) {
- didFireBuildPane = false;
- pane.rebuild();
- assert.strictEqual(didFireBuildPane, expectedDidFireBuildPane);
- }
-
- // No rebuilds should occur when not scheduled.
- checkRebuild(false);
- checkRebuild(false);
-
- // Single rebuild should occur when scheduled once.
- pane.scheduleRebuildPane_();
- checkRebuild(true);
- checkRebuild(false);
-
- // Only a single rebuild should occur even when scheduled multiple times.
- pane.scheduleRebuildPane_();
- pane.scheduleRebuildPane_();
- checkRebuild(true);
- checkRebuild(false);
- });
-
test('changeChildPane', function() {
var pane = document.createElement('tr-ui-a-stacked-pane');
var didFireEvent;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html
index a3c52f780e5..fe0ebf9bd90 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html
@@ -37,10 +37,11 @@ Sample use case:
Create an empty stacked pane view and add it to the DOM:
var paneView = document.createElement('tr-ui-a-stacked-pane-view');
- someParentView.appendChild(paneView);
+ Polymer.dom(someParentView).appendChild(paneView);
Define one or more pane subclasses:
+ TODO(polymer): Write this documentation
<polymer-element name="some-pane-1" extends="tr-ui-a-stacked-pane">
...
</polymer-element>
@@ -70,7 +71,7 @@ Sample use case:
}.bind(this);
}
-->
-<polymer-element name="tr-ui-a-stacked-pane-view">
+<dom-module id='tr-ui-a-stacked-pane-view'>
<template>
<style>
:host {
@@ -85,105 +86,107 @@ Sample use case:
<div id="pane_container">
</div>
</template>
- <script>
- 'use strict';
-
- Polymer({
- /**
- * Add a pane to the stacked pane view. This method performs two operations:
- *
- * 1. Remove existing descendant panes
- * If the optional parent pane is provided, all its current descendant
- * panes are removed. Otherwise, all panes are removed from the view.
- *
- * 2. Build and add new pane
- * If a pane builder is provided and returns a pane, the new pane is
- * appended to the view (after the provided parent, or at the top).
- */
- setPaneBuilder: function(paneBuilder, opt_parentPane) {
- var paneContainer = this.$.pane_container;
-
- // If the parent pane is provided, it must be an HTML element and a child
- // of the pane container.
- if (opt_parentPane) {
- if (!(opt_parentPane instanceof HTMLElement))
- throw new Error('Parent pane must be an HTML element');
- if (opt_parentPane.parentElement !== paneContainer)
- throw new Error('Parent pane must be a child of the pane container');
- }
-
- // Remove all descendants of the parent pane (or all panes if no parent
- // pane was specified) in reverse order.
- while (paneContainer.lastElementChild !== null &&
- paneContainer.lastElementChild !== opt_parentPane) {
- var removedPane = this.$.pane_container.lastElementChild;
- var listener = this.listeners_.get(removedPane);
- if (listener === undefined)
- throw new Error('No listener associated with pane');
- this.listeners_.delete(removedPane);
- removedPane.removeEventListener(
- 'request-child-pane-change', listener);
- paneContainer.removeChild(removedPane);
- }
-
- if (opt_parentPane && opt_parentPane.parentElement !== paneContainer)
- throw new Error('Parent pane was removed from the pane container');
-
- // This check is performed here (and not at the beginning of the method)
- // because undefined pane builder means that the parent pane requested
- // having no child pane (e.g. when selection is cleared).
- if (!paneBuilder)
- return;
-
- var pane = paneBuilder();
- if (!pane)
- return;
-
- if (!(pane instanceof HTMLElement))
- throw new Error('Pane must be an HTML element');
-
- // Listen for child pane change requests from the newly added pane.
- var listener = function(event) {
- this.setPaneBuilder(pane.childPaneBuilder, pane);
- }.bind(this);
- if (!this.listeners_) {
- // Instead of initializing the listeners map in a created() callback,
- // we do it lazily here so that subclasses could provide their own
- // created() callback (Polymer currently doesn't allow calling overriden
- // superclass methods in strict mode).
- this.listeners_ = new WeakMap();
- }
- this.listeners_.set(pane, listener);
- pane.addEventListener('request-child-pane-change', listener);
-
- paneContainer.appendChild(pane);
- pane.appended();
- },
-
- /**
- * Request rebuilding all panes in the view. The panes are rebuilt from the
- * top to the bottom (so that parent panes could request changing their
- * child panes when they're being rebuilt and the newly constructed child
- * panes would be rebuilt as well).
- */
- rebuild: function() {
- var currentPane = this.$.pane_container.firstElementChild;
- while (currentPane) {
- currentPane.rebuild();
- currentPane = currentPane.nextElementSibling;
- }
- },
-
- // For testing purposes.
- get panesForTesting() {
- var panes = [];
- var currentChild = this.$.pane_container.firstElementChild;
- while (currentChild) {
- panes.push(currentChild);
- currentChild = currentChild.nextElementSibling;
- }
- return panes;
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-a-stacked-pane-view',
+
+ /**
+ * Add a pane to the stacked pane view. This method performs two operations:
+ *
+ * 1. Remove existing descendant panes
+ * If the optional parent pane is provided, all its current descendant
+ * panes are removed. Otherwise, all panes are removed from the view.
+ *
+ * 2. Build and add new pane
+ * If a pane builder is provided and returns a pane, the new pane is
+ * appended to the view (after the provided parent, or at the top).
+ */
+ setPaneBuilder: function(paneBuilder, opt_parentPane) {
+ var paneContainer = this.$.pane_container;
+
+ // If the parent pane is provided, it must be an HTML element and a child
+ // of the pane container.
+ if (opt_parentPane) {
+ if (!(opt_parentPane instanceof HTMLElement))
+ throw new Error('Parent pane must be an HTML element');
+ if (opt_parentPane.parentElement !== paneContainer)
+ throw new Error('Parent pane must be a child of the pane container');
+ }
+
+ // Remove all descendants of the parent pane (or all panes if no parent
+ // pane was specified) in reverse order.
+ while (Polymer.dom(paneContainer).lastElementChild !== null &&
+ Polymer.dom(paneContainer).lastElementChild !== opt_parentPane) {
+ var removedPane = Polymer.dom(this.$.pane_container).lastElementChild;
+ var listener = this.listeners_.get(removedPane);
+ if (listener === undefined)
+ throw new Error('No listener associated with pane');
+ this.listeners_.delete(removedPane);
+ removedPane.removeEventListener(
+ 'request-child-pane-change', listener);
+ Polymer.dom(paneContainer).removeChild(removedPane);
+ }
+
+ if (opt_parentPane && opt_parentPane.parentElement !== paneContainer)
+ throw new Error('Parent pane was removed from the pane container');
+
+ // This check is performed here (and not at the beginning of the method)
+ // because undefined pane builder means that the parent pane requested
+ // having no child pane (e.g. when selection is cleared).
+ if (!paneBuilder)
+ return;
+
+ var pane = paneBuilder();
+ if (!pane)
+ return;
+
+ if (!(pane instanceof HTMLElement))
+ throw new Error('Pane must be an HTML element');
+
+ // Listen for child pane change requests from the newly added pane.
+ var listener = function(event) {
+ this.setPaneBuilder(pane.childPaneBuilder, pane);
+ }.bind(this);
+ if (!this.listeners_) {
+ // Instead of initializing the listeners map in a created() callback,
+ // we do it lazily here so that subclasses could provide their own
+ // created() callback (Polymer currently doesn't allow calling overriden
+ // superclass methods in strict mode).
+ this.listeners_ = new WeakMap();
+ }
+ this.listeners_.set(pane, listener);
+ pane.addEventListener('request-child-pane-change', listener);
+
+ Polymer.dom(paneContainer).appendChild(pane);
+ pane.appended();
+ },
+
+ /**
+ * Request rebuilding all panes in the view. The panes are rebuilt from the
+ * top to the bottom (so that parent panes could request changing their
+ * child panes when they're being rebuilt and the newly constructed child
+ * panes would be rebuilt as well).
+ */
+ rebuild: function() {
+ var currentPane = Polymer.dom(this.$.pane_container).firstElementChild;
+ while (currentPane) {
+ currentPane.rebuild();
+ currentPane = currentPane.nextElementSibling;
+ }
+ },
+
+ // For testing purposes.
+ get panesForTesting() {
+ var panes = [];
+ var currentChild = Polymer.dom(this.$.pane_container).firstElementChild;
+ while (currentChild) {
+ panes.push(currentChild);
+ currentChild = currentChild.nextElementSibling;
}
- });
- </script>
-</polymer-element>
+ return panes;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html
index 5afcd1bd1f0..0f3a5e29e60 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html
@@ -21,14 +21,14 @@ tr.b.unittest.testSuite(function() {
paneEl.paneId = paneId;
var divEl = document.createElement('div');
- divEl.textContent = 'Pane ' + paneId;
+ Polymer.dom(divEl).textContent = 'Pane ' + paneId;
divEl.style.width = '400px';
divEl.style.background = '#ccc';
divEl.style.textAlign = 'center';
- paneEl.appendChild(divEl);
+ Polymer.dom(paneEl).appendChild(divEl);
if (opt_rebuildPaneCallback)
- paneEl.rebuildPane_ = opt_rebuildPaneCallback;
+ paneEl.onRebuild_ = opt_rebuildPaneCallback;
if (opt_appendedCallback)
paneEl.appended = opt_appendedCallback;
@@ -176,7 +176,7 @@ tr.b.unittest.testSuite(function() {
// All panes are now marked as dirty, but rebuild isn't triggered (it was
// only scheduled).
viewEl.panesForTesting.forEach(function(pane) {
- pane.scheduleRebuildPane_();
+ pane.scheduleRebuild_();
});
assert.deepEqual(rebuiltPaneIds, []);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html
index c08278c9b44..b606d1736a1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html
@@ -23,8 +23,8 @@ tr.exportTo('tr.ui.analysis', function() {
},
appendChild: function(node) {
- if (node.tagName == 'TFOOT' || node.tagName == 'THEAD' ||
- node.tagName == 'TBODY') {
+ if (node.tagName === 'TFOOT' || node.tagName === 'THEAD' ||
+ node.tagName === 'TBODY') {
node.__proto__ = StubAnalysisTable.prototype;
node.nodes_ = [];
node.ownerDocument_ = document;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html
index fb5b694c17b..b9cc593b5a4 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html
@@ -8,78 +8,81 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name="tr-ui-a-user-expectation-related-samples-table">
+<dom-module id='tr-ui-a-user-expectation-related-samples-table'>
<template>
<style>
#table {
flex: 1 1 auto;
align-self: stretch;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- ready: function() {
- this.samples_ = [];
- this.$.table.tableColumns = [
- {
- title: 'Event(s)',
- value: function(row) {
- var typeEl = document.createElement('span');
- typeEl.innerText = row.type;
- if (row.tooltip)
- typeEl.title = row.tooltip;
- return typeEl;
- },
- width: '150px'
+Polymer({
+ is: 'tr-ui-a-user-expectation-related-samples-table',
+
+ ready: function() {
+ this.samples_ = [];
+ this.$.table.tableColumns = [
+ {
+ title: 'Event(s)',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.type;
+ if (row.tooltip)
+ typeEl.title = row.tooltip;
+ return typeEl;
},
- {
- title: 'Link',
- width: '100%',
- value: function(row) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- if (row.name)
- linkEl.setSelectionAndContent(row.selection, row.name);
- else
- linkEl.selection = row.selection;
- return linkEl;
- }
+ width: '150px'
+ },
+ {
+ title: 'Link',
+ width: '100%',
+ value: function(row) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ if (row.name)
+ linkEl.setSelectionAndContent(row.selection, row.name);
+ else
+ linkEl.selection = row.selection;
+ return linkEl;
}
- ];
- },
+ }
+ ];
+ },
- hasRelatedSamples: function() {
- return (this.samples_ && this.samples_.length > 0);
- },
+ hasRelatedSamples: function() {
+ return (this.samples_ && this.samples_.length > 0);
+ },
- set selection(eventSet) {
- this.samples_ = [];
- var samples = new tr.model.EventSet;
- eventSet.forEach(function(ue) {
- samples.addEventSet(ue.associatedSamples);
- }.bind(this));
+ set selection(eventSet) {
+ this.samples_ = [];
+ var samples = new tr.model.EventSet;
+ eventSet.forEach(function(ue) {
+ samples.addEventSet(ue.associatedSamples);
+ }.bind(this));
- if (samples.length > 0) {
- this.samples_.push({
- type: 'Overlapping samples',
- tooltip: 'All samples overlapping the selected user expectation(s).',
- selection: samples
- });
- }
- this.updateContents_();
- },
-
- updateContents_: function() {
- var table = this.$.table;
- if (this.samples_ && this.samples_.length > 0)
- table.tableRows = this.samples_.slice();
- else
- table.tableRows = [];
- table.rebuild();
+ if (samples.length > 0) {
+ this.samples_.push({
+ type: 'Overlapping samples',
+ tooltip: 'All samples overlapping the selected user expectation(s).',
+ selection: samples
+ });
}
- });
- </script>
-</polymer-element>
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+ if (this.samples_ && this.samples_.length > 0)
+ table.tableRows = this.samples_.slice();
+ else
+ table.tableRows = [];
+ table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html b/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html
index 03eba86146b..30be91ba622 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html
@@ -33,7 +33,8 @@ tr.exportTo('tr.ui.annotations', function() {
__proto__: tr.ui.annotations.AnnotationView.prototype,
removeTextArea: function() {
- this.textArea_.parentNode.removeChild(this.textArea_);
+ Polymer.dom(Polymer.dom(this.textArea_).parentNode).removeChild(
+ this.textArea_);
},
draw: function(ctx) {
@@ -52,7 +53,8 @@ tr.exportTo('tr.ui.annotations', function() {
this.textArea_.value = this.annotation_.text;
// Set the z-index so that this is shown on top of canvas.
this.textArea_.style.zIndex = 1;
- ctx.canvas.parentNode.appendChild(this.textArea_);
+ Polymer.dom(Polymer.dom(ctx.canvas).parentNode)
+ .appendChild(this.textArea_);
}
this.textArea_.style.width = this.styleWidth + 'px';
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html
index b2893762db3..67ec5382c09 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html
@@ -1,173 +1,135 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2014 The Chromium Authors. All rights reserved.
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/chart_base_2d_brushable_x.html">
+<link rel="import" href="/tracing/ui/base/column_chart.html">
<script>
'use strict';
tr.exportTo('tr.ui.b', function() {
- var ColorScheme = tr.b.ColorScheme;
- var ChartBase2DBrushX = tr.ui.b.ChartBase2DBrushX;
- var getColorOfKey = tr.ui.b.getColorOfKey;
+ var ColumnChart = tr.ui.b.ColumnChart;
// @constructor
- var BarChart = tr.ui.b.define('bar-chart', ChartBase2DBrushX);
+ var BarChart = tr.ui.b.define('bar-chart', ColumnChart);
BarChart.prototype = {
- __proto__: ChartBase2DBrushX.prototype,
+ __proto__: ColumnChart.prototype,
decorate: function() {
- ChartBase2DBrushX.prototype.decorate.call(this);
- this.classList.add('bar-chart');
- this.xCushion_ = 0;
- this.isStacked_ = false;
+ ColumnChart.prototype.decorate.call(this);
+ Polymer.dom(this).classList.add('bar-chart');
+ this.verticalScale_ = undefined;
+ this.horizontalScale_ = undefined;
},
- set isStacked(stacked) {
- this.isStacked_ = true;
- this.updateContents_();
+ updateScales_: function() {
+ ColumnChart.prototype.updateScales_.call(this);
+ this.yScale_.range([this.chartAreaSize.width, 0]);
+ this.xScale_.range([0, this.chartAreaSize.height]);
+ this.verticalScale_ = this.isYLogScale_ ? d3.scale.log(10) :
+ d3.scale.linear();
+ this.verticalScale_.domain(this.xScale_.domain());
+ this.verticalScale_.range([this.chartAreaSize.height, 0]);
+ this.horizontalScale_ = d3.scale.linear();
+ this.horizontalScale_.domain(this.yScale_.domain());
+ this.horizontalScale_.range([0, this.chartAreaSize.width]);
},
- get isStacked() {
- return this.isStacked_;
+ drawBrush_: function(brushRectsSel) {
+ brushRectsSel
+ .attr('x', 0)
+ .attr('width', this.chartAreaSize.width)
+ .attr('y', function(d) {
+ return this.verticalScale_(d.max);
+ }.bind(this))
+ .attr('height', function(d) {
+ return this.verticalScale_(d.min) - this.verticalScale_(d.max);
+ }.bind(this));
},
- isDatumFieldSeries_: function(fieldName) {
- return fieldName != 'x';
+ getDataPointAtChartPoint_: function(chartPoint) {
+ var flippedPoint = {
+ x: this.chartAreaSize.height - chartPoint.y,
+ y: this.chartAreaSize.width - chartPoint.x
+ };
+ return ColumnChart.prototype.getDataPointAtChartPoint_.call(
+ this, flippedPoint);
},
- getXForDatum_: function(datum, index) {
- return datum.x;
+ drawXAxis_: function(xAxis) {
+ xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')')
+ .call(d3.svg.axis()
+ .scale(this.horizontalScale_)
+ .orient('bottom'));
},
- updateScales_: function() {
- if (this.data_.length === 0)
- return;
-
- var xDifferences = 0;
- var currentX = undefined;
- var previousX = undefined;
- var yRange = new tr.b.Range();
- this.data_.forEach(function(datum, index) {
- previousX = currentX;
- currentX = this.getXForDatum_(datum, index);
- if (previousX !== undefined) {
- xDifferences += currentX - previousX;
- }
-
- this.seriesKeys_.forEach(function(key) {
- // Allow for sparse data
- if (datum[key] !== undefined)
- yRange.addValue(datum[key]);
- });
- }, this);
-
- // X.
- // Leave a cushion on the right so that the last rect doesn't
- // exceed the chart boundaries. The last rect's width is set to the
- // average width of the rects, which is chart.width / data.length.
- var width = this.chartAreaSize.width;
- this.xScale_.range([0, width]);
- var domain = d3.extent(this.data_, this.getXForDatum_.bind(this));
- this.xCushion_ = xDifferences / (this.data_.length - 1);
- this.xScale_.domain([domain[0], domain[1] + this.xCushion_]);
-
- // Y.
- this.yScale_.range([this.chartAreaSize.height, 0]);
- this.yScale_.domain(this.getYScaleDomain_(yRange.min, yRange.max));
+ drawYAxis_: function(yAxis) {
+ var axisModifier = d3.svg.axis()
+ .scale(this.verticalScale_)
+ .orient('left');
+ yAxis.call(axisModifier);
},
- getYScaleDomain_: function(minValue, maxValue) {
- if (!this.isStacked) {
- return ChartBase2DBrushX.prototype.getYScaleDomain_.call(
- this, minValue, maxValue);
+ drawHoverValueBox_: function(rect) {
+ var seriesKeys = [...this.seriesByKey_.keys()];
+ var chartAreaSel = d3.select(this.chartAreaElement);
+ chartAreaSel.selectAll('.hover').remove();
+ var keyWidthPx = 0;
+ var keyHeightPx = 0;
+ if (seriesKeys.length > 1) {
+ keyWidthPx = tr.ui.b.getSVGTextWidth(
+ this.chartAreaElement, rect.key) + 5;
+ keyHeightPx = 16;
+ }
+ var valueWidthPx = tr.ui.b.getSVGTextWidth(
+ this.chartAreaElement, rect.value) + 5;
+ var valueHeightPx = 16;
+ var hoverWidthPx = Math.max(keyWidthPx, valueWidthPx);
+ var hoverTopPx = rect.topPx + (rect.heightPx / 2);
+ var hoverLeftPx = rect.leftPx + rect.widthPx - hoverWidthPx;
+ chartAreaSel
+ .append('rect')
+ .attr('class', 'hover')
+ .attr('fill', 'white')
+ .attr('x', hoverLeftPx)
+ .attr('y', hoverTopPx)
+ .attr('width', hoverWidthPx)
+ .attr('height', keyHeightPx + valueHeightPx);
+ if (seriesKeys.length > 1) {
+ chartAreaSel
+ .append('text')
+ .attr('class', 'hover')
+ .attr('fill', rect.color)
+ .attr('x', hoverLeftPx + 2)
+ .attr('y', hoverTopPx + keyHeightPx - 3)
+ .text(rect.key);
}
- var range = new tr.b.Range();
- range.addValue(0);
- this.data_.forEach(function(datum, index) {
- var sum = 0;
- this.seriesKeys_.forEach(function(key) {
- if (datum[key] === undefined)
- return;
- sum += datum[key];
- }, this);
- range.addValue(sum);
- }, this);
- return [range.min, range.max];
- },
-
- getStackedRectsForDatum_: function(datum, index) {
- var stacks = [];
- var bottom = this.yScale_.range()[0];
- var sum = 0;
- this.seriesKeys_.forEach(function(key) {
- if (datum[key] === undefined)
- return;
- sum += datum[key];
- var heightPx = bottom - this.yScale_(sum);
- bottom -= heightPx;
- stacks.push({
- color: getColorOfKey(key),
- heightPx: heightPx,
- topPx: bottom
- });
- }, this);
- return stacks;
- },
-
- getRectsForDatum_: function(datum, index) {
- if (this.isStacked)
- return this.getStackedRectsForDatum_(datum, index);
-
- var stacks = [];
- this.seriesKeys_.forEach(function(key) {
- if (datum[key] === undefined)
- return;
- var topPx = this.yScale_(Math.max(datum[key], this.getYScaleMin_()));
- stacks.push({
- topPx: topPx,
- heightPx: this.yScale_.range()[0] - topPx,
- color: getColorOfKey(key)
- });
- }, this);
- stacks.sort(function(a, b) {
- return b.topPx - a.topPx;
- });
- return stacks;
+ chartAreaSel
+ .append('text')
+ .attr('class', 'hover')
+ .attr('fill', rect.color)
+ .attr('x', hoverLeftPx + 2)
+ .attr('y', hoverTopPx + keyHeightPx + valueHeightPx - 3)
+ .text(rect.value);
},
- updateDataContents_: function(dataSel) {
- dataSel.selectAll('*').remove();
- var rectsSel = dataSel.selectAll('path').data(this.seriesKeys_);
- this.data_.forEach(function(datum, index) {
- var currentX = this.getXForDatum_(datum, index);
- var width = undefined;
- if (index < (this.data_.length - 1)) {
- var nextX = this.getXForDatum_(this.data_[index + 1], index + 1);
- width = nextX - currentX;
- } else {
- width = this.xCushion_;
- }
- this.getRectsForDatum_(datum, index).forEach(function(rect) {
- var leftPx = this.xScale_(currentX);
- var rightPx = this.xScale_(currentX + width);
- var widthPx = rightPx - leftPx;
- rectsSel.enter()
- .append('rect')
- .attr('fill', rect.color)
- .attr('x', leftPx)
- .attr('y', rect.topPx)
- .attr('width', widthPx)
- .attr('height', rect.heightPx);
- }, this);
- }, this);
- rectsSel.exit().remove();
+ drawRect_: function(rect, sel) {
+ // Flip |rect| around |y=x|.
+ var colRect = {
+ key: rect.key,
+ value: rect.value,
+ color: rect.color,
+ topPx: this.chartAreaSize.height - rect.leftPx - rect.widthPx,
+ leftPx: this.chartAreaSize.width - rect.topPx - rect.heightPx,
+ widthPx: rect.heightPx,
+ heightPx: rect.widthPx,
+ };
+ ColumnChart.prototype.drawRect_.call(this, colRect, sel);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html
index 7d931d5ff1b..ff991993c15 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/base/bar_chart.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
<script>
'use strict';
@@ -26,6 +27,18 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(chart);
});
+ test('instantiation_singleDatum', function() {
+ var chart = new tr.ui.b.BarChart();
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 0, value: 100},
+ ];
+ chart.data = data;
+ this.addHTMLOutput(chart);
+ });
+
test('instantiation_stacked', function() {
var chart = new tr.ui.b.BarChart();
chart.isStacked = true;
@@ -215,7 +228,7 @@ tr.b.unittest.testSuite(function() {
updateBrushedRange();
});
chart.addEventListener('item-mousemove', function(e) {
- if (e.button == undefined)
+ if (e.button === undefined)
return;
curMouseX = e.x;
updateBrushedRange();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/base.html b/chromium/third_party/catapult/tracing/tracing/ui/base/base.html
new file mode 100644
index 00000000000..e0ca9e23c6b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/base.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/base/polymer_preload.html" data-suppress-import-order>
+
+<!--
+Polymer is imported through third-party HTML files, which means that we have to
+manually list all recursive imports.
+-->
+<link rel="import" href="/components/polymer/polymer-micro.html" data-suppress-import-order>
+<link rel="import" href="/components/polymer/polymer-mini.html" data-suppress-import-order>
+<link rel="import" href="/components/polymer/polymer.html" data-suppress-import-order>
+
+<link rel="import" href="/tracing/ui/base/polymer_postload.html" data-suppress-import-order>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html
index 5155376058a..e57daf3ac6c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+ <!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
@@ -6,16 +6,146 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/color_scheme.html">
+<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/base/d3.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<dom-module id="tr-ui-b-chart-legend-key">
+ <template>
+ <style>
+ #checkbox {
+ margin: 0;
+ visibility: hidden;
+ vertical-align: text-top;
+ }
+ #label, #link {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: inline-block;
+ }
+ </style>
+
+ <input type=checkbox id="checkbox" checked>
+ <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link>
+ <label id="label"></label>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.b', function() {
+ function getSVGTextWidth(parentNode, text) {
+ var textNode = document.createElementNS(
+ 'http://www.w3.org/2000/svg', 'text');
+ textNode.setAttributeNS(null, 'x', 0);
+ textNode.setAttributeNS(null, 'y', 0);
+ textNode.setAttributeNS(null, 'fill', 'black');
+ textNode.appendChild(document.createTextNode(text));
+ parentNode.appendChild(textNode);
+ var widthPx = textNode.getComputedTextLength();
+ parentNode.removeChild(textNode);
+ return widthPx;
+ }
+
+ return {
+ getSVGTextWidth: getSVGTextWidth
+ };
+});
+
+Polymer({
+ is: 'tr-ui-b-chart-legend-key',
+
+ ready: function() {
+ this.$.checkbox.addEventListener(
+ 'change', this.onCheckboxChange_.bind(this));
+ },
+
+ /**
+ * Dispatch an event when the checkbox is toggled.
+ * The checkbox is visible when optional is set to true.
+ */
+ onCheckboxChange_: function() {
+ tr.b.dispatchSimpleEvent(this, tr.ui.b.DataSeriesEnableChangeEventType,
+ true, false,
+ {key: Polymer.dom(this).textContent, enabled: this.enabled});
+ },
+
+ set textContent(t) {
+ Polymer.dom(this.$.label).textContent = t;
+ Polymer.dom(this.$.link).textContent = t;
+ this.updateContents_();
+ },
+
+ set width(w) {
+ w -= 20; // reserve 20px for the checkbox
+ this.$.link.style.width = w + 'px';
+ this.$.label.style.width = w + 'px';
+ },
+
+ get textContent() {
+ return Polymer.dom(this.$.label).textContent;
+ },
+
+ /**
+ * When a legend-key is "optional", then its checkbox is visible to allow
+ * the user to enable/disable the data series for the key.
+ *
+ * @param {boolean} optional
+ */
+ set optional(optional) {
+ this.$.checkbox.style.visibility = optional ? 'visible' : 'hidden';
+ },
+
+ get optional() {
+ return this.$.checkbox.style.visibility === 'visible';
+ },
+
+ set enabled(enabled) {
+ this.$.checkbox.checked = enabled ? 'checked' : '';
+ },
+
+ get enabled() {
+ return this.$.checkbox.checked;
+ },
+
+ set color(c) {
+ this.$.label.style.color = c;
+ this.$.link.color = c;
+ },
+
+ /**
+ * When target is defined, label is hidden and link is shown.
+ * When the link is clicked, then a RequestSelectionChangeEvent is
+ * dispatched containing the target.
+ * When target is undefined, label is shown and link is hidden, so that the
+ * link is not clickable.
+ */
+ set target(target) {
+ this.$.link.setSelectionAndContent(
+ target, Polymer.dom(this.$.label).textContent);
+ this.updateContents_();
+ },
+
+ get target() {
+ return this.$.link.selection;
+ },
+
+ updateContents_: function() {
+ this.$.link.style.display = this.target ? '' : 'none';
+ this.$.label.style.display = this.target ? 'none' : '';
+ this.$.label.htmlFor = this.optional ? 'checkbox' : '';
+ }
+});
+</script>
+
<style>
* /deep/ .chart-base #title {
font-size: 16pt;
}
* /deep/ .chart-base {
- font-size: 12pt;
-webkit-user-select: none;
cursor: default;
}
@@ -26,6 +156,10 @@ found in the LICENSE file.
shape-rendering: crispEdges;
stroke: #000;
}
+
+ * /deep/ .chart-base .legend body {
+ margin: 0;
+ }
</style>
<template id="chart-base-template">
@@ -42,6 +176,8 @@ found in the LICENSE file.
'use strict';
tr.exportTo('tr.ui.b', function() {
+ var DataSeriesEnableChangeEventType = 'data-series-enabled-change';
+
var THIS_DOC = document.currentScript.ownerDocument;
var svgNS = 'http://www.w3.org/2000/svg';
@@ -54,6 +190,65 @@ tr.exportTo('tr.ui.b', function() {
return ColorScheme.colorsAsStrings[id];
}
+ function DataSeries(key) {
+ this.key_ = key;
+ this.target_ = undefined;
+ this.optional_ = false;
+ this.enabled_ = true;
+ this.color_ = getColorOfKey(key, false);
+ this.highlightedColor_ = getColorOfKey(key, true);
+ }
+
+ DataSeries.prototype = {
+ get key() {
+ return this.key_;
+ },
+
+ get color() {
+ return this.color_;
+ },
+
+ set color(c) {
+ this.color_ = c;
+ },
+
+ get highlightedColor() {
+ return this.highlightedColor_;
+ },
+
+ set highlightedColor(c) {
+ this.highlightedColor_ = c;
+ },
+
+ get optional() {
+ return this.optional_;
+ },
+
+ set optional(optional) {
+ this.optional_ = optional;
+ },
+
+ get enabled() {
+ return this.enabled_;
+ },
+
+ set enabled(enabled) {
+ // If the caller is disabling a data series, but it wasn't optional, then
+ // force it to be optional.
+ if (!this.optional && !enabled)
+ this.optional = true;
+ this.enabled_ = enabled;
+ },
+
+ get target() {
+ return this.target_;
+ },
+
+ set target(t) {
+ this.target_ = t;
+ }
+ };
+
/**
* A virtual base class for basic charts that provides X and Y axes, if
* needed, a title, and legend.
@@ -65,20 +260,30 @@ tr.exportTo('tr.ui.b', function() {
ChartBase.prototype = {
__proto__: HTMLUnknownElement.prototype,
+ getDataSeries: function(key) {
+ if (!this.seriesByKey_.has(key))
+ this.seriesByKey_.set(key, new DataSeries(key));
+ return this.seriesByKey_.get(key);
+ },
+
decorate: function() {
- this.classList.add('chart-base');
+ Polymer.dom(this).classList.add('chart-base');
this.chartTitle_ = undefined;
- this.seriesKeys_ = undefined;
+ this.seriesByKey_ = new Map();
this.width_ = 400;
this.height_ = 300;
+ this.margin = {top: 20, right: 72, bottom: 30, left: 50};
+ this.hideLegend_ = false;
// This should use tr.ui.b.instantiateTemplate. However, creating
// svg-namespaced elements inside a template isn't possible. Thus, this
// hack.
- var template = THIS_DOC.querySelector('#chart-base-template');
- var svgEl = template.content.querySelector('svg');
- for (var i = 0; i < svgEl.children.length; i++)
- this.appendChild(svgEl.children[i].cloneNode(true));
+ var template =
+ Polymer.dom(THIS_DOC).querySelector('#chart-base-template');
+ var svgEl = Polymer.dom(template.content).querySelector('svg');
+ for (var i = 0; i < Polymer.dom(svgEl).children.length; i++)
+ Polymer.dom(this).appendChild(
+ Polymer.dom(svgEl.children[i]).cloneNode(true));
// svg likes to take over width & height properties for some reason. This
// works around it.
@@ -102,6 +307,26 @@ tr.exportTo('tr.ui.b', function() {
this.updateContents_();
}
});
+ this.addEventListener(DataSeriesEnableChangeEventType,
+ this.onDataSeriesEnableChange_.bind(this));
+ },
+
+ get hideLegend() {
+ return this.hideLegend_;
+ },
+
+ set hideLegend(h) {
+ this.hideLegend_ = h;
+ this.updateContents_();
+ },
+
+ isSeriesEnabled: function(key) {
+ return this.getDataSeries(key).enabled;
+ },
+
+ onDataSeriesEnableChange_: function(event) {
+ this.getDataSeries(event.key).enabled = event.enabled;
+ this.updateContents_();
},
get chartTitle() {
@@ -109,12 +334,21 @@ tr.exportTo('tr.ui.b', function() {
},
set chartTitle(chartTitle) {
+ if (chartTitle && !this.chartTitle_)
+ this.margin.top += this.titleMarginPx;
+ else if (this.chartTitle_ && !chartTitle)
+ this.margin.top -= this.titleMarginPx;
+
this.chartTitle_ = chartTitle;
this.updateContents_();
},
+ get titleMarginPx() {
+ return 20;
+ },
+
get chartAreaElement() {
- return this.querySelector('#chart-area');
+ return Polymer.dom(this).querySelector('#chart-area');
},
setSize: function(size) {
@@ -123,43 +357,25 @@ tr.exportTo('tr.ui.b', function() {
this.updateContents_();
},
- getMargin_: function() {
- var margin = {top: 20, right: 20, bottom: 30, left: 50};
- if (this.chartTitle_)
- margin.top += 20;
- return margin;
- },
-
- get margin() {
- return this.getMargin_();
- },
-
get chartAreaSize() {
- var margin = this.margin;
return {
- width: this.width_ - margin.left - margin.right,
- height: this.height_ - margin.top - margin.bottom
+ width: this.width_ - this.margin.left - this.margin.right,
+ height: this.height_ - this.margin.top - this.margin.bottom
};
},
- getLegendKeys_: function() {
- throw new Error('Not implemented');
- },
-
updateScales_: function() {
throw new Error('Not implemented');
},
updateContents_: function() {
- var margin = this.margin;
-
var thisSel = d3.select(this);
thisSel.attr('width', this.width_);
thisSel.attr('height', this.height_);
var chartAreaSel = d3.select(this.chartAreaElement);
chartAreaSel.attr('transform',
- 'translate(' + margin.left + ',' + margin.top + ')');
+ 'translate(' + this.margin.left + ',' + this.margin.top + ')');
this.updateScales_();
this.updateTitle_(chartAreaSel);
@@ -181,45 +397,38 @@ tr.exportTo('tr.ui.b', function() {
.text(this.chartTitle_);
},
- // TODO(charliea): We should change updateLegend_ so that it ellipsizes the
- // series names after a certain point. Otherwise, the series names start
- // dipping below the x-axis and continue on outside of the viewport.
updateLegend_: function() {
- var keys = this.getLegendKeys_();
- if (keys === undefined)
- return;
-
var chartAreaSel = d3.select(this.chartAreaElement);
- var chartAreaSize = this.chartAreaSize;
+ chartAreaSel.selectAll('.legend').remove();
+ if (this.hideLegend)
+ return;
- var legendEntriesSel = chartAreaSel.selectAll('.legend')
- .data(keys.slice().reverse());
+ var series = [...this.seriesByKey_.values()].reverse();
+ var legendEntriesSel = chartAreaSel.selectAll('.legend').data(series);
+ var width = this.margin.right - 2;
legendEntriesSel.enter()
- .append('g')
+ .append('foreignObject')
.attr('class', 'legend')
- .attr('transform', function(d, i) {
- return 'translate(0,' + i * 20 + ')';
+ .attr('x', this.chartAreaSize.width + 2)
+ .attr('width', width)
+ .attr('height', 18)
+ .attr('transform', function(series, i) {
+ return 'translate(0,' + i * 18 + ')';
})
- .append('text').text(function(key) {
- return key;
- });
+ .append('xhtml:body')
+ .append('tr-ui-b-chart-legend-key')
+ .property('color', function(series) {
+ if (this.currentHighlightedLegendKey === series.key)
+ return series.highlightedColor;
+ return series.color;
+ }.bind(this))
+ .property('width', width)
+ .property('target', function(series) { return series.target; })
+ .property('optional', function(series) { return series.optional; })
+ .property('enabled', function(series) { return series.enabled; })
+ .text(function(series) { return series.key; });
legendEntriesSel.exit().remove();
-
- legendEntriesSel.attr('x', chartAreaSize.width - 18)
- .attr('width', 18)
- .attr('height', 18)
- .style('fill', function(key) {
- var selected = this.currentHighlightedLegendKey === key;
- return getColorOfKey(key, selected);
- }.bind(this));
-
- legendEntriesSel.selectAll('text')
- .attr('x', chartAreaSize.width - 24)
- .attr('y', 9)
- .attr('dy', '.35em')
- .style('text-anchor', 'end')
- .text(function(d) { return d; });
},
get highlightedLegendKey() {
@@ -245,7 +454,7 @@ tr.exportTo('tr.ui.b', function() {
},
popTempHighlightedLegendKey: function(key) {
- if (this.tempHighlightedLegendKey_ != key)
+ if (this.tempHighlightedLegendKey_ !== key)
throw new Error('pop cannot happen');
this.tempHighlightedLegendKey_ = undefined;
this.updateHighlight_();
@@ -258,18 +467,20 @@ tr.exportTo('tr.ui.b', function() {
var that = this;
legendEntriesSel.each(function(key) {
- var highlighted = key == that.currentHighlightedLegendKey;
- var color = getColorOfKey(key, highlighted);
- this.style.fill = color;
- if (highlighted)
+ var dataSeries = that.getDataSeries(key);
+ if (key === that.currentHighlightedLegendKey) {
+ this.style.fill = dataSeries.highlightedColor;
this.style.fontWeight = 'bold';
- else
+ } else {
+ this.style.fill = dataSeries.color;
this.style.fontWeight = '';
+ }
});
}
};
return {
+ DataSeriesEnableChangeEventType: DataSeriesEnableChangeEventType,
getColorOfKey: getColorOfKey,
ChartBase: ChartBase
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html
index 84cd5019157..566c4dcd26f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/raf.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/ui/base/chart_base.html">
<link rel="import" href="/tracing/ui/base/mouse_tracker.html">
@@ -32,16 +33,17 @@ tr.exportTo('tr.ui.b', function() {
decorate: function() {
ChartBase.prototype.decorate.call(this);
- this.classList.add('chart-base-2d');
+ Polymer.dom(this).classList.add('chart-base-2d');
this.xScale_ = d3.scale.linear();
this.yScale_ = d3.scale.linear();
this.isYLogScale_ = false;
this.yLogScaleMin_ = undefined;
this.dataRange_ = new tr.b.Range();
-
+ this.hideXAxis_ = false;
+ this.hideYAxis_ = false;
this.data_ = [];
- this.seriesKeys_ = [];
- this.leftMargin_ = 50;
+ this.xAxisLabel_ = '';
+ this.yAxisLabel_ = '';
d3.select(this.chartAreaElement)
.append('g')
@@ -53,6 +55,40 @@ tr.exportTo('tr.ui.b', function() {
this.addEventListener('mousedown', this.onMouseDown_.bind(this));
},
+ get xAxisLabel() {
+ return this.xAxisLabel_;
+ },
+
+ set xAxisLabel(label) {
+ this.xAxisLabel_ = label;
+ },
+
+ get yAxisLabel() {
+ return this.yAxisLabel_;
+ },
+
+ set yAxisLabel(label) {
+ this.yAxisLabel_ = label;
+ },
+
+ get hideXAxis() {
+ return this.hideXAxis_;
+ },
+
+ set hideXAxis(h) {
+ this.hideXAxis_ = h;
+ this.updateContents_();
+ },
+
+ get hideYAxis() {
+ return this.hideYAxis_;
+ },
+
+ set hideYAxis(h) {
+ this.hideYAxis_ = h;
+ this.updateContents_();
+ },
+
get data() {
return this.data_;
},
@@ -109,23 +145,15 @@ tr.exportTo('tr.ui.b', function() {
return leftWidth * 0.5 + rightWidth * 0.5;
},
- getLegendKeys_: function() {
- if (this.seriesKeys_ &&
- this.seriesKeys_.length > 1)
- return this.seriesKeys_.slice();
- return [];
- },
-
updateSeriesKeys_: function() {
- // Accumulate the keys on each data point.
- var keySet = {};
+ // Don't clear seriesByKey_; the caller might have put state in it using
+ // getDataSeries() before setting data.
this.data_.forEach(function(datum) {
Object.keys(datum).forEach(function(key) {
if (this.isDatumFieldSeries_(key))
- keySet[key] = true;
+ this.getDataSeries(key);
}, this);
}, this);
- this.seriesKeys_ = Object.keys(keySet);
},
isDatumFieldSeries_: function(fieldName) {
@@ -149,11 +177,12 @@ tr.exportTo('tr.ui.b', function() {
// Y.
var yRange = new tr.b.Range();
- var keySet = new Set(this.seriesKeys_);
- for (var i = 0; i < this.data_.length; i++)
- for (var key in this.data_[i])
- if (keySet.has(key))
+ for (var i = 0; i < this.data_.length; i++) {
+ for (var key in this.data_[i]) {
+ if (!isNaN(Math.max(this.data_[i][key])))
yRange.addValue(this.data_[i][key]);
+ }
+ }
this.yScale_.range([height, 0]);
this.yScale_.domain([yRange.min, yRange.max]);
@@ -166,30 +195,46 @@ tr.exportTo('tr.ui.b', function() {
updateXAxis_: function(xAxis) {
xAxis.selectAll('*').remove();
xAxis[0][0].style.opacity = 0;
+ if (this.hideXAxis)
+ return;
+
+ this.drawXAxis_(xAxis);
+
+ var label = xAxis.append('text').attr('class', 'label');
+
+ tr.b.requestAnimationFrame(() => {
+ this.drawXAxisTicks_(xAxis);
+ this.drawXAxisLabel_(label);
+ });
+ },
+
+ drawXAxis_: function(xAxis) {
xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')')
.call(d3.svg.axis()
.scale(this.xScale_)
.orient('bottom'));
- window.requestAnimationFrame(function() {
- var previousRight = undefined;
- xAxis.selectAll('.tick')[0].forEach(function(tick) {
- var currentLeft = tick.transform.baseVal[0].matrix.e;
- if ((previousRight === undefined) ||
- (currentLeft > (previousRight + 3))) {
- var currentWidth = tick.getBBox().width;
- previousRight = currentLeft + currentWidth;
- } else {
- tick.style.opacity = 0;
- }
- });
- xAxis[0][0].style.opacity = 1;
- });
},
- getMargin_: function() {
- var margin = ChartBase.prototype.getMargin_.call(this);
- margin.left = this.leftMargin_;
- return margin;
+ drawXAxisLabel_: function(label) {
+ label
+ .attr('x', this.chartAreaSize.width + 16)
+ .attr('y', 8)
+ .text(this.xAxisLabel);
+ },
+
+ drawXAxisTicks_: function(xAxis) {
+ var previousRight = undefined;
+ xAxis.selectAll('.tick')[0].forEach(function(tick) {
+ var currentLeft = tick.transform.baseVal[0].matrix.e;
+ if ((previousRight === undefined) ||
+ (currentLeft > (previousRight + 3))) {
+ var currentWidth = tick.getBBox().width;
+ previousRight = currentLeft + currentWidth;
+ } else {
+ tick.style.opacity = 0;
+ }
+ });
+ xAxis[0][0].style.opacity = 1;
},
updateDataRange_: function() {
@@ -206,7 +251,7 @@ tr.exportTo('tr.ui.b', function() {
this.yLogScaleMin_ = undefined;
if (this.dataRange_.min !== undefined) {
var minValue = this.dataRange_.min;
- if (minValue == 0)
+ if (minValue === 0)
minValue = 1;
var onePowerLess = Math.floor(
@@ -218,7 +263,20 @@ tr.exportTo('tr.ui.b', function() {
updateYAxis_: function(yAxis) {
yAxis.selectAll('*').remove();
yAxis[0][0].style.opacity = 0;
+ if (this.hideYAxis)
+ return;
+
+ this.drawYAxis_(yAxis);
+ var label = yAxis.append('text').attr('class', 'label');
+
+ tr.b.requestAnimationFrame(() => {
+ this.drawYAxisTicks_(yAxis);
+ this.drawYAxisLabel_(label);
+ });
+ },
+
+ drawYAxis_: function(yAxis) {
var axisModifier = d3.svg.axis()
.scale(this.yScale_)
.orient('left');
@@ -227,7 +285,7 @@ tr.exportTo('tr.ui.b', function() {
if (this.yLogScaleMin_ === undefined)
return;
var minValue = this.dataRange_.min;
- if (minValue == 0)
+ if (minValue === 0)
minValue = 1;
var largestPower = Math.ceil(
@@ -247,29 +305,40 @@ tr.exportTo('tr.ui.b', function() {
}
yAxis.call(axisModifier);
+ },
- window.requestAnimationFrame(function() {
- var previousTop = undefined;
- var leftMargin = 0;
- yAxis.selectAll('.tick')[0].forEach(function(tick) {
- var bbox = tick.getBBox();
- leftMargin = Math.max(leftMargin, bbox.width);
- var currentTop = tick.transform.baseVal[0].matrix.f;
- var currentBottom = currentTop + bbox.height;
- if ((previousTop === undefined) ||
- (previousTop > (currentBottom + 3))) {
- previousTop = currentTop;
- } else {
- tick.style.opacity = 0;
- }
- });
- if (leftMargin > this.leftMargin_) {
- this.leftMargin_ = leftMargin;
- this.updateContents_();
+ drawYAxisLabel_: function(label) {
+ var labelWidthPx = Math.ceil(tr.ui.b.getSVGTextWidth(
+ this.chartAreaElement, this.yAxisLabel));
+ label
+ .attr('x', -labelWidthPx)
+ .attr('y', -8)
+ .text(this.yAxisLabel);
+ },
+
+ drawYAxisTicks_: function(yAxis) {
+ var previousTop = undefined;
+ var leftMargin = 0;
+ yAxis.selectAll('.tick')[0].forEach(function(tick) {
+ var bbox = tick.getBBox();
+ leftMargin = Math.max(leftMargin, bbox.width);
+ var currentTop = tick.transform.baseVal[0].matrix.f;
+ var currentBottom = currentTop + bbox.height;
+ if ((previousTop === undefined) ||
+ (previousTop > (currentBottom + 3))) {
+ previousTop = currentTop;
} else {
- yAxis[0][0].style.opacity = 1;
+ tick.style.opacity = 0;
}
- }.bind(this));
+ });
+
+ leftMargin = parseInt(Math.ceil(leftMargin));
+ if (leftMargin > this.margin.left) {
+ this.margin.left = leftMargin;
+ this.updateContents_();
+ } else {
+ yAxis[0][0].style.opacity = 1;
+ }
},
updateContents_: function() {
@@ -296,9 +365,9 @@ tr.exportTo('tr.ui.b', function() {
*/
getDataBySeriesKey_: function() {
var dataBySeriesKey = {};
- this.seriesKeys_.forEach(function(seriesKey) {
- dataBySeriesKey[seriesKey] = [];
- });
+ for (var [key, series] of this.seriesByKey_) {
+ dataBySeriesKey[key] = [];
+ }
this.data_.forEach(function(multiSeriesDatum, index) {
var x = this.getXForDatum_(multiSeriesDatum, index);
@@ -323,16 +392,27 @@ tr.exportTo('tr.ui.b', function() {
return dataBySeriesKey;
},
- getDataPointAtClientPoint_: function(clientX, clientY) {
+ getChartPointAtClientPoint_: function(clientPoint) {
var rect = this.getBoundingClientRect();
- var margin = this.margin;
- var x = clientX - rect.left - margin.left;
- var y = clientY - rect.top - margin.top;
- x = this.xScale_.invert(x);
- y = this.yScale_.invert(y);
- x = tr.b.clamp(x, this.xScale_.domain()[0], this.xScale_.domain()[1]);
- y = tr.b.clamp(y, this.yScale_.domain()[0], this.yScale_.domain()[1]);
- return {x: x, y: y};
+ return {
+ x: clientPoint.x - rect.left - this.margin.left,
+ y: clientPoint.y - rect.top - this.margin.top
+ };
+ },
+
+ getDataPointAtChartPoint_: function(chartPoint) {
+ return {
+ x: tr.b.clamp(this.xScale_.invert(chartPoint.x),
+ this.xScale_.domain()[0], this.xScale_.domain()[1]),
+ y: tr.b.clamp(this.yScale_.invert(chartPoint.y),
+ this.yScale_.domain()[0], this.yScale_.domain()[1])
+ };
+ },
+
+ getDataPointAtClientPoint_: function(clientX, clientY) {
+ var chartPoint = this.getChartPointAtClientPoint_(
+ {x: clientX, y: clientY});
+ return this.getDataPointAtChartPoint_(chartPoint);
},
prepareDataEvent_: function(mouseEvent, dataEvent) {
@@ -350,7 +430,7 @@ tr.exportTo('tr.ui.b', function() {
mouseEvent.stopPropagation();
var dataEvent = new tr.b.Event('item-mousedown');
dataEvent.button = mouseEvent.button;
- this.classList.add('updating-brushing-state');
+ Polymer.dom(this).classList.add('updating-brushing-state');
this.prepareDataEvent_(mouseEvent, dataEvent);
this.dispatchEvent(dataEvent);
},
@@ -373,7 +453,7 @@ tr.exportTo('tr.ui.b', function() {
dataEvent.button = button;
this.prepareDataEvent_(mouseEvent, dataEvent);
this.dispatchEvent(dataEvent);
- this.classList.remove('updating-brushing-state');
+ Polymer.dom(this).classList.remove('updating-brushing-state');
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html
index 4cde4b58bdd..5d2f799945e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html
@@ -65,6 +65,10 @@ tr.exportTo('tr.ui.b', function() {
var brushRectsSel = brushSel.selectAll('rect').data(brushes);
brushRectsSel.enter().append('rect');
brushRectsSel.exit().remove();
+ this.drawBrush_(brushRectsSel);
+ },
+
+ drawBrush_: function(brushRectsSel) {
brushRectsSel
.attr('x', function(d) {
return this.xScale_(d.min);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html
index 9de49183853..06469f68170 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html
@@ -9,7 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name='tr-ui-b-checkbox'>
+<dom-module id='tr-ui-b-checkbox'>
<template>
<style>
.inline {
@@ -20,11 +20,12 @@ found in the LICENSE file.
<input type="checkbox" id="checkbox" class="inline"/>
<div id="label" class="inline"></div>
</template>
-
<script>
'use strict';
Polymer({
+ is: 'tr-ui-b-checkbox',
+
created: function() {
this.needsInit_ = true;
this.defaultCheckedValue_ = undefined;
@@ -100,8 +101,7 @@ found in the LICENSE file.
this.checked_ = checked;
this.maybeUpdateElements_();
tr.b.Settings.set(this.settingsKey_, this.checked_);
- },
-
+ }
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html
index 261b15922bd..5b5d242b96b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/checkbox.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name='tr-ui-b-checkbox-picker'>
+<dom-module id='tr-ui-b-checkbox-picker'>
<template>
<style>
#container {
@@ -19,93 +19,91 @@ found in the LICENSE file.
<div id="container">
</div>
-
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.needsInit_ = true;
- this.settingsKey_ = undefined;
- this.is_ready_ = false;
- this.checkboxes_ = undefined;
- },
-
- ready: function() {
- this.is_ready_ = true;
- this.maybeInit_();
- this.maybeRenderCheckboxes_();
- },
-
- get settingsKey() {
- return this.settingsKey_;
- },
-
- set settingsKey(settingsKey) {
- if (!this.needsInit_)
- throw new Error('Already initialized.');
- this.settingsKey_ = settingsKey;
- this.maybeInit_();
- },
-
- maybeInit_: function() {
- if (!this.needsInit_)
- return;
- if (this.settingsKey_ === undefined)
- return;
- if (this.checkboxes_ === undefined)
- return;
-
- this.needsInit_ = false;
-
- for (var key in this.checkboxes_) {
- this.checkboxes_[key].defaultCheckedValue = false;
- this.checkboxes_[key].settingsKey = this.settingsKey_ + key;
- }
- },
-
- set items(items) {
- this.checkboxes_ = {};
- items.forEach(function(e) {
- if (e.key in this.checkboxes_)
- throw new Error(e.key + ' already exists');
- var checkboxEl = document.createElement('tr-ui-b-checkbox');
- checkboxEl.label = e.label;
- this.checkboxes_[e.key] = checkboxEl;
- }.bind(this));
- this.maybeInit_();
- this.maybeRenderCheckboxes_();
- },
-
- maybeRenderCheckboxes_: function() {
- if (!this.is_ready_)
- return;
- if (this.checkboxes_ === undefined)
- return;
- for (var key in this.checkboxes_)
- this.$.container.appendChild(this.checkboxes_[key]);
- },
-
- selectCheckbox: function(key) {
- if (!(key in this.checkboxes_))
- throw new Error(key + ' does not exists');
- this.checkboxes_[key].checked = true;
- },
-
- unselectCheckbox: function(key) {
- if (!(key in this.checkboxes_))
- throw new Error(key + ' does not exists');
- this.checkboxes_[key].checked = false;
- },
-
- get checkedKeys() {
- return Object.keys(this.checkboxes_).filter(function(k) {
- return this.checkboxes_[k].checked;
- }.bind(this));
- },
-
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-b-checkbox-picker',
+ created: function() {
+ this.needsInit_ = true;
+ this.settingsKey_ = undefined;
+ this.is_ready_ = false;
+ this.checkboxes_ = undefined;
+ },
+
+ ready: function() {
+ this.is_ready_ = true;
+ this.maybeInit_();
+ this.maybeRenderCheckboxes_();
+ },
+
+ get settingsKey() {
+ return this.settingsKey_;
+ },
+
+ set settingsKey(settingsKey) {
+ if (!this.needsInit_)
+ throw new Error('Already initialized.');
+ this.settingsKey_ = settingsKey;
+ this.maybeInit_();
+ },
+
+ maybeInit_: function() {
+ if (!this.needsInit_)
+ return;
+ if (this.settingsKey_ === undefined)
+ return;
+ if (this.checkboxes_ === undefined)
+ return;
+
+ this.needsInit_ = false;
+
+ for (var key in this.checkboxes_) {
+ this.checkboxes_[key].defaultCheckedValue = false;
+ this.checkboxes_[key].settingsKey = this.settingsKey_ + key;
+ }
+ },
+
+ set items(items) {
+ this.checkboxes_ = {};
+ items.forEach(function(e) {
+ if (e.key in this.checkboxes_)
+ throw new Error(e.key + ' already exists');
+ var checkboxEl = document.createElement('tr-ui-b-checkbox');
+ checkboxEl.label = e.label;
+ this.checkboxes_[e.key] = checkboxEl;
+ }.bind(this));
+ this.maybeInit_();
+ this.maybeRenderCheckboxes_();
+ },
+
+ maybeRenderCheckboxes_: function() {
+ if (!this.is_ready_)
+ return;
+ if (this.checkboxes_ === undefined)
+ return;
+ for (var key in this.checkboxes_)
+ Polymer.dom(this.$.container).appendChild(this.checkboxes_[key]);
+ },
+
+ selectCheckbox: function(key) {
+ if (!(key in this.checkboxes_))
+ throw new Error(key + ' does not exists');
+ this.checkboxes_[key].checked = true;
+ },
+
+ unselectCheckbox: function(key) {
+ if (!(key in this.checkboxes_))
+ throw new Error(key + ' does not exists');
+ this.checkboxes_[key].checked = false;
+ },
+
+ get checkedKeys() {
+ return Object.keys(this.checkboxes_).filter(function(k) {
+ return this.checkboxes_[k].checked;
+ }.bind(this));
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html
index 40d83361fb6..674696d898b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html
@@ -75,7 +75,7 @@ tr.b.unittest.testSuite(function() {
];
cp.selectCheckbox('Toyota');
cp.selectCheckbox('Tesla');
- container1.appendChild(cp);
+ Polymer.dom(container1).appendChild(cp);
this.addHTMLOutput(container1);
cp.unselectCheckbox('Tesla');
assert.deepEqual(cp.checkedKeys, ['Toyota']);
@@ -93,7 +93,7 @@ tr.b.unittest.testSuite(function() {
{key: 'Honda', label: 'I want to drive Honda'},
{key: 'Tesla', label: 'I want to drive electric car'},
];
- container2.appendChild(cp2);
+ Polymer.dom(container2).appendChild(cp2);
this.addHTMLOutput(container2);
assert.deepEqual(cp2.checkedKeys, ['Toyota']);
});
@@ -110,7 +110,7 @@ tr.b.unittest.testSuite(function() {
cp.settingsKey = 'checkbox-picker-test-one';
cp.selectCheckbox('Toyota');
cp.selectCheckbox('Tesla');
- container1.appendChild(cp);
+ Polymer.dom(container1).appendChild(cp);
this.addHTMLOutput(container1);
assert.deepEqual(cp.checkedKeys.sort(), ['Tesla', 'Toyota']);
@@ -126,7 +126,7 @@ tr.b.unittest.testSuite(function() {
{key: 'Honda', label: 'I want to drive Honda'},
{key: 'Tesla', label: 'I want to drive electric car'},
];
- container2.appendChild(cp2);
+ Polymer.dom(container2).appendChild(cp2);
this.addHTMLOutput(container2);
cp2.settingsKey = 'checkbox-picker-test-one';
assert.deepEqual(cp2.checkedKeys.sort(), ['Tesla', 'Toyota']);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html b/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html
index 3804b4b144c..791440def9e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
The colored square is typically filled with the color associated with
that label, using the getColorId* methods from base/color_scheme.
-->
-<polymer-element name="tr-ui-b-color-legend">
+<dom-module id='tr-ui-b-color-legend'>
<template>
<style>
:host {
@@ -30,50 +30,52 @@ that label, using the getColorId* methods from base/color_scheme.
<span id="square"></span>
<span id="label"></span>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- ready: function() {
- var blackSquareCharCode = 9632;
- this.$.square.innerText = String.fromCharCode(blackSquareCharCode);
- this.label_ = undefined;
+Polymer({
+ is: 'tr-ui-b-color-legend',
- this.compoundEventSelectionState_ =
- tr.model.CompoundEventSelectionState.NOT_SELECTED;
- },
+ ready: function() {
+ var blackSquareCharCode = 9632;
+ this.$.square.innerText = String.fromCharCode(blackSquareCharCode);
+ this.label_ = undefined;
- set compoundEventSelectionState(compoundEventSelectionState) {
- this.compoundEventSelectionState_ = compoundEventSelectionState;
- // TODO(nduca): Adjust appearance based on associated state.
- },
+ this.compoundEventSelectionState_ =
+ tr.model.CompoundEventSelectionState.NOT_SELECTED;
+ },
- get label() {
- return this.label_;
- },
+ set compoundEventSelectionState(compoundEventSelectionState) {
+ this.compoundEventSelectionState_ = compoundEventSelectionState;
+ // TODO(nduca): Adjust appearance based on associated state.
+ },
- set label(label) {
- if (label === undefined) {
- this.setLabelAndColorId(undefined, undefined);
- return;
- }
+ get label() {
+ return this.label_;
+ },
- var colorId = tr.b.ColorScheme.getColorIdForGeneralPurposeString(
- label);
- this.setLabelAndColorId(label, colorId);
- },
+ set label(label) {
+ if (label === undefined) {
+ this.setLabelAndColorId(undefined, undefined);
+ return;
+ }
- setLabelAndColorId: function(label, colorId) {
- this.label_ = label;
+ var colorId = tr.b.ColorScheme.getColorIdForGeneralPurposeString(
+ label);
+ this.setLabelAndColorId(label, colorId);
+ },
- this.$.label.textContent = '';
- this.$.label.appendChild(tr.ui.b.asHTMLOrTextNode(label));
+ setLabelAndColorId: function(label, colorId) {
+ this.label_ = label;
- if (colorId === undefined)
- this.$.square.style.color = 'initial';
- else
- this.$.square.style.color = tr.b.ColorScheme.colorsAsStrings[colorId];
- }
- });
- </script>
-</polymer-element>
+ Polymer.dom(this.$.label).textContent = '';
+ Polymer.dom(this.$.label).appendChild(tr.ui.b.asHTMLOrTextNode(label));
+
+ if (colorId === undefined)
+ this.$.square.style.color = 'initial';
+ else
+ this.$.square.style.color = tr.b.ColorScheme.colorsAsStrings[colorId];
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html
new file mode 100644
index 00000000000..74141d47b08
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html
@@ -0,0 +1,248 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2014 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/base/chart_base_2d_brushable_x.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.b', function() {
+ var ColorScheme = tr.b.ColorScheme;
+ var ChartBase2DBrushX = tr.ui.b.ChartBase2DBrushX;
+
+ // @constructor
+ var ColumnChart = tr.ui.b.define('column-chart', ChartBase2DBrushX);
+
+ ColumnChart.prototype = {
+ __proto__: ChartBase2DBrushX.prototype,
+
+ decorate: function() {
+ ChartBase2DBrushX.prototype.decorate.call(this);
+ Polymer.dom(this).classList.add('column-chart');
+
+ // ColumnChart allows bars to have arbitrary, non-uniform widths. Bars
+ // need not all be the same width. The width of each bar is automatically
+ // computed from the bar's x-coordinate and that of the next bar, which
+ // can not define the width of the last bar. This is the width (in the
+ // xScale's domain (as opposed to the xScale's range (which is measured in
+ // pixels))) of the last bar. When there are at least 2 bars, this is
+ // computed as the average width of the bars. When there is a single bar,
+ // this must default to a non-zero number so that the width of the only
+ // bar will not be zero.
+ this.xCushion_ = 1;
+
+ this.isStacked_ = false;
+ },
+
+ set isStacked(stacked) {
+ this.isStacked_ = true;
+ this.updateContents_();
+ },
+
+ get isStacked() {
+ return this.isStacked_;
+ },
+
+ isDatumFieldSeries_: function(fieldName) {
+ return fieldName !== 'x';
+ },
+
+ getXForDatum_: function(datum, index) {
+ return datum.x;
+ },
+
+ updateScales_: function() {
+ if (this.data_.length === 0)
+ return;
+
+ var xDifferences = 0;
+ var currentX = undefined;
+ var previousX = undefined;
+ var yRange = new tr.b.Range();
+ this.data_.forEach(function(datum, index) {
+ previousX = currentX;
+ currentX = this.getXForDatum_(datum, index);
+ if (previousX !== undefined) {
+ xDifferences += currentX - previousX;
+ }
+
+ for (var [key, series] of this.seriesByKey_) {
+ // Allow for sparse data
+ if (datum[key] !== undefined)
+ yRange.addValue(datum[key]);
+ }
+ }, this);
+
+ // X.
+ // Leave a cushion on the right so that the last rect doesn't
+ // exceed the chart boundaries. The last rect's width is set to the
+ // average width of the rects, which is chart.width / data.length.
+ var width = this.chartAreaSize.width;
+ this.xScale_.range([0, width]);
+ var domain = d3.extent(this.data_, this.getXForDatum_.bind(this));
+ if (this.data_.length > 1)
+ this.xCushion_ = xDifferences / (this.data_.length - 1);
+ this.xScale_.domain([domain[0], domain[1] + this.xCushion_]);
+
+ // Y.
+ this.yScale_.range([this.chartAreaSize.height, 0]);
+ this.yScale_.domain(this.getYScaleDomain_(yRange.min, yRange.max));
+ },
+
+ getYScaleDomain_: function(minValue, maxValue) {
+ if (!this.isStacked) {
+ return ChartBase2DBrushX.prototype.getYScaleDomain_.call(
+ this, minValue, maxValue);
+ }
+
+ var range = new tr.b.Range();
+ range.addValue(0);
+ this.data_.forEach(function(datum, index) {
+ var sum = 0;
+ for (var [key, series] of this.seriesByKey_) {
+ if (datum[key] === undefined)
+ continue;
+ sum += datum[key];
+ }
+ range.addValue(sum);
+ }, this);
+ return [range.min, range.max];
+ },
+
+ getStackedRectsForDatum_: function(datum, index) {
+ var stacks = [];
+ var bottom = this.yScale_.range()[0];
+ var sum = 0;
+ for (var [key, series] of this.seriesByKey_) {
+ if (datum[key] === undefined || !this.isSeriesEnabled(key))
+ continue;
+ sum += datum[key];
+ var heightPx = bottom - this.yScale_(sum);
+ bottom -= heightPx;
+ stacks.push({
+ key: key,
+ value: datum[key],
+ color: this.getDataSeries(key).color,
+ heightPx: heightPx,
+ topPx: bottom
+ });
+ }
+ return stacks;
+ },
+
+ getRectsForDatum_: function(datum, index) {
+ if (this.isStacked)
+ return this.getStackedRectsForDatum_(datum, index);
+
+ var stacks = [];
+ for (var [key, series] of this.seriesByKey_) {
+ if (datum[key] === undefined || !this.isSeriesEnabled(key))
+ continue;
+ var topPx = this.yScale_(Math.max(datum[key], this.getYScaleMin_()));
+ stacks.push({
+ key: key,
+ value: datum[key],
+ topPx: topPx,
+ heightPx: this.yScale_.range()[0] - topPx,
+ color: this.getDataSeries(key).color
+ });
+ }
+ stacks.sort(function(a, b) {
+ return b.topPx - a.topPx;
+ });
+ return stacks;
+ },
+
+ drawHoverValueBox_: function(rect) {
+ var seriesKeys = [...this.seriesByKey_.keys()];
+ var chartAreaSel = d3.select(this.chartAreaElement);
+ chartAreaSel.selectAll('.hover').remove();
+ var keyWidthPx = 0;
+ var keyHeightPx = 0;
+ if (seriesKeys.length > 1) {
+ keyWidthPx = tr.ui.b.getSVGTextWidth(
+ this.chartAreaElement, rect.key) + 5;
+ keyHeightPx = 16;
+ }
+ var valueWidthPx = tr.ui.b.getSVGTextWidth(
+ this.chartAreaElement, rect.value) + 5;
+ var valueHeightPx = 16;
+ var hoverLeftPx = rect.leftPx + (rect.widthPx / 2);
+
+ chartAreaSel
+ .append('rect')
+ .attr('class', 'hover')
+ .attr('fill', 'white')
+ .attr('x', hoverLeftPx)
+ .attr('y', rect.topPx)
+ .attr('width', Math.max(keyWidthPx, valueWidthPx))
+ .attr('height', keyHeightPx + valueHeightPx);
+
+ if (seriesKeys.length > 1) {
+ chartAreaSel
+ .append('text')
+ .attr('class', 'hover')
+ .attr('fill', rect.color)
+ .attr('x', hoverLeftPx + 2)
+ .attr('y', rect.topPx + keyHeightPx - 3)
+ .text(rect.key);
+ }
+
+ chartAreaSel
+ .append('text')
+ .attr('class', 'hover')
+ .attr('fill', rect.color)
+ .attr('x', hoverLeftPx + 2)
+ .attr('y', rect.topPx + keyHeightPx + valueHeightPx - 3)
+ .text(rect.value);
+ },
+
+ clearHoverValueBox_: function() {
+ d3.select(this.chartAreaElement).selectAll('.hover').remove();
+ },
+
+ drawRect_: function(rect, sel) {
+ sel.append('rect')
+ .attr('fill', rect.color)
+ .attr('x', rect.leftPx)
+ .attr('y', rect.topPx)
+ .attr('width', rect.widthPx)
+ .attr('height', rect.heightPx)
+ .on('mouseenter', this.drawHoverValueBox_.bind(this, rect))
+ .on('mouseleave', this.clearHoverValueBox_.bind(this));
+ },
+
+ updateDataContents_: function(dataSel) {
+ dataSel.selectAll('*').remove();
+ var chartAreaSel = d3.select(this.chartAreaElement);
+ var seriesKeys = [...this.seriesByKey_.keys()];
+ var rectsSel = dataSel.selectAll('path').data(seriesKeys);
+ this.data_.forEach(function(datum, index) {
+ var currentX = this.getXForDatum_(datum, index);
+ var width = undefined;
+ if (index < (this.data_.length - 1)) {
+ var nextX = this.getXForDatum_(this.data_[index + 1], index + 1);
+ width = nextX - currentX;
+ } else {
+ width = this.xCushion_;
+ }
+ for (var rect of this.getRectsForDatum_(datum, index)) {
+ rect.leftPx = this.xScale_(currentX);
+ rect.rightPx = this.xScale_(currentX + width);
+ rect.widthPx = rect.rightPx - rect.leftPx;
+ this.drawRect_(rect, rectsSel.enter());
+ }
+ }, this);
+ rectsSel.exit().remove();
+ }
+ };
+
+ return {
+ ColumnChart: ColumnChart,
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html
new file mode 100644
index 00000000000..d8a961350a4
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html
@@ -0,0 +1,295 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2014 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/base/column_chart.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('chartLegendKey', function() {
+ var key = document.createElement('tr-ui-b-chart-legend-key');
+ key.textContent = 'Lorem ipsum dolor sit amet';
+ key.color = 'red';
+ this.addHTMLOutput(key);
+
+ key = document.createElement('tr-ui-b-chart-legend-key');
+ key.textContent = 'ipsum dolor sit amet';
+ key.target = 'orange ipsum';
+ key.color = 'orange';
+ this.addHTMLOutput(key);
+ key.addEventListener('requestSelectionChange', function(e) {
+ console.debug(e);
+ });
+
+ key = document.createElement('tr-ui-b-chart-legend-key');
+ key.target = 'brown dolor';
+ key.color = 'brown';
+ key.textContent = 'dolor sit amet';
+ this.addHTMLOutput(key);
+ key.addEventListener('requestSelectionChange', function(e) {
+ console.debug(e);
+ });
+ });
+
+ test('instantiation_legendTargets', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.getDataSeries('lorem_ipsum').target = 'lorem_ipsumTarget';
+ chart.getDataSeries('qux').target = 'quxTarget';
+ chart.getDataSeries('lorem_ipsum').optional = true;
+ chart.getDataSeries('bar').optional = true;
+ chart.isStacked = true;
+ chart.hideXAxis = true;
+ chart.width = 140;
+ chart.height = 200;
+ chart.chartTitle = 'title';
+ chart.data = [{x: 0, foo: 3, lorem_ipsum: 5, bar: 1, qux: 2}];
+ this.addHTMLOutput(chart);
+ chart.addEventListener('requestSelectionChange', function(e) {
+ console.debug(e);
+ });
+
+ assert.isDefined(tr.b.findDeepElementMatchingPredicate(
+ chart, function(element) {
+ return element.tagName === 'TR-UI-B-CHART-LEGEND-KEY' &&
+ element.textContent === 'lorem_ipsum' &&
+ element.target === 'lorem_ipsumTarget';
+ }));
+ });
+
+ test('instantiation_singleSeries', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.xAxisLabel = 'ms';
+ chart.yAxisLabel = '#';
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, value: 100},
+ {x: 20, value: 110},
+ {x: 30, value: 100},
+ {x: 40, value: 50}
+ ];
+ chart.data = data;
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_singleDatum', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 0, value: 100},
+ ];
+ chart.data = data;
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_stacked', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.isStacked = true;
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'title';
+ var data = [
+ {x: 10, foo: 10, bar: 5, qux: 7},
+ {x: 20, foo: 11, bar: 6, qux: 3},
+ {x: 30, foo: 10, bar: 4, qux: 8},
+ {x: 40, foo: 5, bar: 1, qux: 2}
+ ];
+ chart.data = data;
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_singleSeries_yLogScale', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.isYLogScale = true;
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, value: 100},
+ {x: 20, value: 10},
+ {x: 30, value: 1},
+ {x: 40, value: 0.1},
+ {x: 50, value: 0.01},
+ {x: 60, value: 0.001}
+ ];
+ chart.data = data;
+ this.addHTMLOutput(chart);
+ });
+
+ test('undefined', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ assert.throws(function() {
+ chart.data = undefined;
+ });
+ });
+
+ test('instantiation_twoSeries', function() {
+ var chart = new tr.ui.b.ColumnChart();
+
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, alpha: 100, beta: 50},
+ {x: 20, alpha: 110, beta: 75},
+ {x: 30, alpha: 100, beta: 125},
+ {x: 40, alpha: 50, beta: 125}
+ ];
+ chart.data = data;
+
+ var r = new tr.b.Range();
+ r.addValue(20);
+ r.addValue(40);
+ chart.brushedRange = r;
+
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_twoSeries_yLogScale', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.isYLogScale = true;
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, alpha: 100, beta: 50},
+ {x: 20, alpha: 110, beta: 75},
+ {x: 30, alpha: 100, beta: 125},
+ {x: 40, alpha: 50, beta: 125}
+ ];
+ chart.data = data;
+
+ var r = new tr.b.Range();
+ r.addValue(20);
+ r.addValue(40);
+ chart.brushedRange = r;
+
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_twoSparseSeriesWithFirstValueSparse', function() {
+ var chart = new tr.ui.b.ColumnChart();
+
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, alpha: 20, beta: undefined},
+ {x: 20, alpha: undefined, beta: 10},
+ {x: 30, alpha: 10, beta: undefined},
+ {x: 45, alpha: undefined, beta: 20},
+ {x: 50, alpha: 25, beta: 30}
+ ];
+ chart.data = data;
+
+ this.addHTMLOutput(chart);
+ });
+
+ test('instantiation_twoSparseSeriesWithFirstValueNotSparse', function() {
+ var chart = new tr.ui.b.ColumnChart();
+
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, alpha: 20, beta: 40},
+ {x: 20, alpha: undefined, beta: 10},
+ {x: 30, alpha: 10, beta: undefined},
+ {x: 45, alpha: undefined, beta: 20},
+ {x: 50, alpha: 30, beta: undefined}
+ ];
+ chart.data = data;
+
+ this.addHTMLOutput(chart);
+ });
+
+ test('brushRangeFromIndices', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ var data = [
+ {x: 10, value: 50},
+ {x: 30, value: 60},
+ {x: 70, value: 70},
+ {x: 80, value: 80},
+ {x: 120, value: 90}
+ ];
+ chart.data = data;
+ var r = new tr.b.Range();
+
+ // Range min should be 10.
+ r = chart.computeBrushRangeFromIndices(-2, 1);
+ assert.equal(r.min, 10);
+
+ // Range max should be 120.
+ r = chart.computeBrushRangeFromIndices(3, 10);
+ assert.equal(r.max, 120);
+
+ // Range should be [10, 120]
+ r = chart.computeBrushRangeFromIndices(-2, 10);
+ assert.equal(r.min, 10);
+ assert.equal(r.max, 120);
+
+ // Range should be [20, 100]
+ r = chart.computeBrushRangeFromIndices(1, 3);
+ assert.equal(r.min, 20);
+ assert.equal(r.max, 100);
+ });
+
+ test('instantiation_interactiveBrushing', function() {
+ var chart = new tr.ui.b.ColumnChart();
+ chart.width = 400;
+ chart.height = 200;
+ chart.chartTitle = 'Chart title';
+ var data = [
+ {x: 10, value: 50},
+ {x: 20, value: 60},
+ {x: 30, value: 80},
+ {x: 40, value: 20},
+ {x: 50, value: 30},
+ {x: 60, value: 20},
+ {x: 70, value: 15},
+ {x: 80, value: 20}
+ ];
+ chart.data = data;
+
+ var mouseDownX = undefined;
+ var curMouseX = undefined;
+
+ function updateBrushedRange() {
+ if (mouseDownX === undefined || (mouseDownX === curMouseX)) {
+ chart.brushedRange = new tr.b.Range();
+ return;
+ }
+ var r = new tr.b.Range();
+ r.min = Math.min(mouseDownX, curMouseX);
+ r.max = Math.max(mouseDownX, curMouseX);
+ chart.brushedRange = r;
+ }
+
+ chart.addEventListener('item-mousedown', function(e) {
+ mouseDownX = e.x;
+ curMouseX = e.x;
+ updateBrushedRange();
+ });
+ chart.addEventListener('item-mousemove', function(e) {
+ if (e.button === undefined)
+ return;
+ curMouseX = e.x;
+ updateBrushedRange();
+ });
+ chart.addEventListener('item-mouseup', function(e) {
+ curMouseX = e.x;
+ updateBrushedRange();
+ });
+ this.addHTMLOutput(chart);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html
index 11ed53a5fda..870f266b9aa 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html
@@ -21,7 +21,7 @@ tr.exportTo('tr.ui.b', function() {
var ContainerThatDecoratesItsChildren = tr.ui.b.define('div');
ContainerThatDecoratesItsChildren.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.observer_ = new WebKitMutationObserver(this.didMutate_.bind(this));
@@ -35,34 +35,35 @@ tr.exportTo('tr.ui.b', function() {
},
appendChild: function(x) {
- HTMLUnknownElement.prototype.appendChild.call(this, x);
+ HTMLDivElement.prototype.appendChild.call(this, x);
this.didMutate_(this.observer_.takeRecords());
},
insertBefore: function(x, y) {
- HTMLUnknownElement.prototype.insertBefore.call(this, x, y);
+ HTMLDivElement.prototype.insertBefore.call(this, x, y);
this.didMutate_(this.observer_.takeRecords());
},
removeChild: function(x) {
- HTMLUnknownElement.prototype.removeChild.call(this, x);
+ HTMLDivElement.prototype.removeChild.call(this, x);
this.didMutate_(this.observer_.takeRecords());
},
replaceChild: function(x, y) {
- HTMLUnknownElement.prototype.replaceChild.call(this, x, y);
+ HTMLDivElement.prototype.replaceChild.call(this, x, y);
this.didMutate_(this.observer_.takeRecords());
},
onSetTextContent_: function(textContent) {
- if (textContent != '')
+ if (textContent !== '')
throw new Error('textContent can only be set to \'\'.');
this.clear();
},
clear: function() {
- while (this.lastChild)
- HTMLUnknownElement.prototype.removeChild.call(this, this.lastChild);
+ while (Polymer.dom(this).lastChild)
+ HTMLDivElement.prototype.removeChild.call(
+ this, Polymer.dom(this).lastChild);
this.didMutate_(this.observer_.takeRecords());
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html
index 0f7ff710061..23e53eab9d0 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html
@@ -38,9 +38,9 @@ tr.b.unittest.testSuite(function() {
test('add', function() {
var container = new SimpleContainer();
- container.appendChild(createChild());
- container.appendChild(createChild());
- container.appendChild(createChild());
+ Polymer.dom(container).appendChild(createChild());
+ Polymer.dom(container).appendChild(createChild());
+ Polymer.dom(container).appendChild(createChild());
assert.isTrue(container.children[0].decorated);
assert.isTrue(container.children[1].decorated);
assert.isTrue(container.children[2].decorated);
@@ -49,15 +49,15 @@ tr.b.unittest.testSuite(function() {
test('clearUsingTextContent', function() {
var c0 = createChild();
var container = new SimpleContainer();
- container.appendChild(c0);
- container.textContent = '';
+ Polymer.dom(container).appendChild(c0);
+ Polymer.dom(container).textContent = '';
assert.isFalse(c0.decorated);
});
test('clear', function() {
var c0 = createChild();
var container = new SimpleContainer();
- container.appendChild(c0);
+ Polymer.dom(container).appendChild(c0);
container.clear();
assert.isFalse(c0.decorated);
});
@@ -66,8 +66,8 @@ tr.b.unittest.testSuite(function() {
var c0 = createChild();
var c1 = createChild();
var container = new SimpleContainer();
- container.appendChild(c1);
- container.insertBefore(c0, c1);
+ Polymer.dom(container).appendChild(c1);
+ Polymer.dom(container).insertBefore(c0, c1);
assert.isTrue(c0.decorated);
assert.isTrue(c1.decorated);
});
@@ -76,9 +76,9 @@ tr.b.unittest.testSuite(function() {
var c0 = createChild();
var c1 = createChild();
var container = new SimpleContainer();
- container.appendChild(c1);
- container.appendChild(c0);
- container.insertBefore(c0, c1);
+ Polymer.dom(container).appendChild(c1);
+ Polymer.dom(container).appendChild(c0);
+ Polymer.dom(container).insertBefore(c0, c1);
assert.isTrue(c0.decorated);
assert.isTrue(c1.decorated);
});
@@ -87,8 +87,8 @@ tr.b.unittest.testSuite(function() {
var c0 = createChild();
var c1 = createChild();
var container = new SimpleContainer();
- container.appendChild(c0);
- container.replaceChild(c1, c0);
+ Polymer.dom(container).appendChild(c0);
+ Polymer.dom(container).replaceChild(c1, c0);
assert.isFalse(c0.decorated);
assert.isTrue(c1.decorated);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html b/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html
index ed4c962a25e..bce0554c512 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html
@@ -4,4 +4,6 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<script src="/tracing/ui/base/d3_preload.js"></script>
<script src="/d3.min.js"></script>
+<script src="/tracing/ui/base/d3_postload.js"></script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js
new file mode 100644
index 00000000000..94cefdb15f9
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js
@@ -0,0 +1,8 @@
+/* Copyright (c) 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+'use strict';
+
+(function(window) {
+ window.define = undefined;
+}).call(this, this);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js
new file mode 100644
index 00000000000..57548f1d175
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js
@@ -0,0 +1,11 @@
+/* Copyright (c) 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+'use strict';
+
+(function(window) {
+ window.define = function(x) {
+ window.d3 = x;
+ };
+ window.define.amd = true;
+})(this);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html
index 6476dee1af1..f715938d86c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html
@@ -5,26 +5,32 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/base.html">
+
<script>
'use strict';
tr.exportTo('tr.b', function() {
function _iterateElementDeeplyImpl(element, cb, thisArg, includeElement) {
- if (includeElement) {
- if (cb.call(thisArg, element))
- return true;
- }
+ if (includeElement && cb.call(thisArg, element))
+ return true;
- if (element.shadowRoot) {
- if (_iterateElementDeeplyImpl(element.shadowRoot, cb, thisArg, false))
- return true;
+ if (element.root &&
+ element.root !== element &&
+ _iterateElementDeeplyImpl(element.root, cb, thisArg, false)) {
+ // Some elements, most notably Polymer template dom-repeat='...'
+ // elements, are their own shadow root. Make sure that we avoid infinite
+ // recursion by avoiding these elements.
+ return true;
}
- for (var i = 0; i < element.children.length; i++) {
- if (_iterateElementDeeplyImpl(element.children[i], cb, thisArg, true))
+ var children = Polymer.dom(element).children;
+ for (var i = 0; i < children.length; i++)
+ if (_iterateElementDeeplyImpl(children[i], cb, thisArg, true))
return true;
- }
+
+ return false;
}
+
function iterateElementDeeply(element, cb, thisArg) {
_iterateElementDeeplyImpl(element, cb, thisArg, false);
}
@@ -69,7 +75,7 @@ tr.exportTo('tr.b', function() {
return findDeepElementMatchingPredicate(element, function(element) {
if (element.children.length !== 0)
return false;
- return re.test(element.textContent);
+ return re.test(Polymer.dom(element).textContent);
});
}
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html
index fa0d843e106..38156654ef0 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html
@@ -7,45 +7,63 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/deep_utils.html">
+<dom-module id='tr-ui-b-deep-utils-test-a'>
+ <template>
+ <div></div>
+ </template>
+</dom-module>
+<dom-module id='tr-ui-b-deep-utils-test-b'>
+ <template>
+ <div></div>
+ </template>
+</dom-module>
+<dom-module id='tr-ui-b-deep-utils-test-c'>
+ <template>
+ <tr-ui-b-deep-utils-test-b class='x'></tr-ui-b-deep-utils-test-b>
+ <tr-ui-b-deep-utils-test-a class='x'></tr-ui-b-deep-utils-test-a>
+ <tr-ui-b-deep-utils-test-a class='x'></tr-ui-b-deep-utils-test-a>
+ </template>
+</dom-module>
+<dom-module id='tr-ui-b-deep-utils-test-d'>
+ <template>
+ <tr-ui-b-deep-utils-test-c></tr-ui-b-deep-utils-test-c>
+ </template>
+</dom-module>
<script>
'use strict';
-tr.b.unittest.testSuite(function() {
- function createElement(tagName, opt_class) {
- var el = document.createElement(tagName);
- if (opt_class)
- el.className = opt_class;
- return el;
- }
+Polymer({
+ is: 'tr-ui-b-deep-utils-test-a'
+});
- test('testFindDeepElementMatching', function() {
- var a = createElement('a');
- var a_ = a.createShadowRoot();
+Polymer({
+ is: 'tr-ui-b-deep-utils-test-b'
+});
- var b = createElement('b');
- a_.appendChild(b);
+Polymer({
+ is: 'tr-ui-b-deep-utils-test-c'
+});
- var b_ = b.createShadowRoot();
- b_.appendChild(createElement('c', 'x'));
+Polymer({
+ is: 'tr-ui-b-deep-utils-test-d'
+});
- var m = tr.b.findDeepElementMatching(a, 'c.x');
- assert.equal(m, b_.children[0]);
+tr.b.unittest.testSuite(function() {
+ test('testFindDeepElementMatching', function() {
+ var d = document.createElement('tr-ui-b-deep-utils-test-d');
+
+ var b = tr.b.findDeepElementMatching(d, 'tr-ui-b-deep-utils-test-b.x');
+ assert.isDefined(b);
+ assert.equal(b.tagName, 'TR-UI-B-DEEP-UTILS-TEST-B');
});
test('testFindDeepElementsMatching', function() {
- var a = createElement('a');
- var a_ = a.createShadowRoot();
-
- var b = createElement('b');
- a_.appendChild(b);
-
- var b_ = b.createShadowRoot();
- b_.appendChild(createElement('c', 'x'));
- b_.appendChild(createElement('c', 'x'));
+ var d = document.createElement('tr-ui-b-deep-utils-test-d');
- var m = tr.b.findDeepElementsMatching(a, 'c.x');
- assert.equal(m[0], b_.children[0]);
- assert.equal(m[1], b_.children[1]);
+ var a = tr.b.findDeepElementsMatching(d, 'tr-ui-b-deep-utils-test-a.x');
+ assert.isDefined(a);
+ assert.equal(a[0].tagName, 'TR-UI-B-DEEP-UTILS-TEST-A');
+ assert.equal(a[1].tagName, 'TR-UI-B-DEEP-UTILS-TEST-A');
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html
index 02af70a52fc..b2ced31ed2a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html
@@ -28,12 +28,14 @@ tr.exportTo('tr.ui.b', function() {
if (opt_dictionary) {
if (opt_dictionary.className)
spanEl.className = opt_dictionary.className;
- if (opt_dictionary.textContent)
- spanEl.textContent = opt_dictionary.textContent;
+ if (opt_dictionary.textContent) {
+ Polymer.dom(spanEl).textContent =
+ opt_dictionary.textContent;
+ }
if (opt_dictionary.tooltip)
spanEl.title = opt_dictionary.tooltip;
if (opt_dictionary.parent)
- opt_dictionary.parent.appendChild(spanEl);
+ Polymer.dom(opt_dictionary.parent).appendChild(spanEl);
if (opt_dictionary.bold)
spanEl.style.fontWeight = 'bold';
if (opt_dictionary.italic)
@@ -48,7 +50,7 @@ tr.exportTo('tr.ui.b', function() {
spanEl.style.color = opt_dictionary.color;
}
return spanEl;
- };
+ }
function createDiv(opt_dictionary) {
var divEl = document.createElement('div');
@@ -56,19 +58,20 @@ tr.exportTo('tr.ui.b', function() {
if (opt_dictionary.className)
divEl.className = opt_dictionary.className;
if (opt_dictionary.parent)
- opt_dictionary.parent.appendChild(divEl);
+ Polymer.dom(opt_dictionary.parent).appendChild(divEl);
if (opt_dictionary.textContent)
- divEl.textContent = opt_dictionary.textContent;
+ Polymer.dom(divEl).textContent =
+ opt_dictionary.textContent;
if (opt_dictionary.maxWidth)
divEl.style.maxWidth = opt_dictionary.maxWidth;
}
return divEl;
- };
+ }
function createScopedStyle(styleContent) {
var styleEl = document.createElement('style');
styleEl.scoped = true;
- styleEl.innerHTML = styleContent;
+ Polymer.dom(styleEl).innerHTML = styleContent;
return styleEl;
}
@@ -98,10 +101,10 @@ tr.exportTo('tr.ui.b', function() {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var optionEl = document.createElement('option');
- optionEl.textContent = item.label;
+ Polymer.dom(optionEl).textContent = item.label;
optionEl.targetPropertyValue = item.value;
optionEl.item = item;
- selectorEl.appendChild(optionEl);
+ Polymer.dom(selectorEl).appendChild(optionEl);
}
function onChange(e) {
var value = selectorEl.selectedOptions[0].targetPropertyValue;
@@ -119,7 +122,7 @@ tr.exportTo('tr.ui.b', function() {
for (var i = 0; i < selectorEl.children.length; i++) {
var value = selectorEl.children[i].targetPropertyValue;
if (valuesEqual(value, v)) {
- var changed = selectorEl.selectedIndex != i;
+ var changed = selectorEl.selectedIndex !== i;
if (changed) {
selectorEl.selectedIndex = i;
onChange();
@@ -152,8 +155,8 @@ tr.exportTo('tr.ui.b', function() {
function createEditCategorySpan(optionGroupEl, targetEl) {
var spanEl = createSpan({className: 'edit-categories'});
- spanEl.textContent = 'Edit categories';
- spanEl.classList.add('labeled-option');
+ Polymer.dom(spanEl).textContent = 'Edit categories';
+ Polymer.dom(spanEl).classList.add('labeled-option');
spanEl.addEventListener('click', function() {
targetEl.onClickEditCategories();
@@ -180,9 +183,9 @@ tr.exportTo('tr.ui.b', function() {
var radioEl = document.createElement('input');
radioEl.type = 'radio';
- radioEl.setAttribute('id', id);
- radioEl.setAttribute('name', 'category-presets-group');
- radioEl.setAttribute('value', item.value);
+ Polymer.dom(radioEl).setAttribute('id', id);
+ Polymer.dom(radioEl).setAttribute('name', 'category-presets-group');
+ Polymer.dom(radioEl).setAttribute('value', item.value);
radioEl.addEventListener('change', onChange.bind(radioEl, targetEl,
targetElProperty,
settingsKey));
@@ -190,12 +193,12 @@ tr.exportTo('tr.ui.b', function() {
radioEl.checked = true;
var labelEl = document.createElement('label');
- labelEl.textContent = item.label;
- labelEl.setAttribute('for', id);
+ Polymer.dom(labelEl).textContent = item.label;
+ Polymer.dom(labelEl).setAttribute('for', id);
var spanEl = createSpan({className: 'labeled-option'});
- spanEl.appendChild(radioEl);
- spanEl.appendChild(labelEl);
+ Polymer.dom(spanEl).appendChild(radioEl);
+ Polymer.dom(spanEl).appendChild(labelEl);
spanEl.__defineSetter__('checked', function(opt_bool) {
var changed = radioEl.checked !== (!!opt_bool);
@@ -209,15 +212,16 @@ tr.exportTo('tr.ui.b', function() {
return radioEl.checked;
});
- optionGroupEl.appendChild(spanEl);
+ Polymer.dom(optionGroupEl).appendChild(spanEl);
}
- optionGroupEl.appendChild(createEditCategorySpan(optionGroupEl, targetEl));
+ Polymer.dom(optionGroupEl).appendChild(
+ createEditCategorySpan(optionGroupEl, targetEl));
// Since this option group element is not yet added to the tree,
// querySelector will fail during updateEditCategoriesStatus_ call.
// Hence, creating the element with the 'expanded' classlist category
// added, if last selected value was 'Manual' selection.
if (!initialValue.length)
- optionGroupEl.classList.add('categories-expanded');
+ Polymer.dom(optionGroupEl).classList.add('categories-expanded');
targetEl[targetElProperty] = initialValue;
return optionGroupEl;
@@ -230,13 +234,18 @@ tr.exportTo('tr.ui.b', function() {
var buttonEl = document.createElement('input');
buttonEl.type = 'checkbox';
- var initialValue = tr.b.Settings.get(settingsKey, defaultValue);
- buttonEl.checked = !!initialValue;
+ var initialValue = defaultValue;
+ if (settingsKey !== undefined) {
+ initialValue = tr.b.Settings.get(settingsKey, defaultValue);
+ buttonEl.checked = !!initialValue;
+ }
if (targetEl)
targetEl[targetElProperty] = initialValue;
function onChange() {
- tr.b.Settings.set(settingsKey, buttonEl.checked);
+ if (settingsKey !== undefined) {
+ tr.b.Settings.set(settingsKey, buttonEl.checked);
+ }
if (targetEl)
targetEl[targetElProperty] = buttonEl.checked;
if (opt_changeCb)
@@ -248,13 +257,13 @@ tr.exportTo('tr.ui.b', function() {
var id = '#checkbox-' + nextCheckboxId++;
var spanEl = createSpan({className: 'labeled-checkbox'});
- buttonEl.setAttribute('id', id);
+ Polymer.dom(buttonEl).setAttribute('id', id);
var labelEl = document.createElement('label');
- labelEl.textContent = label;
- labelEl.setAttribute('for', id);
- spanEl.appendChild(buttonEl);
- spanEl.appendChild(labelEl);
+ Polymer.dom(labelEl).textContent = label;
+ Polymer.dom(labelEl).setAttribute('for', id);
+ Polymer.dom(spanEl).appendChild(buttonEl);
+ Polymer.dom(spanEl).appendChild(labelEl);
spanEl.__defineSetter__('checked', function(opt_bool) {
var changed = buttonEl.checked !== (!!opt_bool);
@@ -309,8 +318,8 @@ tr.exportTo('tr.ui.b', function() {
function isElementAttachedToDocument(el) {
var cur = el;
- while (cur.parentNode)
- cur = cur.parentNode;
+ while (Polymer.dom(cur).parentNode)
+ cur = Polymer.dom(cur).parentNode;
return (cur === el.ownerDocument || cur.nodeName === '#document-fragment');
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html
index 64ba68ba36f..61ca370c5be 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html
@@ -9,7 +9,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var THIS_DOC = document._currentScript.ownerDocument;
+ var THIS_DOC = document.currentScript.ownerDocument;
test('simpleSpanAndDiv', function() {
var divEl = tr.ui.b.createDiv({
@@ -21,9 +21,10 @@ tr.b.unittest.testSuite(function() {
textContent: testText,
parent: divEl
});
- var eltInDocument = document.querySelector('.a-div-class>.a-span-class');
- assert.equal(eltInDocument.textContent, testText);
- eltInDocument.parentElement.removeChild(eltInDocument);
+ var eltInDocument = Polymer.dom(document)
+ .querySelector('.a-div-class>.a-span-class');
+ assert.equal(Polymer.dom(eltInDocument).textContent, testText);
+ Polymer.dom(eltInDocument.parentElement).removeChild(eltInDocument);
});
test('createSpan_ownerDocument', function() {
@@ -126,13 +127,13 @@ tr.b.unittest.testSuite(function() {
// Default owner document.
var node = tr.ui.b.asHTMLOrTextNode('Hello, World!');
assert.instanceOf(node, Node);
- assert.equal(node.textContent, 'Hello, World!');
+ assert.equal(Polymer.dom(node).textContent, 'Hello, World!');
assert.strictEqual(node.ownerDocument, document);
// Custom owner document.
var node = tr.ui.b.asHTMLOrTextNode('Bye, World!', THIS_DOC);
assert.instanceOf(node, Node);
- assert.equal(node.textContent, 'Bye, World!');
+ assert.equal(Polymer.dom(node).textContent, 'Bye, World!');
assert.strictEqual(node.ownerDocument, THIS_DOC);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html
index d919bbbad93..405f9538f35 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name="tr-ui-b-drag-handle">
+<dom-module id="tr-ui-b-drag-handle">
<template>
<style>
:host {
@@ -42,143 +42,145 @@ found in the LICENSE file.
width: 7px;
}
</style>
+ <div></div>
</template>
- <script>
- 'use strict';
-
- Polymer({
- __proto__: HTMLDivElement.prototype,
-
- created: function() {
- this.lastMousePos_ = 0;
- this.onMouseMove_ = this.onMouseMove_.bind(this);
- this.onMouseUp_ = this.onMouseUp_.bind(this);
- this.addEventListener('mousedown', this.onMouseDown_);
- this.target_ = undefined;
- this.horizontal = true;
- this.observer_ = new WebKitMutationObserver(
- this.didTargetMutate_.bind(this));
- this.targetSizesByModeKey_ = {};
- },
-
- get modeKey_() {
- return this.target_.className == '' ? '.' : this.target_.className;
- },
-
- get target() {
- return this.target_;
- },
-
- set target(target) {
- this.observer_.disconnect();
- this.target_ = target;
- if (!this.target_)
- return;
- this.observer_.observe(this.target_, {
- attributes: true,
- attributeFilter: ['class']
- });
- },
-
- get horizontal() {
- return this.horizontal_;
- },
-
- set horizontal(h) {
- this.horizontal_ = h;
- if (this.horizontal_)
- this.className = 'horizontal-drag-handle';
- else
- this.className = 'vertical-drag-handle';
- },
-
- get vertical() {
- return !this.horizontal_;
- },
-
- set vertical(v) {
- this.horizontal = !v;
- },
-
- forceMutationObserverFlush_: function() {
- var records = this.observer_.takeRecords();
- if (records.length)
- this.didTargetMutate_(records);
- },
-
- didTargetMutate_: function(e) {
- var modeSize = this.targetSizesByModeKey_[this.modeKey_];
- if (modeSize !== undefined) {
- this.setTargetSize_(modeSize);
- return;
- }
-
- // If we hadn't previously sized the target, then just remove any manual
- // sizing that we applied.
- this.target_.style[this.targetStyleKey_] = '';
- },
-
- get targetStyleKey_() {
- return this.horizontal_ ? 'height' : 'width';
- },
-
- getTargetSize_: function() {
- // If style is not set, start off with computed height.
- var targetStyleKey = this.targetStyleKey_;
- if (!this.target_.style[targetStyleKey]) {
- this.target_.style[targetStyleKey] =
- window.getComputedStyle(this.target_)[targetStyleKey];
- }
- var size = parseInt(this.target_.style[targetStyleKey]);
- this.targetSizesByModeKey_[this.modeKey_] = size;
- return size;
- },
-
- setTargetSize_: function(s) {
- this.target_.style[this.targetStyleKey_] = s + 'px';
- this.targetSizesByModeKey_[this.modeKey_] = s;
- },
-
- applyDelta_: function(delta) {
- // Apply new size to the container.
- var curSize = this.getTargetSize_();
- var newSize;
- if (this.target_ === this.nextElementSibling) {
- newSize = curSize + delta;
- } else {
- newSize = curSize - delta;
- }
- this.setTargetSize_(newSize);
- },
-
- onMouseMove_: function(e) {
- // Compute the difference in height position.
- var curMousePos = this.horizontal_ ? e.clientY : e.clientX;
- var delta = this.lastMousePos_ - curMousePos;
-
- this.applyDelta_(delta);
-
- this.lastMousePos_ = curMousePos;
- e.preventDefault();
- return true;
- },
-
- onMouseDown_: function(e) {
- if (!this.target_)
- return;
- this.forceMutationObserverFlush_();
- this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX;
- document.addEventListener('mousemove', this.onMouseMove_);
- document.addEventListener('mouseup', this.onMouseUp_);
- e.preventDefault();
- return true;
- },
-
- onMouseUp_: function(e) {
- document.removeEventListener('mousemove', this.onMouseMove_);
- document.removeEventListener('mouseup', this.onMouseUp_);
- e.preventDefault();
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-b-drag-handle',
+
+ created: function() {
+ this.lastMousePos_ = 0;
+ this.onMouseMove_ = this.onMouseMove_.bind(this);
+ this.onMouseUp_ = this.onMouseUp_.bind(this);
+ this.addEventListener('mousedown', this.onMouseDown_);
+ this.target_ = undefined;
+ this.horizontal = true;
+ this.observer_ = new WebKitMutationObserver(
+ this.didTargetMutate_.bind(this));
+ this.targetSizesByModeKey_ = {};
+ },
+
+ get modeKey_() {
+ return this.target_.className === '' ? '.' : this.target_.className;
+ },
+
+ get target() {
+ return this.target_;
+ },
+
+ set target(target) {
+ this.observer_.disconnect();
+ this.target_ = target;
+ if (!this.target_)
+ return;
+ this.observer_.observe(this.target_, {
+ attributes: true,
+ attributeFilter: ['class']
+ });
+ },
+
+ get horizontal() {
+ return this.horizontal_;
+ },
+
+ set horizontal(h) {
+ this.horizontal_ = h;
+ if (this.horizontal_)
+ this.className = 'horizontal-drag-handle';
+ else
+ this.className = 'vertical-drag-handle';
+ },
+
+ get vertical() {
+ return !this.horizontal_;
+ },
+
+ set vertical(v) {
+ this.horizontal = !v;
+ },
+
+ forceMutationObserverFlush_: function() {
+ var records = this.observer_.takeRecords();
+ if (records.length)
+ this.didTargetMutate_(records);
+ },
+
+ didTargetMutate_: function(e) {
+ var modeSize = this.targetSizesByModeKey_[this.modeKey_];
+ if (modeSize !== undefined) {
+ this.setTargetSize_(modeSize);
+ return;
}
- });
- </script>
-</polymer-element>
+
+ // If we hadn't previously sized the target, then just remove any manual
+ // sizing that we applied.
+ this.target_.style[this.targetStyleKey_] = '';
+ },
+
+ get targetStyleKey_() {
+ return this.horizontal_ ? 'height' : 'width';
+ },
+
+ getTargetSize_: function() {
+ // If style is not set, start off with computed height.
+ var targetStyleKey = this.targetStyleKey_;
+ if (!this.target_.style[targetStyleKey]) {
+ this.target_.style[targetStyleKey] =
+ window.getComputedStyle(this.target_)[targetStyleKey];
+ }
+ var size = parseInt(this.target_.style[targetStyleKey]);
+ this.targetSizesByModeKey_[this.modeKey_] = size;
+ return size;
+ },
+
+ setTargetSize_: function(s) {
+ this.target_.style[this.targetStyleKey_] = s + 'px';
+ this.targetSizesByModeKey_[this.modeKey_] = s;
+ tr.b.dispatchSimpleEvent(this, 'drag-handle-resize', true, false);
+ },
+
+ applyDelta_: function(delta) {
+ // Apply new size to the container.
+ var curSize = this.getTargetSize_();
+ var newSize;
+ if (this.target_ === this.nextElementSibling) {
+ newSize = curSize + delta;
+ } else {
+ newSize = curSize - delta;
+ }
+ this.setTargetSize_(newSize);
+ },
+
+ onMouseMove_: function(e) {
+ // Compute the difference in height position.
+ var curMousePos = this.horizontal_ ? e.clientY : e.clientX;
+ var delta = this.lastMousePos_ - curMousePos;
+
+ this.applyDelta_(delta);
+
+ this.lastMousePos_ = curMousePos;
+ e.preventDefault();
+ return true;
+ },
+
+ onMouseDown_: function(e) {
+ if (!this.target_)
+ return;
+ this.forceMutationObserverFlush_();
+ this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX;
+ document.addEventListener('mousemove', this.onMouseMove_);
+ document.addEventListener('mouseup', this.onMouseUp_);
+ e.preventDefault();
+ return true;
+ },
+
+ onMouseUp_: function(e) {
+ document.removeEventListener('mousemove', this.onMouseMove_);
+ document.removeEventListener('mouseup', this.onMouseUp_);
+ e.preventDefault();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html
index bd52880503d..0d5ab850564 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html
@@ -27,9 +27,9 @@ tr.b.unittest.testSuite(function() {
var dragHandle = document.createElement('tr-ui-b-drag-handle');
dragHandle.target = lowerEl;
- el.appendChild(upperEl);
- el.appendChild(dragHandle);
- el.appendChild(lowerEl);
+ Polymer.dom(el).appendChild(upperEl);
+ Polymer.dom(el).appendChild(dragHandle);
+ Polymer.dom(el).appendChild(lowerEl);
el.upperEl = upperEl;
el.dragHandle = dragHandle;
el.lowerEl = lowerEl;
@@ -58,9 +58,9 @@ tr.b.unittest.testSuite(function() {
var el = createDragHandle();
var styleEl = document.createElement('style');
- styleEl.textContent =
+ Polymer.dom(styleEl).textContent =
'.mode-a { height: 100px; } .mode-b { height: 50px; }';
- document.head.appendChild(styleEl);
+ Polymer.dom(document.head).appendChild(styleEl);
this.addHTMLOutput(el);
@@ -87,7 +87,7 @@ tr.b.unittest.testSuite(function() {
dragHandle.forceMutationObserverFlush_();
assert.equal(el.getLowerElHeight(), 110);
} finally {
- document.head.removeChild(styleEl);
+ Polymer.dom(document.head).removeChild(styleEl);
}
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html b/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html
index 981f16da3e6..89b9d5dab96 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/event_presenter.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/ui/base/elided_cache.html">
+<link rel="import" href="/tracing/ui/base/event_presenter.html">
<script>
'use strict';
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html
index 2d0fe220eef..5c2f4dfe170 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
-<polymer-element name="tr-ui-b-dropdown">
+<dom-module id='tr-ui-b-dropdown'>
<template>
<style>
:host {
@@ -57,102 +57,104 @@ found in the LICENSE file.
}
</style>
<tr-ui-b-toolbar-button id="outer"
- on-keydown="{{ onOuterKeyDown_ }}"
- on-click="{{ onOuterClick_ }}">
+ on-keydown="onOuterKeyDown_"
+ on-click="onOuterClick_">
<div id="icon">&#9881;</div>
<div id="state">&#9662;</div>
</tr-ui-b-toolbar-button>
<dialog id="dialog"
- on-click="{{ onDialogClick_ }}"
- on-cancel="{{ onDialogCancel_ }}">
+ on-click="onDialogClick_"
+ on-cancel="onDialogCancel_">
<div id="dialog-frame">
<content></content>
</div>
</dialog>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.$.outer.tabIndex = 0;
- },
-
- get iconElement() {
- return this.$.icon;
- },
-
- onOuterKeyDown_: function(e) {
- if (e.keyCode === ' '.charCodeAt(0)) {
- this.toggle_();
- e.preventDefault();
- e.stopPropagation();
- }
- },
-
- onOuterClick_: function(e) {
- var or = this.$.outer.getBoundingClientRect();
- var inside = true;
- inside &= e.clientX >= or.left;
- inside &= e.clientX < or.right;
- inside &= e.clientY >= or.top;
- inside &= e.clientY < or.bottom;
- if (!inside)
- return;
+</dom-module>
+<script>
+'use strict';
- e.preventDefault();
- this.toggle_();
- },
-
- toggle_: function() {
- if (!this.isOpen)
- this.show();
- else
- this.close();
- },
-
- show: function() {
- if (this.isOpen)
- return;
-
- this.$.outer.classList.add('open');
-
- var ddr = this.$.outer.getBoundingClientRect();
- var rW = Math.max(ddr.width, 150);
- this.$.dialog.style.minWidth = rW + 'px';
- this.$.dialog.showModal();
-
- var ddw = this.$.outer.getBoundingClientRect().width;
- var w = this.$.dialog.getBoundingClientRect().width;
- this.$.dialog.style.top = ddr.bottom - 1 + 'px';
- this.$.dialog.style.left = ddr.left + 'px';
- },
-
- onDialogClick_: function(e) {
- if (!this.isOpen)
- return;
- if (e.srcElement !== this.$.dialog)
- return;
- e.preventDefault();
- this.close();
- },
+Polymer({
+ is: 'tr-ui-b-dropdown',
+
+ ready: function() {
+ this.$.outer.tabIndex = 0;
+ },
- onDialogCancel_: function(e) {
+ get iconElement() {
+ return this.$.icon;
+ },
+
+ onOuterKeyDown_: function(e) {
+ if (e.keyCode === ' '.charCodeAt(0)) {
+ this.toggle_();
e.preventDefault();
- this.close();
- },
-
- close: function() {
- if (!this.isOpen)
- return;
- this.$.dialog.close();
- this.$.outer.classList.remove('open');
- this.$.outer.focus();
- },
-
- get isOpen() {
- return this.$.dialog.hasAttribute('open');
+ e.stopPropagation();
}
- });
- </script>
-</polymer-element>
+ },
+
+ onOuterClick_: function(e) {
+ var or = this.$.outer.getBoundingClientRect();
+ var inside = true;
+ inside &= e.clientX >= or.left;
+ inside &= e.clientX < or.right;
+ inside &= e.clientY >= or.top;
+ inside &= e.clientY < or.bottom;
+ if (!inside)
+ return;
+
+ e.preventDefault();
+ this.toggle_();
+ },
+
+ toggle_: function() {
+ if (!this.isOpen)
+ this.show();
+ else
+ this.close();
+ },
+
+ show: function() {
+ if (this.isOpen)
+ return;
+
+ Polymer.dom(this.$.outer).classList.add('open');
+
+ var ddr = this.$.outer.getBoundingClientRect();
+ var rW = Math.max(ddr.width, 150);
+ this.$.dialog.style.minWidth = rW + 'px';
+ this.$.dialog.showModal();
+
+ var ddw = this.$.outer.getBoundingClientRect().width;
+ var w = this.$.dialog.getBoundingClientRect().width;
+ this.$.dialog.style.top = ddr.bottom - 1 + 'px';
+ this.$.dialog.style.left = ddr.left + 'px';
+ },
+
+ onDialogClick_: function(e) {
+ if (!this.isOpen)
+ return;
+ if (e.srcElement !== this.$.dialog)
+ return;
+ e.preventDefault();
+ this.close();
+ },
+
+ onDialogCancel_: function(e) {
+ e.preventDefault();
+ this.close();
+ },
+
+ close: function() {
+ if (!this.isOpen)
+ return;
+ this.$.dialog.close();
+ Polymer.dom(this.$.outer).classList.remove('open');
+ this.$.outer.focus();
+ },
+
+ get isOpen() {
+ return this.$.dialog.hasAttribute('open');
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html
index 8801a927a1f..3d6ebb41cf3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/dropdown.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/dropdown.html">
<script>
'use strict';
@@ -16,18 +16,24 @@ tr.b.unittest.testSuite(function() {
var dd = document.createElement('tr-ui-b-dropdown');
dd.style.marginLeft = '50px';
dd.style.width = '50px';
- dd.iconElement.textContent = 'Settings ' + String.fromCharCode(0x2699);
+ Polymer.dom(dd.iconElement).textContent =
+ 'Settings ' + String.fromCharCode(0x2699);
- dd.appendChild(tr.ui.b.createDiv({textContent: 'item 1'}));
- dd.appendChild(tr.ui.b.createDiv({textContent: 'item 2 longer'}));
- dd.appendChild(tr.ui.b.createDiv({textContent: 'item 3'}));
+ Polymer.dom(dd).appendChild(tr.ui.b.createDiv({textContent: 'item 1'}));
+ Polymer.dom(dd).appendChild(
+ tr.ui.b.createDiv({textContent: 'item 2 longer'}));
+ Polymer.dom(dd).appendChild(
+ tr.ui.b.createDiv({textContent: 'item 3'}));
var container = tr.ui.b.createDiv();
container.style.height = '100px';
- container.appendChild(dd);
- container.appendChild(tr.ui.b.createDiv({textContent: 'some text'}));
- container.appendChild(tr.ui.b.createDiv({textContent: 'some more text'}));
- container.appendChild(tr.ui.b.createDiv({textContent: 'more text'}));
+ Polymer.dom(container).appendChild(dd);
+ Polymer.dom(container).appendChild(
+ tr.ui.b.createDiv({textContent: 'some text'}));
+ Polymer.dom(container).appendChild(
+ tr.ui.b.createDiv({textContent: 'some more text'}));
+ Polymer.dom(container).appendChild(
+ tr.ui.b.createDiv({textContent: 'more text'}));
this.addHTMLOutput(container);
dd.show();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html b/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html
index 7019f9807da..556123b44f4 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html
@@ -20,7 +20,7 @@ tr.exportTo('tr.ui.b', function() {
* value: Another dict whose key is width
* and value is an ElidedStringWidthPair.
*/
- var elidedTitleCacheDict = {};
+ var elidedTitleCacheDict = new Map();
var elidedTitleCache = new ElidedTitleCache();
/**
@@ -30,7 +30,7 @@ tr.exportTo('tr.ui.b', function() {
function ElidedTitleCache() {
// TODO(jrg): possibly obsoleted with the elided string cache.
// Consider removing.
- this.textWidthMap = {};
+ this.textWidthMap = new Map();
}
ElidedTitleCache.prototype = {
@@ -45,19 +45,19 @@ tr.exportTo('tr.ui.b', function() {
* @return {ElidedStringWidthPair} Elided string and width.
*/
get: function(ctx, pixWidth, title, width, sliceDuration) {
- var elidedDict = elidedTitleCacheDict[title];
+ var elidedDict = elidedTitleCacheDict.get(title);
if (!elidedDict) {
- elidedDict = {};
- elidedTitleCacheDict[title] = elidedDict;
+ elidedDict = new Map();
+ elidedTitleCacheDict.set(title, elidedDict);
}
- var elidedDictForPixWidth = elidedDict[pixWidth];
+ var elidedDictForPixWidth = elidedDict.get(pixWidth);
if (!elidedDictForPixWidth) {
- elidedDict[pixWidth] = {};
- elidedDictForPixWidth = elidedDict[pixWidth];
+ elidedDict.set(pixWidth, new Map());
+ elidedDictForPixWidth = elidedDict.get(pixWidth);
}
- var stringWidthPair = elidedDictForPixWidth[sliceDuration];
+ var stringWidthPair = elidedDictForPixWidth.get(sliceDuration);
if (stringWidthPair === undefined) {
var newtitle = title;
var elided = false;
@@ -73,16 +73,16 @@ tr.exportTo('tr.ui.b', function() {
stringWidthPair = new ElidedStringWidthPair(
newtitle, this.labelWidth(ctx, newtitle));
- elidedDictForPixWidth[sliceDuration] = stringWidthPair;
+ elidedDictForPixWidth.set(sliceDuration, stringWidthPair);
}
return stringWidthPair;
},
quickMeasureText_: function(ctx, text) {
- var w = this.textWidthMap[text];
+ var w = this.textWidthMap.get(text);
if (!w) {
w = ctx.measureText(text).width;
- this.textWidthMap[text] = w;
+ this.textWidthMap.set(text, w);
}
return w;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html b/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html
index 66e74de6f65..866591644aa 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html
@@ -11,13 +11,13 @@ found in the LICENSE file.
'use strict';
tr.exportTo('tr.ui.b', function() {
var FaviconsByHue = {
- blue: 'data:image/vndmicrosofticon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjj8xAGArIgqOPzE8nUY3dqJJOJeiSTiXnUY3do4/MTxhKyIKjkAxAAAAAAAAAAAAAAAAAAAAAABQJBwAAAAAAZJBMzSoSzqlsU8+6bRQP/21UT//tVE//7RQP/2wTz3ppko6pY9AMjQAAAABTyMbAAAAAAB7e3sAAP//AKFSRE+wTz3dtVE//7VRP/+1UT//tVE//7VRP/+zUD7/sE89/7BOPf+qTDvdl0M0TwAAAABWJx4A+fn5ANjd3TnIiX7ftVA9/7VRP/+1UT//tVE//7VRP/+xTz3/rE08/6xMO/+sTDv/rE08/6dKOt+SQTM5q0w7ALO0tA3v8fGu05uR/7NMOf+0Tzz/tE88/7RPPv+uTT3/p0o7/6ZJOv+mSTr/pkk6/6ZJOv+mSjr/n0Y4rnIwKg3h4eFK9/j48N2zrP/FeGr/xnps/8Z6bP/AaUv/tlw1/7RbNf+1WzX/tFs1/7RbNf+0WzX/tFs1/7NbNPCqWy1K7e3tjPn5+f/49vX/9vLy//by8v/28vH/8bZv/+6RH//ukyP/7pMj/+6SI//ukiP/7pMj/+2SIv/qjyL/34kfjPHx8bL5+fn/+fn5//n5+f/5+fr/+fn5//W7cP/zlB3/85Yh//OWIf/zliH/85Yh//GVIf/rkR//6ZAf/+KLHrLz8/O2+fn5//n5+f/5+fn/+fn5//n5+f/1unD/85Qd//OWIf/zliH/85Yh//CUIP/mjh//44we/+OMHv/diR628vLymfn5+f/5+fn/+fn5//n5+f/5+fn/9bx0//OXI//zmCb/85gm/++VIv/hjB//3Yoe/92KHv/dih7/2IYdmfHx8Vz4+Pj3+fn5//n5+f/5+fn/+fn5//jo0//33bv/9929//bbtf/euDX/06oJ/9OrC//Tqwv/06oM98yfD1zr6+sY9/f3xvn5+f/5+fn/+fn5//n5+f/5+vv/+fv8//n7/f/3+PH/3Ms6/9O8AP/UvQD/1L0A/9K8AMbItAAY////APT09Fb4+Pjy+fn5//n5+f/5+fn/+fn5//n5+f/5+fr/9/bu/9zKOf/TuwD/1LwA/9S8APLQuABW3cQAAOzs7ADm5uYF9vb2ePn5+fT5+fn/+fn5//n5+f/5+fn/+fn6//f27v/cyTn/07sA/9S8APTRugB4w60ABcmyAAAAAAAA8PDwAOzs7Ab29vZd+Pj40vn5+fz5+fn/+fn5//n5+f/49/H/5Ndu/NjEIdLSugBdybIABsy1AAAAAAAAAAAAAAAAAADn5+cAqKioAPT09CH39/dy+Pj4tvj4+NX4+PjV+Pj4tvX063Lt6MMhOQAAAM+/RAAAAAAAAAAAAPAPAADAAwAAwAMAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCwUEDDgZExxWJx4tYiwiN2IsIjdWJx4tOBkTHAsFBAwAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wAbDAkKZS0jMYs+MWydRjeipko6x6tMO9utTTzjrU0846tMO9umSjrHnUY3oos+MWxlLSMxGwwJCv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgZFAAPBwUHcjMoPJtFNpqsTTzhs1A+/LVRP/+2UT//tVE//7VRP/+1UT//tVE//7ZRP/+1UT//s1A+/KxNPOGbRTaacTInPA8HBQc4GRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/yp4AUCQcGZVDNICtTjzktVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+0UT//s1A+/7JQPv+rTDvkkkEzgE8jGxn/xZoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA////AGswJSqiSTivs1A++7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tFA+/7FPPf+xTz3/sU89/7FPPf+vTj37nkc3r2guJCr///8AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAP/DogB/VEwsqE09v7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7NQPv+vTj3/r049/69OPf+vTj3/r049/69OPf+uTjz/oUg4v20xJiz/nnsAAgEBAAAAAAAAAAAAAAAAAAAAAAD19fUAkp2fHdK2sbW5W0r/tVA+/7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+yUD7/rU08/6xNPP+tTTz/rU08/61NPP+tTTz/rU08/61NPP+sTTz/nkY3tWAqIR2pSzsAAAAAAAAAAAAAAAAAeXl5ADY2Ngnd39+O6tbT/blbSv+1UD7/tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//slA+/6xNPP+rTDv/q0w7/6tMO/+rTDv/q0w7/6tMO/+rTDv/q0w7/6tMO/+qTDv9lkM0jiUQDQlSJR0AAAAAAAAAAAD///8AxMTES/X29u3s2NX/uVtK/7VQPv+1UT//tVE//7VRP/+1UT//tVE//7VRP/+1UT//tVE//7FPPv+qTDv/qEs6/6hLOv+oSzr/qEs6/6hLOv+oSzr/qEs6/6hLOv+oSzr/qEs6/6lLOv+lSTnthDsuS/+TcgAAAAAAm5ubAHBwcA/o6Oix+vv8/+zY1P+5W0r/tVA+/7VRP/+1UT//tVE//7VRP/+1UT//tVE//7VRP/+xTz3/qEs6/6ZKOv+mSjr/pko6/6ZKOv+mSjr/pko6/6ZKOv+mSjr/pko6/6ZKOv+mSjr/pko6/6ZKOv+bRTaxSiEaD2cuJAD///8AycnJRfX19fD6+/z/69fU/7hYR/+0Tjv/tE48/7ROPP+0Tjz/tE48/7ROPP+0Tz3/r04+/6VJOv+jSDn/o0g5/6NIOf+jSDn/o0g5/6NIOf+jSDn/o0g5/6NIOf+jSDr/o0g5/6NIOf+jSDn/o0g6/6BHOfCCOS9F0FxKAAAAAALk5OSN+fn5//n6+v/y5+X/05uS/9CTiP/QlIn/0JSJ/9CUif/QlIn/0JSK/8yGb//AaDb/vWc0/71nNf+9ZzT/vWc0/71nNP+9ZjT/vWY0/71mNP+9ZjT/vGY0/7xmNP+8ZjT/vGY0/7xmNP+8ZjT/u2U0/7FiLY0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/5+vr/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//KWI//ylSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//CUIf/vkyD/5Y0fxY1XExbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n7/f/32LL/85cj//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/wlCD/7pIg/+6SIP/pjx/lunIZM9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fv9//fYsv/zlyP/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/75Mg/+uRH//qkB//6pAf/+iPH/TIfBtQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//OXI//zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh/+6TIP/ojx//548f/+ePH//njx//5o4f+c1/HGHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n7/f/32LL/85cj//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/tkiD/5Y0f/+SNH//ljR//5Y0f/+WNH//kjB/6zn8cZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fv9//fYsv/zlyP/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/65Eg/+KMHv/iix7/4ose/+KLHv/iix7/4ose/+CLHvfLfRta3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//OXI//zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh/+qRIP/gih7/34oe/9+KHv/fih7/34oe/9+KHv/fih7/3Yge78V6GkLS0tIj9fX12fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n7/f/32LH/85Yg//OVHv/zlR7/85Ue//OVHv/zlR7/85Ue//OVIf/pjyH/3ogf/92HH//dhx//3Ycf/92HH//dhx//3Ycf/92HH//ahh7ZunMZI56engjy8vKu+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fr7//jr2f/2ypL/9smP//bJkP/2yZD/9smQ//bJkP/2yZD/5rNI/9OeFP/SnhX/0p4V/9KeFf/SnhX/0Z0V/9GdFf/RnRX/0Z0V/8yWFq6KVBcI////AO3t7Wr5+fn++fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn6//n6/P/5+vz/+fr8//n6/P/5+vz/+fr8//n6/P/h013/0rsA/9O8AP/TvAD/07wA/9O8AP/TvAD/07wA/9O8AP/SvAD+yLMAav/mAADr6+sA4eHhJPb29tv5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/+LSW//TuwD/1LwA/9S8AP/UvAD/1LwA/9S8AP/UvAD/1LwA/9K6ANu/qgAkyLEAALu7uwAAAAAA8vLygfn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/4tJb/9O7AP/UvAD/1LwA/9S8AP/UvAD/1LwA/9S8AP/UvAD/zrYAgQAAAACfjQAAAAAAAOzs7ADk5OQe9vb2zPn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/i0lv/07sA/9S8AP/UvAD/1LwA/9S8AP/UvAD/1LwA/9K6AMzCrAAeybIAAAAAAAAAAAAAsLCwAP///wDv7+9O+Pj47Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/+LSW//TuwD/1LwA/9S8AP/UvAD/1LwA/9S8AP/TuwDsy7QATu7UAACXhQAAAAAAAAAAAAAAAAAA1tbWALS0tAPy8vJv+Pj49Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/4tJb/9O7AP/UvAD/1LwA/9S8AP/UvAD/07wA9M63AG6ZiQADtqIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4uLiANfX1wbz8/Nz+Pj48Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/i0lv/07sA/9S8AP/UvAD/1LwA/9O8APDPuABzuKMABsGrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4+PjANjY2ATy8vJZ+Pj42vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/+HSW//TugD/1LsA/9S8AP/TuwDazrcAWbejAATBqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1NTUAB8fHwDw8PAr9vb2nPj4+O35+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/7uas/+bZdv/j1mvt2cYznMu0ACsUFAAAtaEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOvr6wDj4+MG8vLyOvb29pD4+PjS+fn58vn5+f35+fn/+fn5//n5+f/5+fn/+fn5/fn5+fL4+frS9/j8kPT1/Trs8v8G8PP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADh4eEA1tbWAu/v7xv09PRJ9vb2dvb29pf39/eo9/f3qPb29pf29vZ29PT0Se/v7xvW1tYC4eHhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH4AAAB/AAAA/4AAAf/gAAf/8AAP//wAP/', // @suppress longLineCheck
+ blue: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAAlrklEQVR4Ae2dCXwdVb3H5265yc3SpEk3ukEXCqVUBLT4Wm19oFKtaN0fKijy9CMguPBarIJsIiA8qsjTh7SllAoFeVBaEARkLV1ooXtL0yRdkqZp9u3uy/v/5uY/OZm75y659+acdnLOnP385zv/+58zZ2YMinTplIAhzsoDceaT2RKUQLwHIMFqh0V2ll0kn4XA6byv9/Vw834kX19e7keRQCzhRyk6bJJYRvD1YTXuhRdeqDj77LPPtNls400mU7HRaCzFFggEVJ/iSqhsicFgKIXUKL6bvB6fz9fj9/u7Kb4bPjaK67Xb7Q0HDhw49IUvfKEd2XUb7WpxHIYvXRgJ8AELkzRso1gmKrwkBfjG7373u5Zly5ZNKS8vn2G1Ws80m83YphPI0wnQUemQFp0IzQR9tdfrxXbI5XId6ujo+PCuu+6qXbNmjYfa9NMmngDoBmt+hIe944M53AUhwqwCvXTp0qJrr732opKSkk8XFhZ+imC+gIAryAZB0QnlJuB3OJ3Ot3p6el5/6KGHttxzzz0O6pse+GEP+3AGnKE2EhgG0tAFt99++4WkoT9tsVgW0DaH4guzAeg4+uD0eDxbaXuDNPzrt9xyy3bS8G4qB8BF6OOoKr+yDDfAB0B91VVXFf72t7+9lLT05QUFBZfQoYWtnA+ux+12v0ra/W+/+tWvXlq5cqWTBjUsYR8OgDPU8KGtjR9++OHHx4wZ8+2ioqKv0X4lbfnsWh0Ox9+bmprWzpgxYxsNFBpd1Op5bcbkM+AMtgr11q1bTz/zzDP/gy4Qv02zGtPzmehIY6MZmmq6UF176NChJ+bMmXOkD3QR9khFczY+HwEXwTbV1NTMI229FCYIXSTm43gTho8uUgMwYUir3zN16tR3qAIfbXkJej4dcIxF1dbkm44ePfqZqqqqpTT7MZf2pYsgAZqN2dTS0nLP5MmTX6EsDDrDHqFU7kTnA+Aa2BMmTDBv2bLliyNHjlxCZsgFuXMYhr6nZL7saGtru/eiiy7aUF9f76UeAfKcBz2XAUffVbgJbAuB/Y3KysoldONl5tDjkrs9oBtL+1tbWwH6UwS6/mZSzg0sVwHXTJG9e/deOGXKlOWksS/MOelncYdJo2+vra396axZs7ZTN0XTJYt7Hdq1XANc1dg0DNOqVatGLl68+DZa/3E1XTwCeOn6JLCly6ncU9+mNLnBZRLOYPAHHI5H2l5/8TdHbl3SRjUx6DkztZgrgKOfDLf5xIkT36moqLiLzJG0rAFJAomsKDp1W51S74IZnSIX8DcrXV3LlK/Oe5xqZPsckGc96LkAOPpowrZ79+5ZNK31BzkzQtKI4qxvV0dJTSLJ592kHKu7QfnPxXupFmhzbFkNeTb/tGsae/bs2Va6wr/lrLPO2izhTgLQZIuaaMp1yvTNyvNbb1HomFB1ZtrAUNYqymztGMNt2rhx44T58+evohs1n0r2+AyX8mnT4KIAvZ63lA82f1/55TX1FJ21tnk2As4zJObq6urP0BTgCmlri2TFDmcEcHQDtnlz4w+Uyz+Hm0Rsm2PuPGtcNpkomtZesGBBYXNz8210d+05CXfWsBLaEQNd5I+e8JyyYettCh0zyoBrpawyWbJFg2twv/jiixPnzZu3mhZFzQ2VqIyJRwIZ0+BiZzyeTcqebVcqS350nKKzxmTJBsDRB3WWZN++fXPpps060tpVouxkODEJDAng6GIg0KI0Hv+mcsXnN9FeVsyyDLWJwnCbadXfomnTpm2UcCcGc1blNhiqlNMmblT+9soi6hdmWKC4hlSJDiXgaBsCsNDKvysnTpz4JIWLaJMupyVgKFLGjHtSefrNK2kYFtpwjIeMs6FqWIOb7kr+Yty4cX+m2+0446XLBwkESHuPrPqz8uymX9BwhhTyoQBchZseQiigdcj30grAO+SDCPlAtW4MeLikdMQdyvqt9yp0rCl1SDR5pgFX4V64cGERvdhmRWlp6XU6scjdfJNAcfF1ysqNK5Q5C2F+ZhzyTF4AqHCPGjXKSjdwHqUHfr+ab8cyW8YzZLMo0QTgcj2jfO/S7ynNzS7KxtOI0UqkJC1TGlyFm3pccPDgwfsk3Ck5drlVidX6VWXFxvvAAG0Z0+SZAJzhtjQ2Ni6ld5D8KLeOjOxtyiRgK/6R8uy7S6m+jF14phtwmEBow3L8+PGr6FnJm1MmLFlRbkqgtOxm5am3rgITtIGNtJrJ6QQcHcdPkYUuKL9MsybLKSydlICijKxcrjz+0pdJFKzJ0wZ5ugBnuM27du2aT7ffV9JUIGCXTkqAJEAsjJ2wQlm1fj7tpPWOZzoAB9yo1/zSSy/NoLdJraMwFsdLJyUgSqBQGX/GOuX+FTMoEpCDmZRr8nQBbqIHgovnzp27mtaWlImjkmEpAU0CYGPmR1crF19cTHH4hU854KmuECcMOmo9derUAyNGjLiawtJlWAJZOQ8eTQb27keUyz7xM8qS8jnyVGpwNk0s+/fv/4qEO9oRlWkDJGArvVpZ89JXKC7lMyupApzhNm/YsGH6GWec8eCAAcgdKYFYEhhz2oPK3X+ZTtlSao+nEnDzxWRL0eNmj0q7O9bRlOkhEoA9ft6cR5WPq/Y4IE+J+ZyKSjS7m56jvK+srEzeqQw5epmNyDkbXBRPT8//Kl++6EaKSok9nqwG10yTHTt2fJpWB0q4xYMlw4lLoJhu5z/y3KepYEpMlWQBV7U3mSXFNN99H71YPfEByRJSAqIEwND4yfcpFyzgqcOkGE2mMGtvy2OPPXY9vZjnTLGfMiwlMGgJWCxnKktv/QmVT3pWZbCAM9zmxx9//IzRo0fj0STppARSJ4HykTcqN//3GVRhUqZKMoCrC6no6Zy7yTSxpW5ksiYpAZKA0WhTPj73dxRKakHWYABn7W3Zs2cPvjH5eXlApATSIoGi4i8oK56/tA9ysAr2EnKDARxlzJdddlkJ3dC5N6HWZGYpgUQlMH7SvbRWpYSKsamSUA2JAs7a2/ynP/3pOvrc9eSEWpOZpQQSlYDZPFn54a/xcDoDnpAWTxRw5DfRJ7DL6HUPP060rzK/lMCgJFA+8sfKZd/CqlRc9yXEbCKZWXtbli1b9gN6EX3loDorC0kJJCoBk6lS+ebVP6BiCU8bJgI48ppxU2fs2LHXJNpHmV9KICkJVFZdo3zsY7j5w6ZKXNXFCzhrb/PDDz/8HbK9x8ZVu8wkJZAqCZjNY5Wf3vkdqo4Bj8sWjxdw5DPRt3KKTjvtNNxhkk5KIPMSqBz1E2Xq7ITekBUP4Ky9LevWrfsGae9JmR+ZbFFKgCRgLpik3HL3NygUty0eD+Cq9h4/fnwBbTdIQUsJDKkERo+9QSkr47ubMfmNlQHaG5v56aef/ndaUDVtSAcnG5cSMFumKXc/fDGYpI35jCiXeADH3KOZ7lp+Sy6HjShHmZApCWA57dgJ3wKTtIFNQB7RxQIc6abLL7+cniEesTBiLTJBSiCTEiguWah8/isjqEkAHpXhaIk4M5BuXrp06ZfoOUtcvUonJTD0EjCaipSvff9L1JGYU4bRAEeaCjh9P+fr0jwZ+uMqe9AnAZgpo0Z/nfYY8IgcR0qA9sZmeuCBBybZbLZ/66taelIC2SEBKzF5zTJMWbMdDl5DXDTAVe29aNGib5D2jpQvpEIZISWQEQkYicm5C0QtnjDg6uwJPY72tYx0WDYiJZCoBMorGXDW4iE1hNPMOBMQb1qzZs0MmvueHlJKRmS1BCZYYZoOA2exTFd+dT/eTsuzKSFaPJwkNMDPO++8+fLiMvdA+Z8JJcqPN+9RGnocoZ0PBELjFF2cbjdYIEykvq4wWehd4APb05dBari4gaWCe/p8AT+uFOdT4j7aoJTB7oAGowFurqqqmicBV5QPmgLKX3b7lVbHANmRLLPVVSjnGT6hzFRa44dHHEqIHhQThXC8+YQiqQ66K9rnvakoD1O9DPiAJvSAo8vYjMXFxWZ6U9VFA3IP052fv+5VGntzBW4+SCYl4KtQ/L3tpCBJ0+WpC/hKLgKrvb29DDj41Q4WIvUOcaZHH310lslkGqlPHI77uQd38CgZTBbSVBVKXk+CGYwjS758/ywwS1sIz/oI1uCmmTNnflKaJ7l/OmuQG3migQ9xnvg0W2gaN/2TfYDzoLQDFw5wVYOT/T1XAq7JKacDKuS2csVg1B/unB6W2nkwaiiumEs7rMEBueZEG5zpN9Gt+QKyv+douWQg5yXAkPvtHYO78MxiCZisJXNsVRML7C3HndRN5li1w/WnNPaNDz744Ll0ZpRm8Zhk1wYhAYacjPJBlM7eIgHFUFryxZvPpR6q/Io9DavBJ0yYcJY0T0Qx5U84CDnNrtjb82dQZHqZysefRQPaRltEDc4JRlr7PS1/Ri9HopeAwWRWjLYKQiF/NLnBWgpmocGZY3XYoomCBOybaPXgNKnBVfnk7R8V8qLyvIAcrBoLiqaCXdoYcvXYMeB8KmPfSIBPUVPln7yWQD/kjEEOD7fABsBVfvtGoTIdYoOPHDnSXFhYODmHhyq7noAEgpCPUPyOTiql3QBMoIbsyGo0F04uInYdbW3RTZRbb711AnXZmh3dlr3IhAQYcpooz0RzaWmDTk1r0YLrwS4GwRaJuoMGmXrjOeecI5fHQiLDzKmQF9ILXFXIGYfc8q2jZ4JdBlyFnE9ZHolx1KhR8gJzmMHNw9Ugz8U7nrijWToyZCZFtMEBu7GoqGgiD1j6w08CKuTWUsXv6s65O56GApVdlWM+cnoNbqB3D+JzEdINYwkw5DlnkxvNYJetEdVEETU4Ioy0RLZEzoEPY7r7hh6EvIQ0eQ/FZP/sCpilPgNwKG0VbgyFdzTqCXC8ZFw6KQEAoxgLS3NoPbkR7GosIyxqcBxSgwQcYpCOJWDAOnIrKUbS5AH9M5GcKUt8OiEZcK1HbIMjQiVfAq7JRgb6JADIDQR5tpuuAaMGuGaisAbXIiTgkutwEujX5L2UnJ02uSEIOHdfZVpqcBaH9GNKIKjJQ6yAmOUylYHsa+6cprBZg3MfpA3OkpB+WAkENXmxEnDbs2+e3KABrvU9RINTih56LbMMSAlAAqomL7BRQFOU2SGYgMouOqV1jGHWIrxer50+8iofV8uOQ5a1vVA1OUEecOPtWdlhkxsUH/2saE5lmufBtVifz4erCOmkBGJKIKjJ8V0ETT/GLJPODAG/X8+uOg+O0087BaHB09kJWXd+SSCoyYuUgIceaB/qeXL/AA2uci3a4JB8QGrw/AIwE6NRNbmlcMht8oBftT40ZY2xsw2OsJogAYcopEtUAqomt5Am9w6dJg8ENPNagzysBs/2W7KJCl/mz4wE8OYsg3loNLnKbNAG1+DGqFmDI1LdpA2eGRjytRX19XAEecDr6kMqcyM1BNTrR41ltCxqcAYc6yOlkxIYtASCmhyP9WZ2doVmUXhtL1hWHWtw3lccDkcb1H22L6zROiwDWSmBoCa39mnyDHSRmPV7nG36lliDs1r3t7e31+kzyX0pgcFIQNPkGbrj6be3gV287Z95Vk0U7MCpkdXV1bXyIjMoEPk3eQmokJsKglOIAD1tm6J4Wo7UMsd9PQ+wBse+CvgzzzwjAe+TjvRSIwGGnB4qS02F4WohE8W58zk94CGzKP6XX3652+VyNdN6lFHh6pFxUgKDkQAgDygWxeDzDKZ47DJeV3PvvtfpVQChJgoKs80C+8Xf09NzRJopEIt0qZQAIFfou0GpXoUIVv0uxxHqq8ov+cxzyDShmsFut9elcmCyLikBloAKuZEm71Jsi/vdKrMi4GqTbIMz8cjgw0yK1OB8SKSfagkMgDwVlZMGDzg6oJR9tIFh5lmzwdEMR/pPnjxZiwjppATSJQHVJg/QRaffm3wT9Gvg624GswPgRsXhNLh//fr1u2nRFYCXTkogbRJQbybCXEl2diXgCzh2bthNFQHwAZAz4BgEgEaijz4C29zZ2VkjzRSIRbp0SiAIOT7MgCnExDeyThS/s7uma+vaZqpANFHUbusBZ8i9ra2tWyXgqozknzRLQIMcF56JOiLc19O6lYrB1hmgvVGVCDj2VQ1Ovq+mpmaLBBwikS4TElAhx7vJE55dIWhb6rZQH6G9WYNrXRYBh/ZmDe5buXLlVj85LacMSAmkWQIa5Im0Q4x2bXkUGpzhZo7VWsIBrp4JGzZsaCc7/KDU4olIW+ZNVgL9kMe2x4P2d+dB+86X8NFP1uARAUffWIPDnvHSdOE2CTjEIl0mJRCEPA57nAj3dzXj468qr+SzDa51V9TgiGTAcTZ4yQ7fLAHXZCUDGZSABnlUm5wgba3dDFZpE00Uraf6Bx5YveNM8C5fvnzbJZdc4iwuLqYH7Yavq+ytURq70rRIKIvEGlmZAYswDjZCRBchLUJ0ULeGqYzaQL8AfEj/PA5nz8u/Zw3O2ntAC+EAR0bVnnn33Xe7Gxsb35gyZcqlxhR9mGj/oU7liWfrlPZOd5jRZGfUbK9bmUnPGIYIeEB3B8i1PyUKBHTo+vPFEYrcfpR6orYfR6NZmiUQ8Cs9XU1vbDiyEysI2f5myLVe6wFHAqSlanDyPTt37nz+9NNPTxngv/3DHqW5lV4tkGPO67ErPi+9pgw/mYAGfjyO8zJo+vL6dH2dmc6vb1/fP31/9Pn1+7HK69P15fXt9eUP+LxKR/OB5yk7flrFOfABNehtcCSKgHuvu+66t2n5bGtk7TGgvpg7uQg3BmW22BSTGa8pIwehx+s4L3wxzOXFOM4j+sjHecSwmEcMi3nEsJhHDIt5ENY75IXjMhxWI+P4E6u8Pp3bYV/fHsWDRb/f1Vq3b9XblBzxAhNFowEOte+hlYWO+vr6f6QKcDSaq06F3FQYdeUEow9fDGfLmMU+ieFI/RPziOFU5Y9UT/T4gOJ2tP/D7e7Bmz+hwcNeYKKOcIAjHiaKZqa8+uqr6+l9KYgf9g6QG/sgxwHXbxAQgyCG9fmGal/skxiO1B8xjxhOVf5I9USLV8j+7mjd/Rz1RzRPwGuIiwQ4zBScFaDas3Tp0r0dHR2HpRYPyo8hD+7Jv5mUABj0eeyHjx58Yh+1y4CDVTAb4qIBzpCjEjfNiW+Qd+775dcPeTRdI9NCf+OSlQl98M3RvAFM0sbmCVhNCHAcSah8TYuvXr16PT2MjAql65OAapPjXXzRnP4iCnk5Llw5ToMvhsPlzYU4cQxiOFLfxTxiuC+/3+/xNB9/cz3tito7rHmCIpE0ONJwRrAd7l61alXjkSNHXpBaHKLpd5hZMfELJ3FA9Buy8oESw/p8vC/mEcOcnmu+OAYxHGkcYh4xTPlx38DtaHnhZP3rjZQEDR5xehBF4eIFXDVT1q5d+whp8YhnS7DK4fdXhdyEd/FJl04J+ANef3PDpkeoDTZPkgIcfR2gxe+7776aY8eO/VNq8dDD2A95sjamLE8/eSTggRsuLj2Otn821D5fQ4lxaW8cpWgaHOnQ1pqZQmHXU0899VePxxPWoEeB4ewYchwadhzmw4V4jhPDnJ6oL9YhhuOtRywjhuMtr88n1iGGOZ8YJ4Y5PZKv+H2BthOb/0pl8F5mEfCoFkUswNEHVICLTdVMufPOOw+QFn9TanGIJtTBHjeSucIHCjkQZsfhSOmcL14/2fqSLa/vZ6z6YqXr68M+1p24nK1vHq3++wHaZfMETEaFG2XjARzaWgOcwq4XX3zxYdLiKC9dGAkw5Pqf2czso0OMkRhGXG5u9N5vpb3p/YdpAKy9AR+YjGlJxAs4a3GcPa4lS5bsOnHixGapxUkaEVwQcnqrasYdw80wowMcl/HOJN0gtLfb1bH5yMHHd1FlDDhr75QAjk6yFsdVKyB3bty48UE5owLRRHYa5JgSY8dhniZDPMeJYU5P1BfrEMOR6hHzIBzLcV8j1aePR31cRgxzPjFODPel+xWvv6N5x4OUhCWoYA8MxqW9KV9cJgryAXBocQbcdeONN+6kd4k/J9eoQDyRnQq5se+Fk3yg2UcxDvcdULUmjotcbeQULhtvffr8XC6Sj5a5TORe9KdwXq5PXz5KOn0WUHH2nnyudt/qnVSMtXfMqcH+xuMHHGVYi6sXm2jwpptuWk4PJrfLNSqiSEPDGuShSTImggTUNSdee/uxA2uXUxaGO27bm6uNxwbnvKzF8fOABp2vvfZa89atW/8oLzhZRJF9zVyJnEWmCBKgb14qPZ01f2xv3o03VsE8AXNx295cVSKAo4yoxVXIFy9e/Aw91rZLXnCySCP7Jpo+NNLnPMQvHXAYfjz/UDuXEcNcVowTw5yeal9sQwxHakfMI4bF/HhiyuPq2LV/293PUB6GO2HtjfoHA7g4o4LGnWvWrLnL6XT6pKkCkUZ3gNxAL4HnA4rcCMfrOG+k8rHS420n3nyJthcrPxgK+D2+5oa37qI+qHyRj4vLhLU3xpAo4CjDgOOMUrX4HXfcse/AgQPr6I20SJcuhgQYcvVijS++pN938RpQHD0n1h378Cms99Zrb7CXkBsM4GiAIVenDGnfccMNNzzU0tLSKE2V+OSvmiuYXZFOkwDmvD2e7saa/X99iCLxOBoAF7W3ljfewGABZ1ucpw2d7733XusTTzxxE33+xCNNlfjED3vcqELON2WGr0+WCS03cXtaTmy6qbutppUkyHAnNO+tl/xgAUc9DLmmxWnacAeB/hDdANK3I/cjSCAIebi3d0QokKfRZHcrvZ01D9XtW72DhqjX3mBtUC5ZwGGqaFqcws5LL7109dGjR9+WN4DiPx7DHXLc0HE5Wt7es/m21WCob4PiTOimTjiJJwM46gPg2PiCE2ee/Wc/+9lvyB5vkvY4SSNO12+uxFkgT7LB7vZ6uptq9678DQ3JThsYggkAppgvCg7OJQs4WkUnMH2CMw6dc9ANoJNPPvnkL8ke90p7nCQSpzPS9CFscryHbzhsEEvA7/a2NLzzy46WXSdpV+WH/KQuLFEvu1QAzrY4mypqJ+lVE9u3bdv2Z9jjEnIWd2wfkBsM+W+T9813093K6j/X7l+9nSQjwp3UhaUo5VQAjvoY8gGmysKFC1fSgqxX3G6ckNLFKwEVcu3rY/k5swK729Hb9Mqed29fSXLRmyawCAZ9YSnKOVWAo06GHDTjQgGdti9atOjXdNH5noScpJGAU00VI74+ln+OXv2gOJ0t7x3cduevaXQqJ+TztGDK4IbkUg24aI+rkNNXIrquuOKKG+kBiYNyURZEHr/LR8j99OFXt6v94KH377/R4WjtImkAcBFuMJQS7Q1Jp0NFoHNiBw0Eube2tnbT/PnzFzz3UtMIA76mJV1cEjAYcIhInLgTkuMOZonH3XW8dvdff9zZur+JhtNLGwMO8zal2hviSgfgqBduAOhki7u6u7u3NHWO+yxNidkk5EEhxfM3CHmfSHN0zQq98Fjxunta6w+v+9GphneO0Wj0cKdUc7Nc0wW4qG608AcffNBrMlvfLx0x5XMGo7lAQs6HIbbfLytNnLELZUkOrO2mF2b2nDz64rX1hzccpG7p4YbmBuApd+kCHB3lI8G+2vnOlr0dBYVV+4tKxl1MswWW/gOX8rHlXYUsq+C8ChaeZv8/vOqYvo5hb2l48+d1+9fiNrwId8rmuyMd7HQCLrYJyDXQ20/tOGUxF+6wlU1aYDQWFPGBEwvIcHgJ9MtKE2f4jFkQq9rcnu72xrp//OTIgccx181wY8477XBDBJkGXAO9o2VPm+JzbioZMXWewVRQ2n/g0C3poklgoKyyc57cTxeUXnfHCVrXfU1D7fr9NJ4e2gA4w530OpNoMuK0TAGO9ljlaJB3tVd3u1yNb5ZVzPy40Wyt7L+Y4u5JP5IE+iFnsUbKmfl4zHN7nG3VdXtWXNvU8GYd9QBgZxxujDyTgKM9OAZc9e1dDY6ejoOvl1fNnm0yFY1TaApR/QhoMK/8G0UCGuQGEmUWKHK83jhA89z0gvoPDu1cfn1b864T1H29WZIRzc1iyzTgA+CmTqj7Lkeru6156xsVoy+cQk+fn44DJyHnQxTd1yBXRRk9bzpTsSrQ7/MoLvvJN/a/d9uSno5jLdQew40bOVghmFG4Md5MA4424UJA97rtvub6f71VPupcq9lSNttgNBLj8oZQUFzR/w6UU+ZVOeD2eV2B3u7ax/a9e/PvXI7OTuqxCDcuKDMON6Q2VICjbYacJ/jpHYte/8mjr35gtVUdLCwaPYfmyunDlFKbQ1ixXBByiDRzTl0RGPBiPXd7S8Pbyw68d+/TdAz5YlK8QzkkcEMSQwk42mfI4Wugt53c3uB0nHyttHz6THo4dywOnjRZIK7ojiHPxOw4lg4EYJI4mnfW7V95ff3h9bupd9DarLlhkohTgZk9+/pElS2AA27eVOjt3fW9p4699kr5qFkmc0HZR6TJ0nfEYngDzZUYmQeZrN6ZhEnSeXj1nk2/vr2nsw5vn4LGZrj1i6cG2VLyxYYacIyAz2zW4hro9HPnO3nstZ2FhZX7Cm1j5tCDAEWkyqU2j3HctV+7FJvjWE+CWRKvt6utpeGtX+7f/vv/6zNJGG7McfPFZNpuv8cY/oDkbAAcHRIhF0FXw21N2084HfWv2UonjaHPhEwJaikJ+oAjqdvRINfFD2ZXfSILF5I+Fz2kUP/akT0rlhyv2bCX6mKNDcD1N3CgqIbc4RzPJof+YOoEJx7eioNPl+FDlHSxqdgQnj77h5+oGPeJXxQUlE3Cg7qZ+EmmdnPWYYYjGRec/nMrbnfnsbaT2+6v2f3wZqoPJghDzVOAvNwVDbLCSqbplJTNNsAxKP5hBeR4OBGfSQDkDHpRYWFFyYzzf/Gd4oqpV5JGt+IZxlRqLGorr1zwmdjEmOMZEp/X4erpqFld/f4Djzud7ZghgabGBrDZ1sYsCa/lTqwhKphOly0min6MLCT42KAV2Kbzeb1Ob9Pxf+32utteLSqZOJ4++jRJmi16Efbv95/8rDsi++pzFX3mCM1kvXPkw7X/Vbd31eskc3H6D9pbhBvHJ7mfiv7upjSUjRpcHCD6xyYLa3PW6DBbVM0+4/yffKq88iPXmq0jJuOdf/J2vyjC/nBQk/fviyHRzva6u462N+96qHrng29RHtbUrLUx9cc3bljpsEISq8yKcLYDzkIC5Aw6bHNAzva5CrnZbC6c/pHrLykbefYVZmv5NAk6iy66PwBsV8fhrrYDj1Xv+uOr9GYyBpt9ntcWbe2s1NriiHMFcPSZtTlAhzZn0AE4ww7fOuP86z45ovLcKyzWkecEL0RN0kYnwYguaGP78MJLetl8277O1j2Pffj+n96mPAAZG8BmHxobYPMdSYCdtVqb+qa5XAKcO40+49qBQYc2Z42uAk77qj919tUfqxh1wZXWosrz6cEKslxQbPhOLwZNFKz4I7D9broL2fp+e/OO1TW7H3mPBMNgi75ojgBqvpCkYG64XAQckkW/sYlmCzQ6Ty2KoBeccc53Z5eP/uiXrIWjFpjNRTaD+no0FM1/2DWo6cIRb3D1eh12l7P5jY5TH6yv27cGt9cBsQg1wtDWvIl2dk5obeq75nIVcB4AQ86gs+nCoLNmV7V8YcnY4ikzvr3ANuKMz1mLqi4k0E3q+7nVu6OoIn+cOv9NUyJ4+ACfBKG3t263d9a9XPvh2jecPSdxg4a1M4BmyBlqnvaD1s4ZcyTc0ct1wHlMetBhi7CNziYM+6qmrzrtwtHjJi/6rK1k/OfoiblpAJ1hz0XNzpoai6AANTafu/uwvafh5cajG//ZcmL7KZIJA8xwiz7SoK1ZY+c02DQO1eUL4OJ4grZH0E6HRmetDsAZetE3T5q6eHr5mPPmWQurzjcXls8i0K20VFcx4iWYeA9JFpoyA4CmJatYI0JQu7zOjr0uZ8v7HU073zlW82w1dR7aGPAC5nA+0llj8z2HnDNFaAxhXb4BzoMMUtlvo0Ojs1bXA69qdEqHby4sLLeOm7p4Vln5tAsshRXnFxSMOJseirbgAhXPjAZvmrDYgn7/jRRuPjV+EGLUxbzRBSKWqdJ7RnChGKBPftAt9AMeZ/v7XR2HdzTWPLvX6eyAycFQA2jeGHBOY23NGhuNcEMUzA/HRyo/RhM6ChF0aHbRVhe1O0POceybiovH28ZNW/SR4pJJ55oLiieZzLZJJottPFY2BoHHWnWAT1Wr0owkUn18JJYoHv9xUQiQNd/roJfnNPi89mNed++x3p5jexoPb9zV29uAu4qAlDUx+ww2fI6Dz0CL9nWkzlD23HZ6qef2aKL3HmNl84VBZ83OQEfyOR98lDWOnjB3dFnFOZOttjGTLIWlk81m20RaMlBpUEw2Ay2QoRPARg1SffQXF7F9vtpFaOEgxbSrhuhDAV57gBZ+BBSf3e9ztXq99uMeZ/dRl73pWFf7vqOn6jfBhmYoRe0rwhsuLOZlu5p9tTv5/Gc4Ac7HEWMWN4ZW9AE6Q83Q8z6fHKKvQq+r10DmjrmoZEKx1Ta6yGItK7aYy7AiUvF4u+weV1evy37K4eip7yWzAmBCi4obwwyfta7oI8xAM8TYF/NwWbHevNXWNPYQNxwBF4Uggo4wg8q+CL0IuAg350Ec18H1oi0xjH3RMXiI4zBrVwZcDyxDy1DzPudnn+tjX2x32IQhfOmCEmBZMJDwGXQxLMYBbqSxz5AjDg4+b7wPH9DBMXz6fUCKOEAs+gwv+0gTw9jHBsd+cG+Y/uUDMUyHH3XYLBsGNJIvQq3PgwbEesQGGUDRR1i/Mez6eHEf9WJfOp0EWPi6aLkbQQIsLwYZ2aLFiekRqhwAJkPK8KJMtLhIdcr4PgnwwZECSU4Cejnq91G7Po7BFVvWx+n3xbwyHIcE/h9VLWRYHWXC/QAAAABJRU5ErkJggg==', // @suppress longLineCheck
- green: 'data:image/vndmicrosofticon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWJLAEpCMwptYks8eWxTdn1wVpd9cFaXeWxTdm1iSzxKQzMKbWJLAAAAAAAAAAAAAAAAAAAAAAA+OCsAAAAAAXBlTTSBdFmliHpe6Yp8X/2LfWD/i31g/4p8X/2HeV3pf3NYpW5jTDQAAAABPTcqAAAAAAB7e3sAlv//AIB1Xk+HeV3di31g/4t9YP+LfWD/i31g/4t9YP+Je1//h3pd/4d5Xf+DdVrddGhQTwAAAABDPC4A+fn5ANrb3DmupZPfinxf/4t9YP+LfWD/i31g/4t9YP+Iel7/hHdb/4R2W/+Edlv/hHdb/4BzWN9wZU05g3ZaALS0tA3w8PGuu7Sj/4h5W/+Je17/iXte/4t8X/+HeFz/gnNY/4FyWP+Bclj/gXJY/4FyWP+Bclj/fG1Url9NPA3h4eFK9/j48MvFuf+kmoP/ppuF/6abhf+JkHL/c4Rj/3OEY/9zhGP/coNj/3KDY/9yg2P/coNj/3CDYvBgf19K7e3tjPn5+f/39vb/9fTz//X08//09PP/itKw/0m+h/9Mv4n/TL+J/0y/if9Mv4n/TL+J/0y+iP9Lu4b/RrJ/jPHx8bL5+fn/+fn5//n5+f/5+fn/+fn5/4rXtP9Hwon/SsOL/0rDi/9Kw4v/SsOL/0nCiv9HvYb/RruF/0S1gbLz8/O2+fn5//n5+f/5+fn/+fn5//n5+f+K17P/R8KJ/0rDi/9Kw4v/SsOL/0nBif9GuYT/RbaC/0W2gv9Dsn+28vLymfn5+f/5+fn/+fn5//n5+f/5+fn/jdi1/0vDjP9OxI7/TsSO/0rAiv9FtoP/RLKA/0SygP9EsoD/Qq59mfHx8Vz4+Pj3+fn5//n5+f/5+fn/+fn5/9rw5v/H6tn/yOra/8Lp2f9e1b7/O8yz/z3MtP89zLT/Pcuy9zzApVzr6+sY9/f3xvn5+f/5+fn/+fn5//n5+f/7+vr//Pr7//z6+//z+fn/ZuPY/zbczv853c7/Od3O/zjbzcY10sYY////APT09Fb4+Pjy+fn5//n5+f/5+fn/+fn5//n5+f/6+fn/8Pj3/2Xj1/823Mz/OdzN/znczfI42MlWO+XWAOzs7ADm5uYF9vb2ePn5+fT5+fn/+fn5//n5+f/5+fn/+vn5//D49/9j4tf/NdvM/znczfQ42ct4Ncu9BTbRwgAAAAAA8PDwAOzs7Ab29vZd+Pj40vn5+fz5+fn/+fn5//n5+f/z+Pj/jung/FLf0tI42ctdNdHCBjfUxgAAAAAAAAAAAAAAAADn5+cAqKioAPT09CH39/dy+Pj4tvj4+NX4+PjV+Pj4tu329XLO7+whAFQmAGrUygAAAAAAAAAAAPAPAADAAwAAwAMAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQgGDCsmHRxCOy4tS0M0N0tDNDdCOy4tKyYdHAkIBgwAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wAVEg4KTUU1MWtgSmx5bVOigHNYx4N2W9uFd1zjhXdc44N2W9uAc1jHeW1TomtgSmxNRjUxFRMOCv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsnHgALCggHWE88PHdrUpqEd1vhiXxf/It9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/iXxf/IR3W+F3a1KaV048PAsKCAcrJx4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AAPjcqGXJnT4CFeFzki31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+KfWD/iXxf/4l7Xv+DdlrkcGVNgDw2Khn//+sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AFJKOSp9cFavinxf+4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/inxf/4h6Xv+Iel3/iHpd/4h6Xv+GeV37eW1Ur1BINyr///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAP//3gBsZ1osgnVbv4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4l8X/+HeV3/hnlc/4Z5XP+GeVz/hnlc/4Z5XP+GeFz/fG9Vv1RLOiz/9LoAAgIBAAAAAAAAAAAAAAAAAAAAAAD19fUAl5ibHcbCurWShGn/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+Je1//hXhc/4R3W/+Fd1v/hXdb/4V3W/+Fd1v/hXdb/4V3W/+Ed1v/eW1TtUlCMh2CdVkAAAAAAAAAAAAAAAAAeXl5ADY2Ngne3t+O4t/Z/ZKFaf+LfV//i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/iXte/4R3W/+Ddlr/g3Za/4N2Wv+Ddlr/g3Za/4N2Wv+Ddlr/g3Za/4N2Wv+CdVr9c2dPjhwZEwk/OSsAAAAAAAAAAAD///8AxMTES/X19u3k4dv/koRp/4t9X/+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4h6Xv+CdVr/gXRZ/4F0Wf+BdFn/gXRZ/4F0Wf+BdFn/gXRZ/4F0Wf+BdFn/gXRZ/4F0Wf9+clftZVtGS/3jrgAAAAAAm5ubAHBwcA/o6Oix+/v7/+Pg2/+ShGn/i31f/4t9YP+LfWD/i31g/4t9YP+LfWD/i31g/4t9YP+Iel7/gXRZ/4BzWP+Ac1j/gHNY/4BzWP+Ac1j/gHNY/4BzWP+Ac1j/gHNY/4BzWP+Ac1j/gHNY/4BzWP93a1KxOTMnD1BHNwD///8AycnJRfX19fD7+/v/4+Da/5CCZ/+Jel3/iXtd/4l7Xf+Je13/iXtd/4l7Xf+Ke17/iHhd/4BxV/9/cFb/f3BW/39wVv9/cFb/f3BW/39wVv9/cFb/f3BW/39wVv9/cFb/f3BW/39wVv9/cFb/f3BW/31uVPBnWURFo45tAAAAAALk5OSN+fn5//r6+v/t7Oj/vLSk/7aunP+3rp3/t66d/7eunf+3rp3/uK+e/6Gmjv9vkG3/bI5r/2yOa/9sjmv/bI5r/2yOa/9sjmv/bI5r/2yOa/9sjmr/bI1q/2yNav9sjWr/bI1q/2uNav9rjWr/a41q/16GZI0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/5+fr/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/wOfV/0vCi/9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0nAif9Jv4j/RreCxStxUBbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z6+/+/59X/TMSM/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9JwYn/SL6I/0i+iP9GuoXlOJVqM9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pr7/7/n1f9Mw4z/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/ScCJ/0e8hv9HvIb/R7yG/0a6hfQ9oXJQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/v+fV/0zDjP9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0i/iP9GuoX/RrqE/0a6hP9GuoT/RrmD+T6ldWHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z6+/+/59X/TMOM/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Ivof/RbiD/0W3gv9FuIP/RbiD/0W4g/9Ft4L6PqZ2ZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pr7/7/n1f9Mw4z/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SL2H/0W2gv9FtYH/RbWB/0W1gf9FtYH/RbWB/0S0gPc+o3Ra3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/v+fV/0zDjP9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0e8hv9EtID/RLOA/0SzgP9Es4D/RLOA/0SzgP9Es4D/Q7F/7zyecULS0tIj9fX12fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z6+/+/59X/SsOL/0jCiv9Iwor/SMKK/0jCiv9Iwor/SMKK/0rCiv9HuoT/RLF+/0Owff9EsH3/RLB9/0Swff9EsH3/RLB9/0Swff9CrnzZOJZrI56engjy8vKu+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+vn6/9/x6f+l38X/o9/D/6Tfw/+k38P/pN/D/6Tfw/+k38T/a9Kz/0DBof9BwKH/QcCh/0HAof9BwKD/QcCg/0G/oP9Bv6D/Qb+g/0C4mK4tbU4I////AO3t7Wr5+fn++fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+vn6//v6+//7+vv/+/r7//v6+//7+vv//Pr7//v6+/+B597/NdvN/znczf853M3/OdzN/znczf853M3/OdzN/znczf85283+NtHDakb/+gDr6+sA4eHhJPb29tv5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/3/n3f823Mz/OdzN/znczf853M3/OdzN/znczf853M3/OdzN/zjay9s0x7kkNs/BALu7uwAAAAAA8vLygfn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/f+fd/zbbzP853M3/OdzN/znczf853M3/OdzN/znczf853M3/N9XHgQAAAAAspZoAAAAAAOzs7ADk5OQe9vb2zPn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f9/593/NtvM/znczf853M3/OdzN/znczf853M3/OdzN/zjay8w0yrweNtDCAAAAAAAAAAAAsLCwAP///wDv7+9O+Pj47Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/3/n3f8228z/OdzN/znczf853M3/OdzN/znczf8528zsN9PETkD45gAonJEAAAAAAAAAAAAAAAAA1tbWALS0tAPy8vJv+Pj49Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/f+fd/zbbzP853M3/OdzN/znczf853M3/OdvM9DjWx24qoJUDMb2wAAAAAAAAAAAAAAAAAAAAAAAAAAAA4uLiANfX1wbz8/Nz+Pj48Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f9/593/NtvM/znczf853M3/OdzN/znbzPA418hzMr6xBjTIugAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4+PjANjY2ATy8vJZ+Pj42vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/37m3f8z28z/N9zN/znczf8528zaONbIWTK/sgQ0yLsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1NTUAB8fHwDw8PAr9vb2nPj4+O35+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/vfDr/5Tq4v+L6ODtYODUnDTTxSsAGBsAMrywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOvr6wDj4+MG8vLyOvb29pD4+PjS+fn58vn5+f35+fn/+fn5//n5+f/5+fn/+fn5/fn5+fL6+PjS+vf3kPv09Tr/6u4G/+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADh4eEA1tbWAu/v7xv09PRJ9vb2dvb29pf39/eo9/f3qPb29pf29vZ29PT0Se/v7xvW1tYC4eHhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH4AAAB/AAAA/4AAAf/gAAf/8AAP//wAP/', // @suppress longLineCheck
+ green: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAAltklEQVR4Ae2dCXQcxZnHR3NoNDp8SD7kU7bxFXCchBhMYoLNmhCcOBBykGw2gYTkPV6AhGXD2sTZJQcJG3jsgw3hscuCsTEsOAQW1sbY+MAHxpYtHzI+5EOy5UMStnWPZkZzab9/j75WTWt6NKO5Z6r82lVdXV1d9e/ffPq6uro7zyBDIhXIi7DyngjLyWJRKhDpCYiy2pwoztrpxSwCb+d1bayFm9f1Yu3+cj2MAgOJH2bXnNnEGiHWppW8d999d/inPvWp6YWFheNMJlOR0WgswdLT06PElFdM+xbn5eWVQDXK76TI7vP57H6/v5PyOxFjobwuh8Nx4dixYye+9rWvtaK4ZqFVNY/TiGUIoQCfsBCbcjaLNVHgJRUQG3/4wx9ali1bNmXYsGEzrFbrdLPZjGUagTyNAB2ZCLXoh3CJoD/p9XqxnOju7j7R1tZ2/LHHHqtbtWqVh47pp0X8AaAZbPmRzvnAJzPXhRBhVoBeunSp7b777ruuuLj4xoKCghsI5s8TcPnpIBT9oNwE/D6Xy7Xdbrd/8Oyzz+5+/PHHndQ2LfA5D3suA85QGwmMPLLQ+b///e/nkIW+0WKxLKBlLuUXpAPQEbTB5fF4KmnZShb+g0ceeaSKLLyb9gPgIvQRVJVdRXIN8CCo77777oI//vGPt5CV/n5+fv5NdGrhK2dDsLvd7k1k3f/n17/+9frly5e7qFM5CXsuAM5QI4a1Nh4/fvza0aNH/4PNZvs2rZfRks2h2el0/u2TTz55dcaMGXuoo7DoolXPajcmmwFnsBWoKysrJ02fPv3v6QLxH2hUY1o2E63XNxqhOUkXqq+eOHHitblz557pBV2EXW/XjM3PRsBFsE21tbXXk7VeCheELhKzsb9Rw0cXqT1wYciqP37FFVd8SBX4aMlK0LPphKMvirWm2FRfX//lESNGLKXRj3m0LoOOAjQas/Py5cuPV1RUbKQiDDrDrrNX5mRnA+Aq2OPHjzfv3r3766WlpUvIDfl85pyG1LeU3Jd9LS0tT1x33XVrzp8/76UWAfKMBz2TAUfbFbgJbAuBfUdZWdkSuvFyZepxydwW0I2lo83NzQD9rwS69mZSxnUsUwFXXZHDhw/PmTJlytNksedknPpp3GCy6FV1dXX/OGvWrCpqpui6pHGr+zct0wBXLDZ1w/TSSy+V3n777b+j+R8/pYtHAC9DrwIO9xHD5c5XDF5fS0ya0MWo3+nwvrBx47nfLLlvKypj0DNmaDFTAEc7GW5zQ0PDD4YPH/4YuSMJmQMSExVpsPPxhjsMHt/FuLWkp8dwqb3dt2zhnD2vUKXsnwPytAc9EwBHG01YDh06NIuGtf5DjoyQGmHC4XMLwmwd/Caft2fnmXr3A3d8Zf9hqgXWHEtaQ57Of9pViz179mwrXeE/MnPmzF0S7sEDGuueJnPevCuusO76sPq6R2bPHm2l+sy0gKG0NZTp2jCG27R27drx8+fPf4lu1NwQ6wnKlf0TZcFF/bwe//Z9uxw/vvfuj89Tftr65ukIOI+QmE+ePPllGgJ8UfraIloDp5MBOFoB37zxQvdPvr5gP24SsW+OsfO0CenkoqhWe8GCBQWXLl36Hd1de1vCnTas9GtIXp5h5LgJ1re3H7z2dwsWjMTUYlwrpZXLki4WXIV73bp1E66//vqVNClK3mLvh1RkGcmy4GJr3B7/zkOVXXfd86PD5yg/bVyWdAAcbVBGSY4cOTKPbtqsJqs9QhRPpqNTIBWAo4U0l+1yw1nXd29duH8nrabFKEuqXRSG20yz/hZPnTp1rYQ7OpjTqTRNUhwxtsK69t3tcxZTuzDCAsOVUiOaSsBxbAhgoZl/d02YMOF1SttokSGDFSCabeVj819/v3LOXdQNCy04xynjLFUHVuGmu5K/HDNmzHN0ux2/eBmyQoEe84gRluc2V13zS+pOSiFPBeAK3PQQQj7NQ36CZgA+Kh9EyAqqgzpBQ4h5w4aZH6URlidwrmljSix5sgFX4F60aJGNXmzzYklJyf1BqsiVrFOgqNh0/5ubJr24aFEp3M+kQ57MCwAF7pEjR1rpBs4KeuD3W1l3NtOkQ6kaRQnXfZfL/+Y3bqz7Ed3f6KZyPIwYbpe4bEuWBVfgphbn19TUPCnhjsu5y6hKCgqM33pr4+QnwQAtSbPkyQCc4bY0NjYupXeQ3JNRZ0Y2Nm4KFBab7tlSdc1SqjBpF56JBhwuEI5hOXfu3N30rOS/xk0tWVFGKjB0mPlfN1bOuRtM0AI2EuomJxJwNBx/iix0QfkNupJ+mtIySAUMpSPyn16z5fPfICnYkicM8kQBznCbq6ur59Pt9+U0FAjYZZAK4J6+aczE/BffWn/1fJIjoXc8EwE44Ea95vXr18+gt0mtpjQmx8sgFVAVIEgKJkzJX/2fq66aQZmAHMzE3ZInCnATPRBcNG/evJU0t2SI2iuZkAoIChiNeUM+O6d45cLbxxVRNv7Cxx3weFeIHwwaar148eJTQ4cO/SmlZUiyAuk4Dh5Ogs5O3wsLPrfnQSoT9zHyeFpw/FhQn+Xo0aPflHCHO6Vym6hASYnpp29v+dw3wQ4tYChuhjdegDPc5jVr1kybPHnyM2IHZFoqMJAC48Zbn/nzi1dNo3Jx9cfjCbh54cKFRfS42Qrpdw90OuV2rQLwx6/9QvGKhQsVfxyQx8WKx6MS/EgUv5vmGTw5ZMgQeadSe/aSvJ5pPrgoj73D91/zr97zEOXFxR+P1YKrrsm+fftupNmBEm7xbMl01AoUlRjvWb1u9o20Y1xclVgBV6w3uSVFNN79JL3LLuoOyR2kAqICYKhisu3JBQvG8tBhTIzGsjNbb8vLL7/8C3oxz3SxoTItFRisAhaLcfqyP435Oe0f86jKYAFnuM2vvPLK5FGjRuHRJBmkAnFToLTM8tCfnpk5mSqMyVWJBXBcWFro6Zw/0Z+Vwrj1TFYkFSAFwNQX5w/5N0rGNCFrMICz9bZ8/PHH+MbkV+UZkQokQoGiQtPX/rb+M7f0Qg5WwV5UYTCAYx/zrbfeWkw3dJ6I6miysFQgSgXGV9ieWHjrqGLajV2VqGqIFnC23ua//OUv99PnriuiOposLBWIUgGLJa9iya8q8HA6Ax6VFY8WcJQ30Sewh9DrHn4WZVtlcanAoBQYXmr62fe+NwGzUnHdFxWz0RRm621ZtmzZT+hF9GWDaq3cSSoQpQImU17ZnfeO+gntFvWwYTSAo6wZN3XKy8vvjbKNsrhUICYFykZa7r1mwUjc/GFXJaL6IgWcrbf5+eef/wH53uUR1S4LSQXipIDZklf+m99N/AFVx4BH5ItHCjjKmehbObaxY8fiDpMMUoGkK0BW/OezZxdH9YasSABn621ZvXr1HWS9Jya9Z/KAUgFSID8/b+KjT02/g5IR++KRAK5Y73HjxuXT8oBUWiqQSgVGlVseoCnZfHdzQH4HKgDrjcX8xhtv/B1NqJqays7JY0sFLPl5U59bVbEQTNLCfOoKEwngGHs0013L78npsLo6yg1JUgAMjhlb8D0wSQvYBOS6YSDAsd30/e9/n54hHrpItxa5QSqQRAWKh5gWffWbY4bSIQF4WIbDbcQvA9vNS5cuvY2es8TVqwxSgZQrYDQabHffU34bNWTAIcNwgGObAjh9P+c70j1J+XmVDehVACyOLs//Dq0y4Loc621g59301FNPTSwsLPyiVFcqkE4K2ArzvvjPv52GIWv2w0P64uEAV6z34sWL76BfjF65dOqzbEsOKQAm5/9diWjFowZcGT2hx9G+nUO6ya5mkAL0WBsDzla8X+tDWWa+uDStWrVqBo19T+u3l8xIawUsplFp3b54NY7mik/703/MxNtpeTSlnxWHk64NKuCf/exn58uLS6086b8+3Pqg4WDNHw0O5yf9Gkuf9+sX6N3twXmaVWwMkUWv+Q7eLVShHk1mv310Kg9Vrt/h/PStQoN/PlVxhBYYa7AbVCwc4PQxzxHXS8ANhkZ7jaGq8W8Gh6ed9MuM4C2ebrD7Jhp6CIJsDr481/UGw4nnqY8MeFB3tYDjF6BY8KKiIjO9qeq6oNI5urL+1L8bOt2XM673PrPf4OjwZDXk/p6e68BqV1cXAx5kxUP54MgzrVixYpbJZCrNuLOagAZnItyQwWQ2GgppXlKeEec8OwON75V+/YErZlHv2A8P6qieBTddeeWVX5LuSZBWGbnCkDs7PQa/PyO7EL7RZI5HTCj+EhXaTwt7IKpfprXgintCBU3kf8+TgIfXNlO2AnJbicVAt7izLoBR2xDLPOoYW/CgP1eiBWf6TXRrPp/877lZp0YOd4ghhyUPNUKRydJYbaa5IyYU5l8+53BRP5hjxYprf9NYNz7zzDOfpl9GSSZ3Wra9vwIMORm9rArUn5Kbfzzt09QphV+xcyEt+Pjx42dK90SUKXvSDDksedYEwnrYyIKZ1J89tOhacN5gpLnfU7Om87Ij/RRgyLPJiFlsZjALC84cK/1GBgdswLqJZg9OzabOcwdl3KcAIC8oNuMtrn2ZGZpCHyxW0xXU/H4Xmgw49xLrRgJ8Sob2VTY7CgVUyLNgnLwXcIXfXgkUpvv54KWlpeaCgoKKKHSSRTNYAQXyIrPB1eXVzOLIrE5ZrcaK0lKbuaXFCbDZYCsuCfcEmcbf/va34ym2cqaMs18BhjyTZ/3TmKB17ncngV1Y8X6AM/XGq65SPsaZ/WdV9jBIAUBuLSSfnPFgIjIoHj2pCFO7xR6oFpy7YRw5cqS8wAw69bmz0gc5cMiwQE0uKrH0G0kRfXDFQbfZbBMyrGuyuXFUQIGc3p/Q7fSRT65O6YjjERJXVX6hCewqHPNRsILAFjyP3j2Iz0XIkMMKBCA3ZdwQosloBLsqyziFogXHBiNNkS3OhrFRdE6GwSsAyPPJkrvJkmeCHVeYNeUBcPbBlc7ziko9AY6XjMsgFVDmkysXnqAjAwIN54NdlWWkRQuOLuRJwCGDDKyA0ZRnsNrM5JOn/zi5yZzHgHPz1VEUZCjkS8BVbWSiVwGGXCEkjVUxGlXA1b85bMHVDAl4Gp/BFDaNIXe7vGk7uEL+iOheK0zzKAqkkxY8hQBlwqEBeX4BJmilZ2uNRuX6UeGYW8gWnNelD85KyDikAgy5uzv9xslNRvUiU217PwtOW7TQq4VlQioABRTIrTQzNc1MeU9eD9gNacHVPzper9dBH3mVj6tJlsMqwJB7yJKnyzg5vTXAITRaYZrHwdV8n8/Xpa7IhFQgjAKAnOZhp83gSo/foGVXGQfHD1D9EcKCh+mT3CQVCFKAIfe6yZKrFAUVSdqK39cjsqtwLfrgaEiPtOBJOx9ZcyBAbs7H3JUUd8mnWPCgn5l4QalskICn+CRl6OEVyMld8brp9VkpMuU9fj+7KCrkIS14v9fpZqjostnJVYDuJJIlJ6RSYMrBrK9HAVyFG71nC45MZZE+eHKhyLajMeQ+jz/phtzvy4MPrrIMbUULzoDbs0102Z/kKgDITRZj0g253+8Huwy40mm24KoCTqezBeZezglXJZGJQSgAyA0EOSx5MgLcfp+7p0V7LLbgTL2/tbX1tLaQXJcKDEYBtuSD2Xcw+zg6u8EuflHMs+KiYAVByTx58mSdvMgMCCL/j12BpEFO9Laed9Yxx70t72ELjnUF8DfffFMC3quOjOKjAEOeyMEVfOyqevtFLeD9RlH8GzZs6Ozu7r5E81FGxqd7shapAI1mwCen5zz93sT45H5Pz6UTey52ktb9XBTor1jv3o1+u91+RropkEWGeCoAyI0EebyHV8Bqt8t7htoKuEMCjn4AcqWAw+E4jQwZpALxVkCBnG7tK5DDZ4nT4nb5wawIuNJ09sFFC+7DSIq04PE+tbI+VoAhj5dPjiHCbrsXgNNTGMEWXBwHVyFvamqq48bIWCqQCAUAeQ8ZcJoBGHP1+KF0NHvALCw4c6zUG8qC+995551DNOkq9iPH3HRZQTYrgJuJmKQVa6CvOffUfNhwiOoRXRSFXwYcx0AGCvjoI7CX2tvba6WbAllkSKQCsUKuXGB2eWsr37twidopuihKs7WAM+Te5ubmSgl4Ik+trJsVYMgHMz0E/ndXm6eS6qI3E+m7KHwsxYLTiq+2tna3BJxlkXGiFQDceDe5EiMd6UIPzLU0OneD2d4FDKtBz4L7li9fXkmzs4IKq3vJhFQgAQow5NFUTYT696w5DwsuuieK/416QgGu/BLWrFnTSn54jbTi0cgty8aqgAo5rj0HWHB7vtvhqTnyUVMrlWYLDrhDAo62YQOsNvwZLw0X7pGAkxIyJFWBgHsy8CHhf9tb3Pj4q8IrxWBXhRs1iBYc6ww4fg1e8sN3ScAhiwzJVoAhJ1dc/2YnNaq5oWsXRQBcdFHU5oo3epAJwBly79NPP73npptuchUVFRWoe+RgwnXRZmh3YBQqu4OuMQuyiX0a6GQHCuhs1D1GX7VBKVhp7APgtfvSS4dcm1bUsQVn6x105FCAo6Diz3z00UedjY2NW6dMmXKL0ag19kHtiHil9nyj4b2dVYaOLvEVFhHvnpKCXs9XDUa3m44dpF1QW7TiB23UWdHdR+cw8DlDBlCgE/S30A5h9tOpLubsaG/r6JWnJ+gNrtbmrRdO7sYMQva/GXK1nVrAsQGaoCDMvufgwYP/N2nSpLgB/sJb6w0tHWhTZgV3t4teidBNjYbkkEhPem2/uCyjpt1fu127f7LLa4+vbZ+2Pdry2vWB9tdu1+6vPV6gvN/vMzTUHv8/Ku2hBaz2gxs1hTLLqIEB995///07aPpss661QS1RhEyEG93LtxbQKxH4+7gQPdLAZRGLad5fzOMyYoxyXEZMi2XEtFhGTItlxLRYBmltQFkE3ofTSmYE/w20v3Y7H4dj7fECrorP42mu2rZhB23VvcDEnuEAh9n30MxC5/nz59+LF+A4aKaGAOT5wbxpO6M9X9jOedqyqVjntujxo21Tostrjxfheldnx3tuu91JxWHBQ15goqpQgCMfFpytuGfTpk3v0PtSkJ/zAZBbLL2QMyRiDIUYCjEtlkllWmyTmNZrk1hGTMervF49YfL99JbNpvrat6k5onsCXvsFPcDhpuBXofjhS5cuPdzW1nZKWvGAfhaGvJ+cMiPRCoBBj8t16tCOTUfoWAw4WAWz/UKoi0wUQmGGHJW4aUx8TVlZ2YP0DR9sz/kAyBG8HsgjQ7IUAOD2jvY1dDwMa0F8hjsk4HoWHO2FyVet+MqVK9+hh5Hl2YQyvQGQm/PJXQkXcKcCge9YcFrJDPFftOVDVJFWWdH2Z4Dy9PpjT92R/e9QH8EiPAwwGtI9oXxdHxzb8ItgP9z90ksvNZ45c+ZdOf8K0vQFC42sKJAzwNoYRfmkiWltOV4Xy4hp3p5psdgHMa3XD7GMmKbyALKrs/3dMx8faKQkLDgAB6MhrTflRww4fi3uV1999QWy4rq/FlSYi0GB3GLJxa4ntc9+r9d/5tjHL9BB2T2JCXA0PsiKP/nkk7Vnz559X1rx/ueVIQ9z8a+OJMsygYGmaHTAXVdnZ+f7x/bsqO0FfEC4cZbC+eDYDmutuimU7v7rX//63x6PR/dPAnbK1QDITcoQYq/fDSHwp5hjMR3I7b9d70+3Xj7XPdj6Yt1f266B6htou7a+3nW6c9lTf/Lwf9PuuJ0suidhPYqBAEdzUAEcecVN+cMf/nCMrPg2acUhTf9goYtOk5ncFT5RKII0B07rbedykcax1hfr/tp2DlTfQNu19dE6Rk4c9o5th3d+cIxW2T0Je3HJ1UQCOKy1Cjilu9etW/c8WXGuQ8YaBVTINflydXAK+H007+TUyedpb7begA9MDuhJRAo4W3H8erqXLFlS3dDQsEtacVJDJ0jIdYSJMhvW29nVuevAtvXVtCsDztY7LoCjSWzF4dgDctfatWufkSMqkEY/AHIzja5gLjMHTgcm9AfyOQ9lOM3bo43FOsS0Xj1iGaQHCtG2D/XxPmKa2yPmiWne3uP3+Zvqjj9D21y0gD0wGJH1pnIDXmSiDAIAD7rYfOihhw7Su8TflnNUFH10/zPTRafJbFZOMp9ojrETp/mEinm6lYbZEG192vLcDr042vZp69fuH247psR2tDS/XbVl/UHaj613RKMnLFEkLgqXZSuuXGzigA8//PDT9GByK/6MyKCvAEOuX0Ju0SoAprzd3a3VO9Y/TdsY7oh9b64vWsDZF8cBXZs3b75UWVn5Z3nByXLqxwHI5c0gfYWCt8B6Nzde+HPj6dN4VhDuCZiL2Pfm2qIBHPuIVlyB/Pbbb3+THmurlhecLKl+DH9cHULkYuyfI45kwX68j5jmfcU8Mc3b4x2LxxDTescRy4hpoTwezXN1dVVvfeuVN6kIwx219Ub1gwGcrbhysYkGrFq16jGXy+WTrgokDR8UyE00iZNPKIojHWngsnr7D7Q90uNEWi7a4w1QHgz5vF5f3ZEDj1ETADdfXEZtvdGFaAHHPgw4flGKFX/00UePHDt2bDW9kRbbZRhAAYYcWMslWAMDPcxgb768mm7qYL631nqDvajCYADHARhytuLOBx544NnLly83SlclMv0BuZFGV2ToU6CH4HY7nI37Nr/3LOXicTSt9e4rHGFqsICzL66Oi+/du7f5tddee5g+f+KRrkpk6pvplr4CObsbORwDKBpy9pyuqX74YkN9M60y3FGNe2uVHyzgqIchV604DRvuI9CfpRtA2uPIdR0FFMjlU1L0pQcvjZo0PHvggw37SCqt9QZrgwqxAg5XRbXilHbdcsstK+vr63fIG0CRnw+GPFf9cbpbaejqaNuxZfXylWCod+G7lmAsJYDjDOLgWPiCE788x4MPPvgb8sc/kf44qRFhCECeez45/O5up/OTqo3v/oakwuvOwBBcADDFfFFycCEWC85HRCMwfIJfHBrnpBtATa+//vqvyB/3Sn+cFIkw4Ja+URxCzHKfHGaZ/tJ76SmdX9FrIJpoVeGHYrDEw4KUHHyIB+BoJxrDrorSSHrVRNWePXuegz8uIY/8BCmQG7P/zQVgAn735aYLz+3fsq6KFBLhjunCUlQ7HoCjPoY8yFVZtGjRcpqQtdGtvLhSPKxMh1MgYMkBefZ65TRJ0NDZ1rpxy2vLl1NHta4JDCaYijnEC3A0hCHnURU02rF48eJ/oYvOvRLy6M6ViVwVoymepye64yeytI8sd1dH+94tb6z4FzDSu/CwYNzgRh/iqSAAF/1xNNhBX4nouPPOOx+iByRq5KQsSB55YMizyRXHiEm3vbNm99o3HnJ2dHSQGgBchBsMxcV6Q+lEOHtonNjAPILcW1dXt3P+/PkLPth/eGgePqclQ0QK4L3synvBs2BKMmYIuhz2c/s2rf1ZY33tJyRAFy0MONzbuFpvCJwIwFEvQhDo5It3d3Z27naYCm6mGXWFPNE9UFT+H04B/vhAgPHM9Mv9fvpglNPZfGjnpntOHzl0lvqrhTuulpv1TBTgogVX0wcOHOiix7j2Dx899is0HJYvIefTMHCc1/uFjUwckcL9EHphpv34gY/uq9nzUU0IuGG5AXjcQ6IAR0MZbI6VxjfV17UVlQw5OqR0xEKah2GRkEd+TlXIIW2GGHK86tjtcjnqjx74pwNb38dteNFyx228W0/FRAIuHhOQq6BfqD1+0WIp2Dds1KgFNCRmkz65KFX4tAp5Bvjk8LndDkfriQN7fn5g6waMdTPcGPNOONxQMtmAq6DTnasWn8e1s7R8wvVkyEv4xKFRMoRXQDUIiiGnz16n4b8eGud2d9kbqnd+cC+9bu0o9chOCwBnuHEzJyF+N9WrhmQBjgOyBVchv9xwobOro3XbqPGTrjVZLGV8MaW2TiZ0FQhATlKyqrolk78B49z0HsGT+zatua/uyMHT1AKAnXS40fNkAo7jITDgStx++aKz+cLZD8onTZ1NryEeA59c+uUBoQb6X4UcBdPAJ8dwJt5CRTMDD+xY88YvGs+caqCWad2SpFhu1i7ZgAfBTY1Q1umdz+7zp45uHXfFjCn0AstJeUYJOZ+ggWLVXUmxKcesQHqWkm6/t2zd+saKJW0Xmy5T2xlu3MjBDMGkwg3tkg04jonQD3S60vbVVh/cPmbyFGu+rXA2+eRkyGGWZBhIAdYpYMST75H30Bg3fcqlp62p4eWNry7/N3rVWju1WYQbF5RJhxu6pQpwHJsh5wsN+nit13+quupA4ZChNSVDh881mkw0wiKtOcQaKEAnCJrMoMwIpJESj6Orlaa8Ltv2v6++QeeQLybFO5QpgRtapBJwHJ8hR6yCfuFUzQX6U7d5RPn4K8kvL5cuC6QaOKiQJ8EfJ2/bgItJR3vbwb1b1v3iaOX2Q9RCWG223HBJxKHAZP/+FMHSBXDAzYsCPV18dp06eGBjecVkk7Ww6DPSZVHO14D/sbsyYMEYCuDOpNfj7mlpOL9yw6oXf996sQFvn4LFZri1k6diOFpsu6YacLSef9lsxVXQ6c+d79ShqoN05/NI0TByWYxwWWjAQPrmYc96nz7xNeWBhxRofNvpbDl7rPpX2/73f97qdUkYboxx88Vkwm6/h+28ZmM6AI4miZCLoCvp86eON9ibWzYPHVk+mlyWKXBZMC7WdyI1vZKrvdqwrLEJArAxSoJvgna0XNpctXntkqOVHx6mWtliA3DtDRwYqpQHkJJOAe3BXFr88PCmSist+OKqjZZCpK+55bYvVEy78pcFRcUT8eRL3zAZbZWhnwIAM5bAw3/dXfaz9SeO/vve99fsovrggjDUPATI011xwPj8smJpeO++6QY4mhUwzwHI8Zg5vrQKyBl0W0FJSfENt/39D0pHj73LYrVayXWR1pwE0guBGYjRMaeOkNBDtc1NDSs/XLP6FVdnJ0ZIYKmxAGz2tTFKwnO5ozsQ7ZjIkC4uiraPLBJiLLAK7NP5vG63t/bQvkMOR8emoWWjx9Fr0CZKt0UrYd96nyvHtkM/xhwudkfsra0fHtz6/j/v2/zuB6S5OPwH6y3CjfMT25+KvubGNZWOFlzsINrHLgtbc7bocFsUyz7vq9+6oXzK9PsKCgsraE6L4rb0nVSxutxOByx5aA3Yz/aRn+1yOOobT598dte6N7dTabbUbLUx9Mc3btjosEEKXXkKc9MdcJYGkDPo8M0BOfvnCuRms7lg7uJv31Q+ruJOa1HxVLzcEv65BJ0lDB0z2LiAJD/7VNOF+pcr1/5tE72uhMHmmMe1RV87La222NNMARxtZmsO0GHNGXQAzrAjtn5x0Te/VD556p0FxSVX4Y1RmIorQSdlhKCAjfFsL1lse+eRptOnXv7ovbd2UBGAjAVgcwyLDbD5jiTATlurTW1TQyYBzo1Gm3HtwKDDmrNFVwCndSW+5uavXzNu8oy7CocMuRpfVgi8hiF3hxcDLgpm/GFilMfg6OjYf+H08ZU0MrKXNGOwxVh0RwA1X0hSMjNCJgIOZdFuLKLbAovOQ4si6PlXz7959tipM28rKhm2wGzNL8TrGHLlopShxoQo3Fr3drsdXZ1tWxtO1byzf9v7uL0OiEWokYa15kX0szPCalPb1ZCpgHMHGHIGnV0XBp0tu2Lli4eNKPrc/C8vKC0v/0phybA5NI5uogldivuSbePpGAkB3JifjU+CODrbqlqamjYc2LZxq73tMm7QsHUG0Aw5Q83DfrDaGeOOMBRinOmAc1+0oPONInZfxFix9BOmXjVq+py5Nw8rG/kVmp47lV+XFvDVM8+NUS11H9R0S91xqq350oYTVZXvnzt15CKJxQAz3GKMbbDWbLEzGmwRDE5nQ8ygIwbksOhs1QE54NbG5qu+cMO0cZOmXW8bMvTqgsLiWQS7FW95hc+ersAHA+1XXmRJlrqbXqxz2NnRvv/CmZMfHtm1/ST1F9YY8ALmUDG2s8WGC5IVYFM/lJAtFpz7wzH6xbADdF4AuBZ4xaJTvrKtoLjYOuvaL80qGzPx8wVDSq622Yo/ZTSbLLhbqjwzqsxPp9JKCMiXqBGaAMQ4UMD1xU0Y8jsMmM2HJ9ZpLprH6bQfc3V07m9uPLvv8J4dh112O1wOhhpA88KA8za21myxldqpfFaFbAWcT5IIOvx00VcXrTtDznkcm4aWlRXOuGbeZ4aXjfm0xVYwMT/fOtFsLRhnwsMYyvCjUQG/76KVD62NtVIHoNWWUiAmoHFRCJAVX5pi+oKdk+zzBbe7+6zH6Trb2tz48fG9O6vbm5txVxGQsiXmmMFGzHmIGWjRvw7dGCqc6UGreqb3J1z70VcAzjFbddGVYbC1sVhW+aFUzPzMqNETJ1YUDyubaLUVVeRbrRNMFnOZyWguzAvAj9fToZ6AmwPLjxUKCk1EMltoir30OJOjhyD2+b0On8fb7O7uPtft7Kq3tzWf/eTs2fr6mmr40AylaH1FeEOlxbLsfnCstCeb/2PNs7mP2r6hz+ICeNmycwwwGWqGnde5jBgjjUWsN4/cHfPQ0lFF9PidzVpUWFRgK8KMSIPL2eXo7qLRuvZWZ3vLxS5yKwAmuwgcM8yI2eqKMdIMNEOMdbEM78t1ckzFciPkIuDimQ0CkjYwqByL8IuAY7u4jcujPqS5XkoGpbEuBhE4TrN1ZcC1wDK0DDWvc3mOuT6OxePmTDrXARdPNGvBcCLWgsvrDDEgRzmOOT9UXTgW5wM6BIZPuw5IkQeIxZjh5RjbxDTWsSBwHFjL0f9Z8BztfthuszaIwy0i1NpyOIBYj3hABlCMkdYuDLs2X1xHvViXQaMAi6/Jlqs6CrBeDDKKhcsTt+tUGQQmQ8rwYp9weXp1yvxeBfjkSEFiU0Cro3YdtWvzGFzxyNo87bpYVqYjUOD/AZrbm7Ts1rpFAAAAAElFTkSuQmCC', // @suppress longLineCheck
- red: 'data:image/vndmicrosofticon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQxmbAC0RagpDGZs8ShysdkwdspdMHbKXShysdkMZmzwuEWoKQxmcAAAAAAAAAAAAAAAAAAAAAAAmDlgAAAAAAUQanzRPHrilUx/B6VQgxf1VIMb/VSDG/1Qgxf1TH8DpTh22pUMZnDQAAAABJQ5XAAAAAAB7ensA//8AAFUrr09SH8DdVSDG/1Ugxv9VIMb/VSDG/1Ugxv9UH8P/Ux/B/1IfwP9QHrrdRxqlTwAAAAAoD14A+fn5ANzf1zmMatPfVB7G/1Ugxv9VIMb/VSDG/1Ugxv9TH8L/UR68/1AevP9QHrz/UR68/04dt99EGaA5UB67ALS0sw3x8u+unYDd/1AZxP9THcX/Ux3F/1Qexf9THr//Tx23/08ctv9PHbb/Tx22/08dtv9PHbb/SxuurjkSfg3h4eFK+Pj38LWf5P97UtL/fVXS/31V0/9fOcz/SSfC/0knwP9JJ8D/SSfA/0knwP9JJ8D/SSfA/0gnv/A/KLNK7e3tjPn5+f/29fj/8vD3//Px9//y8Pf/fILz/zQ/8P83QvD/N0Lw/zdC8P83QvD/N0Lw/zdB7/82QOz/Mz3gjPHx8bL5+fn/+fn5//n6+f/5+vn/+fn5/36G9v8yQPT/NkP0/zZD9P82Q/T/NkP0/zVC8v80QOz/M0Dq/zI+47Lz8/O2+fn5//n5+f/5+fn/+fn5//n5+f99hvb/MkD0/zZD9P82Q/T/NkP0/zVC8f8zP+f/Mj7k/zI+5P8xPd628vLymfn5+f/5+fn/+fn5//n5+f/5+fn/gYn2/zdE9P87R/T/O0f0/zZF8P8yQOP/MT/e/zE/3v8xP97/Lz3ZmfHx8Vz4+Pj3+fn5//n5+f/5+fn/+fn5/9fZ+P/Bxfj/wsb4/7vD+P87j/X/Dnzx/xF98f8RffH/EXzw9xZv5Vzr6+sY9/f3xvn5+f/5+fn/+fn5//n5+f/7+/n//Pz5//38+f/x+Pn/OrD+/wCY//8Amf//AJn//wCZ/cYAlPMY////APT09Fb4+Pjy+fn5//n5+f/5+fn/+fn5//n5+f/6+fn/7vX5/zmu/v8Al///AJj//wCY/vIAlfpWAJ//AOzs7ADm5uYF9vb2ePn5+fT5+fn/+fn5//n5+f/5+fn/+vn5/+71+f85rf7/AJb//wCY//QAlvx4AIzrBQCQ8gAAAAAA8PDwAOzs7Ab29vZd+Pj40vn5+fz5+fn/+fn5//n5+f/x9vn/bsP8/CGk/tIAlvxdAJDyBgCT9QAAAAAAAAAAAAAAAADn5+cAqKioAPT09CH39/dy+Pj4tvj4+NX4+PjV+Pj4tuvy93LD4fUhAAC7AESo6wAAAAAAAAAAAPAPAADAAwAAwAMAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgIMDBoKPRwoD14tLhFrNy4RazcoD14tGgo9HAYCDAwAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+3/wANBR0KLxJuMUEYmGxKHKyiTh22x1Aeu9tRHr3jUR6941Aeu9tOHbbHShysokEYmGwvEm4xDQUeCv+6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoKPgAHAxAHNhR9PEkbqppRHr3hVCDE/FUgxv9VIMf/VSDH/1Ugxv9VIMb/VSDH/1Ugx/9VIMb/VCDE/FEevOFIG6maNRR8PAcDEAcaCj0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADVUP8AJg5YGUYao4BRH77kVSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMX/VB/E/1Qfw/9QHrvkRRmggCUOVhnQTv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA////ADITdSpMHbKvVCDE+1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VCDE/1Mfwv9TH8H/Ux/B/1Mfwv9SH7/7ShytrzEScSr///8AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAMto/wBVPoYsUSC3v1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1QfxP9SHsD/Uh6//1Iev/9SHr//Uh6//1Iev/9SHr//SxywvzMTdyymPf8AAQACAAAAAAAAAAAAAAAAAAAAAAD19fUAnaKQHbep1rVfLcn/VB/G/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9UH8P/UR6+/1Eevf9RHr3/UR69/1Eevf9RHr3/UR69/1Eevf9RHr3/ShuttS0RaB1PHrkAAAAAAAAAAAAAAAAAeXl5ADY2Ngnf4NyO18zu/V8tyf9UH8b/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VB/D/1EevP9QHrr/UB67/1Aeu/9QHrv/UB67/1Aeu/9QHrv/UB67/1Aeu/9QHrr9RhqkjhEGKAknDloAAAAAAAAAAAD///8AxMTES/b39O3Zzu//Xy3J/1Qfxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Mfwv9QHbr/Tx24/08duP9PHbj/Tx24/08duP9PHbj/Tx24/08duP9PHbj/Tx24/08duf9NHLTtPheRS5s5/wAAAAAAm5ubAHBwcA/o6Oix+/z6/9jO7/9fLcn/VB/G/1Ugxv9VIMb/VSDG/1Ugxv9VIMb/VSDG/1Ugxv9TH8H/Tx24/04dtv9OHbb/Th22/04dtv9OHbb/Th22/04dtv9OHbb/Th22/04dtv9OHbb/Th22/04dtv9JG6mxIw1RDzAScQD///8AycnJRfX19fD7/Pr/2M3v/1wqyP9SHMX/UhzF/1Icxf9SHMX/UhzF/1Icxf9THcX/Ux7A/04ctf9NHLL/Thyz/04cs/9NHLP/TRyz/00cs/9OHLP/Thyz/04cs/9OHLP/Thyz/04cs/9NHLP/Thyz/0wcsPA/Fo9FYyTkAAAAAALk5OSN+fn5//r6+f/n4vT/noDd/5Z22v+Wdtr/lnba/5Z22v+Wdtr/mHfb/35g1/9KMMr/SC/H/0gvx/9IL8f/SC/H/0gvx/9IL8b/SC/G/0gvxv9HL8b/Ry/G/0cvxv9HL8b/Ry/G/0cvxv9HL8X/Ry7F/z8tuI0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/6+vn/+fr5//n6+f/5+vn/+fr5//n6+f/9/fn/ub73/zhF8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zVC8f81QvD/Mz/mxR8njhbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z8+f+5vff/OEX0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P81QvH/NEHv/zRB7/8zQOrlKTO6M9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pz5/7m99/84RfT/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NULw/zRA7P80QOv/NEDr/zNA6fQsN8lQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8/Pn/ub33/zhF9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zVB7/8zQOn/Mz/o/zM/6P8zQOj/Mz/n+S04zmHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z8+f+5vff/OEX0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P80Qe7/Mz/m/zM/5f8zP+b/Mz/m/zM/5v8yP+X6LjnPZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pz5/7m99/84RfT/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NEHs/zI+4/8yPuP/Mj7j/zI+4/8yPuP/Mj7j/zI+4fctOMxa3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8/Pn/ub33/zhF9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zRA6/8xPeH/MT3g/zE94P8xPeD/MT3g/zE94P8xPeD/MT3e7ys2xkLS0tIj9fX12fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z8+f+4vff/NkP0/zNB9P80QfT/NEH0/zRB9P80QfT/NEH0/zZC8/81P+n/Mjze/zI73f8yO93/Mjvd/zI73f8yO93/Mjvd/zI73f8xO9rZKTO7I56engjy8vKu+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+/r5/9ze+P+covf/mqD3/5qg9/+aoPf/mqD3/5qg9/+aoPf/UoLz/x1p5/8eaeb/Hmnm/x5p5v8eaeX/Hmnl/x5p5f8eaOX/Hmjl/yBh3a4jJokI////AO3t7Wr5+fn++fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+vr5//z8+f/8/Pn//Pz5//z8+f/8/Pn//Pz5//z8+f9dvfz/AJf+/wCZ/v8Amf7/AJn+/wCZ/v8Amf7/AJn+/wCZ/v8AmP7+AJLxagC4/wDr6+sA4eHhJPb29tv5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/1u8/f8Alv//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCW/NsAieckAI/xALu7uwAAAAAA8vLygfn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/W7z9/wCW//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJP3gQAAAAAAcr8AAAAAAOzs7ADk5OQe9vb2zPn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f9bvP3/AJb//wCY//8AmP//AJj//wCY//8AmP//AJj//wCW/MwAi+oeAJDxAAAAAAAAAAAAsLCwAP///wDv7+9O+Pj47Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/1u8/f8Alv//AJj//wCY//8AmP//AJj//wCY//8Al/7sAJL0TgCr/wAAa7QAAAAAAAAAAAAAAAAA1tbWALS0tAPy8vJv+Pj49Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/W7z9/wCW//8AmP//AJj//wCY//8AmP//AJj+9ACU+G4AbrgDAIPaAAAAAAAAAAAAAAAAAAAAAAAAAAAA4uLiANfX1wbz8/Nz+Pj48Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f9bvP3/AJb//wCY//8AmP//AJj//wCY/vAAlflzAITcBgCK5wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4+PjANjY2ATy8vJZ+Pj42vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/1u7/f8Alf//AJf//wCY//8Al/7aAJT4WQCE3AQAiucAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1NTUAB8fHwDw8PAr9vb2nPj4+O35+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/rNv7/3bG/P9rwfztM6r7nACR9SsAER0AAIPZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOvr6wDj4+MG8vLyOvb29pD4+PjS+fn58vn5+f35+fn/+fn5//n5+f/5+fn/+fn5/fn5+fL6+fjS/Pj2kP338jr/+eIG//fqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADh4eEA1tbWAu/v7xv09PRJ9vb2dvb29pf39/eo9/f3qPb29pf29vZ29PT0Se/v7xvW1tYC4eHhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH4AAAB/AAAA/4AAAf/gAAf/8AAP//wAP/', // @suppress longLineCheck
+ red: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAAk/0lEQVR4Ae2dCZxUxZ3Hq8/pnhkGmOEQuQS5VCTxWHEDBlyNkciakMMkxujGuOvHO24IKCae0UQlKwmyroocoqtozGpA4oFiVAQU5IaRcchwDsPczNF39/5/b+bfVL/p7ume6bur+DyqXt31r2//5//q1XvPIJRLpgQMMVYeiDGfyhanBGKdgDirzYvsLLtIPguB0/lc7+vh5vNIvr68Oo8ige6EH6Vo3iSxjODrw1rcm2++2f+MM84YV1hYONRkMhUZjcY+OAKBgOZTXDGVLTYYDH0gNYpvIa/V5/O1+v3+FopvgY+D4tra29uP7N27d98VV1zRiOy6g06DcRyGr1wYCfCEhUnK2yiWiQYvSQG+8ac//all3rx5o/v16ze+oKBgnNlsxjGWQB5LgA5MhrToh1BL0Fd4vV4c+1wu176mpqYvHnnkkf0rVqzwUJt+OuQfALrBmh/hvHc8mfkuCBlmDei5c+fab7nllguLi4svttlsXyeYzyPgrJkgKPpBuQn4LU6n88PW1tZ1ixYt2vjoo486qG964PMe9nwGnKE2EhgG0tDWBx988HzS0BdbLJbpdEymeFsmAB1DH5wej2cTHR+Qhl937733biYN76ZyAFyGPoaqcitLvgEeAvX1119ve/jhhy8nLX211Wq9lKYWtnIuuFa3272WtPv/3nPPPW8tWbLESYPKS9jzAXCGGj60tfGLL764YPDgwT+x2+3fp/MyOnLZ1Tscjj/X1NS8OH78+E9poNDoslbPaTMmlwFnsDWoN23adNq4ceN+TBeIP6FVjbG5THSksdEKTQVdqL64b9++lyZPnlzVCboMe6SiWRufi4DLYJsqKyunkraeCxOELhJzcbxxw0cXqQGYMKTVHz399NM/pgp8dOQk6Lk04RiLpq3JNx04cOAbAwYMmEurH1PoXLkIEqDVmPV1dXWPjhw58l3KwqAz7BFKZU90LgAeBHvYsGHmjRs3/mtpaekcMkPOy55pSH9PyXzZ0tDQ8NiFF1646vDhw17qESDPetCzGXD0XYObwLYQ2FeVlZXNoRsvZ6Yfl+ztAd1Y2lNfXw/QXyHQ9TeTsm5g2Qp40BTZtWvX+aNHj15AGvv8rJN+BneYNPrm/fv3/2LixImbqZuy6ZLBve7atWwDXNPYNAzT0qVLS2fNmvUA7f+4gS4eAbxynRIwHN8ozDseFQZHTW9l4m/3BBa/8nnDfT97vKqBKmPQs2ZpMVsARz8ZbvPRo0ev6d+//yNkjiRlD0hvqUh3ecsrpwtD2+GEdcMfELUNbWLewNniBaqU7XNAnvGgZwPg6KMJx44dOybSstYf1coISSOKsy4tiJLa8ySPX6wvrxN3TLpX7KJaoM1xZDTkmfynPaixJ02aVEBX+PdOmDBhg4K754D2tqTFKKacPVhsOPEnce+kSQK/IjMdYChjFWWmdozhNq1evXrYtGnTltKNmq/3doLypXyyNLgsP49XfPhOpfjZzCcEbKGMtc0zEXBeITFXVFR8g5YAn1O2toxW9+FUAI5ewDY/UC9+PvrXAjeJ2DbH2nnGuEwyUYJae/r06bba2toH6O7a6wrujGGlS0eMBjFw1ADxetMT4oHpZ2lbi3GtlFEmS6Zo8CDca9asGT516tTltClK3WLvglRsEanS4HJvXF6x/v0vxHXfWigOUXzGmCyZADj6oK2S7N69ewrdtFlJWnuALDwVjk8C6QAcPSSTpa6iTvxwwm/EejrNiFWWdJsoDLeZdv3NHDNmzGoFd3wwZ1JuMlkGjBsoVlf9TsykfmGFBYorrUo0nYCjbQjAQjv/rhs+fPjLFLbToVwWS4Boto/sL14++ri4joZhoQNznDbO0tVwEG66K/nLIUOGPEW32/GLVy43JGAeUiKeqvsv8UsaTlohTwfgGtz0EIKV9iE/RjsAH1IPIuQG1SGjCAhDWaF4qHmBeGzwYIG3EaRFk6cacA3uGTNm2OnFNs/16dPn1hChqJOck0CJTdxaeY94bsZkzfxMOeSpvADQ4B44cGAB3cBZRg/8fi/nZjNDBpSuVZRow3d4xGsjHxT/VlsrXJSPlxGjFUlIWqo0uAY39dhaXl4+X8GdkLnLqkrsFvE90uTzwQAdKdPkqQCc4bZUV1fPpXeQ3JhVM6M6mzAJ9LGJG+v/IOZShSm78Ew24DCB0Ibl0KFD19Ozkr9JmLRURVkpgdIi8Zvqx8X1YIIOsJFUMzmZgKPj+FNkoQvK79CqyQIKK6ckIE4pEQsqHxbfIVGwJk8a5MkCnOE2b9++fRrdfl9CS4GAXTklATwiYRpVJp7bfb+YRuJI6h3PZAAOuFGv+a233hpPb5NaSeHkPGJCFSuXnRIgSGwTBomVb/2nGE8jAORgJuGaPFmAm+iB4KIpU6Ysp70lJdk5BarXyZaA0ShKLh4tls+6QBRRW/gLn3DAE10hfjDoaMHx48ef6Nu37w0UVi7FEsjEdfBoImh2iMX97hR3Up6Er5EnUoPjx4L6LHv27PmugjvalKo0WQJ97eKGLx8U3wU7dIChhCneRAHOcJtXrVo1dtSoUQvlAaiwkkB3EqAngxauuk2MpXwJtccTCbj5kksuKaLHzZYpu7u76VTpegnAHr9svFh2yQTNHgfkCdHiiagEPxLN7qbnKOeXlJSoO5X62UvxebbZ4LJ4yB5/muzx2RSXEHu8txo8aJps2bLlYtodqOCWZ0uF45YA7T68cfu94mIqmBBTpbeAa9qbzJIiWu+eTy9Wj3tAqoCSgCwBIETr4/OnjwsuHfaK0d4UZu1tef7552+nF/OMkzuqwkoCPZWA1SzGvXS9uI3K93pVpaeAM9zmF154YdSgQYPwaJJySgIJk8DgvmL2C/8hRlGFvTJVegM4Liwt9HTO78k0KUzYyFRFSgIkATJVCq88S/yOgr3akNUTwFl7W3bu3IlvTH5LzYiSQDIk0KdAXEEbsi7vhBysgr24XE8ARxnzlVdeWUw3dB6LqzWVWUkgTgmMHSgeu3Ky9oFeNlXiqiFewFl7m5988slb6XPXI+NqTWVWEohTAhaTGPnMLIGH0xnwuLR4vIAjv4k+gV1Cr3u4Kc6+quxKAj2SwIA+4qbrpwjsSsV1X1zMxpOZtbdl3rx5P6cX0Zf1qLeqkJJAnBIwmUTZ/TPFz6lY3MuG8QCOvGbc1DnllFNujrOPKruSQK8kQG/Kuple0Yx942yqxFRfrICz9jY/88wz15DtfUpMtatMSgIJkoDZJE5Z9mNxDVXHgMdki8cKOPKZ6Fs59lNPPRV3mJRTEki5BIb0FbdNOj2+N2TFAjhrb8vKlSuvIu09IuUjUw0qCZAErBYx4i/XiasoGLMtHgvgmvYeOnSolY47lKSVBNIpgWH9xR0lJcG7m93y210GaG8c5ldfffVfaEPVmHQOTrWtJEAbsca8f7O4BEzSwXxGFEwsgGPt0Ux3LX+ktsNGlKNKSJEEsJ121CDxIzBJB9gE5BFdd4Aj3XT11VfTM8R9Z0SsRSUoCaRQAn0LxIyrvyb6UpMAPCrD0RLxy0C6ee7cud+m5yzV50VIGMqlXwL0/Kb9nsvEt6kn3S4ZRgMcaRrg9P2cHyjzJP0Tq3rQIQGYKSP6iR/QGQMekeNICdDeOExPPPHEiMLCwq91VK3+VxLIDAkUWcXXnrhaYMma7XDw2sVFA1zT3jNnzryKtHekfF0qVBFKAqmQABFpnDUxRIvHDbi2ekKPo30/FR1WbSgJxCuBwcVBwFmLd6kinGbGLwHxphUrVoynte+xXUqpiIyWQKBoWEb3L1GdozXxsS/9u/Z2Wl5N6aLFYaTrXRDwr371q9PUxaVePJl/3nzef4uaN28S7hNHunQ2EOgSRa/r1rkuEXild1enr6unecJVHktd9OlwaOJp1LPddEApg92QotEANw8YMGCqApwktmen8K9cIURTI8kv810BdXGI72JR73LR9+ND5jvzOx9nD80u11QhVj1DxRjwkBr0gOMXoGnwoqIiM72p6sKQ3Hl64nv0fhGoPZ5Vo8ff7P5+v2jw+Eil5S7kfQKBC8FqW1sbAx6ixRGpd4gzLVu2bKLJZCrVJ+bjebbBzXNkoTsipfRQo0HTWRybWz7BWvqHkYMn0qjYDg8ZoB5w1uCmM8888yJlnoTIKitPGHIj3R3hyc0lHwCPLbRdRB4A56EF5yoc4Igzkf09RQEelFNWBwB5f3okJhfnE2MqNZumgFk6wC4gDzoZcKbfRLfmrWR/Tw7mUoGsl0Ao5DzVueEXmUyThxcW8heUeVDanMmAIwLnxoULF55Nv4w+Wg71X85IgCE3AoEccjScPr8ZderZNCSNX3lo8ioKk28aNmzYhFz8cyYPPF/DHZAbRKPXmzNrK6B6qM0ygbxP6WCOtaUjWYNzgpH2fo/JVwDyYdxmUuH9zWZN3eXKePuYjGAWPDPH2tD0GhwZTLR7cIzS4Jp8cvY/QN6PIG/KAU0OVouMxtPBLh0MuTZ3rMFBPRzOjQT4aO1M/ZfTEmDIc8Emt5s0wDV+OydNY5oBR5ym2ktLS802m21kTs+sGlxQAoC8r4nMFZp9DQAGIct8m9EwstRuh0XCw9DGqAfceP/992MrGrYzKJcnEjgJOdjIUhcQBbcPHQx2wXRwIGyDM/XGs846S22PzdI57k23AXkJmbAnfNm5dwUAn1mkbe3+ohNwRAVYgwcBHzhwoLrA7A0pWVxWg5xe5Wo8qQCzZjQAuNRs7rKSwhocAwHsRrvdPhwnyuWnBAB5H9LkLZomzy4ZFJmNYFfjmHuu1+AGevdgMScqPz8loEGuafLsGr/ZYAC7bI3A1x6751EgwkhbZIvVGjiLJH99QF5Mmrw1SzQ5mKVFcAAOpa3BjdnjkyD1BDheMq6ckoDQNDntQsQSYjY4ghzsBllGWLbBMQaDAhxiUI4lYCLNWEzmiqbJM/zBIKvByIBz9zUNzica+QpwFofyWQIMObGe0c4kAgx4sKeswYMRCvCMnsO0dY4hb/P5M/YZT7NJ0+AsI41pXkVBJCKUicLiUX4XCQDyIhNWyYP6sEuedEZE0+DcLwU4S0L5YSXAkLdrmjxslrRFGmOxwal3bLakraOq4cyWACAv1DR5ZvWTVlHArmaJcM/YRAn+zfF6ve2cqHwlgUgSYMi7rDNTASYs1b7PH5DZ1Zjm/gXH4fP52oInKqAkEEUCgJz2YWeMRU6Xv3p2NZWO1c3gCqfS4FFmVCV1kQBD7qS3aKX7LXE+v1/W4BrXbKJwxwNKg7MolB+rBAC5jd69Ql5anS8goMGDyhqdkS8otQQFeFrnKGsb1zQ5Qa5p8jSNwm8ImihByMNq8EC6/9akSUCq2d5JAK+H0zR576rpUWkwSyuXETW4Zq9QzQFlg/dIvqpQpwQYche9vDvVb7X1BgRs8CDL6JKswbUEAry1s6/KUxLokQQAeQFtQUz1HU96FzrYZcC1vss2uBbhcDgaoO7VnvAeza0q1CmBDsiFcPlTIxJQ7aTXoetbYw3O1PsbGxv/oc+kzpUEeiKBk5q8J6XjL9Pk9YBd/KSYZ81EwQmcFllRUbFfXWR2CET933sJAHKrZq4k9w4nelrldOwnLwg3wqzBka4lvPbaawpwSEO5hEkgCHkS18kB72v1zXrAg+vgTL3/7bffbnG5XLVms3lgwkaoKsp7CQByC0nBo+nRxIvD7ffXrjve1EI1dzFR0FoQcGRobW2tUmYKxKJcIiWgQU6gJ1qRg9U2X6CK+gq4wwKOcQByLUN7e/s/EKGckkCiJQDI6fUOCd9x2O7zgVkZcK3rbIPLGtyHlRSlwRM9tao+loAMOcf1xge8TT4vAPfREaLB5XXwIOTHjh3b35sGVVklge4kAMhhqngTsC0E9dR6fGA2BG70IZwG97/xxhs7aNMVgFdOSSBpEsDNxA5zpXdWuY/MjVW1zTuoowA8BHIGHIMA0Ej00Udga5ubmyuVmQKxKJdMCQByE/ENfd6Tf6C2xR+ofPFITS31UzZRtG7rAWfIvfX19ZsU4MmcWlU3SyAIeQ8UOYCt93g3keelI0R7o34ZcJxrGpx8X2Vl5UYFOESiXCokAMgBI3lxHTDkqxyujVQU2ps1eLDLMuD4MbAG9y1ZsmSTn1wwpwooCSRZAgx5PM3Qg3L+JTX10OAMN3OsVRMOcO2XsGrVqkayw8uVFo9H3CpvbyXAkMNa6e7AQ6DNXl/5W8fqGyk7a/CIgKNvrMFhz3hpufBTBTjEolwqJQDIAXd3DrDWuj34+KvGK/lsgweLyhockQw4fg1essM3KMCDslKBFEqAIY+mxdGdynbPBvIAuGyiIElz8o0eRLB6xy/Bu2DBgk8vvfRSZ1FRkU3Lnaf/VRaVCM/xmpwffSRlBijCuUjxyBsxLUJCpMfbkB39AvD6/jn8fufjh46wBmftHdJCOMCRUbNnPvnkk5bq6uoPRo8efbmRnphOhGvbWiGO/c9fhaeuORHVpaQOt+8rwlmCb7uHyC6k7UgpUctEKBStTEijnSf6iZfzRGhCyxJvO3K96Q7T42mi2nnig21N5dhByPY3Qx7snh5wJEAmmgYn37Nt27a/nnbaaQkDfP+dTwp3dT3aySrn9HtEu9+r2YYQUCw2IgbIeRk0lOO4cOmIk12q88ttI8x9jdR/fX79eXfl9en68pHG7w34xW5nzV8pv4cOeQ08pIpwahltMuDeW2+99SPaPlsfTUuE1NjNSTbCjSEVGS2i0NihD2KFG+U4L3w5jDQ4OY7zyL6cRw7LeeSwnEcOy3nksJwHYb1DXjguw2EtMob/uiuvT+d22Ne3h3iw6Az46he37PyITiNeYKJsNMCh9j20s9Bx+PDhvyUKcDSarQ6Q2wnyaNf4nMa3nTFWjsuEcXNfYu1fsvP3RCbQwLU+598a3W4HBaHBw15gou5wgCMeGpy1uGft2rVv0OskEJ/3DpDbjCYNWoZE9iEghkIOy3nSGZb7JIcj9UnOI4cTlT9SPdHiAeZ2Z93r5MnmCaK7uEiA40eCXwWo9sydO3dXU1PTl0qLd8iPIe84U/+nUgJgsC3g+XJJ8+7d1C4DDlbBbBcX7iITmZCZIUclbloTX1VWVnYnfcMH6XnvADmcKwDZKpcqCUBN13jbVpHnpoPNE+a1SzciaXBkRF1BLb58+fI36GFkVKhcpwQ0Td7lS4xKPMmUgFv4PG+3HXmD2pC1d1jzBP2IBjh+FSgIM8W9dOnS6qqqqjfV/iuShuSwsmJTkEsSSV4Qa9+1Pseb77ZWVVMr0OBgE4yC1bAuVsA1M+XFF19cTFo84q8lbAt5EKkgT80kuwMB/7q2I4upNTZPegU4eh2ixefPn1958ODBd5QW7zqhDHm0q3+V1nMJkPIW9f72d149UVHZCXi3cGOWomlwpENbB80UCrteeeWVZz0eT8Q/CSiUr64DciwhnnQcjnbjArk5PV6fy3KL+va6q6+35fX1d1dfd+n6+vjcL/yBjx3Vz1J5Fx2yeRLVougOcPQHFeBiUzNTfvvb3+4lLf53pcUhmq4ON4IKDB2QY3Lg2JfDPHFyHMLxOq67p/X1try+v93V1126vj6cd9jezr+vaCrfS6dsnoDJqHCjbCyAQ1sHAaewa82aNc+QFkd55cJIQA85w5cKH91hiORwKtpOVhs+4nij89gzNB7W3oAPTHZrScQKOGtx/Hpcc+bM2X706NENSouTNCI4QG4lTZ5qx3AzbGif41Ldl0S0B+1d73dtWNy4ezvVx4Cz9k4I4Ogna3EY9oDcuXr16oVqRQWiiexOavKTiOEyC44vtzisRXbGcxznicfnsrHWp8/P5SL5+v531zd9/fry3aV7aOVkk+P4QsrnpAPsgcGYtDfli8lEQT4ADi3OgLtmz569jd4l/rraowLxRHY2TZPjY6kd/5CTJ1kOR0qPXHP4FK471vr0+blcJF/uc/gehMbq69eXj5buoy2xR31trz/duGMblWPtHdPqCfciFhOF87IW1y420eBdd921gB5MblR7VFhE4X2GPHyqig0ngY49J97GxU27FlA6wx2z7c11xgs42+Jo0Pnee+/Vbtq06U/qgpPFGdkH5FhdUS42CeD5qb2exj997qzFG6tgnoC5mG1vbiUewFFG1uIa5LNmzXqNHmvbri44WaSR/QLaZstLiJyLrXP4sRwox2XkMJeV4+Qwpyfal9uQw5HakfPIYTk/tHej37X9vuMbX6M8DHfc2hv19wRw1uLaxSY6sGLFikecTifegYg6lYsiAUCO1RWeUGRFOFbHeSOV7y491nZizRdve93lB0Nu+qD8O22HH6E+AG6+uIxbe2MM8QKOMgw4flGaFn/ooYd27927dyW9kRbpynUjgSDkeP+HOkJkEKBfwCF/68oXmvdgv7dee4O9uFxPAEcDDDlrcccdd9yxqK6urlqZKrHJH5BbeqRfYqs/G3NhzftEwF39ZNPORdR/PI6m195xD6ungLMtzsuGzs8++6z+pZdeuos+f0JLl8pUiWUmGHL82c73A69hcwm/5/3WQ3eVOxrw2gWGO651b73cewo46mHIg1qclg23EOiL6AaQvh11HkECgNysNDltdPKLfe6GRU837d5CotJr7x5rzN4CDlMlqMUp7Lz88suXHzhw4CN1AygC0WGi8x1y3NCp8To++lXN+uVgqPPgu5ZgLC2AY6rQOA6+4MQvr/3OO++8j+zxGmWPkzRidJq5YuiNvomxoQzLBru72e+pWdS46z7qWjsdYAgmAJhivijYM5cIiaITWD7BLw6dc9ANoGMvv/zy3WSP0zeGevzjo6ryy2H50EKQR7pNnmvx0MvugN/7vuPw3Vucx47RbGv8kA+WeFmwVxAkAnAQjM6wqaJ1kl41sfnTTz99Cva4gjz2OQLk+DBTrjswAbt7r6fhqacbdm6m8cpw9+rCUpZdIgBHfQx5iKkyY8aMJbQh6123Gz9I5WKVwElNnrurK16C+4i39d05NeuXkFz0pgkUZkL+9CcKcMwdQw6acaGATrfPnDnz13TR+ZmCnKQRh4OpYs5Rm9yjXVS2f3ZX3YZfk0g0TsjnZcGEwQ1xJxpw2R7XIKevRJy49tprZ9MDEuVqUxZEHrtjyHNpjRwrJvU+R/nDjZtn13scJ0gaAFyGGwwlRHtD0snY3obOyR00EOTe/fv3r582bdr0pmXv9MVXbpWLTQImklWHQGWRxlY203IB7kaf69CC5p037XDU4osCbXQw4DBvE6q9Mf5kAI564UJAJ1vc1dLSsnFUZctltKOuUEHeIaRY/gfkcBBotq6k+KnzJwKe+mUnym9c13roIA1FD3dCNTfkBZcswGV1Ewxv3bq1rcBk+Xycpd836c+vVUHeMQmx/M+yCgozlkIZkoe2mYrWgKf19ROVt/y55cty6pYebmhuAJ5wlyzA0VGeC/a1zm9z1jaVme17hluKL6HVAgtPXMJHloMVsqxCBJrh4+yA292+tv3Ifz7btAu34WW4E7beHUkMyQRcbhNzEpyXTY5jx+kJly2jrSXTSZPbeeLkAiocXgIsq6Aww2fLiFjY3Cf8nsbX2/bf9mzjLqx1M9xY80463BBCqgEPgr7VWdvQbvCuH28tnUo2eR+eOHRKuegSCMqKTHOY55l44F0mDQHn0eXNX9z8yomKPTSiVjoAOMONmzlJsbup3qBLFeBokJVOEPJyV2PLUW/738+2DbjAZjCV8cVUsHcqEFECgDwoyIi50pOAde46n6NiYePuW9a2HfgH9QJgpxxujD6VgKM9OJ4XzT/gOeHY7W5Yd65t0CS70TRE24nRuWrQkV39H0kCDHmmrK1gZnH7/ZjXsfWRhs23b3HUHKW+682SlGhullmqAQ+Bmzqhndd6He5PHDUfTC48ZXShwXyagpynp3ufzRUIMp0OuwLpWUq6/d72wd21G+fsdzfVUX8YbtzIwQ7BlMINeaQacLQJ1wX0Fr/b9zfnwQ/PKxhUUGKyTjIJo4Enr6OI+j+SBGQ5YcU81Qfgdga8gQpP0/O/qP/4d41eB77yK8ONC8qUww15pQtwtM2Q84VGwEsbyN9srdo60FRYPsRin2wxmOzYS4AHc5WLLoGT5kr0fIlMxY5AvL+k2e9ufK/98Lz7aje9SnPIF5PyHcq0wI2xphNwtM+Qww+CvsFRfaTa2/beuILSM+0G0ynKZIGounephJxNkhpf+7aFjTtvp5WSHdRDaG3W3DBJ5KVAzHHKXaYADrj50KCv8rS0rXFUvXtOwSBTX5P1K8pkiY0NNleSSRNu3sAkKfc0L7+j9sMH97ua8fYpaGyGW795KrbOJyFXugHHkHgu4DPkmjanP3e+Na1V2waa7buHmAsn0/ZRu7YXQ5ksUVE4adIlducKcU0mCW7euBvWOo7c/UDtxr90miQMN9a4+WIyabffow5el5gJgKNLMuQy6Fp4g+PY0cNksoyylgymz4SM7nioS9nmurkMOT0JeUh0j05ga/toiuj78OKQr/W9RY3b57x64stdVBlrbACuv4EDJZV2l2lXb+gPrivxw8OXVgvosNFhp6MQ4TvKzvnni+yn/rLUaB2BJ1/4TzKlKRdGArCVe+PY1m70uw9+7Kz+wx/rt26g+mCCMNS8BMjbXbW/vr1pM5FlMw1wjA19wgHI8SVmKx2AnEG39zfbiu8vu+CasdZ+19HHWAvM2ESqzBYSUXgHDRwv5rxC0ub3uCrI1n6w/tMXGr1OrJBAU+MA2GxrY5WE93LH2xQVTZ7LFBNFP0IWEnwc0Aps0/mcfq/3rbYDO+r9zrUjLMVDaePWCGW26EV48px//Kw5ovl4wxSbI/Ty+Y+fa97zq0WNO9aRzOXlP2hvGW7MT0aYJCdH3RHCWDPZoX9ssrA2Z40Os0XT7HMGnP/1C2yDbulrtI7E64nx7lae1EweXKr7Bq0cybGd7SI7m9a1D3zmqln0WN3nH1J+1tSstbH0xzduWOlErjhSgymKz3TAWQyAnEGHbQ7I2T7XIDebzba7+p1z6STbgGv7GwvGKNBZdNF9GWx6J/eXO5x1z/++aetaejMZg80+r2vLtnZGam15xNkCOPrM2hygQ5sz6ACcYYdf8Kuy8y86zz7g2jKj7SwFOkkkjJPBJlNv9xZH3fOP12/+iLICZBwAm31obIDNdyQBdsZqbepb0GUT4Nxp9BnXDgw6tDlrdA1wOtf828rO+afJtkHXDTLZz7XiNQxUBIXz1XwB1KASa9n0Rilx3Of4fJPz+PKF9Vs/o2gGW/ZlcwRQ84UkBbPDZSPgkKzGKfmy2QKNzkuLMujWG0rPmnRhwZBvDzbbp9sN5kLAni8XpQy1n9AG1I6At51edPnBRlf1G4sbduP2OiCWoUYY2poP2c7OCq1NfQ+6bAWcB4D+A3IGnU0XBp01u6blh5qLi27od8b0Mdb+3xxosp9PoJvwch3Anmvr6Vi/BtRegprA9tX6HJu/dDe+vbhp7wf0RincoGHtDKAZcoaal/2gtbPGHKG+dnHZDjgPSA86TBi20dmEYV/T9FMKTx00q3j0ZSOsfb5ZYrCO0UyYLNbssqbuhBpfS/jyoLvl7f9r3f/O+vajx0kmDDDDLftIg7ZmjZ3VYNM4NJcrgMvjgTbHuAA5NDprdQDO0Mu++Yf9xo2dXDB4Kmn1c/uZCibShWkBPi+CR+gy1ZSRgcbmJzxJQ0t8riafaxdp6883uWo+Xtm0r4LGDG0MeAFzOB/prLFhguQE2DQOzeUa4PK4WKsDdD4Ath54TaNTvJbWz2wr+FHfsRMnWErPG2iyndvfVHAGwW7BBSqA7/jX0QwLL1kXrYAYjg1f+LhMBNC4UCSoPfSmqL21Pufn5Z6GLS83V+xq8jphcjDUAJoPBpzTWFuzxu6ongrkkuM5yqUxyWPB+Bh0va0ua3eGnOPYNw21FRX+oHDcV06zlpxdQvtfCg2mEYVGy1CrMNpZw7Mvwy93AmG9oBlafT6GGPYzQGbfLfyOdr/nSHvAd5B28x2scp/Y+Wr7vu1HnG24qwhIWROzz2DD5zj4DLRsX0fqDmXPbqeXe3aPJnrvGXT2WavLpgyDrfflvNoP5eLiYYMmWctGDjEVj+hrtowsMliG01cayugppEK6k2qnbWCFlNGMxhh81vRsXkAbgywizUuvWWinW+QOT8DX7vL76tsCnkPNXs+Bal/rwR3u+gPrWg/DhmYoZe0rwxsuLOdl84P96BLLgdR8Apynq4O5DqWKMOAFtLIPwBlqhp3P9Xk14DvrCKmbzB3zSGtx0RBjob2fuaCoj8GKHZGiJeBub/K62qr97Y4D7tY2MisAZofyPukzzPBZ68o+wgw0Q4xzOQ+X1ddN2fLD5SPg8syGAEkJMqx6kGXA9WlcDvUhzPWiLTmMc9kxeIjjMGtXBlwPLEPLUPM552ef62NfbjdvwhC+ch0SYFkwkPD14PI5QwzokY99jg9XF1rheEAHx/DpzwEp4gCx7DO87CNNDuMcBxz7HWd5+j8LPE+HH3XYLBv40Q4Zan0+NCDXIzfIAMo+wvqDYdfHy+eoF+fK6STAwtdFq9MIEmB5McjIFi1OTo9QZQiYDCnDizLR4iLVqeI7JcCTowTSOwno5ag/R+36OAZXblkfpz+X86pwDBL4fwN/IZwMBwH5AAAAAElFTkSuQmCC', // @suppress longLineCheck
- yellow: 'data:image/vndmicrosofticon;base64,AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAZKhQAOWAiAEV0KgBFdCoAOWAiABkqFAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8ZAAAChAHAEp8JwBvu10AgNeSAInluACN7c4Aj/DXAI/w1wCN7c4AieW4AIDXkgBvu10ASnwnAAoQBwA8ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbLgAAAAAFAFmWMwB/1YwAj/DXAJX7+QCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJX7+QCP79cAftWMAFmVMwAAAAUAGy4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7v8AAD1mFQB6zXYAkPLdAJf+/gCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP7/AJf+/wCV/P4AjvDdAHjKdgA8ZBUA6f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AABWkCYAh+KoAJb8+QCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJf+/wCV+v8AlPr/AJT6/wCV+v8Akvf5AIPdqABTjCYA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICABb//wAka5wqAozquwCY/v8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCX/f8Ak/j/AJP3/wCT9/8Ak/f/AJP3/wCT9/8Akvb/AIbiuwBZlyoA//8AAAECAAAAAAAAAAAAAAAAAAAAAADz8/MAqJaJHZDD5rQLnP7/AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8Alvz/AJL2/wCR9P8AkfT/AJH0/wCR9P8AkfT/AJH0/wCR9P8AkfT/AITftABQhh0AjO0AAAAAAAAAAAAAAAAAfX19ADw8PAni3tuPuuD5/Quc//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJb8/wCQ8/8Aj/H/AI/x/wCP8f8Aj/H/AI/x/wCP8f8Aj/H/AI/x/wCP8f8AjvD9AH7UjwAiOQkASHkAAAAAAAgICAD///8AxcXFT/j19O+94vv/Cpz//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCV+/8Aj/H/AI3u/wCN7v8Aje7/AI3u/wCN7v8Aje7/AI3u/wCN7v8Aje7/AI3u/wCO7v8AiunvAHC8TwD//wAABQgAqKioAHp6ehHp6em3/fv5/7zh+v8KnP//AJj//wCY//8AmP//AJj//wCY//8AmP//AJj//wCY//8Alfr/AI7u/wCM6/8AjOv/AIzr/wCM6/8AjOv/AIzr/wCM6/8AjOv/AIzr/wCM6/8AjOv/AIzr/wCM6/8Ag9y3AERyEQBenQD///8AzMzMTfb29vP9+/n/vOH6/wqb//8Alv//AJb//wCW//8Alv//AJb//wCW//8Al///AJT5/wCL6/8Aiej/AIno/wCJ6P8Aiej/AIno/wCJ6P8Aiej/AIno/wCJ6P8Aiej/AIno/wCJ6P8Aiej/AIno/wCH5fMAb75NAMP/AAAAAAXl5eWX+fn5//v6+f/T6vr/Wbv9/0+3/f9Qt/3/ULf9/1C3/f9Qt/3/Ubj9/zew+/8InO//B5nr/weZ6/8Hmev/B5nq/weZ6v8Hmer/B5nq/weZ6v8Hmer/B5jq/weY6v8HmOn/B5jp/weY6f8HmOn/Bpjp/weP15cBAAAFpKSkHfDw8M/5+fn/+fn5//n5+f/1+Pn/9Pf5//T3+f/09/n/9Pf5//T3+f/4+Pn/o+T6/wq//f8Hv/3/CL/9/wi//f8Iv/3/CL/9/wi//f8Iv/3/CL/8/wi+/P8Ivvz/CL78/wi+/P8Ivvz/CL78/we9+/8HvPr/BrbxzwR9pR3Ly8tA9fX17Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//36+f+l5vv/CcL//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hv/3/Br36/wa9+v8GuvbsBZnLQNra2mD39/f4+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//fr5/6Xm+/8Jwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B778/wa79/8Guvf/Brr3/wa59fgFo9hg4uLidPj4+P35+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/9+vn/peb7/wnB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//we++/8GufX/Brj0/wa49P8GuPT/Brfz/QWm3XTk5OR6+Pj4/fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//36+f+l5vv/CcH//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hvfr/Brfy/wa28f8GtvH/Brbx/wa28f8GtfD9BafdeuXl5W/4+Pj8+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//fr5/6Xm+/8Jwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B7z5/wa17/8GtO7/BrTu/wa07v8GtO7/BrTu/waz7fwFpdtv4eHhVvj4+Pb5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/9+vn/peb7/wnB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//we7+P8Gsu3/BrHr/wax6/8Gsev/BrHr/wax6/8Gsev/BrDq9gWh1Vba2toz9vb25vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//36+f+k5fv/BsH//wPA//8DwP//A8D//wPA//8DwP//A8D//wXA//8Guvb/BrDq/wau6P8Gruj/Bq7o/wau6P8Gruj/Bq7o/wau6P8GreXmBZnLM7+/vxH09PTC+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+/r5/83v+v9x2vz/btn9/2/Z/f9v2f3/b9n9/2/Z/f9v2f3/RdL5/yXG7v8mxOz/JsTs/ybE6/8mxOv/JsTr/yXE6/8lw+v/JcPr/yK95cIQirAR////APDw8IH5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+vn5//r5+f/6+fn/+vn5//r5+f/6+fn/+vn5//r5+f+H8Pz/Oer+/zzq/v886v7/POr+/zzq/v886v7/POr+/zzq/v886v3/OuDzgWz//wD09PQA5+fnNPf39+n5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/4Xw/f846///O+v//zvr//876///O+v//zvr//876///O+v//zvp/ek32+00Ouf6AMrKygCzs7MF8/Pzmvn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/hfD9/zjr//876///O+v//zvr//876///O+v//zvr//876///OuX5miqptwUwv88AAAAAAPPz8wDp6eku9/f33fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f+F8P3/OOv//zvr//876///O+v//zvr//876///O+v//zvp/d033O8uOuX5AAAAAAAAAAAAvr6+AP///wDx8fFl+Pj49fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/4Xw/f846///O+v//zvr//876///O+v//zvr//876v71OeP2ZY7//wAus8IAAAAAAAAAAAAAAAAA4ODgANPT0wj09PSI+fn5+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/hfD9/zjr//876///O+v//zvr//876///O+v/+jrm+Ygyx9gINdPlAAAAAAAAAAAAAAAAAAAAAAAAAAAA6enpAOHh4Q309PSM+fn5+Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f+F8P3/OOv//zvr//876///O+v//zvr//g65/qMNtXnDTjd7wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6enpAOLi4gr09PRw+Pj45/n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/4Pw/f816///Oev//zvr//876v7nOub5cDbW5wo33O4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgANHR0QLx8fE89/f3sfn5+fX5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/t/T7/4Xx/f+A8P31Xez8sTnk9zwuxdUCNtTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREAP///wDo6OgM9PT0Tff396T4+Pjf+fn5+Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+fj5+Pjf9vf3pPL09E3m6OgM7/3/APtbOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMjIwD19fUA4uLiBvHx8Sn19fVd9vb2jff396739/e99/f3vff396729vaN9fX1XfHx8Snl4uIG9PX1AFEnIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wD///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABgAAAAcAAAAPgAAAH4AAAB/AAAA/4AAAf/AAAP/8AAP//wAP/KAAAABAAAAAgAAAAAQAgAAAAAAAABAAAEgsAABILAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABorgAAS34IAHTDNQCC22wAh+OMAIfjjACC22wAdMQ1AEx/CABorwAAAAAAAAAAAAAAAAAAAAAAAEBrAAAAAAAAecswAIzsngCU+OUAl/37AJj+/wCY/v8Al/37AJP35QCL6Z4Ad8gwAAAAAAA+aQAAAAAAcXd6AP8AAAAOiNtNAJP32gCY//8AmP//AJj//wCY//8AmP//AJb8/wCU+f8Ak/j/AI7w2gB+1E0AAAAAAEd4APn7/ADc2NU5T7P33gCX//8AmP//AJj//wCY//8AmP//AJX6/wCR8/8AkPL/AJDz/wCQ8/8AjOzeAHrOOQCR9AC3t7cO8e/vsGnA/f8Alf//AJf//wCX//8Al///AJP4/wCN7v8AjOz/AIzs/wCM7P8AjOz/AIzt/wCG4rAAY6oO4uLiT/j39/GIzfz/Mav+/zSs/v80rP7/FaH5/wOV7f8DlOv/A5Tr/wOU6/8DlOv/A5Tr/wOU6/8Dk+jxBIvVT+3t7ZT5+fn/8fb5/+vz+f/r9Pn/6vP5/1nR+/8EvPz/B738/we9/P8Hvfz/B738/we9/P8HvPv/B7r4/wax7ZTy8vK7+fn5//n5+f/6+fn/+vn5//n5+f9e1f3/A8D//wfB//8Hwf//B8H//wfB//8HwP3/Brv3/wa59f8GtO678/Pzwfn5+f/5+fn/+fn5//n5+f/4+fn/XtX9/wPA//8Hwf//B8H//wfB//8Hv/z/Brfz/wa17/8Gte//BrHqwfPz86X5+fn/+fn5//n5+f/5+fn/+Pn5/2DW/f8Gwf//CsL//wrC//8Jv/v/CLXu/wix6f8Isen/CLHp/wet5KXy8vJo+fn5+vn5+f/5+fn/+fn5//n5+f/I7vr/quf7/6zn+/+m5/v/Tdz5/yzV9P8u1fT/LtX0/y7U8/ooyOpo7OzsH/f399D5+fn/+fn5//n5+f/5+fn//Pr5//36+f/++vn/9fn5/2rv/v857P//POz//zzs//886/3QOuLzH////wD09PRh+fn59vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//H4+f9o7v7/OOv//zvr//876//2Ouf6YUH//wDu7u4A6enpB/b29oT5+fn3+fn5//n5+f/5+fn/+fn5//n5+f/x+Pn/Zu7+/zfr//876//3Ouj8hDfc7wc44PMAAAAAAPHx8QDu7u4I9vb2aPj4+Nn5+fn9+fn5//n5+f/5+fn/8/n5/4zx/P1S7P7ZO+n8aDfh9Ag55PcAAAAAAAAAAAAAAAAA6+vrAN/f3wH19fUo9/f3fvj4+MH4+Pje+Pj43vj4+MHq9vh+w/H2KADM5wFk4e8AAAAAAAAAAADwDwAA4AcAAMADAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAAgAEAAMADAADgBwAA' // @suppress longLineCheck
+ yellow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALcAAAC4CAYAAAChOH1KAAAlaElEQVR4Ae2dCZhUxbXHTy+zL8ywDDsSVhEVJQoCkoSIIr4kvohLxO2ZfC8an0mQrCQm+uJ7qHkv5hE/xSQaNokBogkxigaUuLDIpsiOMA4MOwyz7zPd7/yLOZfqnu7p7umeXut83+2qW7du3apTv3v63Lr31rWRkUhowOZViPc6Nutpbq/8WPVO8173sYtJ6kgDusI7yme2nYdTdIZQj0NH1vrgwYNtc+bMyb344otzCgsL87KysnLT0tKym5ub6+rr62vKy8urd+7cWfv444/XlJSUAGSB2VfoKw3HM9KBBqQzOsiSspsEXgmhCMTtDGT2TTfdNDwvL28kQzvC6XSOcDgcQ2w2Wzfenme323M5nuN2uwPql/O5OF+dy+Wq4X2rOV7Z2tpa3NLSsp9Pgv3V1dX7XnnllU/4RKnj7S5edNARl4WjRnQNBFS+njnJ4wKxHtp37NgxpG/fvlPY6l7CAI/kZTgv/YMBN1L64hPAzcAf5eUTXvax9d9x/PjxtZdcckkxH0OAF8gljNThE7acVIdbQLZzDyJuX7du3YChQ4dOycnJ+QJb5M+zFR4Qr73L1v4IW/h3amtr/3nw4MG1kyZNOsJ1FdglBOwpKakItwfQTz31VN4dd9wxnd2LL7J1/hzDPCxRSWDYD7BVf5fdmbeXLl26avbs2dXcFsCdkqCnCtwCNEL7gAEDnBs2bPh8QUHBnenp6TdyWi4vySY1TU1NKysqKl6cMGHCO0eOHGnhBuqQJ71FT3a4FczcqQgdu3btGtWvX787MzMzv8YWun+y0eyvPWzRjzY0NPzp2LFjL44ePXoP52vlRbfo/nZN6PRkhdvyoX/7299245GNe9iHvoMvBC9P6N6KQOX5gvRD9tGX8gjMovvuu6+SixRrjjCpJJngRluwAGz78uXLu0+dOvXbDPW3eL2QFyOeGihnyOevWbPm6VtvvfUsbwLcAnpSuCzJALcH1KtXr+4zduzYWbm5uf/OnZWMvrQnouGv1bD8ftu2bf937bXXnmgDPCkgT3S4lZXmDrGvX79+0EUXXTSbRz3u5fXM8Ps85Upo4FGWBbt3735q4sSJh7n1YskRJqQkKtyoN8B2vPzyyz2uueaaX2RnZ9/NN1bSE7IX4qjSfMOoqa6ubvFbb7318xkzZpRx1XDxKZY8jmoauCqJBjfqi8WB4bzNmzf/W/fu3R/j9R6Bm5o6OWyuErK1fMiKwuhfJ8VNZWUVtT/77MTHFrYNI8oIS8L444kEt7ggju3bt182bNiweXwHcXwnuy5pdwPYzrofMdiR8SaaW9wffFLc+N3RE/7xEStNrHhkCu/iXkgEuFFHBfb8+fMLb7vttkf4YvGb7II4u1g3CVm8vXEpORtfiGzdbbaWmpqW3724ou4/v/WDj8u5cMAd965KvMMt1tp56NCh24qKip7gmy99IttzyVWao3ERYekKcbnpxKmy5h/3HbVpGZcvdzzj1ooDnngUnHQOLI8++mhBZWXlC3369FlowI5tV9lt1KdPz7SFdaUTXnj00REF0kccxqWRjMdKWWBv2rTpUn7YfwnfWRwZ225NnKN3peXWtdDion0799TedfkXPvqY0+GLywWnni2m8Xiz3KgPLLbz6NGj3xgzZsw7BuyY8uH34E47jRxzUc47J/eN/wb6ixf0W1zxFC+VEWvtnDt3biE/ybagZ8+ez7CysngxEqcasNkoq6i785m6w1ctmDt3GB5xEMjjwiOIh0qgDjjJMG49hp9ae5Gt9fA47c+4r1a03BJvRbS43J/s3FN3R5ubIhebMR0Tj7XlFoudtm/fvmsuvfTSNQZsb2wSY91ptw0fMzrnrYObr7iGa5zGC9yUmBrPWMItYGOY7xZ+W/wvrIw8XowkqAa4Q/M+MzjjL0d2jL+FmxBzFyVWcOO4OLPT+AH6b/ELuAs5bp4LYSUkujDg6f37Ohee3ncVHjUWCx4TzmJxUAE7/eTJk4/06NHjKb7bGIt6JDpH8Vt/N9l7dnc8dfaTcY9wJWG0YjKSEm2oFNh80ZhRVlb2NL/D+KP47SFTs3A1UFiQ9qOakglPjx7dKyMWgEcTbgX2+PHjs3j6hCX8fMjXw1We2T/+NZCTY//65jeGLRk/vjuGdaNqwaN1NavA5salnz179jl+9evO+O+WxKxhrIYCA2mrtq71xdwLNt7P+Zp4kacLA+0W1vZoWG4BO4197McM2GH1V8LunJPtuLP84FWPcQOidpHZ1XCjfCxppaWl32Ef+6GE7R1T8bA1UJDveOjUnvHfAQ+8CBthl+uvgK6EGy6PAru4uPj23r17z/VXCZOeOhro1cs5t3T7uNu5xQJ4l7nGXQU3KqzGsfmF0+v79+8/P5oTR6YOKgnYUjfZ+vdLm7/vg7HXtwEOTroE8K6AWyy2kx9ZHTdkyJAlbY1IwJ4wVe4KDTAgacMHZy3Z9vbl47h83MkEhxEHvCvgRpnOefPmFfF49lLMU83rRowGPDRgs1POpRdlLZ33xJAi3iCAe+QJdyXSZ4sCmyuVwY+truA5RKaFW0Gzf2gaiNehQH+tqKt3vZkzaAOeRWnkRZ4m9Jc9pPRIWm6cKMrPPnz48HcN2CH1Q8pmzs6yTzux+8rvsgJkiDBiBjdScAvY8LOv4hd58UyBEaOBoDRQ1DPtEfa/r+LMEX2SMFJwoxzHE0880Yv97AXsZ6OSRowGgtIAeLl0VNaCJx4d0ot3wL9/RLiMxF8AKgKY4WcvY3dkOseNxEgDieZz62qqq29dlTNo422cFhH/O9wzBCeHgptfOHjAgK13lYmHqoHsLMf0ozvHPcD7yehJWMY3HLgtsBcvXnwB34F8ONTGmPxGA94a6FuU9vDiZy6+gNPDBjxcuNXoyA033PA4+01mLmzvnjLrIWuA36jP/dcb8h7nHcMePeks3JbV3rp167X8sVF8NMmI0UBENJCXa7/xo3fGXsuFhWW9Ows39nNed911uRdeeOEvI9IiU4jRgKaBi0Zk/vK663rDGxDAta3BRTsDt2W1n3/++Vk8jfDQ4A5lchkNBK+BNKdt6OJfD5rFewjcIV9chgq3BTZ/UGkY36wxz2cH318mZ4ga4Js7Dy1fMHpYZwHvDNzqIpI/1fEkX0Sab8+E2GEme/AasNltmdO/kP8k79Gpi8tQ4Las9rvvvjuBXxe7LvhqmpxGA53TQE6O7bp1r4+RW/PgNWj3JFS4ldXmW+zfY6vdudqavYwGQtAAOONb89/nXUK23sHCbVnt119//TKelmFqCPUzWY0GwtJAbq596j9eueQyLiSki8tQ4IbVdl555ZWzOTRmO6zuMjuHpgGbbfxlOeAOcIPDoPgLBm7LavM3H0fl5+d/KbSKmdxGA+FrID/P/qWXXxw1iksK2noHC7ey2pMnT8bQXzD7hN8aU4LRgIcGbPYpV3UDf0Fb70CgitV2LFq0aAhb7RkexzMrRgNR1ADPezJj0fyLhvAhYWzBbofuSbBwO6dOnfogX7miUCNGAzHRAA+cOP5lSt6DfPCgXJNg4HawO5LDs0XdFJMWmYMaDWgaKChw3DR5ck/MqBDwwrIjuMUlwTQN0/lzHvjuoBGjgZhqwG6ngmfnDsTbXgGtd0dwY5u6kBwwYMCt5qZNTPvUHLxNA+BwYP/0W3lVLiz9MuxvA6w2FsecOXN68fPaX2wr2wRGAzHXQF6O44tzZlsvEwur7erVEdzY5rz77rtv5s9S49anEaOBuNCA3W5L+/rt3W/mynTomnQEt3JJ+JvrmA3IiNFAXGmgX1FawC+m+YJbzLxjyZIlI/mNdtzTN2I0EFcayMqyXfbS7y4cyZWSURNw6yH+4MYOjokTJ95iLiQ99BX3K271Tx331Qy7guBy0vg8WG/FKoft4IbP4i3IpPztwsLCz3tvNOvxrYEW23iqKPs9VxKfnUlc4fncPSrvtUpYb2lygU+/frc33JZLcs899xSwS3KpxxFSdMVWv4dsle+Qzd0c9xqAGevm/AJVVBSTy+ViCDwhQQN8JLVLc1P7/bz39VXOuTye+/rK5zvNcz+U1ZG4XO5Lb5teWbBs1QHMUCXsWoV4w42yYLUd99133yQ2/dBVSoutbhc5997MmkscS4hOK2hxU1mlb7h9daj3f7r3uq99Yp3GJ67jnqktk5atopVcF3Dr0UnecKNNCu5+/fpNNv42m4PyN8jWdDTW/Rjy8TF22yPLTWeriFyWLQu5mLjeAbD26eaezMHfeQG3SLJaiwRdsK7g5icAJ+kbUjVuc+OziYkpPD0Cdc/nDk0EM9xJFedn2ybyrvizEnatknS4oQIsjlmzZvXMzs6+0MplIgmrAQHcwT0tHZxMYXaGe9QDX03vCW55kaap/vIFt33mzJlXt2VUmcxPYmsAgBfmsWkD4Nz9SbbYvnq1G7yC5Q7hRgYH35W82vjbiQ20d+11wL23JfI6OO1TSIBbXBMArsTbciu4eU4Sc1dSNJREoQKcZ9+DBY+U4F8AIv8GEleJUfrJyiTw2g5uGS0R2hXcPL79mSjVyxwmyhpwwkXJdVNFTeRGUQRwNEXiEkajedkZBF4FblUN/nHr5zDi9p/85Cd92NSzh2YkWTUAwAtgwcWkJXhD+UTKm3VLWh9uhmJYmiNwo5lY7Pw8yXDZaMLk1YAArkZRuOdhaRN5mXSxDdyCZ2FZrUgPKrj55s1QczEpKknuEIB347cRYcGFiEQMUf++3V1DubcEbtVx7Sw3v3UzLLm71LRO14AADqudyJKbaQO3ArdqjQ434naeB3CIsdyJ3M2h110Aj+QoSui16Pwe4DUnm4ZwCYphDhXcGC2Rcxahg0dKkMlIimkAgOdnu6mqzvdTg/Gujqx0G7jFiInFM0iHIME+atSo9MzMzAEqxfyknAbOAc4gMBWJdnGZke4eMOozmengmBcFuA63bdq0aYV4jDDletU02NIAAM/LOge3lZgYEceUMa2FXFWAbcEtKzaen4RHP42kugYE8M6Mg8uFqVh+6FLSfOlVtnU2v+yHcFCRG/xaPOt3KG29evUyN2989UAKpgHwXH4evKZee0A6SD0IsMgucQl9FaFvk7iEgfLr27vnucGvwK38E9lu42FAY7lFGyYkZcGz2YkFLgkg+TkOsdyqtjJaomjnZ7gN3AnQidGsosOhWXDrHZdo1iC4YwHgzEzfbglKsBm4g1NkquUSwGsb4neYEG5MTjp5WG6P0RIeBswxN3BSDd3g2gvAc/irox35wsGV1DW5UK/0DDemNlZeCI5ijQkikT91jY1GjAZ8asAX4AI7Qj3us4BOJOpl6nFfRaU77AI3Ntv00RK+gDBw+1KaSTuvgXOAu6mOZwqRuUcEOuSSuITn9+x8TC9L4hLqpTqdynIjCdbbc+6t1tbWFiQaMRroSAMAnF/MpXoA3lHGKG9rddk8+BWfG9WwNTU11fqaoSjKdTSHSwANAPCsjDYTGQf1xb9IYzPVclWU1UaVdLipoaEBG40YDQSlAR1wuYrzDlGQRZuPUmWb937+1r3L0/fnuQM9+NXhdhu4fWjfJHWoAQtwocwrtyQHC6vX7u1WvctDBkmrb7YBbstTErhVQl1dHb82asRoIDQNAHA8j+frIi+0ksLLzRe5wq/iGaMlQrq7oqLCw6yHdyizdypp4JwFd1MDzz4noyjRbD9OrMpaD8vtlqFAAO4uLy8X8qNZL3OsJNEAf6uGLfg5wKPdJMBdXuMCv4plHF/cElWX06dPV5vREqUK89NJDZwDPPouCv4tTpVTtV5tgVvRvnv37hoDt64eE++MBgB4Bs+hDGvqvaA8pIlIXPIhXdIkjx7KNskvIa4q9xyyA24Py40ViHvlypXVPNbNMzobMRoITwMW4F7FeMOJzZKmxwVa71DPg7hIczNVvba+SdwSJFszTgntbh4xKTHWW1RmwnA0AMDTYcG5kK5ccAXLIyUlfBiLY9Rb3BLEscFVW1tbghUjRgOR0IAFuOaKRKJc7zJqG2wlnObiRTwRBbfQjg0uHg781Fhu1oSRiGkAgKfxuJy3ixGpdVS0qtb9KQeKYQ4V02K5BXA3j5gUI7MRo4FIakAAj2SZelmnKuggr1scYxvg1hNaecTkoLHcUI2RSGtAAI+UxZZyUM89h1wwyviamcWzWG5sVyZ94cKFn/L3CxE3YjQQcQ0AcCfPjAMwIyVMq2vhasenXJ5iWMoVuIV2165duxp4xOSYZDCh0UCkNaADLtY3nLC+yXZs14EmfsPTuqAEz9ZoiQU3p7XW1NQY1wTaMdJlGsC7urDg4Qpc6JoGN/xtuCSw3MKyB9xi0l0nTpzYbPzucNVu9g+kAQE8lDFwlOnh0TDKJ8tsmznZ4pfjHpYb+yABGVq3bNmywbjdUImRrtYAAHeE4IML2HJC4OvIW/e3buB66pZbVbudz41MP/3pT3fziwvmNnxX96wpX2kAgHd2ZtnGFqr68QuO3eCWF59uCQ5iWe7q6uqms2fPbjWuCdRiJBoaEMBDORb4LKugLYwrvmGuw62KEcuNFQtujrccO3bsAwO30pH5iZIGBPBgR05QrWNltk0c4K33gHADcGRq2bBhw3rjd7MmjERVAwAccAcj8LfX7Wxdz3kFbvCLRYleDOIYnOEX9tWca93OnDmznmd+7aFypuiP48jjhMVIdDUQjNdQVecuK7iheSLXrJIXPO7KM6ko46wAl9fMOE0Rj0Q1YsJhC8O9mT+Vfb09Ub8EhFaFKc2taVReYRmDMEszu4eigY4Ad7HZPnyKMAQoVtvjYhLH0eHGusCNHVr27du3euDAgRGF21axm2zH1pLN3Yzjxb3YG89Qel02PzIM3bUXf9jjtSdf4i8def3s4veFW39l+StHHaODjaGW5zd/R8fw08pQy2ppddOuva2rGVPFKrdN4EYzlehuCRKwDuB5Pk/KGzlyZM/169e/z5/vi8gXFwC28x9fZrDh1ieOVNW7cBcscSqcAjWtbXRXf/l/K6/ed6rpDDcXr5fh9jtAtzrKl+XGRtDXzJa77siRI6tHjBhxUyRcE9vhV8lWe4SLTizJR3XZLtRiwMlIzDWAx/qOn6HV+04Rf1iQ4AKAV3Brgc1x6/Y74iIw71hwFjTxqMlKniBTtoUV2lyJS0c+f+GLJzc3EgcaYI+EthyilVwVAAVOhVmP2unj3LJBLLfyZe6///5NVVVVRzty7mXHZA8BeC6PJcF3M0tsdADbzF94OPq9P5OMb4NTsdweCPqDWwCHyW8uKSl5zcB9Tm95fDWSg8FSIzHRAC48SyvoNT64YpNDARvMeogvuJEBZh474axo5ikf/trM784bOacBATzYO2kmH1t5/quLxNLCCK/aSX8Fl7yI1Qav7cQf3DgLLL/7ySefLC4rK9turPd5/QHwbOODn1dIFGKw2uW1tP3/3qZiPpzub7ez2qhOMHDj7GjasWPHSy1qSBG7GYEGlAVnwI3/HR0dtLK53XWCXmLVC9hgE0Y4JLg5v9oBO8L8N82cOfM1nvah1FhvqOa85BoLfl4ZXRiD1a6sp9L7lil/G3CDS79goyr+LDe24Wyw/G5+9axh+/btf4jUsCAOkCwigEfCpzRl+PbN8ZDUzhP0h5oadbNG97d9Wm2wFQhuAVxZ729+85t/raysPGmsd/vTEoBn8dRhRiKvAWW1G+jk7OXqQlKstt9REqlBR3AjD8w+CgHcjUePHq3duXPnImO9WRs+xFhw31Y33H8jWO29J2jR0Qr1QSc8+QcewSX49CuB4IblRgHqopLDxm9/+9sr+E2dMmO9fesUY+DGgvvWTWdSYbVrmqjsxytpBfjjRS4mO/S3caxAcCOPWG8FOD9vUrVnz54XjfWGanyLAG5GUcIfRcFzJPtP0ov7jhPe6RWwA1pt9EwwcIv1Vn4379M4Z86cl9h6VxrrDRX6FgW4GQf3rZwgU2G1qxup8ud/V8N/YrXBYUCrjUMEAzfyifVWvvfGjRvLN2/e/LS5awnV+Bfc5MnCOHiE7s6lWjktTN22Unp6awmVs5aD9rWlR4KF29t6N8yYMWMFT96z07xnKar0HQLwTDOK4ls5HaTCHTlVTTvvWqR8bTyrLaMkQVltFB0s3MjrYb358yL1y5Ytm8vzm7iMewL1+BcB3PjgwfnguMPC85G4Xt5Gc3nShnrWbMhWG70RCtztrPfDDz/88f79+/9sLi79gy1bBHBZN6F/DeA2+4Ez9OdfvE4fc65OWW2UHgrcyC/WG38ROJsavv/97/+Gb8ufNdYb6ulY4H/DRUk13zmU9kKDlY109sd/pd9wFGDLhWRQIyTYXyRUuGG9cRAMC+Kg9e+9914ZX2D+mt0UXjUSSAMAPMP75b5AO6XQ9iama0sJ/XrjQSrjZotLAt7AHfgLWkKFGwUL4GrkhNfr+eJyJd+93Gbck+D0LoCHYtFSIS/uRJ6oom23v6BeIROwwVnIYKMnOgs33BPrriXHG+bNm/cIv45WY0ZPoNbAIoAHznk+By5IIXJhKnGV2JYuaXpe2R4o1PfR4/720/PocX/5O0rH6EhlA9U88096hPPp7gg4A28hWW0cqzNwYz/xvS3r/dxzzx1cvXr1L3j0hOfZCLkeKDPlBP43XBSAEcwCBQlEelz21dP0uGwPFOr76HF/++l59Li//P7S20ZHaO0++sXv31cfbvK22uAtZOks3DgQDijWG2da/V133fXm3r17l5ubO1BPcALA01PcB29mp4OnaVj+jcX0JmsNYMsIiVjt4JTplSscuGGeAbhYb1So7pZbbvnV8ePH9xr/20vTHaxaFpxNWyr41nob4WefrKG9dy6kX4EfXsQlAVfgq9NuQAS+SsKHPy829rt5gquWDydMmPCVjIyMdMzaKWI/8S5hMdJeA+r7MNyN6GwR0Zy/v/NIp+O4ckw9LsfR0/S4bA81xAx1VQ1U+8s19K1/7qVjXGYtL7Dc8oCUpg0cMTQJx3LjSDi4t3tSN3/+fPjfjxn/O7TOyGAXJQ2f0ODdsEAkPLfWtb9yLH/HD7Q9lNrhsqyBnY639tJjv39X+dlitQXssKw26hIu3ChDABf3BGdeHfvfq/jR2BVm/BsqCl4E8OD3SMycGM/ec4JW3LuYVnELADa4wb2TsN0RLkNJJOBGQTjLMBbpAfj06dOfLC4uft8ADhUFLwAcF5m6b5pMcVxAlpyl9298jp5krXiDDY7AU9gSKbhREVhwffSkjt+3rLn55pt/WFpa+rEZQQmtrwA3XJRkE4B9pJw+/trz9MPKOjVhvLc7Ao4iIpGGW/xv/L2o0ZMDBw5U8HyDD/HjscUteEDXSNAaEMCTxWrjgaiT1VT84Ev00IFTVMGKELDBiwz7RQzurrYNqqKHDh1q4tvzGyZfmHVNbsUHufz5byNBasDRZn7kvpiuOokj9LXgEJJHj/vKK/kk7Ex+7KOLlIUQdyBP19CJOa/Q/W/soSOchJERwB1RP5vLs6Qr4PZ55vHFZb2r1b1lXNHRa/muXKYB3OqDgBFfgOvg+CtAz6PHuyo/jqEvOA7WYbF5GrSKX71NDyzaQAc4SYb88O+O67SI+dlcliVdATcKB+CyyMFsH+w6WsnTAO+8pD9dx4CnGcBFNYFDAVwfBw+8V+xzAGyeKar+D+vpu798k7ZzjWCtxR3Rh/0iXtmugluvqECO0MbPD5zpmUs7RvamKQx4Rgp/S0rXUVBxAVwpkk1ivPviAPtsPVUv2Uizfvaq+jgToBarDbBhsdGcLpFowo0GqIas3kOnud0fjBlAk/nWc450Wpe0MMkKFV3BB9ddgHiLtzC27GOfmvcWPTj3DfqIuwFQY4ErolvshIab22KdnWiIasyGYqrkZwreu/ICmsivYBVIpyGzkY41IP92cpHZce7ob23icY/jVXToZ3+jB55fR59wDfCNSN1iR3xkxFcro2G55bhyhlqAf3yEanccp7WfG05j+XszRQAcf7VGAmsgHgHHyQawedqzXQ8up/949WNrVEQHO2J3IANpKZpwS10EbhV+eoYaV++lt68dRaPyM2mAAVzUFDgUwJEz1v436oBb6p+W0cZbX6CHNn1KpzkJUMPP1h+GYo/U+ifnaNdJtOHWwZZGus/UUMufPqS114+mfvkZNNxpLHjQPS6Ax9JFwRh2Hdtjnqzy9WnP0k9Ky9QNmpiCDQVGG27pNB1yxF31jeT63Xu07ooLqLx3N7oy3UFO6TjZyYS+NaAPqUbbgquhvkZq5FGwX13/ND3L/YgPnsLH9jXch76OmsQKbjRQQd0WWrAv30r7bXbaOLIPXZHppG7GTQmOBQ/AeZeuHj1B7/HEOXSikg4/vZZmzV5Ba/mwsNbiX8uoiNygQR9HVWIJtzQUjYaLYrkp6w5QOfvhb04aSn3YDx9m3BRRVcehAN7VFCk3hAfz9p6kN29fQD9Y+REd4poJ2GKx9TuPXV0ln4qJNdxotPeiQD9dTc3sprw39gI60zufxsFNkb9cny0xiUoDMtrUFTTBr1e30huo8e399D/TfkPPcj9V8oF1/1qeFRGLHbOeiTXcaLj0g1hvPXSv2EqfuG20bngRXc43fAod/H8rHRgzrcX5gS39tOlKjEI4IcDGmzPHKql43ts0i7/g+y6rQe44yoiIgC19GFNNwTWLF0FdcLJh4cf1Cd/p5Q9SqyW7ex7lLL2X7vjsILq3WyZ/vIBzWZ3ImYy01wDch3AFUOMZbJ5TpH7rYVrAs64uPVvtYan1N2hgrbGIwQr38GHtHw+WW28AlCKLnP0IW+ubyLX0A9pxqIzWXNib+vLk7oPlYtNArqvwfDwcvYgLUsu2eP9pemfOSvrBwyvpHe4HuCAyGgKwvZ/siwuwoYV4styojwieYsaCGT14dj1lxfl7YZYlz3j2drr6Xy6m2T3zqD+PqpAZNmTt+BGAiiVYgcWHC8L3H46+toOeenAZvc/7wuUAzAI01vVnRCLwP8ElRlDiFW40EXUTwAVyAG4tA3tR3oI76J4xA+mOvHTKgKtiIIfq2kswcANquCDVTdTIj0YsvXcpLSo9rcatYZ31RaDmU8Aa5Wp/0BinxDPcUA3qhwXuEwCHLw5LbgGO+MyraNCDk+nuEb1pOrsr6TyyYiBnxXiLP8ABNW6dswvStP8UrXrmPVr8x410mPfXgUYcUGOID1CLbx3CfwLvFUWJd7hFFagnrLhALq4KLjoF9IyvXkb9Zk+lmSOK6Cv8XfZMfl7cQC4a9BECatyIqW6gBob6b0+toT/+5SM1OQ5cDgEbcd0FAdRwQeIWaq6bkkSBG5VFXQVyWHFxVQC4QK7iU4ZTr4e/RLeN7kdfzcugXAU57xnOBRYfIykE1htv8yioG6lm1zH6y3/9nZat/UQ96CQgA2yJ+3JB4h5sdFYiwS1wCeDe/jjAFosOa57+2c9Q4X9/mW4Z3Zdm8J3OQszJJ3c7Uwl0AI0Fkw80sFPBU5iV7zpOL//0VVqx9VP1pTAALEAjrltq8asTwlpz3S1JRLil8gI5XBUs8MdlfFwgV8AX5lHW4zfSxCsG0vUDu9NEfnY8Xax5Ml+Awu0QK13bRE2lZ2n9llJ6g4f11pdXW4+h6hYacfjUcus8YVwQrnM7SWS40RjUXyAXn1wgB+ACucTTxw2mbj+cRlNH9aZp/QroYobcpmZ3QkFcUiJbdLHQ8Bnw0gC7Hu5jFbRzDz8Dwi/nrtlUom6VwzLLIhYa6zrUsNJiqRPCBeH6tpNEh1sa5AtyfXQFcAN6gVydAHdNoAF3j6PpQ3rQlIIcGoxRFoCubg5x5niHXYcZz3wAaIx6VNRSSXEZrV28iVYt2UBHuCkCrkCNdT0O10OsdMJDzW1Rkixw6+0R0MVd0V0WuQgV0MXKO798CRV9bRxdMbQHje3TjS7n0Za+cF0wdq7DjgPFwroDZIgCmkPAjDHpttGO4/zo6YcHy2jbnzbRlld30CnOAmB1qAVoPR1Ay4IjyMLRxJdkg1vvEbQNroq4KwI7ABeovUNsQz7nzHHU78YxdMWQnjSWn0q8LDuNemIObVyQAnbrwpQzQ3Tg9fi5rYF/BV7klLgijX9wIQiYEeKtcn7r5czJKvqo+AxtW7mdtvxxkxq+E+urwytwSyh5BGgu0XI/AlcywXIkM9zSFWLJBXSEFsQcB+BYF+glriBvS7dPGU6FUy+iwcOKaFBRPg3qlkUD89NpIFv4fmzdnQAez1OLK6POLK91bBPLq0IGFxd8AjHSsN5mlVt4/PlYVROV8qQ2paeq6DDPr3d4zW4q4WE7fAsdYAJWAVbiANk7DpiRJjAjVIflMGkFfZAqgrbqC+AF6Ahl8QU20mS7vo86WXIzyfm1K6jfZQNpQEEm5fP0w1lZaZTNw47Z7L9ns4XPZl8+i61+NsOdwQA3svWtY9+4ni1xHfvJdTw8V1fPS2Mz1Vc0UNVHpXTkT1voWE2DB5AAFFCK1RVgBWR9Xc8j+wjMEnJRyS2pBLfekzrkiCtQOdThFaB9wS0nhYRShne5so5jIy4CwCACmncolhWQCpwIJS7wAmyJ+8rrXS5nTx3RFZ46rfZsqQCohwK7Hgr4HaXpZUgcR9PjWBfo9LikIRSQBWZ93V8a0vUyJI5jpKRA6UY8NSAgeoeAGmmBQu/9UDrSvAXwQQRCPRRQA4X6PhI/V6r59al0oxZPDQisSPUVlzQ9lLx6iLi3AEiIHgqk3qHk886rCjA/7TWADjESugZ0vUncO5RSJV3W9VBAlTRZ9w6xXdIkrwkDaKAjxQfY1WwOoIFQdGvADaDMzmz+f6SMYEX4z7hMAAAAAElFTkSuQmCC' // @suppress longLineCheck
};
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html
index c599c5e3ef8..5c99f4604e9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html
@@ -21,8 +21,8 @@ tr.exportTo('tr.ui.b', function() {
reject(err);
};
- var is_binary = filename.endsWith('.gz') || filename.endsWith('.zip');
- if (is_binary)
+ var isBinary = filename.endsWith('.gz') || filename.endsWith('.zip');
+ if (isBinary)
reader.readAsArrayBuffer(fileBlob);
else
reader.readAsText(fileBlob);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html
index 341574145c6..a0e52e85697 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name="tr-ui-b-grouping-table">
+<dom-module id='tr-ui-b-grouping-table'>
<template>
<style>
:host {
@@ -15,11 +15,12 @@ found in the LICENSE file.
}
#table {
flex: 1 1 auto;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -104,7 +105,9 @@ tr.exportTo('tr.ui.b', function() {
}
};
- Polymer('tr-ui-b-grouping-table', {
+ Polymer({
+ is: 'tr-ui-b-grouping-table',
+
created: function() {
this.dataToGroup_ = undefined;
this.groupBy_ = undefined;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html
index ef12f0450d6..ad24d1b6b7e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html
@@ -4,89 +4,226 @@ Copyright (c) 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/settings.html">
<link rel="import" href="/tracing/ui/base/dropdown.html">
-<polymer-element name="tr-ui-b-grouping-table-groupby-picker">
+<dom-module id='tr-ui-b-grouping-table-groupby-picker'>
<template>
<style>
:host {
display: flex;
- flex-direction: row;
align-items: center;
}
+
+ :host(:not([vertical])), :host(:not([vertical])) groups {
+ flex-direction: row;
+ }
+
+ :host([vertical]), :host([vertical]) groups {
+ flex-direction: column;
+ }
+
groups {
-webkit-user-select: none;
display: flex;
- flex-direction: row;
- padding-left: 10px;
}
- group, possible-group {
+ possible-group {
display: span;
padding-right: 10px;
padding-left: 10px;
}
+ </style>
+
+ <groups id="groups"></groups>
+ <tr-ui-b-dropdown id="add_group"></tr-ui-b-dropdown>
+ </template>
+</dom-module>
- group {
- border-left: 1px solid rgba(0,0,0,0);
+<dom-module id="tr-ui-b-grouping-table-groupby-picker-group">
+ <template>
+ <style>
+ :host {
+ white-space: nowrap;
+ border: 3px solid white;
+ background-color: #dddddd;
cursor: move;
}
- group.dragging {
- opacity: 0.2;
+ :host(:not([vertical])) {
+ display: inline;
}
- group.drop-targeted {
- border-left: 1px solid black;
+ :host([vertical]) {
+ display: block;
}
+ :host(:not([vertical]).drop-before) {
+ border-left: 3px solid black;
+ }
- #remove {
- cursor: default;
+ :host([vertical].drop-before) {
+ border-top: 3px solid black;
+ }
+
+ :host(:not([vertical]).drop-after) {
+ border-right: 3px solid black;
}
- #remove:not([hovered]) {
+ :host([vertical].drop-after) {
+ border-bottom: 3px solid black;
+ }
+
+ :host([dragging]) {
+ opacity: 0.5;
+ }
+
+ #remove {
visibility: hidden;
+ padding-left: 3px;
+ width: 20px;
+ height: 20px;
+ cursor: auto;
+ }
+
+ #key {
+ padding-right: 3px;
}
</style>
- <groups>
- </groups>
- <tr-ui-b-dropdown id="add-group"></tr-ui-b-dropdown>
- </template>
-</polymer-element>
-<template id="tr-ui-b-grouping-table-groupby-picker-group-template">
- <span id="key"></span>
- <span id="remove">&times;</span>
-</template>
+ <!-- TODO(eakuefner): Use an iron-icon here once
+ https://github.com/catapult-project/catapult/issues/2772 is fixed. -->
+ <span id="remove" on-click="remove_">&times;</span>
+ <span id="key"></span>
+ </template>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui.b', function() {
- var THIS_DOC = document._currentScript.ownerDocument;
+ var THIS_DOC = document.currentScript.ownerDocument;
+
+ Polymer({
+ is: 'tr-ui-b-grouping-table-groupby-picker-group',
- Polymer('tr-ui-b-grouping-table-groupby-picker', {
created: function() {
- this.needsInit_ = true;
+ this.picker_ = undefined;
+ this.group_ = undefined;
+ },
+
+ ready: function() {
+ this.setAttribute('draggable', true);
+ this.addEventListener('mouseover', this.onMouseOver_.bind(this));
+ this.addEventListener('mouseleave', this.onMouseLeave_.bind(this));
+ this.addEventListener('dragstart', this.onDragStart_.bind(this));
+ this.addEventListener('dragover', this.onDragOver_.bind(this));
+ },
+
+ set group(g) {
+ this.group_ = g;
+ this.$.key.textContent = g.label;
+ },
+
+ get key() {
+ return this.group_.key;
+ },
+
+ get picker() {
+ return this.picker_;
+ },
+
+ set picker(picker) {
+ this.picker_ = picker;
+ this.vertical = picker.vertical;
+ },
+
+ // TODO(benjhayden): Use data-binding?
+ get vertical() {
+ return this.getAttribute('vertical');
+ },
+
+ set vertical(vertical) {
+ if (vertical)
+ this.setAttribute('vertical', true);
+ else
+ this.removeAttribute('vertical');
+ },
+
+ onMouseOver_: function(event) {
+ this.$.remove.style.visibility = 'visible';
+ },
+
+ onMouseLeave_: function(event) {
+ this.$.remove.style.visibility = 'hidden';
+ },
+
+ onDragStart_: function(event) {
+ event.dataTransfer.effectAllowed = 'move';
+ this.setAttribute('dragging', true);
+ },
+
+ onDragOver_: function(event) {
+ event.preventDefault(); // Allows us to drop.
+ event.dataTransfer.dropEffect = 'move';
+
+ this.picker.clearDragIndicators_();
+ if (this.picker.shouldDropBefore_(this, event)) {
+ this.classList.add('drop-before');
+ if (this.previousElementSibling)
+ this.previousElementSibling.classList.add('drop-after');
+ } else {
+ this.classList.add('drop-after');
+ if (this.nextElementSibling)
+ this.nextElementSibling.classList.add('drop-before');
+ }
+ return false;
+ },
+
+ remove_: function(event) {
+ var newKeys = this.picker.currentGroupKeys.slice();
+ newKeys.splice(newKeys.indexOf(this.key), 1);
+ this.picker.currentGroupKeys = newKeys;
+ }
+ });
+
+ Polymer({
+ is: 'tr-ui-b-grouping-table-groupby-picker',
+
+ created: function() {
+ this.currentGroupKeys_ = undefined;
this.defaultGroupKeys_ = undefined;
this.possibleGroups_ = [];
this.settingsKey_ = [];
+ },
- this.currentGroupKeys_ = undefined;
-
- this.dragging_ = false;
+ ready: function() {
+ Polymer.dom(this.$.add_group.iconElement).textContent = 'Add another...';
+ this.addEventListener('dragend', this.onDragEnd_.bind(this));
+ this.addEventListener('drop', this.onDrop_.bind(this));
},
get defaultGroupKeys() {
return this.defaultGroupKeys_;
},
+ set vertical(vertical) {
+ if (vertical)
+ this.setAttribute('vertical', true);
+ else
+ this.removeAttribute('vertical');
+
+ for (var groupEl of this.$.groups.childNodes)
+ groupEl.vertical = vertical;
+ },
+
+ get vertical() {
+ return this.getAttribute('vertical');
+ },
+
set defaultGroupKeys(defaultGroupKeys) {
- if (!this.needsInit_)
- throw new Error('Already initialized.');
this.defaultGroupKeys_ = defaultGroupKeys;
this.maybeInit_();
},
@@ -96,8 +233,6 @@ tr.exportTo('tr.ui.b', function() {
},
set possibleGroups(possibleGroups) {
- if (!this.needsInit_)
- throw new Error('Already initialized.');
this.possibleGroups_ = possibleGroups;
this.maybeInit_();
},
@@ -107,27 +242,16 @@ tr.exportTo('tr.ui.b', function() {
},
set settingsKey(settingsKey) {
- if (!this.needsInit_)
- throw new Error('Already initialized.');
this.settingsKey_ = settingsKey;
this.maybeInit_();
},
maybeInit_: function() {
- if (!this.needsInit_)
- return;
-
- if (this.settingsKey_ === undefined)
+ if (!this.settingsKey_ ||
+ !this.defaultGroupKeys_ ||
+ !this.possibleGroups_) {
return;
- if (this.defaultGroupKeys_ === undefined)
- return;
- if (this.possibleGroups_ === undefined)
- return;
-
- this.needsInit_ = false;
-
- var addGroupEl = this.shadowRoot.querySelector('#add-group');
- addGroupEl.iconElement.textContent = 'Add another...';
+ }
this.currentGroupKeys = tr.b.Settings.get(
this.settingsKey_, this.defaultGroupKeys_);
@@ -139,12 +263,9 @@ tr.exportTo('tr.ui.b', function() {
get currentGroups() {
var groupsByKey = {};
- this.possibleGroups_.forEach(function(group) {
+ for (var group of this.possibleGroups_)
groupsByKey[group.key] = group;
- });
- return this.currentGroupKeys_.map(function(groupKey) {
- return groupsByKey[groupKey];
- });
+ return this.currentGroupKeys.map(groupKey => groupsByKey[groupKey]);
},
set currentGroupKeys(currentGroupKeys) {
@@ -154,156 +275,136 @@ tr.exportTo('tr.ui.b', function() {
if (!(currentGroupKeys instanceof Array))
throw new Error('Must be array');
- this.currentGroupKeys_ = currentGroupKeys;
+ var availableGroupKeys = new Set();
+ for (var group of this.possibleGroups_)
+ availableGroupKeys.add(group.key);
+ this.currentGroupKeys_ = currentGroupKeys.filter(
+ k => availableGroupKeys.has(k));
this.updateGroups_();
tr.b.Settings.set(
this.settingsKey_, this.currentGroupKeys_);
- var e = new tr.b.Event('current-groups-changed');
- this.dispatchEvent(e);
+ this.dispatchEvent(new tr.b.Event('current-groups-changed'));
},
- updateGroups_: function() {
- var groupsEl = this.shadowRoot.querySelector('groups');
- var addGroupEl = this.shadowRoot.querySelector('#add-group');
+ /**
+ * @return {undefined|Element}
+ */
+ get draggingGroupElement() {
+ for (var group of this.$.groups.children)
+ if (group.getAttribute('dragging'))
+ return group;
+ return undefined;
+ },
- groupsEl.textContent = '';
- addGroupEl.textContent = '';
+ shouldDropBefore_: function(groupEl, event) {
+ var dragBoxRect = this.draggingGroupElement.getBoundingClientRect();
+ var dropBoxRect = groupEl.getBoundingClientRect();
+ // compare horizontally if drag and drop overlap vertically
+ var dragVertRange = tr.b.Range.fromExplicitRange(
+ dragBoxRect.top, dragBoxRect.bottom);
+ var dropVertRange = tr.b.Range.fromExplicitRange(
+ dropBoxRect.top, dropBoxRect.bottom);
+ if (dragVertRange.intersectsRangeInclusive(dropVertRange))
+ return event.clientX < ((dropBoxRect.left + dropBoxRect.right) / 2);
+ return event.clientY < ((dropBoxRect.top + dropBoxRect.bottom) / 2);
+ },
+
+ clearDragIndicators_: function() {
+ for (var groupEl of this.$.groups.children) {
+ groupEl.classList.remove('drop-before');
+ groupEl.classList.remove('drop-after');
+ }
+ },
+
+ onDragEnd_: function(event) {
+ this.clearDragIndicators_();
+ for (var groupEl of this.$.groups.children)
+ groupEl.removeAttribute('dragging');
+ },
+
+ onDrop_: function(event) {
+ event.stopPropagation(); // stops the browser from redirecting.
+
+ var draggingGroupEl = this.draggingGroupElement;
+ var dropBeforeEl = undefined;
+ var dropAfterEl = undefined;
+ for (var groupEl of this.$.groups.children) {
+ if (groupEl.classList.contains('drop-before')) {
+ dropBeforeEl = groupEl;
+ break;
+ }
+ if (groupEl.classList.contains('drop-after')) {
+ dropAfterEl = groupEl;
+ break;
+ }
+ }
+
+ if (!dropBeforeEl && !dropAfterEl)
+ return;
+
+ this.$.groups.removeChild(draggingGroupEl);
+ var lastGroupEl = this.$.groups.children[
+ this.$.groups.children.length - 1];
+
+ if (dropBeforeEl)
+ this.$.groups.insertBefore(draggingGroupEl, dropBeforeEl);
+ else if (dropAfterEl === lastGroupEl)
+ this.$.groups.appendChild(draggingGroupEl);
+ else
+ this.$.groups.insertBefore(draggingGroupEl, dropAfterEl.nextSibling);
+
+ var currentGroupKeys = [];
+ for (var group of this.$.groups.children)
+ currentGroupKeys.push(group.key);
+ this.currentGroupKeys = currentGroupKeys;
+ return false;
+ },
+
+ updateGroups_: function() {
+ Polymer.dom(this.$.groups).textContent = '';
+ Polymer.dom(this.$.add_group).textContent = '';
var unusedGroups = {};
var groupsByKey = {};
- this.possibleGroups_.forEach(function(group) {
+ for (var group of this.possibleGroups_) {
unusedGroups[group.key] = group;
groupsByKey[group.key] = group;
- });
+ }
- this.currentGroupKeys_.forEach(function(key) {
+ for (var key of this.currentGroupKeys_)
delete unusedGroups[key];
- });
// Create groups.
- var groupTemplateEl = THIS_DOC.querySelector(
- '#tr-ui-b-grouping-table-groupby-picker-group-template');
- this.currentGroupKeys_.forEach(function(key, index) {
+ for (var key of this.currentGroupKeys_) {
var group = groupsByKey[key];
- var groupEl = document.createElement('group');
- groupEl.groupKey = key;
- groupEl.appendChild(document.importNode(groupTemplateEl.content, true));
- groupEl.querySelector('#key').textContent = group.label;
- groupsEl.appendChild(groupEl);
-
- this.configureRemoveButtonForGroup_(groupEl);
- this.configureDragAndDropForGroup_(groupEl);
- }, this);
+ var groupEl = document.createElement(
+ 'tr-ui-b-grouping-table-groupby-picker-group');
+ groupEl.picker = this;
+ groupEl.group = group;
+ Polymer.dom(this.$.groups).appendChild(groupEl);
+ }
// Adjust dropdown.
tr.b.iterItems(unusedGroups, function(key, group) {
var groupEl = document.createElement('possible-group');
- groupEl.textContent = group.label;
+ Polymer.dom(groupEl).textContent = group.label;
groupEl.addEventListener('click', function() {
var newKeys = this.currentGroupKeys.slice();
newKeys.push(key);
this.currentGroupKeys = newKeys;
- addGroupEl.close();
+ this.$.add_group.close();
}.bind(this));
- addGroupEl.appendChild(groupEl);
+ Polymer.dom(this.$.add_group).appendChild(groupEl);
}, this);
// Hide dropdown if needed.
- if (tr.b.dictionaryLength(unusedGroups) == 0) {
- addGroupEl.style.display = 'none';
+ if (tr.b.dictionaryLength(unusedGroups) === 0) {
+ this.$.add_group.style.display = 'none';
} else {
- addGroupEl.style.display = '';
+ this.$.add_group.style.display = '';
}
- },
-
- configureRemoveButtonForGroup_: function(groupEl) {
- var removeEl = groupEl.querySelector('#remove');
- removeEl.addEventListener('click', function() {
- var newKeys = this.currentGroupKeys.slice();
- var i = newKeys.indexOf(groupEl.groupKey);
- newKeys.splice(i, 1);
- this.currentGroupKeys = newKeys;
- }.bind(this));
-
- groupEl.addEventListener('mouseenter', function() {
- removeEl.setAttribute('hovered', true);
- });
- groupEl.addEventListener('mouseleave', function() {
- removeEl.removeAttribute('hovered');
- });
- },
-
- configureDragAndDropForGroup_: function(groupEl) {
- var groupsEl = groupEl.parentElement;
-
- groupEl.setAttribute('draggable', true);
-
- groupEl.addEventListener('dragstart', function(e) {
- e.dataTransfer.setData('groupKey', groupEl.groupKey);
- groupEl.querySelector('#remove').removeAttribute('hovered');
- groupEl.classList.add('dragging');
- this.dragging_ = true;
- }.bind(this));
-
- groupEl.addEventListener('dragend', function(e) {
- console.log(e.type, groupEl.groupKey);
- for (var i = 0; i < groupsEl.children.length; i++)
- groupsEl.children[i].classList.remove('drop-targeted');
- groupEl.classList.remove('dragging');
- this.dragging_ = false;
- }.bind(this));
-
- // Drop targeting.
- groupEl.addEventListener('dragenter', function(e) {
- if (!this.dragging_)
- return;
- groupEl.classList.add('drop-targeted');
- if (this.dragging_)
- e.preventDefault();
- }.bind(this));
-
- groupEl.addEventListener('dragleave', function(e) {
- if (!this.dragging_)
- return;
- groupEl.classList.remove('drop-targeted');
- e.preventDefault();
- }.bind(this));
-
-
- // Drop logic.
- groupEl.addEventListener('dragover', function(e) {
- if (!this.dragging_)
- return;
- e.preventDefault();
- groupEl.classList.add('drop-targeted');
- }.bind(this));
-
- groupEl.addEventListener('drop', function(e) {
- if (!this.dragging_)
- return;
-
- var srcKey = e.dataTransfer.getData('groupKey');
- var dstKey = groupEl.groupKey;
-
- if (srcKey === dstKey)
- return;
-
- var newKeys = this.currentGroupKeys_.slice();
-
- var srcIndex = this.currentGroupKeys_.indexOf(srcKey);
- newKeys.splice(srcIndex, 1);
-
- var dstIndex = this.currentGroupKeys_.indexOf(dstKey);
- newKeys.splice(dstIndex, 0, srcKey);
-
- this.currentGroupKeys = newKeys;
-
- e.dataTransfer.clearData();
- e.preventDefault();
- e.stopPropagation();
- }.bind(this));
}
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html b/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html
index 0c884b65a96..b83e46c9d47 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel='import' href='/tracing/ui/base/constants.html'>
-<polymer-element name='tr-ui-heading'>
+<dom-module id='tr-ui-heading'>
<template>
<style>
:host {
@@ -39,104 +39,105 @@ found in the LICENSE file.
display: none;
}
</style>
- <heading id='heading' on-click='{{onHeadingDivClicked_}}'>
+ <heading id='heading' on-click='onHeadingDivClicked_'>
<span id='arrow'></span>
<span id='heading_content'></span>
<tr-ui-a-analysis-link id='link'></tr-ui-a-analysis-link>
</heading>
</template>
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-heading',
+
+ DOWN_ARROW: String.fromCharCode(0x25BE),
+ RIGHT_ARROW: String.fromCharCode(0x25B8),
+
+ ready: function(viewport) {
+ // Minus 6 === 1px border + 5px padding right.
+ this.style.width = (tr.ui.b.constants.HEADING_WIDTH - 6) + 'px';
+
+ this.heading_ = '';
+ this.expanded_ = true;
+ this.arrowVisible_ = false;
+ this.selectionGenerator_ = undefined;
+
+ this.updateContents_();
+ },
+
+ get heading() {
+ return this.heading_;
+ },
+
+ set heading(text) {
+ if (this.heading_ === text)
+ return;
+
+ this.heading_ = text;
+ this.updateContents_();
+ },
+
+ set arrowVisible(val) {
+ if (this.arrowVisible_ === val)
+ return;
+
+ this.arrowVisible_ = !!val;
+ this.updateContents_();
+ },
+
+ set tooltip(text) {
+ this.$.heading.title = text;
+ },
+
+ set selectionGenerator(generator) {
+ if (this.selectionGenerator_ === generator)
+ return;
+
+ this.selectionGenerator_ = generator;
+ this.updateContents_();
+ },
+
+ get expanded() {
+ return this.expanded_;
+ },
+
+ set expanded(expanded) {
+ if (this.expanded_ === expanded)
+ return;
+
+ this.expanded_ = !!expanded;
+ this.updateContents_();
+ },
+
+ onHeadingDivClicked_: function() {
+ this.dispatchEvent(new tr.b.Event('heading-clicked', true));
+ },
+
+ updateContents_: function() {
+ if (this.arrowVisible_) {
+ this.$.arrow.style.display = '';
+ } else {
+ this.$.arrow.style.display = 'none';
+ this.$.heading.style.display = this.expanded_ ? '' : 'none';
+ }
+
+ if (this.arrowVisible_) {
+ Polymer.dom(this.$.arrow).textContent =
+ this.expanded_ ? this.DOWN_ARROW : this.RIGHT_ARROW;
+ }
+
+ this.$.link.style.display = 'none';
+ this.$.heading_content.style.display = 'none';
- <script>
- 'use strict';
- Polymer({
- DOWN_ARROW: String.fromCharCode(0x25BE),
- RIGHT_ARROW: String.fromCharCode(0x25B8),
-
- ready: function(viewport) {
- // Minus 6 == 1px border + 5px padding right.
- this.style.width = (tr.ui.b.constants.HEADING_WIDTH - 6) + 'px';
-
- this.heading_ = '';
- this.expanded_ = true;
- this.arrowVisible_ = false;
- this.selectionGenerator_ = undefined;
-
- this.updateContents_();
- },
-
- get heading() {
- return this.heading_;
- },
-
- set heading(text) {
- if (this.heading_ === text)
- return;
-
- this.heading_ = text;
- this.updateContents_();
- },
-
- set arrowVisible(val) {
- if (this.arrowVisible_ === val)
- return;
-
- this.arrowVisible_ = !!val;
- this.updateContents_();
- },
-
- set tooltip(text) {
- this.$.heading.title = text;
- },
-
- set selectionGenerator(generator) {
- if (this.selectionGenerator_ === generator)
- return;
-
- this.selectionGenerator_ = generator;
- this.updateContents_();
- },
-
- get expanded() {
- return this.expanded_;
- },
-
- set expanded(expanded) {
- if (this.expanded_ === expanded)
- return;
-
- this.expanded_ = !!expanded;
- this.updateContents_();
- },
-
- onHeadingDivClicked_: function() {
- this.dispatchEvent(new tr.b.Event('heading-clicked', {'bubbles': true}));
- },
-
- updateContents_: function() {
- if (this.arrowVisible_) {
- this.$.arrow.style.display = '';
- } else {
- this.$.arrow.style.display = 'none';
- this.$.heading.style.display = this.expanded_ ? '' : 'none';
- }
-
- if (this.arrowVisible_) {
- this.$.arrow.textContent =
- this.expanded_ ? this.DOWN_ARROW : this.RIGHT_ARROW;
- }
-
- this.$.link.style.display = 'none';
- this.$.heading_content.style.display = 'none';
-
- if (this.selectionGenerator_) {
- this.$.link.style.display = 'inline-block';
- this.$.link.selection = this.selectionGenerator_;
- this.$.link.textContent = this.heading_;
- } else {
- this.$.heading_content.style.display = 'inline-block';
- this.$.heading_content.textContent = this.heading_;
- }
+ if (this.selectionGenerator_) {
+ this.$.link.style.display = 'inline-block';
+ this.$.link.selection = this.selectionGenerator_;
+ Polymer.dom(this.$.link).textContent = this.heading_;
+ } else {
+ this.$.heading_content.style.display = 'inline-block';
+ Polymer.dom(this.$.heading_content).textContent = this.heading_;
}
- });
- </script>
-</polymer-element>
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html
index 892b7e7593a..38b7967a17a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html
@@ -7,260 +7,264 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/guid.html">
<link rel="import" href="/tracing/ui/base/hot_key.html">
-<polymer-element name="tv-ui-b-hotkey-controller">
- <script>
- 'use strict';
- Polymer({
- created: function() {
- this.isAttached_ = false;
- this.globalMode_ = false;
- this.slavedToParentController_ = undefined;
- this.curHost_ = undefined;
- this.childControllers_ = [];
+<dom-module id='tv-ui-b-hotkey-controller'>
+ <template>
+ <div></div>
+ </template>
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tv-ui-b-hotkey-controller',
+
+ created: function() {
+ this.isAttached_ = false;
+ this.globalMode_ = false;
+ this.slavedToParentController_ = undefined;
+ this.curHost_ = undefined;
+ this.childControllers_ = [];
+
+ this.bubblingKeyDownHotKeys_ = {};
+ this.capturingKeyDownHotKeys_ = {};
+ this.bubblingKeyPressHotKeys_ = {};
+ this.capturingKeyPressHotKeys_ = {};
+
+ this.onBubblingKeyDown_ = this.onKey_.bind(this, false);
+ this.onCapturingKeyDown_ = this.onKey_.bind(this, true);
+ this.onBubblingKeyPress_ = this.onKey_.bind(this, false);
+ this.onCapturingKeyPress_ = this.onKey_.bind(this, true);
+ },
+
+ attached: function() {
+ this.isAttached_ = true;
+
+ var host = this.findHost_();
+ if (host.__hotkeyController)
+ throw new Error('Multiple hotkey controllers attached to this host');
+
+ host.__hotkeyController = this;
+ this.curHost_ = host;
+
+ var parentElement;
+ if (host.parentElement)
+ parentElement = host.parentElement;
+ else
+ parentElement = Polymer.dom(host).parentNode.host;
+ var parentController = tr.b.getHotkeyControllerForElement(
+ parentElement);
+
+ if (parentController) {
+ this.slavedToParentController_ = parentController;
+ parentController.addChildController_(this);
+ return;
+ }
- this.bubblingKeyDownHotKeys_ = {};
- this.capturingKeyDownHotKeys_ = {};
- this.bubblingKeyPressHotKeys_ = {};
- this.capturingKeyPressHotKeys_ = {};
+ host.addEventListener('keydown', this.onBubblingKeyDown_, false);
+ host.addEventListener('keydown', this.onCapturingKeyDown_, true);
+ host.addEventListener('keypress', this.onBubblingKeyPress_, false);
+ host.addEventListener('keypress', this.onCapturingKeyPress_, true);
+ },
- this.onBubblingKeyDown_ = this.onKey_.bind(this, false);
- this.onCapturingKeyDown_ = this.onKey_.bind(this, true);
- this.onBubblingKeyPress_ = this.onKey_.bind(this, false);
- this.onCapturingKeyPress_ = this.onKey_.bind(this, true);
- },
+ detached: function() {
+ this.isAttached_ = false;
- attached: function() {
- this.isAttached_ = true;
+ var host = this.curHost_;
+ if (!host)
+ return;
- var host = this.findHost_();
- if (host.__hotkeyController)
- throw new Error('Multiple hotkey controllers attached to this host');
+ delete host.__hotkeyController;
+ this.curHost_ = undefined;
- host.__hotkeyController = this;
- this.curHost_ = host;
+ if (this.slavedToParentController_) {
+ this.slavedToParentController_.removeChildController_(this);
+ this.slavedToParentController_ = undefined;
+ return;
+ }
- var parentElement;
- if (host.parentElement)
- parentElement = host.parentElement;
+ host.removeEventListener('keydown', this.onBubblingKeyDown_, false);
+ host.removeEventListener('keydown', this.onCapturingKeyDown_, true);
+ host.removeEventListener('keypress', this.onBubblingKeyPress_, false);
+ host.removeEventListener('keypress', this.onCapturingKeyPress_, true);
+ },
+
+ addChildController_: function(controller) {
+ var i = this.childControllers_.indexOf(controller);
+ if (i !== -1)
+ throw new Error('Controller already registered');
+ this.childControllers_.push(controller);
+ },
+
+ removeChildController_: function(controller) {
+ var i = this.childControllers_.indexOf(controller);
+ if (i === -1)
+ throw new Error('Controller not registered');
+ this.childControllers_.splice(i, 1);
+ return controller;
+ },
+
+ getKeyMapForEventType_: function(eventType, useCapture) {
+ if (eventType === 'keydown') {
+ if (!useCapture)
+ return this.bubblingKeyDownHotKeys_;
else
- parentElement = host.parentNode.host;
- var parentController = tr.b.getHotkeyControllerForElement(
- parentElement);
-
- if (parentController) {
- this.slavedToParentController_ = parentController;
- parentController.addChildController_(this);
- return;
- }
-
- host.addEventListener('keydown', this.onBubblingKeyDown_, false);
- host.addEventListener('keydown', this.onCapturingKeyDown_, true);
- host.addEventListener('keypress', this.onBubblingKeyPress_, false);
- host.addEventListener('keypress', this.onCapturingKeyPress_, true);
- },
-
- detached: function() {
- this.isAttached_ = false;
-
- var host = this.curHost_;
- if (!host)
- return;
-
- delete host.__hotkeyController;
- this.curHost_ = undefined;
-
- if (this.slavedToParentController_) {
- this.slavedToParentController_.removeChildController_(this);
- this.slavedToParentController_ = undefined;
- return;
- }
-
- host.removeEventListener('keydown', this.onBubblingKeyDown_, false);
- host.removeEventListener('keydown', this.onCapturingKeyDown_, true);
- host.removeEventListener('keypress', this.onBubblingKeyPress_, false);
- host.removeEventListener('keypress', this.onCapturingKeyPress_, true);
- },
-
- addChildController_: function(controller) {
- var i = this.childControllers_.indexOf(controller);
- if (i !== -1)
- throw new Error('Controller already registered');
- this.childControllers_.push(controller);
- },
-
- removeChildController_: function(controller) {
- var i = this.childControllers_.indexOf(controller);
- if (i === -1)
- throw new Error('Controller not registered');
- this.childControllers_.splice(i, 1);
- return controller;
- },
-
- getKeyMapForEventType_: function(eventType, useCapture) {
- if (eventType === 'keydown') {
- if (!useCapture)
- return this.bubblingKeyDownHotKeys_;
- else
- return this.capturingKeyDownHotKeys_;
- } else if (eventType === 'keypress') {
- if (!useCapture)
- return this.bubblingKeyPressHotKeys_;
- else
- return this.capturingKeyPressHotKeys_;
- } else {
- throw new Error('Unsupported key event');
- }
- },
+ return this.capturingKeyDownHotKeys_;
+ } else if (eventType === 'keypress') {
+ if (!useCapture)
+ return this.bubblingKeyPressHotKeys_;
+ else
+ return this.capturingKeyPressHotKeys_;
+ } else {
+ throw new Error('Unsupported key event');
+ }
+ },
- addHotKey: function(hotKey) {
- if (!(hotKey instanceof tr.ui.b.HotKey))
- throw new Error('hotKey must be a tr.ui.b.HotKey');
+ addHotKey: function(hotKey) {
+ if (!(hotKey instanceof tr.ui.b.HotKey))
+ throw new Error('hotKey must be a tr.ui.b.HotKey');
- var keyMap = this.getKeyMapForEventType_(
- hotKey.eventType, hotKey.useCapture);
+ var keyMap = this.getKeyMapForEventType_(
+ hotKey.eventType, hotKey.useCapture);
- for (var i = 0; i < hotKey.keyCodes.length; i++) {
- var keyCode = hotKey.keyCodes[i];
- if (keyMap[keyCode])
- throw new Error('Key is already bound for keyCode=' + keyCode);
- }
+ for (var i = 0; i < hotKey.keyCodes.length; i++) {
+ var keyCode = hotKey.keyCodes[i];
+ if (keyMap[keyCode])
+ throw new Error('Key is already bound for keyCode=' + keyCode);
+ }
- for (var i = 0; i < hotKey.keyCodes.length; i++) {
- var keyCode = hotKey.keyCodes[i];
- keyMap[keyCode] = hotKey;
- }
- return hotKey;
- },
+ for (var i = 0; i < hotKey.keyCodes.length; i++) {
+ var keyCode = hotKey.keyCodes[i];
+ keyMap[keyCode] = hotKey;
+ }
+ return hotKey;
+ },
- removeHotKey: function(hotKey) {
- if (!(hotKey instanceof tr.ui.b.HotKey))
- throw new Error('hotKey must be a tr.ui.b.HotKey');
+ removeHotKey: function(hotKey) {
+ if (!(hotKey instanceof tr.ui.b.HotKey))
+ throw new Error('hotKey must be a tr.ui.b.HotKey');
- var keyMap = this.getKeyMapForEventType_(
- hotKey.eventType, hotKey.useCapture);
+ var keyMap = this.getKeyMapForEventType_(
+ hotKey.eventType, hotKey.useCapture);
- for (var i = 0; i < hotKey.keyCodes.length; i++) {
- var keyCode = hotKey.keyCodes[i];
- if (!keyMap[keyCode])
- throw new Error('Key is not bound for keyCode=' + keyCode);
- keyMap[keyCode] = hotKey;
- }
- for (var i = 0; i < hotKey.keyCodes.length; i++) {
- var keyCode = hotKey.keyCodes[i];
- delete keyMap[keyCode];
- }
- return hotKey;
- },
-
- get globalMode() {
- return this.globalMode_;
- },
-
- set globalMode(globalMode) {
- var wasAttached = this.isAttached_;
- if (wasAttached)
- this.detached();
- this.globalMode_ = !!globalMode;
- if (wasAttached)
- this.attached();
- },
-
- get topmostConroller_() {
- if (this.slavedToParentController_)
- return this.slavedToParentController_.topmostConroller_;
- return this;
- },
-
- childRequestsGeneralFocus: function(child) {
- var topmost = this.topmostConroller_;
- if (topmost.curHost_) {
- if (topmost.curHost_.hasAttribute('tabIndex')) {
- topmost.curHost_.focus();
- } else {
- if (document.activeElement)
- document.activeElement.blur();
- }
+ for (var i = 0; i < hotKey.keyCodes.length; i++) {
+ var keyCode = hotKey.keyCodes[i];
+ if (!keyMap[keyCode])
+ throw new Error('Key is not bound for keyCode=' + keyCode);
+ keyMap[keyCode] = hotKey;
+ }
+ for (var i = 0; i < hotKey.keyCodes.length; i++) {
+ var keyCode = hotKey.keyCodes[i];
+ delete keyMap[keyCode];
+ }
+ return hotKey;
+ },
+
+ get globalMode() {
+ return this.globalMode_;
+ },
+
+ set globalMode(globalMode) {
+ var wasAttached = this.isAttached_;
+ if (wasAttached)
+ this.detached();
+ this.globalMode_ = !!globalMode;
+ if (wasAttached)
+ this.attached();
+ },
+
+ get topmostConroller_() {
+ if (this.slavedToParentController_)
+ return this.slavedToParentController_.topmostConroller_;
+ return this;
+ },
+
+ childRequestsGeneralFocus: function(child) {
+ var topmost = this.topmostConroller_;
+ if (topmost.curHost_) {
+ if (topmost.curHost_.hasAttribute('tabIndex')) {
+ topmost.curHost_.focus();
} else {
if (document.activeElement)
document.activeElement.blur();
}
- },
-
- childRequestsBlur: function(child) {
- child.blur();
+ } else {
+ if (document.activeElement)
+ document.activeElement.blur();
+ }
+ },
- var topmost = this.topmostConroller_;
- if (topmost.curHost_) {
- topmost.curHost_.focus();
- }
- },
+ childRequestsBlur: function(child) {
+ child.blur();
- findHost_: function() {
- if (this.globalMode_) {
- return document.body;
- } else {
- if (this.parentElement)
- return this.parentElement;
-
- var node = this;
- while (node.parentNode) {
- node = node.parentNode;
- }
- return node.host;
- }
- },
-
- appendMatchingHotKeysTo_: function(matchedHotKeys,
- useCapture, e) {
- var localKeyMap = this.getKeyMapForEventType_(e.type, useCapture);
- var localHotKey = localKeyMap[e.keyCode];
- if (localHotKey)
- matchedHotKeys.push(localHotKey);
-
- for (var i = 0; i < this.childControllers_.length; i++) {
- var controller = this.childControllers_[i];
- controller.appendMatchingHotKeysTo_(matchedHotKeys,
- useCapture, e);
+ var topmost = this.topmostConroller_;
+ if (topmost.curHost_) {
+ topmost.curHost_.focus();
+ }
+ },
+
+ findHost_: function() {
+ if (this.globalMode_) {
+ return document.body;
+ } else {
+ if (this.parentElement)
+ return this.parentElement;
+
+ var node = this;
+ while (Polymer.dom(node).parentNode) {
+ node = Polymer.dom(node).parentNode;
}
- },
+ return node.host;
+ }
+ },
+
+ appendMatchingHotKeysTo_: function(matchedHotKeys,
+ useCapture, e) {
+ var localKeyMap = this.getKeyMapForEventType_(e.type, useCapture);
+ var localHotKey = localKeyMap[e.keyCode];
+ if (localHotKey)
+ matchedHotKeys.push(localHotKey);
+
+ for (var i = 0; i < this.childControllers_.length; i++) {
+ var controller = this.childControllers_[i];
+ controller.appendMatchingHotKeysTo_(matchedHotKeys,
+ useCapture, e);
+ }
+ },
- onKey_: function(useCapture, e) {
- // Keys dispatched to INPUT elements still bubble, even when they're
- // handled. So, skip any events that targeted the input element.
- if (useCapture == false && e.path[0].tagName == 'INPUT')
- return;
+ onKey_: function(useCapture, e) {
+ // Keys dispatched to INPUT elements still bubble, even when they're
+ // handled. So, skip any events that targeted the input element.
+ if (!useCapture && e.path[0].tagName === 'INPUT')
+ return;
- var sortedControllers;
+ var sortedControllers;
- var matchedHotKeys = [];
- this.appendMatchingHotKeysTo_(matchedHotKeys, useCapture, e);
+ var matchedHotKeys = [];
+ this.appendMatchingHotKeysTo_(matchedHotKeys, useCapture, e);
- if (matchedHotKeys.length === 0)
- return false;
+ if (matchedHotKeys.length === 0)
+ return false;
- if (matchedHotKeys.length > 1) {
- // TODO(nduca): To do support for coddling hotKeys, we need to
- // sort the listeners by their capturing/bubbling order and then pick
- // the one that would topologically win the tie, per DOM dispatch rules.
- throw new Error('More than one hotKey is currently unsupported');
- }
+ if (matchedHotKeys.length > 1) {
+ // TODO(nduca): To do support for coddling hotKeys, we need to
+ // sort the listeners by their capturing/bubbling order and then pick
+ // the one that would topologically win the tie, per DOM dispatch rules.
+ throw new Error('More than one hotKey is currently unsupported');
+ }
- var hotKey = matchedHotKeys[0];
+ var hotKey = matchedHotKeys[0];
- var prevented = 0;
- prevented |= hotKey.call(e);
+ var prevented = 0;
+ prevented |= hotKey.call(e);
- // We want to return false if preventDefaulted, or one of the handlers
- // return false. But otherwise, we want to return undefiend.
- return !prevented && e.defaultPrevented;
- }
- });
- </script>
-</polymer-element>
+ // We want to return false if preventDefaulted, or one of the handlers
+ // return false. But otherwise, we want to return undefiend.
+ return !prevented && e.defaultPrevented;
+ }
+});
+</script>
<script>
'use strict';
-
tr.exportTo('tr.b', function() {
function getHotkeyControllerForElement(refElement) {
@@ -285,8 +289,8 @@ tr.exportTo('tr.b', function() {
function findHost(initialNode) {
var node = initialNode;
- while (node.parentNode) {
- node = node.parentNode;
+ while (Polymer.dom(node).parentNode) {
+ node = Polymer.dom(node).parentNode;
}
return node.host;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html
index 0895e724250..2ef4c5bb737 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html
@@ -24,15 +24,15 @@ tr.b.unittest.testSuite(function() {
test('simpleHotkeyManager', function() {
var rootElement = document.createElement('div');
- document.body.appendChild(rootElement);
+ Polymer.dom(document.body).appendChild(rootElement);
try {
var elementShadow = rootElement.createShadowRoot();
var hkc = document.createElement('tv-ui-b-hotkey-controller');
- elementShadow.appendChild(hkc);
+ Polymer.dom(elementShadow).appendChild(hkc);
var subElement = document.createElement('div');
- elementShadow.appendChild(subElement);
+ Polymer.dom(elementShadow).appendChild(subElement);
assert.equal(tr.b.getHotkeyControllerForElement(subElement), hkc);
@@ -57,25 +57,25 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(didGetCalled);
} finally {
- document.body.removeChild(rootElement);
+ Polymer.dom(document.body).removeChild(rootElement);
}
});
test('nestedHotkeyController', function() {
var rootElement = document.createElement('div');
- document.body.appendChild(rootElement);
+ Polymer.dom(document.body).appendChild(rootElement);
try {
var elementShadow = rootElement.createShadowRoot();
var hkc = document.createElement('tv-ui-b-hotkey-controller');
- elementShadow.appendChild(hkc);
+ Polymer.dom(elementShadow).appendChild(hkc);
var subElement = document.createElement('div');
- elementShadow.appendChild(subElement);
+ Polymer.dom(elementShadow).appendChild(subElement);
assert.equal(tr.b.getHotkeyControllerForElement(elementShadow), hkc);
var subHKC = document.createElement('tv-ui-b-hotkey-controller');
- subElement.appendChild(subHKC);
+ Polymer.dom(subElement).appendChild(subHKC);
assert.equal(tr.b.getHotkeyControllerForElement(subElement), subHKC);
@@ -93,21 +93,21 @@ tr.b.unittest.testSuite(function() {
rootElement.dispatchEvent(e);
assert.isTrue(didGetCalled);
} finally {
- document.body.removeChild(rootElement);
+ Polymer.dom(document.body).removeChild(rootElement);
}
});
test('inputInsideHKC', function() {
var rootElement = document.createElement('div');
- document.body.appendChild(rootElement);
+ Polymer.dom(document.body).appendChild(rootElement);
try {
var elementShadow = rootElement.createShadowRoot();
var hkc = document.createElement('tv-ui-b-hotkey-controller');
- elementShadow.appendChild(hkc);
+ Polymer.dom(elementShadow).appendChild(hkc);
var inputEl = document.createElement('input');
- elementShadow.appendChild(inputEl);
+ Polymer.dom(elementShadow).appendChild(inputEl);
var didGetCalled = false;
hkc.addHotKey(new tr.ui.b.HotKey({
@@ -130,7 +130,7 @@ tr.b.unittest.testSuite(function() {
inputEl.dispatchEvent(e);
assert.isFalse(didGetCalled);
} finally {
- document.body.removeChild(rootElement);
+ Polymer.dom(document.body).removeChild(rootElement);
}
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html
index a9b188556d1..6ad1bdbbfde 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name='tr-ui-b-info-bar' is='HTMLDivElement'>
+<dom-module id='tr-ui-b-info-bar'>
<template>
<style>
:host {
@@ -34,49 +34,50 @@ found in the LICENSE file.
<span id='message'></span>
<span id='buttons'></span>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-b-info-bar',
- Polymer({
- ready: function() {
- this.messageEl_ = this.$.message;
- this.buttonsEl_ = this.$.buttons;
+ ready: function() {
+ this.messageEl_ = this.$.message;
+ this.buttonsEl_ = this.$.buttons;
- this.message = '';
- this.visible = false;
- },
+ this.message = '';
+ this.visible = false;
+ },
- get message() {
- return this.messageEl_.textContent;
- },
+ get message() {
+ return Polymer.dom(this.messageEl_).textContent;
+ },
- set message(message) {
- this.messageEl_.textContent = message;
- },
+ set message(message) {
+ Polymer.dom(this.messageEl_).textContent = message;
+ },
- get visible() {
- return !this.classList.contains('info-bar-hidden');
- },
+ get visible() {
+ return !Polymer.dom(this).classList.contains('info-bar-hidden');
+ },
- set visible(visible) {
- if (visible)
- this.classList.remove('info-bar-hidden');
- else
- this.classList.add('info-bar-hidden');
- },
+ set visible(visible) {
+ if (visible)
+ Polymer.dom(this).classList.remove('info-bar-hidden');
+ else
+ Polymer.dom(this).classList.add('info-bar-hidden');
+ },
- removeAllButtons: function() {
- this.buttonsEl_.textContent = '';
- },
+ removeAllButtons: function() {
+ Polymer.dom(this.buttonsEl_).textContent = '';
+ },
- addButton: function(text, clickCallback) {
- var button = document.createElement('button');
- button.textContent = text;
- button.addEventListener('click', clickCallback);
- this.buttonsEl_.appendChild(button);
- return button;
- }
- });
- </script>
-</polymer-element>
+ addButton: function(text, clickCallback) {
+ var button = document.createElement('button');
+ Polymer.dom(button).textContent = text;
+ button.addEventListener('click', clickCallback);
+ Polymer.dom(this.buttonsEl_).appendChild(button);
+ return button;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html
index 4d44a1b1099..af82995de01 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html
@@ -6,7 +6,7 @@ found in the LICENSE file.
-->
<link rel='import' href='/tracing/ui/base/info_bar.html'>
-<polymer-element name='tr-ui-b-info-bar-group' is='HTMLUnknownElement'>
+<dom-module id='tr-ui-b-info-bar-group'>
<template>
<style>
:host {
@@ -17,49 +17,50 @@ found in the LICENSE file.
</style>
<div id='messages'></div>
</template>
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-b-info-bar-group',
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- this.messages_ = [];
- },
+ ready: function() {
+ this.messages_ = [];
+ },
- clearMessages: function() {
- this.messages_ = [];
- this.updateContents_();
- },
+ clearMessages: function() {
+ this.messages_ = [];
+ this.updateContents_();
+ },
- addMessage: function(text, opt_buttons) {
- opt_buttons = opt_buttons || [];
- for (var i = 0; i < opt_buttons.length; i++) {
- if (opt_buttons[i].buttonText === undefined)
- throw new Error('buttonText must be provided');
- if (opt_buttons[i].onClick === undefined)
- throw new Error('onClick must be provided');
- }
-
- this.messages_.push({
- text: text,
- buttons: opt_buttons || []
- });
- this.updateContents_();
- },
+ addMessage: function(text, opt_buttons) {
+ opt_buttons = opt_buttons || [];
+ for (var i = 0; i < opt_buttons.length; i++) {
+ if (opt_buttons[i].buttonText === undefined)
+ throw new Error('buttonText must be provided');
+ if (opt_buttons[i].onClick === undefined)
+ throw new Error('onClick must be provided');
+ }
- updateContents_: function() {
- this.$.messages.textContent = '';
- this.messages_.forEach(function(message) {
- var bar = document.createElement('tr-ui-b-info-bar');
- bar.message = message.text;
- bar.visible = true;
+ this.messages_.push({
+ text: text,
+ buttons: opt_buttons || []
+ });
+ this.updateContents_();
+ },
- message.buttons.forEach(function(button) {
- bar.addButton(button.buttonText, button.onClick);
- }, this);
+ updateContents_: function() {
+ Polymer.dom(this.$.messages).textContent = '';
+ this.messages_.forEach(function(message) {
+ var bar = document.createElement('tr-ui-b-info-bar');
+ bar.message = message.text;
+ bar.visible = true;
- this.$.messages.appendChild(bar);
+ message.buttons.forEach(function(button) {
+ bar.addButton(button.buttonText, button.onClick);
}, this);
- }
- });
- </script>
-</polymer-element>
+
+ Polymer.dom(this.$.messages).appendChild(bar);
+ }, this);
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html
index ba431695242..00acef33a19 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html
@@ -25,11 +25,11 @@ tr.exportTo('tr.ui.b', function() {
decorate: function() {
ChartBase2DBrushX.prototype.decorate.call(this);
- this.classList.add('line-chart');
+ Polymer.dom(this).classList.add('line-chart');
},
isDatumFieldSeries_: function(fieldName) {
- return fieldName != 'x';
+ return fieldName !== 'x';
},
getXForDatum_: function(datum, index) {
@@ -39,13 +39,14 @@ tr.exportTo('tr.ui.b', function() {
updateDataContents_: function(dataSel) {
dataSel.selectAll('*').remove();
var dataBySeriesKey = this.getDataBySeriesKey_();
- var pathsSel = dataSel.selectAll('path').data(this.seriesKeys_);
+ var seriesKeys = [...this.seriesByKey_.keys()];
+ var pathsSel = dataSel.selectAll('path').data(seriesKeys);
pathsSel.enter()
.append('path')
.attr('class', 'line')
.style('stroke', function(key) {
- return tr.ui.b.getColorOfKey(key);
- })
+ return this.getDataSeries(key).color;
+ }.bind(this))
.attr('d', function(key) {
var line = d3.svg.line()
.x(function(d) { return this.xScale_(d.x); }.bind(this))
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html
index 5a6cc13b754..eee61c646f8 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html
@@ -148,7 +148,7 @@ tr.b.unittest.testSuite(function() {
updateBrushedRange();
});
chart.addEventListener('item-mousemove', function(e) {
- if (e.button == undefined)
+ if (e.button === undefined)
return;
curMouseIndex = e.index;
updateBrushedRange();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html
index 3d1d8260954..2898344a87e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html
@@ -24,7 +24,7 @@ tr.exportTo('tr.ui.b', function() {
*/
var ListAndAssociatedView = tr.ui.b.define('x-list-and-associated-view');
ListAndAssociatedView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.list_ = undefined;
@@ -35,8 +35,8 @@ tr.exportTo('tr.ui.b', function() {
this.listView_.addEventListener('selection-changed',
this.onSelectionChanged_.bind(this));
this.placeholder_ = document.createElement('div');
- this.appendChild(this.listView_);
- this.appendChild(this.placeholder_);
+ Polymer.dom(this).appendChild(this.listView_);
+ Polymer.dom(this).appendChild(this.placeholder_);
},
get listView() {
@@ -94,19 +94,19 @@ tr.exportTo('tr.ui.b', function() {
var itemEl;
if (i >= this.listView_.children.length) {
itemEl = document.createElement('div');
- this.listView_.appendChild(itemEl);
+ Polymer.dom(this.listView_).appendChild(itemEl);
} else {
itemEl = this.listView_.children[i];
}
itemEl.item = this.list_[i];
var getter = this.list_[i].__lookupGetter__(this.listProperty_);
if (getter)
- itemEl.textContent = getter.call(this.list_[i]);
+ Polymer.dom(itemEl).textContent = getter.call(this.list_[i]);
else
- itemEl.textContent = this.list_[i][this.listProperty_];
+ Polymer.dom(itemEl).textContent = this.list_[i][this.listProperty_];
}
- if (this.children[1] == this.placeholder_) {
+ if (this.children[1] === this.placeholder_) {
this.replaceChild(this.view_,
this.children[1]);
}
@@ -119,7 +119,7 @@ tr.exportTo('tr.ui.b', function() {
var setter = this.view_.__lookupSetter__(this.viewProperty_);
if (!setter) {
var prop = this.viewProperty_;
- setter = function(value) { this[prop] = value; }
+ setter = function(value) { this[prop] = value; };
}
if (this.listView_.selectedElement) {
setter.call(this.view_,
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html
index f35a8b26861..28d95ca64fc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html
@@ -43,7 +43,7 @@ tr.b.unittest.testSuite(function() {
var lavListView = lav.listView;
assert.equal(lavListView.children.length, 3);
- assert.equal(lavListView.children[0].textContent, '1');
+ assert.equal(Polymer.dom(lavListView.children[0]).textContent, '1');
});
test('listViewNamingWithProperty', function() {
@@ -72,7 +72,7 @@ tr.b.unittest.testSuite(function() {
var lavListView = lav.listView;
assert.equal(lavListView.children.length, 3);
- assert.equal(lavListView.children[0].textContent, '1');
+ assert.equal(Polymer.dom(lavListView.children[0]).textContent, '1');
});
test('selectionChangesView', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html
index c8279565620..c50c4637758 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html
@@ -31,7 +31,7 @@ tr.exportTo('tr.ui.b', function() {
decorate: function() {
tr.ui.b.ContainerThatDecoratesItsChildren.prototype.decorate.call(this);
- this.classList.add('x-list-view');
+ Polymer.dom(this).classList.add('x-list-view');
this.onItemClicked_ = this.onItemClicked_.bind(this);
this.onKeyDown_ = this.onKeyDown_.bind(this);
this.tabIndex = 0;
@@ -41,7 +41,7 @@ tr.exportTo('tr.ui.b', function() {
},
decorateChild_: function(item) {
- item.classList.add('list-item');
+ Polymer.dom(item).classList.add('list-item');
item.addEventListener('click', this.onItemClicked_, true);
var listView = this;
@@ -51,14 +51,15 @@ tr.exportTo('tr.ui.b', function() {
configurable: true,
set: function(value) {
var oldSelection = listView.selectedElement;
- if (oldSelection && oldSelection != this && value)
- listView.selectedElement.removeAttribute('selected');
+ if (oldSelection && oldSelection !== this && value)
+ Polymer.dom(listView.selectedElement).removeAttribute(
+ 'selected');
if (value)
- this.setAttribute('selected', 'selected');
+ Polymer.dom(this).setAttribute('selected', 'selected');
else
- this.removeAttribute('selected');
+ Polymer.dom(this).removeAttribute('selected');
var newSelection = listView.selectedElement;
- if (newSelection != oldSelection)
+ if (newSelection !== oldSelection)
tr.b.dispatchSimpleEvent(listView, 'selection-changed', false);
},
get: function() {
@@ -70,7 +71,7 @@ tr.exportTo('tr.ui.b', function() {
undecorateChild_: function(item) {
this.selectionChanged_ |= item.selected;
- item.classList.remove('list-item');
+ Polymer.dom(item).classList.remove('list-item');
item.removeEventListener('click', this.onItemClicked_);
delete item.selected;
},
@@ -85,7 +86,7 @@ tr.exportTo('tr.ui.b', function() {
},
get selectedElement() {
- var el = this.querySelector('.list-item[selected]');
+ var el = Polymer.dom(this).querySelector('.list-item[selected]');
if (!el)
return undefined;
return el;
@@ -98,14 +99,15 @@ tr.exportTo('tr.ui.b', function() {
return;
}
- if (el.parentElement != this)
+ if (el.parentElement !== this)
throw new Error(
'Can only select elements that are children of this list view');
el.selected = true;
},
getElementByIndex: function(index) {
- return this.querySelector('.list-item:nth-child(' + index + ')');
+ return Polymer.dom(this)
+ .querySelector('.list-item:nth-child(' + index + ')');
},
clear: function() {
@@ -118,12 +120,12 @@ tr.exportTo('tr.ui.b', function() {
onItemClicked_: function(e) {
var currentSelectedElement = this.selectedElement;
if (currentSelectedElement)
- currentSelectedElement.removeAttribute('selected');
+ Polymer.dom(currentSelectedElement).removeAttribute('selected');
var element = e.target;
- while (element.parentElement != this)
+ while (element.parentElement !== this)
element = element.parentElement;
if (element !== currentSelectedElement)
- element.setAttribute('selected', 'selected');
+ Polymer.dom(element).setAttribute('selected', 'selected');
tr.b.dispatchSimpleEvent(this, 'selection-changed', false);
},
@@ -131,16 +133,16 @@ tr.exportTo('tr.ui.b', function() {
if (this.selectedElement === undefined)
return;
- if (e.keyCode == 38) { // Up arrow.
- var prev = this.selectedElement.previousSibling;
+ if (e.keyCode === 38) { // Up arrow.
+ var prev = Polymer.dom(this.selectedElement).previousSibling;
if (prev) {
prev.selected = true;
tr.ui.b.scrollIntoViewIfNeeded(prev);
e.preventDefault();
return true;
}
- } else if (e.keyCode == 40) { // Down arrow.
- var next = this.selectedElement.nextSibling;
+ } else if (e.keyCode === 40) { // Down arrow.
+ var next = Polymer.dom(this.selectedElement).nextSibling;
if (next) {
next.selected = true;
tr.ui.b.scrollIntoViewIfNeeded(next);
@@ -152,8 +154,8 @@ tr.exportTo('tr.ui.b', function() {
addItem: function(textContent) {
var item = document.createElement('div');
- item.textContent = textContent;
- this.appendChild(item);
+ Polymer.dom(item).textContent = textContent;
+ Polymer.dom(this).appendChild(item);
return item;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html
index f31837e5c1b..f400a99656e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/ui/base/mouse_modes.html">
-<polymer-element name="tr-ui-b-mouse-mode-icon">
+<dom-module id='tr-ui-b-mouse-mode-icon'>
<template>
<style>
:host {
@@ -21,92 +21,95 @@ found in the LICENSE file.
}
</style>
</template>
- <script>
- 'use strict';
-
- Polymer({
- publish: {
- modeName: {
- value: undefined,
- reflect: true
- }
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-b-mouse-mode-icon',
+
+ properties: {
+ modeName: {
+ type: String,
+ reflectToAttribute: true,
+ observer: 'modeNameChanged'
},
-
- created: function() {
- this.active_ = false;
- this.acceleratorKey_ = undefined;
- },
-
- ready: function() {
- this.updateContents_();
- },
-
- get mode() {
- return tr.ui.b.MOUSE_SELECTOR_MODE[this.modeName];
- },
-
- set mode(mode) {
- var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode];
- var modeName = tr.b.findFirstKeyInDictMatching(
- tr.ui.b.MOUSE_SELECTOR_MODE,
- function(modeName, candidateMode) {
- return candidateMode === mode;
- });
- if (modeName === undefined)
- throw new Error('Unknown mode');
- this.modeName = modeName;
- },
-
- modeNameChanged: function() {
- this.updateContents_();
- },
-
- get active() {
- return this.active_;
- },
-
- set active(active) {
- this.active_ = !!active;
- if (this.active_)
- this.classList.add('active');
- else
- this.classList.remove('active');
- this.updateContents_();
- },
-
- get acceleratorKey() {
- return this.acceleratorKey_;
- },
-
- set acceleratorKey(acceleratorKey) {
- this.acceleratorKey_ = acceleratorKey;
- this.updateContents_();
- },
-
- updateContents_: function() {
- if (this.modeName === undefined)
- return;
-
- var mode = this.mode;
- if (mode === undefined)
- throw new Error('Invalid mode');
-
- var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode];
- if (!modeInfo)
- throw new Error('Invalid mode');
-
- var title = modeInfo.title;
- if (this.acceleratorKey_)
- title = title + ' (' + this.acceleratorKey_ + ')';
- this.title = title;
-
- var bp;
- if (this.active_)
- bp = modeInfo.activeBackgroundPosition;
- else
- bp = modeInfo.defaultBackgroundPosition;
- this.style.backgroundPosition = bp;
- }
- });
- </script>
-</polymer-element>
+ },
+
+ created: function() {
+ this.active_ = false;
+ this.acceleratorKey_ = undefined;
+ },
+
+ ready: function() {
+ this.updateContents_();
+ },
+
+ get mode() {
+ return tr.ui.b.MOUSE_SELECTOR_MODE[this.modeName];
+ },
+
+ set mode(mode) {
+ var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode];
+ var modeName = tr.b.findFirstKeyInDictMatching(
+ tr.ui.b.MOUSE_SELECTOR_MODE,
+ function(modeName, candidateMode) {
+ return candidateMode === mode;
+ });
+ if (modeName === undefined)
+ throw new Error('Unknown mode');
+ this.modeName = modeName;
+ },
+
+ modeNameChanged: function() {
+ this.updateContents_();
+ },
+
+ get active() {
+ return this.active_;
+ },
+
+ set active(active) {
+ this.active_ = !!active;
+ if (this.active_)
+ Polymer.dom(this).classList.add('active');
+ else
+ Polymer.dom(this).classList.remove('active');
+ this.updateContents_();
+ },
+
+ get acceleratorKey() {
+ return this.acceleratorKey_;
+ },
+
+ set acceleratorKey(acceleratorKey) {
+ this.acceleratorKey_ = acceleratorKey;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ if (this.modeName === undefined)
+ return;
+
+ var mode = this.mode;
+ if (mode === undefined)
+ throw new Error('Invalid mode');
+
+ var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode];
+ if (!modeInfo)
+ throw new Error('Invalid mode');
+
+ var title = modeInfo.title;
+ if (this.acceleratorKey_)
+ title = title + ' (' + this.acceleratorKey_ + ')';
+ this.title = title;
+
+ var bp;
+ if (this.active_)
+ bp = modeInfo.activeBackgroundPosition;
+ else
+ bp = modeInfo.defaultBackgroundPosition;
+ this.style.backgroundPosition = bp;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html
index 905a1bbcf0d..1be3baf48a8 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html
@@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() {
test('modeNameSetter', function() {
var icon = document.createElement('tr-ui-b-mouse-mode-icon');
- icon.setAttribute('modeName', 'SELECTION');
+ Polymer.dom(icon).setAttribute('mode-name', 'SELECTION');
this.addHTMLOutput(icon);
return Promise.resolve().then(function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html
index a8980d5ee8d..3570826ac99 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html
@@ -8,13 +8,13 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/event.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/ui/base/hotkey_controller.html">
+<link rel="import" href="/tracing/ui/base/mouse_mode_icon.html">
+<link rel="import" href="/tracing/ui/base/mouse_modes.html">
<link rel="import" href="/tracing/ui/base/mouse_tracker.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/base/utils.html">
-<link rel="import" href="/tracing/ui/base/mouse_modes.html">
-<link rel="import" href="/tracing/ui/base/mouse_mode_icon.html">
-<polymer-element name="tr-ui-b-mouse-mode-selector">
+<dom-module id='tr-ui-b-mouse-mode-selector'>
<template>
<style>
:host {
@@ -61,7 +61,7 @@ found in the LICENSE file.
<div class="buttons">
</div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -90,8 +90,8 @@ tr.exportTo('tr.ui.b', function() {
* It handles the user interaction and dispatches events for the various
* modes.
*/
- Polymer('tr-ui-b-mouse-mode-selector', {
- __proto__: HTMLDivElement.prototype,
+ Polymer({
+ is: 'tr-ui-b-mouse-mode-selector',
created: function() {
this.supportedModeMask_ = MOUSE_SELECTOR_MODE.ALL_MODES;
@@ -122,8 +122,9 @@ tr.exportTo('tr.ui.b', function() {
},
ready: function() {
- this.buttonsEl_ = this.shadowRoot.querySelector('.buttons');
- this.dragHandleEl_ = this.shadowRoot.querySelector('.drag-handle');
+ this.buttonsEl_ = Polymer.dom(this.root).querySelector('.buttons');
+ this.dragHandleEl_ = Polymer.dom(this.root).querySelector(
+ '.drag-handle');
this.supportedModeMask = MOUSE_SELECTOR_MODE.ALL_MODES;
this.dragHandleEl_.addEventListener('mousedown',
@@ -210,9 +211,9 @@ tr.exportTo('tr.ui.b', function() {
}
this.supportedModeMask_ = supportedModeMask;
- this.buttonsEl_.textContent = '';
+ Polymer.dom(this.buttonsEl_).textContent = '';
for (var modeName in MOUSE_SELECTOR_MODE) {
- if (modeName == 'ALL_MODES')
+ if (modeName === 'ALL_MODES')
continue;
var mode = MOUSE_SELECTOR_MODE[modeName];
if ((this.supportedModeMask_ & mode) === 0)
@@ -220,9 +221,9 @@ tr.exportTo('tr.ui.b', function() {
var button = document.createElement('tr-ui-b-mouse-mode-icon');
button.mode = mode;
- button.classList.add('tool-button');
+ Polymer.dom(button).classList.add('tool-button');
- this.buttonsEl_.appendChild(button);
+ Polymer.dom(this.buttonsEl_).appendChild(button);
}
},
@@ -403,7 +404,7 @@ tr.exportTo('tr.ui.b', function() {
onKeyDown_: function(e) {
// Keys dispatched to INPUT elements still bubble, even when they're
// handled. So, skip any events that targeted the input element.
- if (e.path[0].tagName == 'INPUT')
+ if (e.path[0].tagName === 'INPUT')
return;
if (e.keyCode === ' '.charCodeAt(0))
@@ -414,7 +415,7 @@ tr.exportTo('tr.ui.b', function() {
onKeyUp_: function(e) {
// Keys dispatched to INPUT elements still bubble, even when they're
// handled. So, skip any events that targeted the input element.
- if (e.path[0].tagName == 'INPUT')
+ if (e.path[0].tagName === 'INPUT')
return;
if (e.keyCode === ' '.charCodeAt(0))
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html
index dcfdbaa17c6..4a6503e4f44 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html
@@ -5,43 +5,36 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/ui/base/column_chart.html">
<link rel="import" href="/tracing/ui/base/d3.html">
-<link rel="import" href="/tracing/ui/base/bar_chart.html">
<script>
'use strict';
tr.exportTo('tr.ui.b', function() {
- var BarChart = tr.ui.b.BarChart;
+ var ColumnChart = tr.ui.b.ColumnChart;
// @constructor
- var NameBarChart = tr.ui.b.define('name-bar-chart', BarChart);
+ var NameBarChart = tr.ui.b.define('name-bar-chart', ColumnChart);
NameBarChart.prototype = {
- __proto__: BarChart.prototype,
+ __proto__: ColumnChart.prototype,
decorate: function() {
- BarChart.prototype.decorate.call(this);
- this.classList.remove('bar-chart');
- this.classList.add('name-bar-chart');
- this.bottomMargin_ = 40;
+ ColumnChart.prototype.decorate.call(this);
+ Polymer.dom(this).classList.remove('bar-chart');
+ Polymer.dom(this).classList.add('name-bar-chart');
},
isDatumFieldSeries_: function(fieldName) {
- return fieldName != 'x';
+ return fieldName !== 'x';
},
getXForDatum_: function(datum, index) {
return index;
},
- getMargin_: function() {
- var margin = BarChart.prototype.getMargin_.call(this);
- margin.bottom = this.bottomMargin_;
- return margin;
- },
-
updateXAxis_: function(xAxis) {
xAxis.selectAll('*').remove();
var y = this.chartAreaSize.height + 10;
@@ -68,8 +61,10 @@ tr.exportTo('tr.ui.b', function() {
// If the nameTexts extend past the bottom of the chart, then increase
// this.bottomMargin_ and re-render.
- var bottomMargin = this.bottomMargin_;
- window.requestAnimationFrame(function() {
+ // TODO(benjhayden): Refactor with the code that is very similar to this
+ // in chart_base_2d.
+ var bottomMargin = this.margin.bottom;
+ tr.b.requestAnimationFrame(function() {
nameTexts[0].forEach(function(t) {
var box = t.getBBox();
// When the text is rotated, its height is the hypotenuse
@@ -77,14 +72,15 @@ tr.exportTo('tr.ui.b', function() {
// triangle W. The bottomMargin must be equal to a side of H plus a
// side of W.
var h = Math.cos(Math.PI / 4) * (box.height + box.width);
- bottomMargin = Math.max(this.bottomMargin_, h);
+ bottomMargin = Math.max(bottomMargin, h);
}, this);
- if (Math.round(bottomMargin) !== Math.round(this.bottomMargin_)) {
- this.bottomMargin_ = bottomMargin;
+ bottomMargin = parseInt(Math.ceil(bottomMargin));
+ if (bottomMargin > this.margin.bottom) {
+ this.margin.bottom = bottomMargin;
this.updateContents_();
}
- }.bind(this));
+ }, this);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html
index df8e13ceddf..911c68afbee 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/base/event.html">
+<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/base/utils.html">
@@ -142,7 +142,7 @@ tr.exportTo('tr.ui.b', function() {
* Initializes the overlay element.
*/
decorate: function() {
- this.classList.add('overlay');
+ Polymer.dom(this).classList.add('overlay');
this.parentEl_ = this.ownerDocument.body;
@@ -162,30 +162,33 @@ tr.exportTo('tr.ui.b', function() {
var createShadowRoot = this.createShadowRoot ||
this.webkitCreateShadowRoot;
this.shadow_ = createShadowRoot.call(this);
- this.shadow_.appendChild(tr.ui.b.instantiateTemplate('#overlay-template',
- THIS_DOC));
+ Polymer.dom(this.shadow_).appendChild(
+ tr.ui.b.instantiateTemplate('#overlay-template', THIS_DOC));
- this.closeBtn_ = this.shadow_.querySelector('close-button');
+ this.closeBtn_ = Polymer.dom(this.shadow_).querySelector('close-button');
this.closeBtn_.addEventListener('click', this.onClose_);
- this.shadow_
+ Polymer.dom(this.shadow_)
.querySelector('overlay-frame')
.addEventListener('click', this.onClick_);
this.observer_ = new WebKitMutationObserver(
this.didButtonBarMutate_.bind(this));
- this.observer_.observe(this.shadow_.querySelector('button-bar'),
- { childList: true });
+ this.observer_.observe(
+ Polymer.dom(this.shadow_).querySelector('button-bar'),
+ { childList: true });
// title is a variable on regular HTMLElements. However, we want to
// use it for something more useful.
Object.defineProperty(
this, 'title', {
get: function() {
- return this.shadow_.querySelector('title').textContent;
+ return Polymer.dom(Polymer.dom(this.shadow_)
+ .querySelector('title')).textContent;
},
set: function(title) {
- this.shadow_.querySelector('title').textContent = title;
+ Polymer.dom(Polymer.dom(this.shadow_).querySelector('title'))
+ .textContent = title;
}
});
},
@@ -197,7 +200,7 @@ tr.exportTo('tr.ui.b', function() {
},
get buttons() {
- return this.shadow_.querySelector('button-bar');
+ return Polymer.dom(this.shadow_).querySelector('button-bar');
},
get visible() {
@@ -218,11 +221,12 @@ tr.exportTo('tr.ui.b', function() {
},
show_: function() {
- this.parentEl_.appendChild(this);
+ Polymer.dom(this.parentEl_).appendChild(this);
if (this.userCanClose_) {
this.addEventListener('keydown', this.onKeyDown_.bind(this));
this.addEventListener('click', this.onDocumentClick_.bind(this));
+ this.closeBtn_.addEventListener('click', this.onClose_);
}
this.parentEl_.addEventListener('focusin', this.onFocusIn_);
@@ -231,7 +235,8 @@ tr.exportTo('tr.ui.b', function() {
// Focus the first thing we find that makes sense. (Skip the close button
// as it doesn't make sense as the first thing to focus.)
var focusEl = undefined;
- var elList = this.querySelectorAll('button, input, list, select, a');
+ var elList =
+ Polymer.dom(this).querySelectorAll('button, input, list, select, a');
if (elList.length > 0) {
if (elList[0] === this.closeBtn_) {
if (elList.length > 1)
@@ -246,7 +251,7 @@ tr.exportTo('tr.ui.b', function() {
},
hide_: function() {
- this.parentEl_.removeChild(this);
+ Polymer.dom(this.parentEl_).removeChild(this);
this.parentEl_.removeEventListener('focusin', this.onFocusIn_);
@@ -259,7 +264,7 @@ tr.exportTo('tr.ui.b', function() {
onClose_: function(e) {
this.visible = false;
- if ((e.type != 'keydown') ||
+ if ((e.type !== 'keydown') ||
(e.type === 'keydown' && e.keyCode === 27))
e.stopPropagation();
e.preventDefault();
@@ -277,10 +282,13 @@ tr.exportTo('tr.ui.b', function() {
didButtonBarMutate_: function(e) {
var hasButtons = this.buttons.children.length > 0;
- if (hasButtons)
- this.shadow_.querySelector('button-bar').style.display = undefined;
- else
- this.shadow_.querySelector('button-bar').style.display = 'none';
+ if (hasButtons) {
+ Polymer.dom(this.shadow_).querySelector('button-bar').style.display =
+ undefined;
+ } else {
+ Polymer.dom(this.shadow_).querySelector('button-bar').style.display =
+ 'none';
+ }
},
onKeyDown_: function(e) {
@@ -313,25 +321,25 @@ tr.exportTo('tr.ui.b', function() {
Overlay.showError = function(msg, opt_err) {
var o = new Overlay();
o.title = 'Error';
- o.textContent = msg;
+ Polymer.dom(o).textContent = msg;
if (opt_err) {
var e = tr.b.normalizeException(opt_err);
var stackDiv = document.createElement('pre');
- stackDiv.textContent = e.stack;
+ Polymer.dom(stackDiv).textContent = e.stack;
stackDiv.style.paddingLeft = '8px';
stackDiv.style.margin = 0;
- o.appendChild(stackDiv);
+ Polymer.dom(o).appendChild(stackDiv);
}
var b = document.createElement('button');
- b.textContent = 'OK';
+ Polymer.dom(b).textContent = 'OK';
b.addEventListener('click', function() {
o.visible = false;
});
- o.buttons.appendChild(b);
+ Polymer.dom(o.buttons).appendChild(b);
o.visible = true;
return o;
- }
+ };
return {
Overlay: Overlay
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html
index d1d1b31e8e3..caf03dab11f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html
@@ -4,15 +4,15 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/overlay.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
function addShowButtonForDialog(dlg) {
var btn = document.createElement('button');
- btn.textContent = 'Launch Overlay';
+ Polymer.dom(btn).textContent = 'Launch Overlay';
btn.addEventListener('click', function(e) {
dlg.visible = true;
e.stopPropagation();
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
function makeButton(title) {
var btn = document.createElement('button');
- btn.textContent = title;
+ Polymer.dom(btn).textContent = title;
return btn;
}
@@ -37,31 +37,31 @@ tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var dlg = new tr.ui.b.Overlay();
- dlg.classList.add('example-overlay');
+ Polymer.dom(dlg).classList.add('example-overlay');
dlg.title = 'ExampleOverlay';
- dlg.innerHTML = 'hello';
- dlg.buttons.appendChild(makeButton('i am a button'));
- dlg.buttons.appendChild(makeCloseButton(dlg));
- dlg.buttons.appendChild(tr.ui.b.createSpan(
+ Polymer.dom(dlg).innerHTML = 'hello';
+ Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button'));
+ Polymer.dom(dlg.buttons).appendChild(makeCloseButton(dlg));
+ Polymer.dom(dlg.buttons).appendChild(tr.ui.b.createSpan(
{textContent: 'i am a span'}));
addShowButtonForDialog.call(this, dlg);
});
test('instantiate_noButtons', function() {
var dlg = new tr.ui.b.Overlay();
- dlg.classList.add('example-overlay');
+ Polymer.dom(dlg).classList.add('example-overlay');
dlg.title = 'ExampleOverlay';
- dlg.innerHTML = 'hello';
+ Polymer.dom(dlg).innerHTML = 'hello';
addShowButtonForDialog.call(this, dlg);
});
test('instantiate_disableUserClose', function() {
var dlg = new tr.ui.b.Overlay();
- dlg.classList.add('example-overlay');
+ Polymer.dom(dlg).classList.add('example-overlay');
dlg.userCanClose = false;
dlg.title = 'Unclosable';
- dlg.innerHTML = 'This has no close X button.';
- dlg.buttons.appendChild(makeCloseButton(dlg));
+ Polymer.dom(dlg).innerHTML = 'This has no close X button.';
+ Polymer.dom(dlg.buttons).appendChild(makeCloseButton(dlg));
addShowButtonForDialog.call(this, dlg);
});
@@ -70,16 +70,16 @@ tr.b.unittest.testSuite(function() {
dlg.title = 'TallContent';
var contentEl = document.createElement('div');
contentEl.style.overflowY = 'auto';
- dlg.appendChild(contentEl);
+ Polymer.dom(dlg).appendChild(contentEl);
for (var i = 0; i < 1000; i++) {
var el = document.createElement('div');
- el.textContent = 'line ' + i;
- contentEl.appendChild(el);
+ Polymer.dom(el).textContent = 'line ' + i;
+ Polymer.dom(contentEl).appendChild(el);
}
- dlg.buttons.appendChild(makeButton('i am a button'));
+ Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button'));
addShowButtonForDialog.call(this, dlg);
});
@@ -89,11 +89,11 @@ tr.b.unittest.testSuite(function() {
for (var i = 0; i < 100; i++) {
var el = document.createElement('div');
el.style.webkitFlex = '1 0 auto';
- el.textContent = 'line ' + i;
- dlg.appendChild(el);
+ Polymer.dom(el).textContent = 'line ' + i;
+ Polymer.dom(dlg).appendChild(el);
}
- dlg.buttons.appendChild(makeButton('i am a button'));
+ Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button'));
addShowButtonForDialog.call(this, dlg);
});
@@ -101,7 +101,7 @@ tr.b.unittest.testSuite(function() {
var dlg = new tr.ui.b.Overlay();
dlg.title = 'Test closeclick event';
var closeBtn = makeCloseButton(dlg);
- dlg.buttons.appendChild(closeBtn);
+ Polymer.dom(dlg.buttons).appendChild(closeBtn);
var closeClicked = false;
dlg.addEventListener('closeclick', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html
index 5edfd795219..36418c41473 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html
@@ -4,10 +4,11 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/ui/base/chart_base.html">
<link rel="import" href="/tracing/ui/base/d3.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<link rel="import" href="/tracing/ui/base/chart_base.html">
<link rel="stylesheet" href="/tracing/ui/base/pie_chart.css">
<script>
@@ -15,7 +16,6 @@ found in the LICENSE file.
tr.exportTo('tr.ui.b', function() {
var ChartBase = tr.ui.b.ChartBase;
- var getColorOfKey = tr.ui.b.getColorOfKey;
var MIN_RADIUS = 100;
@@ -29,10 +29,9 @@ tr.exportTo('tr.ui.b', function() {
decorate: function() {
ChartBase.prototype.decorate.call(this);
- this.classList.add('pie-chart');
+ Polymer.dom(this).classList.add('pie-chart');
this.data_ = undefined;
- this.seriesKeys_ = undefined;
var chartAreaSel = d3.select(this.chartAreaElement);
var pieGroupSel = chartAreaSel.append('g')
@@ -54,6 +53,9 @@ tr.exportTo('tr.ui.b', function() {
return this.data_;
},
+ get titleMarginPx() {
+ return 40;
+ },
/**
* @param {Array} data Data for the chart, where each element in the array
@@ -64,30 +66,21 @@ tr.exportTo('tr.ui.b', function() {
// Figure out the label values in the data set. E.g. from
// [{label: 'a', ...}, {label: 'b', ...}]
// we would commpute ['a', 'y']. These become the series keys.
- var seriesKeys = [];
+ // Don't clear seriesByKey_; the caller might have put state in it using
+ // getDataSeries() before setting data.
var seenSeriesKeys = {};
data.forEach(function(d) {
var k = d.label;
if (seenSeriesKeys[k])
throw new Error('Label ' + k + ' has been used already');
- seriesKeys.push(k);
+ this.getDataSeries(k);
seenSeriesKeys[k] = true;
}, this);
- this.seriesKeys_ = seriesKeys;
- } else {
- this.seriesKeys_ = undefined;
}
this.data_ = data;
this.updateContents_();
},
- get margin() {
- var margin = {top: 0, right: 0, bottom: 0, left: 0};
- if (this.chartTitle_)
- margin.top += 40;
- return margin;
- },
-
getMinSize: function() {
this.updateContents_();
@@ -98,14 +91,14 @@ tr.exportTo('tr.ui.b', function() {
labelSel.each(function(l) {
var r = this.getBoundingClientRect();
maxLabelWidth = Math.max(maxLabelWidth, r.width + 32);
- if (this.style.textAnchor == 'end') {
+ if (this.style.textAnchor === 'end') {
leftTextHeightSum += r.height;
} else {
rightTextHeightSum += r.height;
}
});
- var titleWidth = this.querySelector(
+ var titleWidth = Polymer.dom(this).querySelector(
'#title').getBoundingClientRect().width;
var margin = this.margin;
var marginWidth = margin.left + margin.right;
@@ -119,12 +112,6 @@ tr.exportTo('tr.ui.b', function() {
};
},
-
- getLegendKeys_: function() {
- // This class creates its own legend, instead of using ChartBase.
- return undefined;
- },
-
updateScales_: function(width, height) {
if (this.data_ === undefined)
return;
@@ -178,9 +165,10 @@ tr.exportTo('tr.ui.b', function() {
.attr('class', 'arc')
.attr('fill', function(d, i) {
var origData = this.data_[i];
- var highlighted = (origData.label ===
- this.currentHighlightedLegendKey);
- return getColorOfKey(origData.label, highlighted);
+ var dataSeries = this.getDataSeries(origData.label);
+ if (origData.label === this.currentHighlightedLegendKey)
+ return dataSeries.highlightedColor;
+ return dataSeries.color;
}.bind(this))
.attr('d', pathsArc)
.on('click', function(d, i) {
@@ -208,6 +196,14 @@ tr.exportTo('tr.ui.b', function() {
})
.attr('dy', '.35em')
.style('text-anchor', 'middle')
+ .on('mouseenter', function(d, i) {
+ var origData = this.data_[i];
+ this.pushTempHighlightedLegendKey(origData.label);
+ }.bind(this))
+ .on('mouseleave', function(d, i) {
+ var origData = this.data_[i];
+ this.popTempHighlightedLegendKey(origData.label);
+ }.bind(this))
.text(function(d, i) {
var origData = this.data_[i];
if (origData.valueText === undefined)
@@ -263,9 +259,11 @@ tr.exportTo('tr.ui.b', function() {
var that = this;
pathsGroupSel.selectAll('.arc').each(function(d, i) {
var origData = that.data_[i];
- var highlighted = origData.label == that.currentHighlightedLegendKey;
- var color = getColorOfKey(origData.label, highlighted);
- this.style.fill = color;
+ var dataSeries = that.getDataSeries(origData.label);
+ if (origData.label === that.currentHighlightedLegendKey)
+ this.style.fill = dataSeries.highlightedColor;
+ else
+ this.style.fill = dataSeries.color;
});
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html
index 7c0b35f5462..854c872055e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html
@@ -63,7 +63,7 @@ tr.b.unittest.testSuite(function() {
didGetClick = true;
});
- var arc0 = chart.querySelectorAll('.paths > path')[1];
+ var arc0 = Polymer.dom(chart).querySelectorAll('.paths > path')[1];
tr.b.dispatchSimpleEvent(arc0, 'click');
assert.isTrue(didGetClick);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html
new file mode 100644
index 00000000000..fc93631bb88
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<script>
+'use strict';
+
+if (!Polymer.Settings.useNativeShadow) {
+ tr.b.showPanic('Polymer error', 'base only works in shadow mode');
+}
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html
new file mode 100644
index 00000000000..8860b5befec
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<script>
+'use strict';
+
+// Force Polymer into native shadowDom mode
+if (window.Polymer)
+ throw new Error('Cannot proceed. Polymer already present.');
+window.Polymer = {};
+window.Polymer.dom = 'shadow';
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html
deleted file mode 100644
index b8c5e9d050d..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<link rel="import" href="/tracing/base/base.html">
-
-<script>
-'use strict';
-
-/**
- * @fileoverview Helper code for working with Polymer.
- */
-tr.exportTo('tr.ui.b', function() {
-
- function getPolymerElementNamed(tagName) {
- for (var i = 0; i < Polymer.elements.length; i++) {
- if (Polymer.elements[i].name === tagName)
- return Polymer.elements[i];
- }
- }
-
- function getPolymerElementsThatSubclass(tagName) {
- if (Polymer.waitingFor().length) {
- throw new Error('There are unresolved polymer elements. ' +
- 'Wait until Polymer.whenReady');
- }
-
- var baseElement;
- var elementNamesThatExtend = {};
- Polymer.elements.forEach(function(element) {
- if (element.name === tagName)
- baseElement = element;
-
- if (element.extends) {
- if (elementNamesThatExtend[element.extends] === undefined)
- elementNamesThatExtend[element.extends] = [];
- elementNamesThatExtend[element.extends].push(element.name);
- }
- });
-
- if (!baseElement)
- throw new Error(tagName + ' is not a polymer element');
-
- var allFoundSubElementNames = [baseElement.name];
- for (var i = 0; i < allFoundSubElementNames.length; i++) {
- var elementName = allFoundSubElementNames[i];
- allFoundSubElementNames.push.apply(
- allFoundSubElementNames, elementNamesThatExtend[elementName]);
- }
-
- // Remove the base element tag name from the list.
- allFoundSubElementNames.shift();
-
- return allFoundSubElementNames;
- }
-
- return {
- getPolymerElementNamed: getPolymerElementNamed,
- getPolymerElementsThatSubclass: getPolymerElementsThatSubclass
- };
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html
deleted file mode 100644
index 698ec0cdc17..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2016 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/ui/base/polymer_utils.html">
-
-<!--
-The Polymer elements defined in this file form the following class hierarchy:
-
- A (common superclass)
- / \
- B C
- / \
- D E
- / \
- F G
--->
-
-<polymer-element name="polymer-utils-test-element-a" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-b"
- extends="polymer-utils-test-element-a" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-c"
- extends="polymer-utils-test-element-a" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-d"
- extends="polymer-utils-test-element-c" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-e"
- extends="polymer-utils-test-element-c" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-f"
- extends="polymer-utils-test-element-d" noscript>
-</polymer-element>
-
-<polymer-element name="polymer-utils-test-element-g"
- extends="polymer-utils-test-element-d" noscript>
-</polymer-element>
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- test('getPolymerElementsThatSubclass', function() {
- function checkSubclasses(classNameSuffix, subclassNameSuffixes) {
- var className = 'polymer-utils-test-element-' + classNameSuffix;
- var subclassNames = subclassNameSuffixes.map(
- function(subclassNameSuffix) {
- return 'polymer-utils-test-element-' + subclassNameSuffix;
- });
- assert.sameMembers(
- tr.ui.b.getPolymerElementsThatSubclass(className), subclassNames);
- }
-
- checkSubclasses('a', ['b', 'c', 'd', 'e', 'f', 'g']);
- checkSubclasses('b', []);
- checkSubclasses('c', ['d', 'e', 'f', 'g']);
- checkSubclasses('d', ['f', 'g']);
- checkSubclasses('e', []);
- checkSubclasses('f', []);
- checkSubclasses('g', []);
- });
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html
index 7c181a61857..bb43d8bbce7 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html
@@ -85,40 +85,40 @@ tr.exportTo('tr.ui.b', function() {
// Care of bckenney@ via
// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
function drawTexturedTriangle(ctx, img, p0, p1, p2, t0, t1, t2) {
- var tmp_p0 = [p0[0], p0[1]];
- var tmp_p1 = [p1[0], p1[1]];
- var tmp_p2 = [p2[0], p2[1]];
- var tmp_t0 = [t0[0], t0[1]];
- var tmp_t1 = [t1[0], t1[1]];
- var tmp_t2 = [t2[0], t2[1]];
+ var tmpP0 = [p0[0], p0[1]];
+ var tmpP1 = [p1[0], p1[1]];
+ var tmpP2 = [p2[0], p2[1]];
+ var tmpT0 = [t0[0], t0[1]];
+ var tmpT1 = [t1[0], t1[1]];
+ var tmpT2 = [t2[0], t2[1]];
ctx.beginPath();
- ctx.moveTo(tmp_p0[0], tmp_p0[1]);
- ctx.lineTo(tmp_p1[0], tmp_p1[1]);
- ctx.lineTo(tmp_p2[0], tmp_p2[1]);
+ ctx.moveTo(tmpP0[0], tmpP0[1]);
+ ctx.lineTo(tmpP1[0], tmpP1[1]);
+ ctx.lineTo(tmpP2[0], tmpP2[1]);
ctx.closePath();
- tmp_p1[0] -= tmp_p0[0];
- tmp_p1[1] -= tmp_p0[1];
- tmp_p2[0] -= tmp_p0[0];
- tmp_p2[1] -= tmp_p0[1];
+ tmpP1[0] -= tmpP0[0];
+ tmpP1[1] -= tmpP0[1];
+ tmpP2[0] -= tmpP0[0];
+ tmpP2[1] -= tmpP0[1];
- tmp_t1[0] -= tmp_t0[0];
- tmp_t1[1] -= tmp_t0[1];
- tmp_t2[0] -= tmp_t0[0];
- tmp_t2[1] -= tmp_t0[1];
+ tmpT1[0] -= tmpT0[0];
+ tmpT1[1] -= tmpT0[1];
+ tmpT2[0] -= tmpT0[0];
+ tmpT2[1] -= tmpT0[1];
- var det = 1 / (tmp_t1[0] * tmp_t2[1] - tmp_t2[0] * tmp_t1[1]),
+ var det = 1 / (tmpT1[0] * tmpT2[1] - tmpT2[0] * tmpT1[1]),
// linear transformation
- a = (tmp_t2[1] * tmp_p1[0] - tmp_t1[1] * tmp_p2[0]) * det,
- b = (tmp_t2[1] * tmp_p1[1] - tmp_t1[1] * tmp_p2[1]) * det,
- c = (tmp_t1[0] * tmp_p2[0] - tmp_t2[0] * tmp_p1[0]) * det,
- d = (tmp_t1[0] * tmp_p2[1] - tmp_t2[0] * tmp_p1[1]) * det,
+ a = (tmpT2[1] * tmpP1[0] - tmpT1[1] * tmpP2[0]) * det,
+ b = (tmpT2[1] * tmpP1[1] - tmpT1[1] * tmpP2[1]) * det,
+ c = (tmpT1[0] * tmpP2[0] - tmpT2[0] * tmpP1[0]) * det,
+ d = (tmpT1[0] * tmpP2[1] - tmpT2[0] * tmpP1[1]) * det,
// translation
- e = tmp_p0[0] - a * tmp_t0[0] - c * tmp_t0[1],
- f = tmp_p0[1] - b * tmp_t0[0] - d * tmp_t0[1];
+ e = tmpP0[0] - a * tmpT0[0] - c * tmpT0[1],
+ f = tmpP0[1] - b * tmpT0[0] - d * tmpT0[1];
ctx.save();
ctx.transform(a, b, c, d, e, f);
@@ -128,8 +128,8 @@ tr.exportTo('tr.ui.b', function() {
}
function drawTriangleSub(
- ctx, img, p0, p1, p2, t0, t1, t2, opt_recursion_depth) {
- var depth = opt_recursion_depth || 0;
+ ctx, img, p0, p1, p2, t0, t1, t2, opt_recursionDepth) {
+ var depth = opt_recursionDepth || 0;
// We may subdivide if we are not at the limit of recursion.
var subdivisionIndex = 0;
@@ -232,16 +232,16 @@ tr.exportTo('tr.ui.b', function() {
}
// Created to avoid creating garbage when doing bulk transforms.
- var tmp_vec4 = vec4.create();
+ var tmpVec4 = vec4.create();
function transform(transformed, point, matrix, viewport) {
- vec4.set(tmp_vec4, point[0], point[1], 0, 1);
- vec4.transformMat4(tmp_vec4, tmp_vec4, matrix);
+ vec4.set(tmpVec4, point[0], point[1], 0, 1);
+ vec4.transformMat4(tmpVec4, tmpVec4, matrix);
- var w = tmp_vec4[3];
+ var w = tmpVec4[3];
if (w < 1e-6) w = 1e-6;
- transformed[0] = ((tmp_vec4[0] / w) + 1) * viewport.width / 2;
- transformed[1] = ((tmp_vec4[1] / w) + 1) * viewport.height / 2;
+ transformed[0] = ((tmpVec4[0] / w) + 1) * viewport.width / 2;
+ transformed[1] = ((tmpVec4[1] / w) + 1) * viewport.height / 2;
transformed[2] = w;
}
@@ -341,22 +341,22 @@ tr.exportTo('tr.ui.b', function() {
}
}
- var tmp_p1 = vec3.create();
- var tmp_p2 = vec3.create();
- var tmp_p3 = vec3.create();
- var tmp_p4 = vec3.create();
+ var tmpP1 = vec3.create();
+ var tmpP2 = vec3.create();
+ var tmpP3 = vec3.create();
+ var tmpP4 = vec3.create();
function transformAndProcessQuads(
matrix, viewport, quads, numPasses, handleQuadFunc, opt_arg1, opt_arg2) {
for (var passNumber = 0; passNumber < numPasses; passNumber++) {
for (var i = 0; i < quads.length; i++) {
var quad = quads[i];
- transform(tmp_p1, quad.p1, matrix, viewport);
- transform(tmp_p2, quad.p2, matrix, viewport);
- transform(tmp_p3, quad.p3, matrix, viewport);
- transform(tmp_p4, quad.p4, matrix, viewport);
+ transform(tmpP1, quad.p1, matrix, viewport);
+ transform(tmpP2, quad.p2, matrix, viewport);
+ transform(tmpP3, quad.p3, matrix, viewport);
+ transform(tmpP4, quad.p4, matrix, viewport);
handleQuadFunc(passNumber, quad,
- tmp_p1, tmp_p2, tmp_p3, tmp_p4,
+ tmpP1, tmpP2, tmpP3, tmpP4,
opt_arg1, opt_arg2);
}
}
@@ -368,23 +368,23 @@ tr.exportTo('tr.ui.b', function() {
var QuadStackView = tr.ui.b.define('quad-stack-view');
QuadStackView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.className = 'quad-stack-view';
var node = tr.ui.b.instantiateTemplate('#quad-stack-view-template',
THIS_DOC);
- this.appendChild(node);
+ Polymer.dom(this).appendChild(node);
this.updateHeaderVisibility_();
- this.canvas_ = this.querySelector('#canvas');
+ this.canvas_ = Polymer.dom(this).querySelector('#canvas');
this.chromeImages_ = {
- left: this.querySelector('#chrome-left'),
- mid: this.querySelector('#chrome-mid'),
- right: this.querySelector('#chrome-right')
+ left: Polymer.dom(this).querySelector('#chrome-left'),
+ mid: Polymer.dom(this).querySelector('#chrome-mid'),
+ right: Polymer.dom(this).querySelector('#chrome-right')
};
- var stackingDistanceSlider = this.querySelector(
+ var stackingDistanceSlider = Polymer.dom(this).querySelector(
'#stacking-distance-slider');
stackingDistanceSlider.value = tr.b.Settings.get(
'quadStackView.stackingDistance', 45);
@@ -408,17 +408,17 @@ tr.exportTo('tr.ui.b', function() {
updateHeaderVisibility_: function() {
if (this.headerText)
- this.querySelector('#header').style.display = '';
+ Polymer.dom(this).querySelector('#header').style.display = '';
else
- this.querySelector('#header').style.display = 'none';
+ Polymer.dom(this).querySelector('#header').style.display = 'none';
},
get headerText() {
- return this.querySelector('#header').textContent;
+ return Polymer.dom(this).querySelector('#header').textContent;
},
set headerText(headerText) {
- this.querySelector('#header').textContent = headerText;
+ Polymer.dom(this).querySelector('#header').textContent = headerText;
this.updateHeaderVisibility_();
},
@@ -430,7 +430,7 @@ tr.exportTo('tr.ui.b', function() {
},
get stackingDistance() {
- return this.querySelector('#stacking-distance-slider').value;
+ return Polymer.dom(this).querySelector('#stacking-distance-slider').value;
},
get mouseModeSelector() {
@@ -643,7 +643,7 @@ tr.exportTo('tr.ui.b', function() {
tr.ui.b.MOUSE_SELECTOR_MODE.ROTATE;
this.mouseModeSelector_.mode = tr.ui.b.MOUSE_SELECTOR_MODE.PANSCAN;
this.mouseModeSelector_.pos = {x: 0, y: 100};
- this.appendChild(this.mouseModeSelector_);
+ Polymer.dom(this).appendChild(this.mouseModeSelector_);
this.mouseModeSelector_.settingsKey =
'quadStackView.mouseModeSelector';
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html
index 85d204a9a30..ceb82527cad 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html
@@ -7,116 +7,137 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name='tr-ui-b-radio-picker'>
+<dom-module id='tr-ui-b-radio-picker'>
<template>
<style>
+ :host([vertical]) #container {
+ flex-direction: column;
+ }
+ :host(:not[vertical]) #container {
+ flex-direction: row;
+ }
#container {
display: flex;
- flex-direction: column;
+ }
+ #container > div {
+ padding-left: 1em;
+ padding-bottom: 0.5em;
}
</style>
+ <div id="container"></div>
+ </template>
+</dom-module>
+<script>
+'use strict';
- <div id="container">
- </div>
+Polymer({
+ is: 'tr-ui-b-radio-picker',
- </template>
+ created: function() {
+ this.needsInit_ = true;
+ this.settingsKey_ = undefined;
+ this.isReady_ = false;
+ this.radioButtons_ = undefined;
+ // Keeping track of which key is selected. This member should only be set
+ // set inside select() method to make sure that logical state & the UI
+ // state is consistent.
+ this.selectedKey_ = undefined;
+ },
+
+ ready: function() {
+ this.isReady_ = true;
+ this.maybeInit_();
+ this.maybeRenderRadioButtons_();
+ },
+
+ get vertical() {
+ return this.getAttribute('vertical');
+ },
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.needsInit_ = true;
- this.settingsKey_ = undefined;
- this.is_ready_ = false;
- this.radio_buttons_ = undefined;
- // Keeping track of which key is selected. This member should only be set
- // set inside select() method to make sure that logical state & the UI
- // state is consistent.
- this.selectedKey_ = undefined;
- },
-
- ready: function() {
- this.is_ready_ = true;
- this.maybeInit_();
- this.maybeRenderRadioButtons_();
- },
-
- get settingsKey() {
- return this.settingsKey_;
- },
-
- set settingsKey(settingsKey) {
- if (!this.needsInit_)
- throw new Error('Already initialized.');
- this.settingsKey_ = settingsKey;
- this.maybeInit_();
- },
-
- maybeInit_: function() {
- if (!this.needsInit_)
- return;
- if (this.settingsKey_ === undefined)
- return;
- this.needsInit_ = false;
- this.select(tr.b.Settings.get(this.settingsKey_));
- },
-
- set items(items) {
- this.radio_buttons_ = {};
- items.forEach(function(e) {
- if (e.key in this.radio_buttons_)
- throw new Error(e.key + ' already exists');
- var radio_button = document.createElement('div');
- var input = document.createElement('input');
- var label = document.createElement('div');
- input.type = 'radio';
- input.addEventListener('click', function() {
- this.select(e.key);
- }.bind(this));
- label.innerHTML = e.label;
- label.style.display = 'inline';
- radio_button.appendChild(input);
- radio_button.appendChild(label);
- this.radio_buttons_[e.key] = input;
+ set vertical(vertical) {
+ if (vertical)
+ this.setAttribute('vertical', true);
+ else
+ this.removeAttribute('vertical');
+ },
+
+ get settingsKey() {
+ return this.settingsKey_;
+ },
+
+ set settingsKey(settingsKey) {
+ if (!this.needsInit_)
+ throw new Error('Already initialized.');
+ this.settingsKey_ = settingsKey;
+ this.maybeInit_();
+ },
+
+ maybeInit_: function() {
+ if (!this.needsInit_)
+ return;
+ if (this.settingsKey_ === undefined)
+ return;
+ this.needsInit_ = false;
+ this.select(tr.b.Settings.get(this.settingsKey_));
+ },
+
+ set items(items) {
+ this.radioButtons_ = {};
+ items.forEach(function(e) {
+ if (e.key in this.radioButtons_)
+ throw new Error(e.key + ' already exists');
+ var radioButton = document.createElement('div');
+ var input = document.createElement('input');
+ var label = document.createElement('div');
+ input.type = 'radio';
+ input.addEventListener('click', function() {
+ this.select(e.key);
}.bind(this));
+ Polymer.dom(label).innerHTML = e.label;
+ label.style.display = 'inline';
+ Polymer.dom(radioButton).appendChild(input);
+ Polymer.dom(radioButton).appendChild(label);
+ this.radioButtons_[e.key] = input;
+ }.bind(this));
+
+ this.maybeInit_();
+ this.maybeRenderRadioButtons_();
+ },
- this.maybeInit_();
- this.maybeRenderRadioButtons_();
- },
-
- maybeRenderRadioButtons_: function() {
- if (!this.is_ready_)
- return;
- if (this.radio_buttons_ === undefined)
- return;
- for (var key in this.radio_buttons_)
- this.$.container.appendChild(this.radio_buttons_[key].parentElement);
- if (this.selectedKey_ !== undefined)
- this.select(this.selectedKey_);
- },
-
- select: function(key) {
- if (key === undefined)
- return;
- if (this.radio_buttons_ == undefined) {
- this.selectedKey_ = key;
- return;
- }
- if (!(key in this.radio_buttons_))
- throw new Error(key + ' does not exists');
- // Unselect the previous radio, update the key & select the new one.
- if (this.selectedKey_ !== undefined)
- this.radio_buttons_[this.selectedKey_].checked = false;
+ maybeRenderRadioButtons_: function() {
+ if (!this.isReady_)
+ return;
+ if (this.radioButtons_ === undefined)
+ return;
+ for (var key in this.radioButtons_)
+ Polymer.dom(this.$.container).appendChild(
+ this.radioButtons_[key].parentElement);
+ if (this.selectedKey_ !== undefined)
+ this.select(this.selectedKey_);
+ },
+
+ select: function(key) {
+ if (key === undefined || key === this.selectedKey_)
+ return;
+ if (this.radioButtons_ === undefined) {
this.selectedKey_ = key;
- tr.b.Settings.set(this.settingsKey_, this.selectedKey_);
- if (this.selectedKey_ !== undefined)
- this.radio_buttons_[this.selectedKey_].checked = true;
- },
-
- get selectedKey() {
- return this.selectedKey_;
- },
- });
- </script>
-</polymer-element>
+ return;
+ }
+ if (!(key in this.radioButtons_))
+ throw new Error(key + ' does not exists');
+ // Unselect the previous radio, update the key & select the new one.
+ if (this.selectedKey_ !== undefined)
+ this.radioButtons_[this.selectedKey_].checked = false;
+ this.selectedKey_ = key;
+ tr.b.Settings.set(this.settingsKey_, this.selectedKey_);
+ if (this.selectedKey_ !== undefined)
+ this.radioButtons_[this.selectedKey_].checked = true;
+
+ this.dispatchEvent(new tr.b.Event('change', false));
+ },
+
+ get selectedKey() {
+ return this.selectedKey_;
+ },
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html
index dea60cdd492..8d29c269796 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/radio_picker.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/radio_picker.html">
<script>
'use strict';
@@ -36,7 +36,7 @@ tr.b.unittest.testSuite(function() {
var rp = document.createElement('tr-ui-b-radio-picker');
rp.items = items;
rp.settingsKey = 'radio-picker-test-one';
- container1.appendChild(rp);
+ Polymer.dom(container1).appendChild(rp);
this.addHTMLOutput(container1);
assert.equal(rp.selectedKey, undefined);
rp.select('Toyota');
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
var rp2 = document.createElement('tr-ui-b-radio-picker');
rp2.items = items;
rp2.settingsKey = 'radio-picker-test-one';
- container2.appendChild(rp2);
+ Polymer.dom(container2).appendChild(rp2);
this.addHTMLOutput(container2);
assert.equal(rp2.selectedKey, 'Toyota');
@@ -65,7 +65,7 @@ tr.b.unittest.testSuite(function() {
var rp = document.createElement('tr-ui-b-radio-picker');
rp.settingsKey = 'radio-picker-test-two';
rp.items = items;
- container1.appendChild(rp);
+ Polymer.dom(container1).appendChild(rp);
this.addHTMLOutput(container1);
assert.equal(rp.selectedKey, undefined);
rp.select('Boeing');
@@ -76,14 +76,47 @@ tr.b.unittest.testSuite(function() {
container2.style.border = 'solid';
var rp2 = document.createElement('tr-ui-b-radio-picker');
rp2.settingsKey = 'radio-picker-test-two';
- container2.appendChild(rp2);
+ Polymer.dom(container2).appendChild(rp2);
this.addHTMLOutput(container2);
rp2.items = items;
assert.equal(rp2.selectedKey, 'Boeing');
});
+ test('changeEventFired', function() {
+ var items = [
+ {key: 'Toyota', label: 'I want to drive Toyota'},
+ {key: 'Boeing', label: 'I want to fly'},
+ {key: 'Submarine', label: 'I want to swim'}
+ ];
+ var rp = document.createElement('tr-ui-b-radio-picker');
+ rp.items = items;
+ this.addHTMLOutput(rp);
+ rp.select('Boeing');
+ assert.equal(rp.selectedKey, 'Boeing');
+ var fired = false;
+ rp.addEventListener('change', function(e) {
+ fired = true;
+ assert.equal('Toyota', e.target.selectedKey);
+ });
+ rp.select('Toyota');
+ assert.isTrue(fired);
+ });
-
+ test('verticalAttribute', function() {
+ var items = [
+ {key: 'Toyota', label: 'I want to drive Toyota'},
+ {key: 'Boeing', label: 'I want to fly'},
+ {key: 'Submarine', label: 'I want to swim'}
+ ];
+ var rp = document.createElement('tr-ui-b-radio-picker');
+ rp.items = items;
+ this.addHTMLOutput(rp);
+ assert.isNull(rp.getAttribute('vertical'));
+ rp.vertical = true;
+ assert.equal(rp.getAttribute('vertical'), 'true');
+ rp.vertical = false;
+ assert.isNull(rp.getAttribute('vertical'));
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html
index bbb696062bf..6eb63b79bc1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html
@@ -12,7 +12,7 @@ found in the LICENSE file.
<!--
@fileoverview A container that senses when its size changes.
-->
-<polymer-element name="tr-ui-b-resize-sensor">
+<dom-module id='tr-ui-b-resize-sensor'>
<template>
<style>
:host {
@@ -24,27 +24,28 @@ found in the LICENSE file.
<content></content>
</div>
</template>
+</dom-module>
+<script>
+'use strict';
+(function() {
+ Polymer({
+ is: 'tr-ui-b-resize-sensor',
- <script>
- 'use strict';
- (function() {
- Polymer({
- attached: function() {
- // ResizeSensor only works if it's rooted in a document when it's
- // created, so wait until the tr-ui-b-resize-sensor is attached to the
- // DOM before creating the ResizeSensor.
- this.sensor_ = new ResizeSensor(this.$.container,
- this.onResize_.bind(this));
- // ResizeSensor appends a div to this.$.container. That div must be a
- // direct sibling of <content>.
- // ResizeSensor's first argument must be a Node, so it cannot be
- // this.shadowRoot.
- },
+ attached: function() {
+ // ResizeSensor only works if it's rooted in a document when it's
+ // created, so wait until the tr-ui-b-resize-sensor is attached to the
+ // DOM before creating the ResizeSensor.
+ this.sensor_ = new ResizeSensor(this.$.container,
+ this.onResize_.bind(this));
+ // ResizeSensor appends a div to this.$.container. That div must be a
+ // direct sibling of <content>.
+ // ResizeSensor's first argument must be a Node, so it cannot be
+ // this.root.
+ },
- onResize_: function() {
- this.dispatchEvent(new tr.b.Event('resize', false, false));
- }
- });
- })();
- </script>
-</polymer-element>
+ onResize_: function() {
+ this.dispatchEvent(new tr.b.Event('resize', false, false));
+ }
+ });
+})();
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html
index fea1f71669b..aa4132bf54e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html
@@ -18,7 +18,7 @@ tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var sensor = document.createElement('tr-ui-b-resize-sensor');
- sensor.appendChild(document.createTextNode('hello'));
+ Polymer.dom(sensor).appendChild(document.createTextNode('hello'));
var resizeCount = 0;
function onResize(event) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html
index 5dffbe8da02..4996f69684b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html
@@ -31,7 +31,7 @@ tr.exportTo('tr.ui.b', function() {
decorate: function() {
ChartBase2D.prototype.decorate.call(this);
- this.classList.add('scatter-chart');
+ Polymer.dom(this).classList.add('scatter-chart');
this.brushedXRange_ = new tr.b.Range();
this.brushedYRange_ = new tr.b.Range();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html
index c8ecceb51cd..0818c83f91f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html
@@ -5,424 +5,265 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<polymer-element name="tr-ui-a-tab-view"
- constructor="TracingAnalysisTabView">
+<link rel="import" href="/tracing/base/base.html">
+
+<!--
+@fileoverview A view that allows the user to control which single tab is
+displayed.
+
+We follow a fairly standard web convention of backing our tabs with hidden radio
+buttons but visible radio button labels (the tabs themselves) which toggle the
+input element when clicked. Using hidden radio buttons makes sense, as both tabs
+and radio buttons are input elements that allow user selection through clicking
+and limit users to having one option selected at a time.
+-->
+<dom-module id='tr-ui-b-tab-view'>
<template>
<style>
:host {
display: flex;
- flex-flow: column nowrap;
- overflow: hidden;
- box-sizing: border-box;
+ flex-direction: column;
}
- tab-strip[tabs-hidden] {
- display: none;
+ #selection_description, #tabs {
+ font-size: 12px;
}
- tab-strip {
- background-color: rgb(236, 236, 236);
- border-bottom: 1px solid #8e8e8e;
- display: flex;
- flex: 0 0 auto;
- flex-flow: row;
- overflow-x: auto;
- padding: 0 10px 0 10px;
- font-size: 12px;
+ #selection_description {
+ display: inline-block;
+ font-weight: bold;
+ margin: 9px 0px 4px 20px;
}
- tab-button {
- display: block;
+ #tabs {
flex: 0 0 auto;
- padding: 4px 15px 1px 15px;
- margin-top: 2px;
+ border-top: 1px solid #8e8e8e;
+ border-bottom: 1px solid #8e8e8e;
+ background-color: #ececec;
+ overflow: hidden;
+ margin: 0;
}
- tab-button[selected=true] {
- background-color: white;
- border: 1px solid rgb(163, 163, 163);
- border-bottom: none;
- padding: 3px 14px 1px 14px;
+ #tabs input[type=radio] {
+ display: none;
}
- tabs-content-container {
- display: flex;
- flex: 1 1 auto;
- overflow: auto;
- width: 100%;
+ #tabs tab label {
+ cursor: pointer;
+ display: inline-block;
+ border: 1px solid #ececec;
+ margin: 5px 0px 0px 15px;
+ padding: 3px 10px 3px 10px;
}
- ::content > * {
- flex: 1 1 auto;
+ #tabs tab label span {
+ font-weight: bold;
}
- ::content > *:not([selected]) {
- display: none;
+ #tabs:focus input[type=radio]:checked ~ label {
+ outline: dotted 1px #8e8e8e;
+ outline-offset: -2px;
}
- button-label {
- display: inline;
+ #tabs input[type=radio]:checked ~ label {
+ background-color: white;
+ border: 1px solid #8e8e8e;
+ border-bottom: 1px solid white;
}
- tab-strip-heading {
- display: block;
- flex: 0 0 auto;
- padding: 4px 15px 1px 15px;
- margin-top: 2px;
- margin-before: 20px;
- margin-after: 10px;
- }
- #tsh {
- display: inline;
- font-weight: bold;
+ #subView {
+ flex: 1 1 auto;
+ overflow: auto;
}
</style>
-
- <tab-strip>
- <tab-strip-heading id="tshh">
- <span id="tsh"></span>
- </tab-strip-heading>
- <template repeat="{{tab in tabs_}}">
- <tab-button
- button-id="{{ tab.id }}"
- on-click="{{ tabButtonSelectHandler_ }}"
- selected="{{ selectedTab_.id === tab.id }}">
- <button-label>{{ tab.label ? tab.label : 'No Label'}}</button-label>
- </tab-button>
+ <div id='tabs' hidden="[[tabsHidden]]">
+ <label id=selection_description>[[label_]]</label>
+ <template is=dom-repeat items=[[subViews_]]>
+ <tab>
+ <input type=radio name=tabs id$=[[computeRadioId_(item)]]
+ on-change='onTabChanged_'
+ checked$='[[isChecked_(item)]]' />
+ <label for$=[[computeRadioId_(item)]]>
+ <template is=dom-if if=[[item.tabIcon]]>
+ <span style$='[[item.tabIcon.style]]'>[[item.tabIcon.text]]</span>
+ </template>
+ [[item.tabLabel]]
+ </label>
+ </tab>
</template>
- </tab-strip>
-
- <tabs-content-container id='content-container'>
- <content></content>
- </tabs-content-container>
-
+ </div>
+ <div id='subView'></div>
+ <content>
+ </content>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- this.$.tshh.style.display = 'none';
-
- // A tab is represented by the following tuple:
- // (id, label, content, observer, savedScrollTop, savedScrollLeft).
- // The properties are used in the following way:
- // id: Uniquely identifies a tab. It is the same number as the index
- // in the tabs array. Used primarily by the on-click event attached
- // to buttons.
- // label: A string, representing the label printed on the tab button.
- // content: The light-dom child representing the contents of the tab.
- // The content is appended to this tab-view by the user.
- // observers: The observers attached to the content node to watch for
- // attribute changes. The attributes of interest are: 'selected',
- // and 'tab-label'.
- // savedScrollTop/Left: Used to return the scroll position upon switching
- // tabs. The values are generally saved when a tab switch occurs.
- //
- // The order of the tabs is relevant for the tab ordering.
- this.tabs_ = [];
- this.selectedTab_ = undefined;
-
- // Register any already existing children.
- for (var i = 0; i < this.children.length; i++)
- this.processAddedChild_(this.children[i]);
-
- // In case the user decides to add more tabs, make sure we watch for
- // any child mutations.
- this.childrenObserver_ = new MutationObserver(
- this.childrenUpdated_.bind(this));
- this.childrenObserver_.observe(this, { childList: 'true' });
- },
-
- get tabStripHeadingText() {
- return this.$.tsh.textContent;
- },
-
- set tabStripHeadingText(tabStripHeadingText) {
- this.$.tsh.textContent = tabStripHeadingText;
- if (!!tabStripHeadingText)
- this.$.tshh.style.display = '';
- else
- this.$.tshh.style.display = 'none';
- },
-
- get selectedTab() {
- // Make sure we process any pending children additions / removals, before
- // trying to select a tab. Otherwise, we might not find some children.
- this.childrenUpdated_(
- this.childrenObserver_.takeRecords(), this.childrenObserver_);
-
- // Do not give access to the user to the inner data structure.
- // A user should only be able to mutate the added tab content.
- if (this.selectedTab_)
- return this.selectedTab_.content;
- return undefined;
- },
-
- set selectedTab(content) {
- // Make sure we process any pending children additions / removals, before
- // trying to select a tab. Otherwise, we might not find some children.
- this.childrenUpdated_(
- this.childrenObserver_.takeRecords(), this.childrenObserver_);
-
- if (content === undefined || content === null) {
- this.changeSelectedTabById_(undefined);
- return;
- }
-
- // Search for the specific node in our tabs list.
- // If it is not there print a warning.
- var contentTabId = undefined;
- for (var i = 0; i < this.tabs_.length; i++)
- if (this.tabs_[i].content === content) {
- contentTabId = this.tabs_[i].id;
- break;
- }
+Polymer({
+ is: 'tr-ui-b-tab-view',
- if (contentTabId === undefined)
- return;
-
- this.changeSelectedTabById_(contentTabId);
- },
-
- get tabsHidden() {
- var ts = this.shadowRoot.querySelector('tab-strip');
- return ts.hasAttribute('tabs-hidden');
+ properties: {
+ label_: {
+ type: String,
+ value: () => ''
},
-
- set tabsHidden(tabsHidden) {
- tabsHidden = !!tabsHidden;
- var ts = this.shadowRoot.querySelector('tab-strip');
- if (tabsHidden)
- ts.setAttribute('tabs-hidden', true);
- else
- ts.removeAttribute('tabs-hidden');
- },
-
- get tabs() {
- return this.tabs_.map(function(tabObject) {
- return tabObject.content;
- });
- },
-
- /**
- * Function called on light-dom child addition.
- */
- processAddedChild_: function(child) {
- var observerAttributeSelected = new MutationObserver(
- this.childAttributesChanged_.bind(this));
- var observerAttributeTabLabel = new MutationObserver(
- this.childAttributesChanged_.bind(this));
- var tabObject = {
- id: this.tabs_.length,
- content: child,
- label: child.getAttribute('tab-label'),
- observers: {
- forAttributeSelected: observerAttributeSelected,
- forAttributeTabLabel: observerAttributeTabLabel
- }
- };
-
- this.tabs_.push(tabObject);
- if (child.hasAttribute('selected')) {
- // When receiving a child with the selected attribute, if we have no
- // selected tab, mark the child as the selected tab, otherwise keep
- // the previous selection.
- if (this.selectedTab_)
- child.removeAttribute('selected');
- else
- this.setSelectedTabById_(tabObject.id);
- }
-
- // This is required because the user might have set the selected
- // property before we got to process the child.
- var previousSelected = child.selected;
-
- var tabView = this;
-
- Object.defineProperty(
- child,
- 'selected', {
- configurable: true,
- set: function(value) {
- if (value) {
- tabView.changeSelectedTabById_(tabObject.id);
- return;
- }
-
- var wasSelected = tabView.selectedTab_ === tabObject;
- if (wasSelected)
- tabView.changeSelectedTabById_(undefined);
- },
- get: function() {
- return this.hasAttribute('selected');
- }
- });
-
- if (previousSelected)
- child.selected = previousSelected;
-
- observerAttributeSelected.observe(child,
- { attributeFilter: ['selected'] });
- observerAttributeTabLabel.observe(child,
- { attributeFilter: ['tab-label'] });
-
+ selectedSubView_: Object,
+ subViews_: {
+ type: Array,
+ value: () => []
},
-
- /**
- * Function called on light-dom child removal.
- */
- processRemovedChild_: function(child) {
- for (var i = 0; i < this.tabs_.length; i++) {
- // Make sure ids are the same as the tab position after removal.
- this.tabs_[i].id = i;
- if (this.tabs_[i].content === child) {
- this.tabs_[i].observers.forAttributeSelected.disconnect();
- this.tabs_[i].observers.forAttributeTabLabel.disconnect();
- // The user has removed the currently selected tab.
- if (this.tabs_[i] === this.selectedTab_) {
- this.clearSelectedTab_();
- this.fire('selected-tab-change');
- }
- child.removeAttribute('selected');
- delete child.selected;
- // Remove the observer since we no longer care about this child.
- this.tabs_.splice(i, 1);
- i--;
- }
- }
- },
-
-
- /**
- * This function handles child attribute changes. The only relevant
- * attributes for the tab-view are 'tab-label' and 'selected'.
- */
- childAttributesChanged_: function(mutations, observer) {
- var tabObject = undefined;
- // First figure out which child has been changed.
- for (var i = 0; i < this.tabs_.length; i++) {
- var observers = this.tabs_[i].observers;
- if (observers.forAttributeSelected === observer ||
- observers.forAttributeTabLabel === observer) {
- tabObject = this.tabs_[i];
- break;
- }
- }
-
- // This should not happen, unless the user has messed with our internal
- // data structure.
- if (!tabObject)
- return;
-
- // Next handle the attribute changes.
- for (var i = 0; i < mutations.length; i++) {
- var node = tabObject.content;
- // 'tab-label' attribute has been changed.
- if (mutations[i].attributeName === 'tab-label')
- tabObject.label = node.getAttribute('tab-label');
- // 'selected' attribute has been changed.
- if (mutations[i].attributeName === 'selected') {
- // The attribute has been set.
- var nodeIsSelected = node.hasAttribute('selected');
- if (nodeIsSelected)
- this.changeSelectedTabById_(tabObject.id);
- else
- this.changeSelectedTabById_(undefined);
- }
- }
- },
-
- /**
- * This function handles light-dom additions and removals from the
- * tab-view component.
- */
- childrenUpdated_: function(mutations, observer) {
- mutations.forEach(function(mutation) {
- for (var i = 0; i < mutation.removedNodes.length; i++)
- this.processRemovedChild_(mutation.removedNodes[i]);
- for (var i = 0; i < mutation.addedNodes.length; i++)
- this.processAddedChild_(mutation.addedNodes[i]);
- }, this);
- },
-
- /**
- * Handler called when a click event happens on any of the tab buttons.
- */
- tabButtonSelectHandler_: function(event, detail, sender) {
- this.changeSelectedTabById_(sender.getAttribute('button-id'));
- },
-
- /**
- * This does the actual work. :)
- */
- changeSelectedTabById_: function(id) {
- var newTab = id !== undefined ? this.tabs_[id] : undefined;
- var changed = this.selectedTab_ !== newTab;
- this.saveCurrentTabScrollPosition_();
- this.clearSelectedTab_();
- if (id !== undefined) {
- this.setSelectedTabById_(id);
- this.restoreCurrentTabScrollPosition_();
+ tabsHidden: {
+ type: Boolean,
+ value: false,
+ observer: 'tabsHiddenChanged_'
+ }
+ },
+
+ ready: function() {
+ this.$.tabs.addEventListener('keydown', this.onKeyDown_.bind(this), true);
+ this.updateFocusability_();
+ },
+
+ set label(newLabel) {
+ this.set('label_', newLabel);
+ },
+
+ get tabs() {
+ return this.get('subViews_');
+ },
+
+ get selectedSubView() {
+ return this.selectedSubView_;
+ },
+
+ set selectedSubView(subView) {
+ if (subView === this.selectedSubView_)
+ return;
+
+ if (this.selectedSubView_) {
+ Polymer.dom(this.$.subView).removeChild(this.selectedSubView_);
+ var oldInput = this.root.getElementById(this.computeRadioId_(
+ this.selectedSubView_));
+ if (oldInput) {
+ oldInput.checked = false;
}
+ }
- if (changed)
- this.fire('selected-tab-change');
- },
-
- /**
- * This function updates the currently selected tab based on its internal
- * id. The corresponding light-dom element receives the selected attribute.
- */
- setSelectedTabById_: function(id) {
- this.selectedTab_ = this.tabs_[id];
- // Disconnect observer while we mutate the child.
- this.selectedTab_.observers.forAttributeSelected.disconnect();
- this.selectedTab_.content.setAttribute('selected', 'selected');
- // Reconnect the observer to watch for changes in the future.
- this.selectedTab_.observers.forAttributeSelected.observe(
- this.selectedTab_.content, { attributeFilter: ['selected'] });
-
- },
-
- saveTabStates: function() {
- // Scroll positions of unselected tabs have already been saved.
- this.saveCurrentTabScrollPosition_();
- },
+ this.set('selectedSubView_', subView);
- saveCurrentTabScrollPosition_: function() {
- if (this.selectedTab_) {
- this.selectedTab_.content._savedScrollTop =
- this.$['content-container'].scrollTop;
- this.selectedTab_.content._savedScrollLeft =
- this.$['content-container'].scrollLeft;
+ if (subView) {
+ Polymer.dom(this.$.subView).appendChild(subView);
+ var newInput = this.root.getElementById(this.computeRadioId_(subView));
+ if (newInput) {
+ newInput.checked = true;
}
- },
+ }
- restoreCurrentTabScrollPosition_: function() {
- if (this.selectedTab_) {
- this.$['content-container'].scrollTop =
- this.selectedTab_.content._savedScrollTop || 0;
- this.$['content-container'].scrollLeft =
- this.selectedTab_.content._savedScrollLeft || 0;
- }
- },
+ this.fire('selected-tab-change');
+ },
+
+ clearSubViews: function() {
+ this.splice('subViews_', 0, this.subViews_.length);
+ this.selectedSubView = undefined;
+ this.updateFocusability_();
+ },
+
+ addSubView: function(subView) {
+ this.push('subViews_', subView);
+ if (!this.selectedSubView_)
+ this.selectedSubView = subView;
+
+ this.updateFocusability_();
+ },
+
+ resetSubViews: function(subViews) {
+ this.splice('subViews_', 0, this.subViews_.length);
+ if (subViews.length) {
+ for (var subView of subViews)
+ this.push('subViews_', subView);
+ this.selectedSubView = subViews[0];
+ }
+ else {
+ this.selectedSubView = undefined;
+ }
+ this.updateFocusability_();
+ },
+
+ onTabChanged_: function(event) {
+ this.selectedSubView = event.model.item;
+ },
+
+ isChecked_: function(subView) {
+ return this.selectedSubView_ === subView;
+ },
+
+ tabsHiddenChanged_: function() {
+ this.updateFocusability_();
+ },
+
+ onKeyDown_: function(e) {
+ if (this.tabsHidden)
+ return;
+
+ var keyHandled = false;
+ switch (e.keyCode) {
+ // Arrow left.
+ case 37:
+ keyHandled = this.selectPreviousTabIfPossible();
+ break;
+
+ // Arrow right.
+ case 39:
+ keyHandled = this.selectNextTabIfPossible();
+ break;
+ }
- /**
- * This function clears the currently selected tab. This handles removal
- * of the selected attribute from the light-dom element.
- */
- clearSelectedTab_: function() {
- if (this.selectedTab_) {
- // Disconnect observer while we mutate the child.
- this.selectedTab_.observers.forAttributeSelected.disconnect();
- this.selectedTab_.content.removeAttribute('selected');
- // Reconnect the observer to watch for changes in the future.
- this.selectedTab_.observers.forAttributeSelected.observe(
- this.selectedTab_.content, { attributeFilter: ['selected'] });
- this.selectedTab_ = undefined;
- }
+ if (!keyHandled)
+ return;
+ e.stopPropagation();
+ e.preventDefault();
+ },
+
+ selectNextTabIfPossible: function() {
+ return this.selectTabByOffsetIfPossible_(1);
+ },
+
+ selectPreviousTabIfPossible: function() {
+ return this.selectTabByOffsetIfPossible_(-1);
+ },
+
+ selectTabByOffsetIfPossible_: function(offset) {
+ if (!this.selectedSubView_)
+ return false;
+ var currentIndex = this.subViews_.indexOf(this.selectedSubView_);
+ var newSubView = this.tabs[currentIndex + offset];
+ if (!newSubView)
+ return false;
+ this.selectedSubView = newSubView;
+ return true;
+ },
+
+ shouldBeFocusable_: function() {
+ return !this.tabsHidden && this.subViews_.length > 0;
+ },
+
+ updateFocusability_: function() {
+ if (this.shouldBeFocusable_()) {
+ Polymer.dom(this.$.tabs).setAttribute('tabindex', 0);
+ } else {
+ Polymer.dom(this.$.tabs).removeAttribute('tabindex');
}
- });
- </script>
-</polymer-element>
+ },
+
+ computeRadioId_: function(subView) {
+ // We can't just use the tagName as the radio's ID because there are
+ // instances where a single subview type can handle multiple event types,
+ // and thus might be present multiple times in a single tab view. In order
+ // to avoid the case where we might have two tabs with the same ID, we
+ // uniquify this ID by appending the tab's label with all spaces replaced
+ // by dashes (because spaces aren't allowed in HTML IDs).
+ return subView.tagName + '-' + subView.tabLabel.replace(/ /g, '-');
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html
index 42f16e594ae..a7be3802cb8 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html
@@ -5,319 +5,122 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/model/power_series.html">
+<link rel="import" href="/tracing/ui/analysis/alert_sub_view.html">
+<link rel="import" href="/tracing/ui/analysis/multi_power_sample_sub_view.html">
<link rel="import" href="/tracing/ui/base/tab_view.html">
-<template id="tab-view-test-template">
- <tr-ui-a-tab-view>
- <p tab-label="Existing Label"> Tab with label already set </p>
- <p> Tab Content with no label </p>
- <p selected="selected" tab-label="Should be selected">
- Already selected tab
- </p>
- <p selected="selected" tab-label="Should not be selected">
- Second already selected tab
- </p>
- </tr-ui-a-tab-view>
-</template>
+<dom-module id='tr-ui-b-tab-view-test-non-sub-view'>
+ <template>
+ <div></div>
+ </template>
+</dom-module>
<script>
'use strict';
-tr.b.unittest.testSuite(function() {
- var THIS_DOC = document._currentScript.ownerDocument;
-
- test('instantiate', function() {
-
- var TAB_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' +
- ' Cras eleifend elit nec erat tristique pellentesque. Cras placerat ' +
- 'lectus, sed semper tortor ornare quis. Maecenas vitae hendrerit. ' +
- 'Cras mattis interdum nisi, eget egestas dui iaculis ultricies. Proi' +
- 'n magna at nibh fringilla tincidunt id vitae ante. Fusce nec urna n' +
- 'on porttitor tincidunt. Pellentesque habitant morbi tristique senec' +
- 'tus netus et malesuada fames ac turpis egestas. Suspendisse sed vel' +
- 'it mollis ornare sit amet vel augue. Nullam rhoncus in tellus id. ' +
- 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices ' +
- 'cubilia Curae; Nunc at velit consectetur ipsum tempus tempus. Nunc ' +
- 'mattis sapien, a placerat erat. Vivamus ac enim ultricies, gravida ' +
- 'nulla ut, scelerisque magna. Sed a volutpat enim. Morbi vulputate, ' +
- 'sed egestas mollis, urna nisl varius sem, sed venenatis turpis null' +
- 'a ipsum. Suspendisse potenti.';
-
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '500px';
- tabViewContainer.style.height = '200px';
-
- var tabView = new TracingAnalysisTabView();
-
- var firstTab = document.createElement('div');
- firstTab.setAttribute('tab-label', 'First Tab Label');
- firstTab.innerHTML = '<p>' + TAB_TEXT + '<p>';
-
- var secondTab = document.createElement('div');
- secondTab.setAttribute('tab-label', 'Second Tab Label');
- secondTab.innerHTML = '<b>' + 'Second Tab Text' + '</b>';
-
- var thirdTab = document.createElement('div');
- thirdTab.setAttribute('tab-label', 'Third Tab Label');
- thirdTab.innerHTML = '<b>' + 'Third Tab Text' + '</b>';
+var nonSubViewBehavior = {};
- tabView.appendChild(firstTab);
- tabView.appendChild(secondTab);
- tabView.appendChild(thirdTab);
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
-
- thirdTab.setAttribute('tab-label', 'Something Different');
-
- var button = document.createElement('button');
- button.textContent = 'Change label';
+Polymer({
+ is: 'tr-ui-b-tab-view-test-non-sub-view',
+ behaviors: [nonSubViewBehavior]
+});
- button.addEventListener('click', function() {
- thirdTab.setAttribute('tab-label', 'Label Changed');
+tr.b.unittest.testSuite(function() {
+ function createPowerSampleSubView() {
+ var model = tr.c.TestUtils.newModel(function(m) {
+ m.device.powerSeries = new tr.model.PowerSeries(m.device);
+
+ m.device.vSyncTimestamps = [0];
+ m.device.powerSeries.addPowerSample(1, 1);
+ m.device.powerSeries.addPowerSample(2, 2);
+ m.device.powerSeries.addPowerSample(3, 3);
+ m.device.powerSeries.addPowerSample(4, 2);
});
- tabView.selectedTab = secondTab;
- this.addHTMLOutput(button);
+ var subView = document.createElement('tr-ui-a-multi-power-sample-sub-view');
+ subView.selection = new tr.model.EventSet(model.device.powerSeries.samples);
+ subView.tabLabel = 'Power samples';
+ return subView;
+ }
+
+ function createAlertSubView() {
+ var slice = tr.c.TestUtils.newSliceEx(
+ {title: 'b', start: 0, duration: 0.002});
+ var alertInfo = new tr.model.EventInfo(
+ 'Alert 1', 'Critical alert',
+ [{
+ label: 'Example',
+ textContent: 'Example page',
+ href: 'http://www.example.com'
+ }]);
+
+ var alert = new tr.model.Alert(alertInfo, 5, [slice]);
+ var subView = document.createElement('tr-ui-a-alert-sub-view');
+ subView.selection = new tr.model.EventSet(alert);
+ subView.tabLabel = 'Alerts';
+ subView.tabIcon = { text: '\u26A0', style: 'color: red;' };
+
+ return subView;
+ }
+
+ test('instantiate_noTabs', function() {
+ var tabView = document.createElement('tr-ui-b-tab-view');
+ tabView.label = 'No items selected.';
+ this.addHTMLOutput(tabView);
});
-
- test('instantiateWithTabHeading', function() {
- var TAB_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' +
- ' Cras eleifend elit nec erat tristique pellentesque. Cras placerat ' +
- 'lectus, sed semper tortor ornare quis. Maecenas vitae hendrerit. ' +
- 'Cras mattis interdum nisi, eget egestas dui iaculis ultricies. Proi' +
- 'n magna at nibh fringilla tincidunt id vitae ante. Fusce nec urna n' +
- 'on porttitor tincidunt. Pellentesque habitant morbi tristique senec' +
- 'tus netus et malesuada fames ac turpis egestas. Suspendisse sed vel' +
- 'it mollis ornare sit amet vel augue. Nullam rhoncus in tellus id. ' +
- 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices ' +
- 'cubilia Curae; Nunc at velit consectetur ipsum tempus tempus. Nunc ' +
- 'mattis sapien, a placerat erat. Vivamus ac enim ultricies, gravida ' +
- 'nulla ut, scelerisque magna. Sed a volutpat enim. Morbi vulputate, ' +
- 'sed egestas mollis, urna nisl varius sem, sed venenatis turpis null' +
- 'a ipsum. Suspendisse potenti.';
-
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '500px';
- tabViewContainer.style.height = '200px';
-
- var tabView = new TracingAnalysisTabView();
- tabView.tabStripHeadingText = 'Hello world:';
-
- var firstTab = document.createElement('div');
- firstTab.setAttribute('tab-label', 'First Tab Label');
- firstTab.innerHTML = '<p>' + TAB_TEXT + '<p>';
-
- var secondTab = document.createElement('div');
- secondTab.setAttribute('tab-label', 'Second Tab Label');
- secondTab.innerHTML = '<b>' + 'Second Tab Text' + '</b>';
-
- var thirdTab = document.createElement('div');
- thirdTab.setAttribute('tab-label', 'Third Tab Label');
- thirdTab.innerHTML = '<b>' + 'Third Tab Text' + '</b>';
-
- tabView.appendChild(firstTab);
- tabView.appendChild(secondTab);
- tabView.appendChild(thirdTab);
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
- tabView.selectedTab = secondTab;
+ test('instantiate_oneTab', function() {
+ var tabView = document.createElement('tr-ui-b-tab-view');
+ tabView.label = '1 item selected.';
+ tabView.addSubView(createPowerSampleSubView());
+ this.addHTMLOutput(tabView);
});
- test('instantiateChildrenAlreadyInside', function() {
- var tabViewTemplate = THIS_DOC.querySelector('#tab-view-test-template');
- var tabView = tabViewTemplate.createInstance();
-
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '400px';
- tabViewContainer.style.height = '200px';
-
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
-
+ test('instantiate_twoTabs', function() {
+ var tabView = document.createElement('tr-ui-b-tab-view');
+ tabView.label = '3 items selected.';
+ tabView.addSubView(createPowerSampleSubView());
+ tabView.addSubView(createAlertSubView());
+ this.addHTMLOutput(tabView);
});
- test('programaticallySetSelectedTab', function() {
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '500px';
- tabViewContainer.style.height = '200px';
-
- var tabView = new TracingAnalysisTabView();
-
- var t1 = document.createElement('div');
- var t2 = document.createElement('div');
- var t3 = document.createElement('div');
-
- tabView.appendChild(t1);
- tabView.appendChild(t2);
- tabView.appendChild(t3);
-
- assert.isUndefined(tabView.selectedTab);
- tabView.selectedTab = t1;
-
- assert.isTrue(t1.hasAttribute('selected'));
- assert.isFalse(t2.hasAttribute('selected'));
- assert.isFalse(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t1, tabView.selectedTab));
+ test('clearSubViews_selectedSubViewNullAfter', function() {
+ var tabView = document.createElement('tr-ui-b-tab-view');
+ tabView.label = '3 items selected.';
+ tabView.addSubView(createPowerSampleSubView());
+ tabView.addSubView(createAlertSubView());
- tabView.selectedTab = t2;
- assert.isFalse(t1.hasAttribute('selected'));
- assert.isTrue(t2.hasAttribute('selected'));
- assert.isFalse(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t2, tabView.selectedTab));
+ tabView.clearSubViews();
- tabView.selectedTab = t3;
- assert.isFalse(t1.hasAttribute('selected'));
- assert.isFalse(t2.hasAttribute('selected'));
- assert.isTrue(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t3, tabView.selectedTab));
-
- t1.selected = true;
- assert.isTrue(t1.hasAttribute('selected'));
- assert.isFalse(t2.hasAttribute('selected'));
- assert.isFalse(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t1, tabView.selectedTab));
-
- // Make sure just randomly setting a tab as not selected does not
- // break the existing selection.
- t2.selected = false;
- t3.selected = false;
- assert.isTrue(t1.hasAttribute('selected'));
- assert.isFalse(t2.hasAttribute('selected'));
- assert.isFalse(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t1, tabView.selectedTab));
-
- t3.selected = true;
- assert.isFalse(t1.hasAttribute('selected'));
- assert.isFalse(t2.hasAttribute('selected'));
- assert.isTrue(t3.hasAttribute('selected'));
- assert.isTrue(Object.is(t3, tabView.selectedTab));
-
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
+ assert.isUndefined(tabView.selectedSubView);
});
- /**
- * This test checks that if an element has a selected property already set,
- * before being attached to the tabView, it still gets selected if the
- * property is true, after it gets attached.
- */
- test('instantiateSetSelectedTabAlreadySet', function() {
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '500px';
- tabViewContainer.style.height = '200px';
-
- var tabView = new TracingAnalysisTabView();
-
- var t1 = document.createElement('div');
- t1.textContent = 'This text should BE visible.';
- var t2 = document.createElement('div');
- t2.textContent = 'This text should NOT be visible.';
- var t3 = document.createElement('div');
- t3.textContent = 'This text should NOT be visible, also.';
-
- t1.selected = true;
- t2.selected = false;
- t3.selected = false;
-
- tabView.appendChild(t1);
- tabView.appendChild(t2);
- tabView.appendChild(t3);
-
- t1.setAttribute('tab-label', 'This should be selected');
- t2.setAttribute('tab-label', 'Not selected');
- t3.setAttribute('tab-label', 'Not selected');
-
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
- });
-
- test('selectingInvalidTabWorks', function() {
- var tabView = new TracingAnalysisTabView();
- var t1 = document.createElement('div');
- var t2 = document.createElement('div');
- var t3 = document.createElement('div');
- var invalidChild = document.createElement('div');
-
- tabView.appendChild(t1);
- tabView.appendChild(t2);
- tabView.appendChild(t3);
-
- tabView.selectedTab = t1;
-
- assert.equal(tabView.selectedTab, t1);
-
- // Make sure that selecting an invalid tab does not break the current
- // selection.
- tabView.selectedTab = invalidChild;
- assert.equal(t1, tabView.selectedTab);
-
- // Also make sure the invalidChild does not influence the tab view when
- // it has a selected property set.
- invalidChild.selected = true;
- tabView.selectedTab = invalidChild;
- assert.equal(t1, tabView.selectedTab);
- });
-
- test('changeTabCausesEvent', function() {
- var tabView = new TracingAnalysisTabView();
- var t1 = document.createElement('div');
- var t2 = document.createElement('div');
- var invalidChild = document.createElement('div');
-
- tabView.appendChild(t1);
- tabView.appendChild(t2);
-
- var numChangeEvents = 0;
+ test('changeSelectedSubView', function() {
+ var selectedTabChangeEventCount = 0;
+ var tabView = document.createElement('tr-ui-b-tab-view');
tabView.addEventListener('selected-tab-change', function() {
- numChangeEvents++;
+ selectedTabChangeEventCount++;
});
- tabView.selectedTab = t1;
- assert.equal(numChangeEvents, 1);
- tabView.selectedTab = t1;
- assert.equal(numChangeEvents, 1);
- tabView.selectedTab = t2;
- assert.equal(numChangeEvents, 2);
- tabView.selectedTab = undefined;
- assert.equal(numChangeEvents, 3);
- });
-
- /**
- * This test makes sure that removing the selected tab does not select
- * any other tab.
- */
- test('instantiateRemovingSelectedTab', function() {
- var tabViewContainer = document.createElement('div');
- tabViewContainer.style.width = '500px';
- tabViewContainer.style.height = '200px';
-
- var tabView = new TracingAnalysisTabView();
- var t1 = document.createElement('div');
- t1.textContent = 'This text should BE visible.';
- var t2 = document.createElement('div');
- t2.textContent = 'This text should NOT be visible.';
- var t3 = document.createElement('div');
- t3.textContent = 'This text should NOT be visible, also.';
+ assert.isUndefined(tabView.selectedSubView);
+ assert.strictEqual(selectedTabChangeEventCount, 0);
- tabView.appendChild(t1);
- tabView.appendChild(t2);
- tabView.appendChild(t3);
+ var view1 = createPowerSampleSubView();
+ tabView.addSubView(view1);
+ assert.strictEqual(tabView.selectedSubView, view1);
+ assert.strictEqual(selectedTabChangeEventCount, 1);
- t1.setAttribute('tab-label', 'This should not exist');
- t2.setAttribute('tab-label', 'Not selected');
- t3.setAttribute('tab-label', 'Not selected');
+ var view2 = createAlertSubView();
+ tabView.addSubView(view2);
+ assert.strictEqual(tabView.selectedSubView, view1);
+ assert.strictEqual(selectedTabChangeEventCount, 1);
- tabView.selectedTab = t1;
- tabView.removeChild(t1);
-
- tabViewContainer.appendChild(tabView);
-
- this.addHTMLOutput(tabViewContainer);
- });
+ tabView.selectedSubView = view2;
+ assert.strictEqual(tabView.selectedSubView, view2);
+ assert.strictEqual(selectedTabChangeEventCount, 2);
+ })
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table.html
index 1292a3af758..91b00cb9d65 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/table.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table.html
@@ -57,7 +57,7 @@ tr.exportTo('tr.ui.b', function() {
});
</script>
-<polymer-element name="tr-ui-b-table">
+<dom-module id="tr-ui-b-table">
<template>
<style>
:host {
@@ -66,8 +66,6 @@ tr.exportTo('tr.ui.b', function() {
}
table {
- font-size: 12px;
-
flex: 1 1 auto;
align-self: stretch;
border-collapse: separate;
@@ -78,13 +76,17 @@ tr.exportTo('tr.ui.b', function() {
tr > td {
padding: 2px 4px 2px 4px;
- vertical-align: text-top;
+ vertical-align: top;
}
- tr:focus,
- td:focus {
- outline: 1px dotted rgba(0,0,0,0.1);
- outline-offset: 0;
+ table > tbody:focus {
+ outline: none;
+ }
+ table > tbody:focus[selection-mode="row"] > tr[selected],
+ table > tbody:focus[selection-mode="cell"] > tr > td[selected],
+ table > tbody:focus > tr.empty-row > td {
+ outline: 1px dotted #666666;
+ outline-offset: -1px;
}
button.toggle-button {
@@ -153,6 +155,10 @@ tr.exportTo('tr.ui.b', function() {
background-color: rgb(171, 217, 202); /* semi-light turquoise */
}
+ table > colgroup > col[selected] {
+ background-color: #e6e6e6; /* grey */
+ }
+
table > tbody > tr.empty-row > td {
color: #666;
font-style: italic;
@@ -167,20 +173,24 @@ tr.exportTo('tr.ui.b', function() {
border-top: 1px solid #ffffff;
}
+ :host([zebra]) table tbody tr:nth-child(even) {
+ background-color: #f4f4f4;
+ }
+
expand-button {
-webkit-user-select: none;
- display: inline-block;
cursor: pointer;
- font-size: 9px;
- min-width: 8px;
- max-width: 8px;
+ margin-right: 3px;
+ font-size: smaller;
}
- .button-expanded {
+ expand-button.button-expanded {
transform: rotate(90deg);
}
</style>
<table>
+ <colgroup id="cols">
+ </colgroup>
<thead id="head">
</thead>
<tbody id="body">
@@ -189,1186 +199,1419 @@ tr.exportTo('tr.ui.b', function() {
</tfoot>
</table>
</template>
- <script>
- 'use strict';
- (function() {
- var RIGHT_ARROW = String.fromCharCode(0x25b6);
- var UNSORTED_ARROW = String.fromCharCode(0x25BF);
- var ASCENDING_ARROW = String.fromCharCode(0x25B4);
- var DESCENDING_ARROW = String.fromCharCode(0x25BE);
- var BASIC_INDENTATION = 8;
-
- var SelectionMode = tr.ui.b.TableFormat.SelectionMode;
- var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle;
- var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment;
-
- Polymer({
- created: function() {
- this.selectionMode_ = SelectionMode.NONE;
- this.rowHighlightStyle_ = HighlightStyle.DEFAULT;
- this.cellHighlightStyle_ = HighlightStyle.DEFAULT;
- this.selectedTableRowInfo_ = undefined;
- this.selectedColumnIndex_ = undefined;
+</dom-module>
+<script>
+'use strict';
+(function() {
+ var RIGHT_ARROW = String.fromCharCode(0x25b6);
+ var UNSORTED_ARROW = String.fromCharCode(0x25BF);
+ var ASCENDING_ARROW = String.fromCharCode(0x25B4);
+ var DESCENDING_ARROW = String.fromCharCode(0x25BE);
+
+ var SelectionMode = tr.ui.b.TableFormat.SelectionMode;
+ var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle;
+ var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment;
- this.tableColumns_ = [];
- this.tableRows_ = [];
- this.tableRowsInfo_ = new WeakMap();
- this.tableFooterRows_ = [];
- this.tableFooterRowsInfo_ = new WeakMap();
- this.sortColumnIndex_ = undefined;
- this.sortDescending_ = false;
- this.columnsWithExpandButtons_ = [];
- this.headerCells_ = [];
- this.showHeader_ = true;
- this.emptyValue_ = undefined;
- this.subRowsPropertyName_ = 'subRows';
- this.customizeTableRowCallback_ = undefined;
- },
-
- ready: function() {
- this.$.body.addEventListener(
- 'keydown', this.onKeyDown_.bind(this), true);
- },
-
- clear: function() {
- this.selectionMode_ = SelectionMode.NONE;
- this.rowHighlightStyle_ = HighlightStyle.DEFAULT;
- this.cellHighlightStyle_ = HighlightStyle.DEFAULT;
- this.selectedTableRowInfo_ = undefined;
- this.selectedColumnIndex_ = undefined;
+ Polymer({
+ is: 'tr-ui-b-table',
- this.textContent = '';
- this.tableColumns_ = [];
- this.tableRows_ = [];
- this.tableRowsInfo_ = new WeakMap();
- this.tableFooterRows_ = [];
- this.tableFooterRowsInfo_ = new WeakMap();
- this.sortColumnIndex_ = undefined;
- this.sortDescending_ = false;
- this.columnsWithExpandButtons_ = [];
- this.headerCells_ = [];
- this.subRowsPropertyName_ = 'subRows';
- this.defaultExpansionStateCallback_ = undefined;
- },
-
- get showHeader() {
- return this.showHeader_;
- },
-
- set showHeader(showHeader) {
- this.showHeader_ = showHeader;
- this.scheduleRebuildHeaders_();
- },
-
- set subRowsPropertyName(name) {
- this.subRowsPropertyName_ = name;
- },
-
- /**
- * This callback will be called whenever a body row is built
- * for a userRow that has subRows and does not have an explicit
- * isExpanded field.
- * The callback should return true if the row should be expanded,
- * or false if the row should be collapsed.
- * @param {function(userRow, parentUserRow): boolean} cb The callback.
- */
- set defaultExpansionStateCallback(cb) {
- this.defaultExpansionStateCallback_ = cb;
- this.scheduleRebuildBody_();
- },
-
- /**
- * This callback will be called whenever a body row is built.
- * The callback's return value is ignored.
- * @param {function(userRow, trElement)} cb The callback.
- */
- set customizeTableRowCallback(cb) {
- this.customizeTableRowCallback_ = cb;
+ created: function() {
+ this.selectionMode_ = SelectionMode.NONE;
+ this.rowHighlightStyle_ = HighlightStyle.DEFAULT;
+ this.cellHighlightStyle_ = HighlightStyle.DEFAULT;
+ this.selectedTableRowInfo_ = undefined;
+ this.selectedColumnIndex_ = undefined;
+
+ this.tableColumns_ = [];
+ this.tableRows_ = [];
+ this.tableRowsInfo_ = new WeakMap();
+ this.tableFooterRows_ = [];
+ this.tableFooterRowsInfo_ = new WeakMap();
+ this.sortColumnIndex_ = undefined;
+ this.sortDescending_ = false;
+ this.columnsWithExpandButtons_ = [];
+ this.headerCells_ = [];
+ this.showHeader_ = true;
+ this.emptyValue_ = undefined;
+ this.subRowsPropertyName_ = 'subRows';
+ this.customizeTableRowCallback_ = undefined;
+ this.defaultExpansionStateCallback_ = undefined;
+ this.userCanModifySortOrder_ = true;
+ },
+
+ ready: function() {
+ this.$.body.addEventListener(
+ 'keydown', this.onKeyDown_.bind(this), true);
+ this.$.body.addEventListener(
+ 'focus', this.onFocus_.bind(this), true);
+ },
+
+ clear: function() {
+ this.selectionMode_ = SelectionMode.NONE;
+ this.rowHighlightStyle_ = HighlightStyle.DEFAULT;
+ this.cellHighlightStyle_ = HighlightStyle.DEFAULT;
+ this.selectedTableRowInfo_ = undefined;
+ this.selectedColumnIndex_ = undefined;
+
+ Polymer.dom(this).textContent = '';
+ this.tableColumns_ = [];
+ this.tableRows_ = [];
+ this.tableRowsInfo_ = new WeakMap();
+ this.tableFooterRows_ = [];
+ this.tableFooterRowsInfo_ = new WeakMap();
+ this.sortColumnIndex_ = undefined;
+ this.sortDescending_ = false;
+ this.columnsWithExpandButtons_ = [];
+ this.headerCells_ = [];
+ this.showHeader_ = true;
+ this.emptyValue_ = undefined;
+ this.subRowsPropertyName_ = 'subRows';
+ this.defaultExpansionStateCallback_ = undefined;
+ this.userCanModifySortOrder_ = true;
+ },
+
+ set zebra(zebra) {
+ if (zebra) {
+ this.setAttribute('zebra', true);
+ } else {
+ this.removeAttribute('zebra');
+ }
+ },
+
+ get zebra() {
+ return this.getAttribute('zebra');
+ },
+
+ get showHeader() {
+ return this.showHeader_;
+ },
+
+ set showHeader(showHeader) {
+ this.showHeader_ = showHeader;
+ this.scheduleRebuildHeaders_();
+ },
+
+ set subRowsPropertyName(name) {
+ this.subRowsPropertyName_ = name;
+ },
+
+ /**
+ * This callback will be called whenever a body row is built
+ * for a userRow that has subRows and does not have an explicit
+ * isExpanded field.
+ * The callback should return true if the row should be expanded,
+ * or false if the row should be collapsed.
+ * @param {function(userRow, parentUserRow): boolean} cb The callback.
+ */
+ set defaultExpansionStateCallback(cb) {
+ this.defaultExpansionStateCallback_ = cb;
+ this.scheduleRebuildBody_();
+ },
+
+ /**
+ * This callback will be called whenever a body row is built.
+ * The callback's return value is ignored.
+ * @param {function(userRow, trElement)} cb The callback.
+ */
+ set customizeTableRowCallback(cb) {
+ this.customizeTableRowCallback_ = cb;
+ this.scheduleRebuildBody_();
+ },
+
+ get emptyValue() {
+ return this.emptyValue_;
+ },
+
+ set emptyValue(emptyValue) {
+ var previousEmptyValue = this.emptyValue_;
+ this.emptyValue_ = emptyValue;
+ if (this.tableRows_.length === 0 && emptyValue !== previousEmptyValue)
this.scheduleRebuildBody_();
- },
-
- get emptyValue() {
- return this.emptyValue_;
- },
-
- set emptyValue(emptyValue) {
- var previousEmptyValue = this.emptyValue_;
- this.emptyValue_ = emptyValue;
- if (this.tableRows_.length === 0 && emptyValue !== previousEmptyValue)
- this.scheduleRebuildBody_();
- },
-
- /**
- * Data objects should have the following fields:
- * mandatory: title, value
- * optional: width {string}, cmp {function}, colSpan {number},
- * showExpandButtons {boolean},
- * align {tr.ui.b.TableFormat.ColumnAlignment}
- *
- * @param {Array} columns An array of data objects.
- */
- set tableColumns(columns) {
- // Figure out the columns with expand buttons...
- var columnsWithExpandButtons = [];
- for (var i = 0; i < columns.length; i++) {
- if (columns[i].showExpandButtons)
- columnsWithExpandButtons.push(i);
- }
- if (columnsWithExpandButtons.length === 0) {
- // First column if none have specified.
- columnsWithExpandButtons = [0];
- }
+ },
- // Sanity check columns.
- for (var i = 0; i < columns.length; i++) {
- var colInfo = columns[i];
- if (colInfo.width === undefined)
- continue;
+ /**
+ * Data objects should have the following fields:
+ * mandatory: title, value
+ * optional: width {string}, cmp {function}, colSpan {number},
+ * showExpandButtons {boolean},
+ * align {tr.ui.b.TableFormat.ColumnAlignment}
+ *
+ * @param {Array} columns An array of data objects.
+ */
+ set tableColumns(columns) {
+ // Figure out the columns with expand buttons...
+ var columnsWithExpandButtons = [];
+ for (var i = 0; i < columns.length; i++) {
+ if (columns[i].showExpandButtons)
+ columnsWithExpandButtons.push(i);
+ }
+ if (columnsWithExpandButtons.length === 0) {
+ // First column if none have specified.
+ columnsWithExpandButtons = [0];
+ }
- var hasExpandButton = columnsWithExpandButtons.indexOf(i) !== -1;
+ // Sanity check columns.
+ for (var i = 0; i < columns.length; i++) {
+ var colInfo = columns[i];
+ if (colInfo.width === undefined)
+ continue;
- var w = colInfo.width;
- if (w) {
- if (/\d+px/.test(w)) {
- continue;
- } else if (/\d+%/.test(w)) {
- if (hasExpandButton) {
- throw new Error('Columns cannot be %-sized and host ' +
- ' an expand button');
- }
- } else {
- throw new Error('Unrecognized width string');
+ var hasExpandButton = columnsWithExpandButtons.indexOf(i) !== -1;
+
+ var w = colInfo.width;
+ if (w) {
+ if (/\d+px/.test(w)) {
+ continue;
+ } else if (/\d+%/.test(w)) {
+ if (hasExpandButton) {
+ throw new Error('Columns cannot be %-sized and host ' +
+ ' an expand button');
}
+ } else {
+ throw new Error('Unrecognized width string');
}
}
+ }
- // Commit the change.
- this.tableColumns_ = columns;
- this.headerCells_ = [];
- this.columnsWithExpandButtons_ = columnsWithExpandButtons;
- this.sortColumnIndex = undefined;
- this.scheduleRebuildHeaders_();
-
- // Blow away the table rows, too.
- this.tableRows = this.tableRows_;
- },
-
- get tableColumns() {
- return this.tableColumns_;
- },
-
- /**
- * @param {Array} rows An array of 'row' objects with the following
- * fields:
- * optional: subRows An array of objects that have the same 'row'
- * structure. Set subRowsPropertyName to use an
- * alternative field name.
- */
- set tableRows(rows) {
- this.selectedTableRowInfo_ = undefined;
- this.selectedColumnIndex_ = undefined;
- this.maybeUpdateSelectedRow_();
- this.tableRows_ = rows;
- this.tableRowsInfo_ = new WeakMap();
- this.scheduleRebuildBody_();
- },
+ // Try to preserve the user's sort choice.
+ // This is a 'best-effort' attempt, for example we compare columns by
+ // thier titles which can be HTML nodes in which case we might consider
+ // them different even if they look the same to the user.
+ var sortIndex = undefined;
+ var currentSortColumn = this.tableColumns[this.sortColumnIndex_];
+ if (currentSortColumn) {
+ for (var [i, column] of columns.entries()) {
+ if (currentSortColumn.title === column.title) {
+ sortIndex = i;
+ break;
+ }
+ }
+ }
- get tableRows() {
- return this.tableRows_;
- },
+ // Commit the change.
+ this.tableColumns_ = columns;
+ this.headerCells_ = [];
+ this.columnsWithExpandButtons_ = columnsWithExpandButtons;
+ this.scheduleRebuildHeaders_();
+ this.sortColumnIndex = sortIndex;
- set footerRows(rows) {
- this.tableFooterRows_ = rows;
- this.tableFooterRowsInfo_ = new WeakMap();
- this.scheduleRebuildFooter_();
- },
+ // Blow away the table rows, too.
+ this.tableRows = this.tableRows_;
+ },
- get footerRows() {
- return this.tableFooterRows_;
- },
+ get tableColumns() {
+ return this.tableColumns_;
+ },
- set sortColumnIndex(number) {
- if (number === this.sortColumnIndex_)
- return;
+ /**
+ * @param {Array} rows An array of 'row' objects with the following
+ * fields:
+ * optional: subRows An array of objects that have the same 'row'
+ * structure. Set subRowsPropertyName to use an
+ * alternative field name.
+ */
+ set tableRows(rows) {
+ this.selectedTableRowInfo_ = undefined;
+ this.selectedColumnIndex_ = undefined;
+ this.tableRows_ = rows;
+ this.tableRowsInfo_ = new WeakMap();
+ this.scheduleRebuildBody_();
+ },
- if (number === undefined) {
- this.sortColumnIndex_ = undefined;
- this.updateHeaderArrows_();
- this.dispatchSortingChangedEvent_();
- return;
- }
+ get tableRows() {
+ return this.tableRows_;
+ },
+
+ set footerRows(rows) {
+ this.tableFooterRows_ = rows;
+ this.tableFooterRowsInfo_ = new WeakMap();
+ this.scheduleRebuildFooter_();
+ },
+
+ get footerRows() {
+ return this.tableFooterRows_;
+ },
+
+ get userCanModifySortOrder() {
+ return this.userCanModifySortOrder_;
+ },
+
+ set userCanModifySortOrder(userCanModifySortOrder) {
+ var newUserCanModifySortOrder = !!userCanModifySortOrder;
+ if (newUserCanModifySortOrder === this.userCanModifySortOrder_)
+ return
+ this.userCanModifySortOrder_ = newUserCanModifySortOrder;
+ this.scheduleRebuildHeaders_();
+ },
+
+ set sortColumnIndex(number) {
+ if (number === this.sortColumnIndex_)
+ return;
+
+ if (number !== undefined) {
if (this.tableColumns_.length <= number)
throw new Error('Column number ' + number + ' is out of bounds.');
if (!this.tableColumns_[number].cmp)
throw new Error('Column ' + number + ' does not have a comparator.');
+ }
+
+ this.sortColumnIndex_ = number;
+ this.updateHeaderArrows_();
+ this.scheduleRebuildBody_();
+ this.dispatchSortingChangedEvent_();
+ },
+
+ get sortColumnIndex() {
+ return this.sortColumnIndex_;
+ },
+
+ set sortDescending(value) {
+ var newValue = !!value;
- this.sortColumnIndex_ = number;
+ if (newValue !== this.sortDescending_) {
+ this.sortDescending_ = newValue;
this.updateHeaderArrows_();
this.scheduleRebuildBody_();
this.dispatchSortingChangedEvent_();
- },
-
- get sortColumnIndex() {
- return this.sortColumnIndex_;
- },
+ }
+ },
- set sortDescending(value) {
- var newValue = !!value;
+ get sortDescending() {
+ return this.sortDescending_;
+ },
- if (newValue !== this.sortDescending_) {
- this.sortDescending_ = newValue;
- this.updateHeaderArrows_();
- this.scheduleRebuildBody_();
- this.dispatchSortingChangedEvent_();
+ updateHeaderArrows_: function() {
+ for (var i = 0; i < this.headerCells_.length; i++) {
+ var headerCell = this.headerCells_[i];
+ var isColumnCurrentlySorted = i === this.sortColumnIndex_;
+ if (!this.tableColumns_[i].cmp ||
+ (!this.userCanModifySortOrder_ && !isColumnCurrentlySorted)) {
+ headerCell.sideContent = '';
+ continue;
}
- },
-
- get sortDescending() {
- return this.sortDescending_;
- },
-
- updateHeaderArrows_: function() {
- for (var i = 0; i < this.headerCells_.length; i++) {
- if (!this.tableColumns_[i].cmp) {
- this.headerCells_[i].sideContent = '';
- continue;
- }
- if (i !== this.sortColumnIndex_) {
- this.headerCells_[i].sideContent = UNSORTED_ARROW;
- continue;
- }
- this.headerCells_[i].sideContent = this.sortDescending_ ?
- DESCENDING_ARROW : ASCENDING_ARROW;
+ if (!isColumnCurrentlySorted) {
+ headerCell.sideContent = UNSORTED_ARROW;
+ headerCell.sideContentDisabled = false;
+ continue;
}
- },
+ headerCell.sideContent = this.sortDescending_ ?
+ DESCENDING_ARROW : ASCENDING_ARROW;
+ headerCell.sideContentDisabled = !this.userCanModifySortOrder_;
+ }
+ },
- sortRows_: function(rows) {
- rows.sort(function(rowA, rowB) {
- if (this.sortDescending_)
- return this.tableColumns_[this.sortColumnIndex_].cmp(
- rowB.userRow, rowA.userRow);
- return this.tableColumns_[this.sortColumnIndex_].cmp(
- rowA.userRow, rowB.userRow);
- }.bind(this));
- // Sort expanded sub rows recursively.
- for (var i = 0; i < rows.length; i++) {
- if (this.getExpandedForUserRow_(rows[i]))
- this.sortRows_(rows[i][this.subRowsPropertyName_]);
+ generateHeaderColumns_: function() {
+ var selectedTableColumnIndex = this.selectedTableColumnIndex;
+ Polymer.dom(this.$.cols).textContent = '';
+ for (var i = 0; i < this.tableColumns_.length; ++i) {
+ var colElement = document.createElement('col');
+ if (i === selectedTableColumnIndex) {
+ colElement.setAttribute('selected', true);
}
- },
+ Polymer.dom(this.$.cols).appendChild(colElement);
+ }
- generateHeaderColumns_: function() {
- this.headerCells_ = [];
- this.$.head.textContent = '';
- if (!this.showHeader_)
- return;
+ this.headerCells_ = [];
+ Polymer.dom(this.$.head).textContent = '';
+ if (!this.showHeader_)
+ return;
- var tr = this.appendNewElement_(this.$.head, 'tr');
- for (var i = 0; i < this.tableColumns_.length; i++) {
- var td = this.appendNewElement_(tr, 'td');
+ var tr = this.appendNewElement_(this.$.head, 'tr');
+ for (var i = 0; i < this.tableColumns_.length; i++) {
+ var td = this.appendNewElement_(tr, 'td');
- var headerCell = document.createElement('tr-ui-b-table-header-cell');
- headerCell.cellTitle = this.tableColumns_[i].title;
- headerCell.align = this.tableColumns_[i].align;
+ var headerCell = document.createElement('tr-ui-b-table-header-cell');
+ headerCell.column = this.tableColumns_[i];
- // If the table can be sorted by this column, attach a tap callback
- // to the column.
- if (this.tableColumns_[i].cmp) {
- td.classList.add('sensitive');
- headerCell.tapCallback = this.createSortCallback_(i);
- // Set arrow position, depending on the sortColumnIndex.
- if (this.sortColumnIndex_ === i)
- headerCell.sideContent = this.sortDescending_ ?
+ // If the table can be sorted by this column and the user can modify
+ // the sort order, attach a tap callback to the column.
+ if (this.tableColumns_[i].cmp) {
+ var isColumnCurrentlySorted = i === this.sortColumnIndex_;
+ if (isColumnCurrentlySorted) {
+ headerCell.sideContent = this.sortDescending_ ?
DESCENDING_ARROW : ASCENDING_ARROW;
- else
+ if (!this.userCanModifySortOrder_)
+ headerCell.sideContentDisabled = true;
+ }
+ if (this.userCanModifySortOrder_) {
+ Polymer.dom(td).classList.add('sensitive');
+ if (!isColumnCurrentlySorted)
headerCell.sideContent = UNSORTED_ARROW;
+ headerCell.tapCallback = this.createSortCallback_(i);
}
-
- td.appendChild(headerCell);
- this.headerCells_.push(headerCell);
}
- },
- applySizes_: function() {
- if (this.tableRows_.length === 0 && !this.showHeader)
- return;
- var rowToRemoveSizing;
- var rowToSize;
- if (this.showHeader) {
- rowToSize = this.$.head.children[0];
- rowToRemoveSizing = this.$.body.children[0];
- } else {
- rowToSize = this.$.body.children[0];
- rowToRemoveSizing = this.$.head.children[0];
- }
- for (var i = 0; i < this.tableColumns_.length; i++) {
- if (rowToRemoveSizing && rowToRemoveSizing.children[i]) {
- var tdToRemoveSizing = rowToRemoveSizing.children[i];
- tdToRemoveSizing.style.minWidth = '';
- tdToRemoveSizing.style.width = '';
- }
+ Polymer.dom(td).appendChild(headerCell);
+ this.headerCells_.push(headerCell);
+ }
+ },
- // Apply sizing.
- var td = rowToSize.children[i];
+ applySizes_: function() {
+ if (this.tableRows_.length === 0 && !this.showHeader)
+ return;
+ var rowToRemoveSizing;
+ var rowToSize;
+ if (this.showHeader) {
+ rowToSize = Polymer.dom(this.$.head).children[0];
+ rowToRemoveSizing = Polymer.dom(this.$.body).children[0];
+ } else {
+ rowToSize = Polymer.dom(this.$.body).children[0];
+ rowToRemoveSizing = Polymer.dom(this.$.head).children[0];
+ }
+ for (var i = 0; i < this.tableColumns_.length; i++) {
+ if (rowToRemoveSizing && Polymer.dom(rowToRemoveSizing).children[i]) {
+ var tdToRemoveSizing = Polymer.dom(rowToRemoveSizing).children[i];
+ tdToRemoveSizing.style.minWidth = '';
+ tdToRemoveSizing.style.width = '';
+ }
- var delta;
- if (this.columnsWithExpandButtons_.indexOf(i) !== -1) {
- td.style.paddingLeft = BASIC_INDENTATION + 'px';
- delta = BASIC_INDENTATION + 'px';
- } else {
- delta = undefined;
- }
+ // Apply sizing.
+ var td = Polymer.dom(rowToSize).children[i];
- function calc(base, delta) {
- if (delta)
- return 'calc(' + base + ' - ' + delta + ')';
- else
- return base;
- }
-
- var w = this.tableColumns_[i].width;
- if (w) {
- if (/\d+px/.test(w)) {
- td.style.minWidth = calc(w, delta);
- } else if (/\d+%/.test(w)) {
- td.style.width = w;
- } else {
- throw new Error('Unrecognized width string: ' + w);
- }
- }
+ var delta;
+ if (this.columnsWithExpandButtons_.indexOf(i) !== -1) {
+ td.style.paddingLeft = this.basicIndentation_ + 'px';
+ delta = this.basicIndentation_ + 'px';
+ } else {
+ delta = undefined;
}
- },
-
- createSortCallback_: function(columnNumber) {
- return function() {
- var previousIndex = this.sortColumnIndex;
- this.sortColumnIndex = columnNumber;
- if (previousIndex !== columnNumber)
- this.sortDescending = false;
+
+ function calc(base, delta) {
+ if (delta)
+ return 'calc(' + base + ' - ' + delta + ')';
else
- this.sortDescending = !this.sortDescending;
- }.bind(this);
- },
-
- generateTableRowNodes_: function(tableSection, userRows, rowInfoMap,
- indentation, lastAddedRow,
- parentRowInfo) {
- if (this.sortColumnIndex_ !== undefined &&
- tableSection === this.$.body) {
- userRows = userRows.slice(); // Don't mess with the input data.
- userRows.sort(function(rowA, rowB) {
- var c = this.tableColumns_[this.sortColumnIndex_].cmp(
- rowA, rowB);
- if (this.sortDescending_)
- c = -c;
- return c;
- }.bind(this));
+ return base;
}
- for (var i = 0; i < userRows.length; i++) {
- var userRow = userRows[i];
- var rowInfo = this.getOrCreateRowInfoFor_(rowInfoMap, userRow,
- parentRowInfo);
- var htmlNode = this.getHTMLNodeForRowInfo_(
- tableSection, rowInfo, rowInfoMap, indentation);
-
- if (lastAddedRow === undefined) {
- // Put first into the table.
- tableSection.insertBefore(htmlNode, tableSection.firstChild);
+ var w = this.tableColumns_[i].width;
+ if (w) {
+ if (/\d+px/.test(w)) {
+ td.style.minWidth = calc(w, delta);
+ } else if (/\d+%/.test(w)) {
+ td.style.width = w;
} else {
- // This is shorthand for insertAfter(htmlNode, lastAdded).
- var nextSiblingOfLastAdded = lastAddedRow.nextSibling;
- tableSection.insertBefore(htmlNode, nextSiblingOfLastAdded);
+ throw new Error('Unrecognized width string: ' + w);
}
- this.updateTabIndexForTableRowNode_(htmlNode);
-
- lastAddedRow = htmlNode;
- if (!rowInfo.isExpanded)
- continue;
-
- // Append subrows now.
- lastAddedRow = this.generateTableRowNodes_(
- tableSection, userRow[this.subRowsPropertyName_], rowInfoMap,
- indentation + 1, lastAddedRow, rowInfo);
}
- return lastAddedRow;
- },
+ }
+ },
- getOrCreateRowInfoFor_: function(rowInfoMap, userRow, parentRowInfo) {
- var rowInfo = undefined;
+ createSortCallback_: function(columnNumber) {
+ return function() {
+ if (!this.userCanModifySortOrder_)
+ return;
+ var previousIndex = this.sortColumnIndex;
+ this.sortColumnIndex = columnNumber;
+ if (previousIndex !== columnNumber)
+ this.sortDescending = false;
+ else
+ this.sortDescending = !this.sortDescending;
+ }.bind(this);
+ },
- if (rowInfoMap.has(userRow)) {
- rowInfo = rowInfoMap.get(userRow);
+ generateTableRowNodes_: function(tableSection, userRows, rowInfoMap,
+ indentation, lastAddedRow,
+ parentRowInfo) {
+ if (this.sortColumnIndex_ !== undefined &&
+ tableSection === this.$.body) {
+ userRows = userRows.slice(); // Don't mess with the input data.
+ userRows.sort(function(rowA, rowB) {
+ var c = this.tableColumns_[this.sortColumnIndex_].cmp(
+ rowA, rowB);
+ if (this.sortDescending_)
+ c = -c;
+ return c;
+ }.bind(this));
+ }
+
+ for (var i = 0; i < userRows.length; i++) {
+ var userRow = userRows[i];
+ var rowInfo = this.getOrCreateRowInfoFor_(rowInfoMap, userRow,
+ parentRowInfo);
+ var htmlNode = this.getHTMLNodeForRowInfo_(
+ tableSection, rowInfo, rowInfoMap, indentation);
+
+ if (lastAddedRow === undefined) {
+ // Put first into the table.
+ Polymer.dom(tableSection).insertBefore(
+ htmlNode, Polymer.dom(tableSection).firstChild);
} else {
- rowInfo = {
- userRow: userRow,
- htmlNode: undefined,
- parentRowInfo: parentRowInfo
- };
- rowInfoMap.set(userRow, rowInfo);
+ // This is shorthand for insertAfter(htmlNode, lastAdded).
+ var nextSiblingOfLastAdded = Polymer.dom(lastAddedRow).nextSibling;
+ Polymer.dom(tableSection).insertBefore(
+ htmlNode, nextSiblingOfLastAdded);
}
- // Recompute isExpanded in case defaultExpansionStateCallback_ has
- // changed.
- rowInfo.isExpanded = this.getExpandedForUserRow_(userRow);
+ lastAddedRow = htmlNode;
+ if (!rowInfo.isExpanded)
+ continue;
- return rowInfo;
- },
+ // Append subrows now.
+ lastAddedRow = this.generateTableRowNodes_(
+ tableSection, userRow[this.subRowsPropertyName_], rowInfoMap,
+ indentation + 1, lastAddedRow, rowInfo);
+ }
+ return lastAddedRow;
+ },
- customizeTableRow_: function(userRow, trElement) {
- if (!this.customizeTableRowCallback_)
- return;
- this.customizeTableRowCallback_(userRow, trElement);
- },
-
- getHTMLNodeForRowInfo_: function(tableSection, rowInfo,
- rowInfoMap, indentation) {
- if (rowInfo.htmlNode) {
- this.customizeTableRow_(rowInfo.userRow, rowInfo.htmlNode);
- return rowInfo.htmlNode;
- }
+ getOrCreateRowInfoFor_: function(rowInfoMap, userRow, parentRowInfo) {
+ var rowInfo = undefined;
- var INDENT_SPACE = indentation * 16;
- var INDENT_SPACE_NO_BUTTON = indentation * 16 + BASIC_INDENTATION;
- var trElement = this.ownerDocument.createElement('tr');
- rowInfo.htmlNode = trElement;
- rowInfo.indentation = indentation;
- trElement.rowInfo = rowInfo;
- this.customizeTableRow_(rowInfo.userRow, trElement);
+ if (rowInfoMap.has(userRow)) {
+ rowInfo = rowInfoMap.get(userRow);
+ } else {
+ rowInfo = {
+ userRow: userRow,
+ htmlNode: undefined,
+ parentRowInfo: parentRowInfo
+ };
+ rowInfoMap.set(userRow, rowInfo);
+ }
- for (var i = 0; i < this.tableColumns_.length;) {
- var td = this.appendNewElement_(trElement, 'td');
- td.columnIndex = i;
+ // Recompute isExpanded in case defaultExpansionStateCallback_ has
+ // changed.
+ rowInfo.isExpanded = this.getExpandedForUserRow_(userRow);
- var column = this.tableColumns_[i];
- var value = column.value(rowInfo.userRow);
- var colSpan = column.colSpan ? column.colSpan : 1;
- td.style.colSpan = colSpan;
+ return rowInfo;
+ },
- switch (column.align) {
- case undefined:
- case ColumnAlignment.LEFT:
- break;
+ customizeTableRow_: function(userRow, trElement) {
+ if (!this.customizeTableRowCallback_)
+ return;
+ this.customizeTableRowCallback_(userRow, trElement);
+ },
- case ColumnAlignment.RIGHT:
- td.style.textAlign = 'right';
- break;
+ get basicIndentation_() {
+ var px = parseInt(getComputedStyle(this).fontSize) || 16;
+ return px - 2;
+ },
- default:
- throw new Error('Invalid alignment of column at index=' + i +
- ': ' + column.align);
- }
+ getHTMLNodeForRowInfo_: function(tableSection, rowInfo,
+ rowInfoMap, indentation) {
+ if (rowInfo.htmlNode) {
+ this.customizeTableRow_(rowInfo.userRow, rowInfo.htmlNode);
+ return rowInfo.htmlNode;
+ }
- if (this.doesColumnIndexSupportSelection(i))
- td.classList.add('supports-selection');
-
- if (this.columnsWithExpandButtons_.indexOf(i) != -1) {
- if (rowInfo.userRow[this.subRowsPropertyName_] &&
- rowInfo.userRow[this.subRowsPropertyName_].length > 0) {
- td.style.paddingLeft = INDENT_SPACE + 'px';
- var expandButton = this.appendNewElement_(td,
- 'expand-button');
- expandButton.textContent = RIGHT_ARROW;
- if (rowInfo.isExpanded)
- expandButton.classList.add('button-expanded');
- } else {
- td.style.paddingLeft = INDENT_SPACE_NO_BUTTON + 'px';
- }
- }
+ var INDENT_SPACE = indentation * 16;
+ var INDENT_SPACE_NO_BUTTON = indentation * 16 + this.basicIndentation_;
+ var trElement = this.ownerDocument.createElement('tr');
+ rowInfo.htmlNode = trElement;
+ rowInfo.indentation = indentation;
+ trElement.rowInfo = rowInfo;
+ this.customizeTableRow_(rowInfo.userRow, trElement);
+
+ var isBodyRow = tableSection === this.$.body;
+ var isExpandableRow = rowInfo.userRow[this.subRowsPropertyName_] &&
+ rowInfo.userRow[this.subRowsPropertyName_].length;
+
+ for (var i = 0; i < this.tableColumns_.length;) {
+ var td = this.appendNewElement_(trElement, 'td');
+ td.columnIndex = i;
+
+ var column = this.tableColumns_[i];
+ var value = column.value(rowInfo.userRow);
+ var colSpan = column.colSpan ? column.colSpan : 1;
+ td.style.colSpan = colSpan;
+
+ switch (column.align) {
+ case undefined:
+ case ColumnAlignment.LEFT:
+ break;
- if (value !== undefined)
- td.appendChild(tr.ui.b.asHTMLOrTextNode(value, this.ownerDocument));
+ case ColumnAlignment.RIGHT:
+ td.style.textAlign = 'right';
+ break;
- i += colSpan;
+ default:
+ throw new Error('Invalid alignment of column at index=' + i +
+ ': ' + column.align);
}
- var isSelectable = tableSection === this.$.body;
- var isExpandable = rowInfo.userRow[this.subRowsPropertyName_] &&
- rowInfo.userRow[this.subRowsPropertyName_].length;
+ if (this.doesColumnIndexSupportSelection(i))
+ Polymer.dom(td).classList.add('supports-selection');
+
+ if (this.columnsWithExpandButtons_.indexOf(i) !== -1) {
+ if (rowInfo.userRow[this.subRowsPropertyName_] &&
+ rowInfo.userRow[this.subRowsPropertyName_].length > 0) {
+ td.style.paddingLeft = INDENT_SPACE + 'px';
+ td.style.display = 'flex';
+ var expandButton = this.appendNewElement_(td, 'expand-button');
+ Polymer.dom(expandButton).textContent = RIGHT_ARROW;
+ if (rowInfo.isExpanded)
+ Polymer.dom(expandButton).classList.add('button-expanded');
+ } else {
+ td.style.paddingLeft = INDENT_SPACE_NO_BUTTON + 'px';
+ }
+ }
+
+ if (value !== undefined) {
+ Polymer.dom(td).appendChild(
+ tr.ui.b.asHTMLOrTextNode(value, this.ownerDocument));
+ }
- if (isSelectable || isExpandable) {
- trElement.addEventListener('click', function(e) {
+ // Add a click handler for selection and row expansion (if applicable).
+ if (isBodyRow || isExpandableRow) {
+ td.addEventListener('click', function(i, e) {
e.stopPropagation();
- if (e.target.tagName == 'EXPAND-BUTTON') {
+ if (e.target.tagName === 'EXPAND-BUTTON') {
this.setExpandedForUserRow_(
tableSection, rowInfoMap,
rowInfo.userRow, !rowInfo.isExpanded);
return;
}
- function getTD(cur) {
- if (cur === trElement)
- throw new Error('woah');
- if (cur.parentElement === trElement)
- return cur;
- return getTD(cur.parentElement);
- }
-
// If the row/cell can be selected and it's not selected yet,
// select it.
- if (isSelectable && this.selectionMode_ !== SelectionMode.NONE) {
+ if (isBodyRow && this.selectionMode_ !== SelectionMode.NONE) {
var shouldSelect = false;
- var columnIndex = getTD(e.target).columnIndex;
+ var shouldFocus = false;
switch (this.selectionMode_) {
case SelectionMode.ROW:
shouldSelect = this.selectedTableRowInfo_ !== rowInfo;
+ shouldFocus = true;
break;
-
case SelectionMode.CELL:
- if (this.doesColumnIndexSupportSelection(columnIndex)) {
+ if (this.doesColumnIndexSupportSelection(i)) {
shouldSelect = this.selectedTableRowInfo_ !== rowInfo ||
- this.selectedColumnIndex_ !== columnIndex;
+ this.selectedColumnIndex_ !== i;
+ shouldFocus = true;
}
break;
-
default:
throw new Error('Invalid selection mode ' +
this.selectionMode_);
}
+ if (shouldFocus) {
+ this.focus();
+ }
if (shouldSelect) {
- this.didTableRowInfoGetClicked_(rowInfo, columnIndex);
+ this.didTableRowInfoGetClicked_(rowInfo, i);
return;
}
}
// Otherwise, if the row is expandable, expand/collapse it.
- if (isExpandable) {
+ if (isExpandableRow) {
this.setExpandedForUserRow_(tableSection, rowInfoMap,
rowInfo.userRow, !rowInfo.isExpanded);
}
- }.bind(this));
+ }.bind(this, i));
}
- return rowInfo.htmlNode;
- },
+ td.addEventListener('mousedown', function(e) {
+ // Prevent automatically focusing on the table upon clicking on the
+ // table. Explicitly focus on it when appropriate (upon clicking on a
+ // selectable row/cell) instead.
+ e.preventDefault();
+ });
+
+ // Add a double-click handler for stepping into a row/cell (if
+ // applicable).
+ if (isBodyRow) {
+ td.addEventListener('dblclick', function(i, e) {
+ e.stopPropagation();
+ this.dispatchStepIntoEvent_(rowInfo, i);
+ }.bind(this, i));
+ }
- removeSubNodes_: function(tableSection, rowInfo, rowInfoMap) {
- if (rowInfo.userRow[this.subRowsPropertyName_] === undefined)
- return;
- for (var i = 0;
- i < rowInfo.userRow[this.subRowsPropertyName_].length; i++) {
- var subRow = rowInfo.userRow[this.subRowsPropertyName_][i];
- var subRowInfo = rowInfoMap.get(subRow);
- if (!subRowInfo)
- continue;
+ i += colSpan;
+ }
- var subNode = subRowInfo.htmlNode;
- if (subNode && subNode.parentNode === tableSection) {
- tableSection.removeChild(subNode);
- this.removeSubNodes_(tableSection, subRowInfo, rowInfoMap);
- }
+ return rowInfo.htmlNode;
+ },
+
+ removeSubNodes_: function(tableSection, rowInfo, rowInfoMap) {
+ if (rowInfo.userRow[this.subRowsPropertyName_] === undefined)
+ return;
+ for (var i = 0;
+ i < rowInfo.userRow[this.subRowsPropertyName_].length; i++) {
+ var subRow = rowInfo.userRow[this.subRowsPropertyName_][i];
+ var subRowInfo = rowInfoMap.get(subRow);
+ if (!subRowInfo)
+ continue;
+
+ var subNode = subRowInfo.htmlNode;
+ if (subNode && Polymer.dom(subNode).parentNode === tableSection) {
+ Polymer.dom(tableSection).removeChild(subNode);
+ this.removeSubNodes_(tableSection, subRowInfo, rowInfoMap);
}
- },
+ }
+ },
- scheduleRebuildHeaders_: function() {
- this.headerDirty_ = true;
- this.scheduleRebuild_();
- },
+ scheduleRebuildHeaders_: function() {
+ this.headerDirty_ = true;
+ this.scheduleRebuild_();
+ },
- scheduleRebuildBody_: function() {
- this.bodyDirty_ = true;
- this.scheduleRebuild_();
- },
+ scheduleRebuildBody_: function() {
+ this.bodyDirty_ = true;
+ this.scheduleRebuild_();
+ },
- scheduleRebuildFooter_: function() {
- this.footerDirty_ = true;
- this.scheduleRebuild_();
- },
+ scheduleRebuildFooter_: function() {
+ this.footerDirty_ = true;
+ this.scheduleRebuild_();
+ },
- scheduleRebuild_: function() {
- if (this.rebuildPending_)
- return;
- this.rebuildPending_ = true;
- setTimeout(function() {
- this.rebuildPending_ = false;
- this.rebuild();
- }.bind(this), 0);
- },
-
- rebuildIfNeeded_: function() {
+ scheduleRebuild_: function() {
+ if (this.rebuildPending_)
+ return;
+ this.rebuildPending_ = true;
+ setTimeout(function() {
+ this.rebuildPending_ = false;
this.rebuild();
- },
-
- rebuild: function() {
- var wasBodyOrHeaderDirty = this.headerDirty_ || this.bodyDirty_;
+ }.bind(this), 0);
+ },
- if (this.headerDirty_) {
- this.generateHeaderColumns_();
- this.headerDirty_ = false;
- }
- if (this.bodyDirty_) {
- this.$.body.textContent = '';
- this.generateTableRowNodes_(
- this.$.body,
- this.tableRows_, this.tableRowsInfo_, 0,
- undefined, undefined);
- if (this.tableRows_.length === 0 && this.emptyValue_ !== undefined) {
- var trElement = this.ownerDocument.createElement('tr');
- this.$.body.appendChild(trElement);
- trElement.classList.add('empty-row');
- var td = this.ownerDocument.createElement('td');
- trElement.appendChild(td);
- td.colSpan = this.tableColumns_.length;
- var emptyValue = this.emptyValue_;
- td.appendChild(
- tr.ui.b.asHTMLOrTextNode(emptyValue, this.ownerDocument));
- }
- this.bodyDirty_ = false;
- }
+ rebuildIfNeeded_: function() {
+ this.rebuild();
+ },
- if (wasBodyOrHeaderDirty)
- this.applySizes_();
+ rebuild: function() {
+ var wasBodyOrHeaderDirty = this.headerDirty_ || this.bodyDirty_;
- if (this.footerDirty_) {
- this.$.foot.textContent = '';
- this.generateTableRowNodes_(
- this.$.foot,
- this.tableFooterRows_, this.tableFooterRowsInfo_, 0,
- undefined, undefined);
- if (this.tableFooterRowsInfo_.length) {
- this.$.body.classList.add('has-footer');
- } else {
- this.$.body.classList.remove('has-footer');
- }
- this.footerDirty_ = false;
+ if (this.headerDirty_) {
+ this.generateHeaderColumns_();
+ this.headerDirty_ = false;
+ }
+ if (this.bodyDirty_) {
+ Polymer.dom(this.$.body).textContent = '';
+ this.generateTableRowNodes_(
+ this.$.body,
+ this.tableRows_, this.tableRowsInfo_, 0,
+ undefined, undefined);
+ if (this.tableRows_.length === 0 && this.emptyValue_ !== undefined) {
+ var trElement = this.ownerDocument.createElement('tr');
+ Polymer.dom(this.$.body).appendChild(trElement);
+ Polymer.dom(trElement).classList.add('empty-row');
+ var td = this.ownerDocument.createElement('td');
+ Polymer.dom(trElement).appendChild(td);
+ td.colSpan = this.tableColumns_.length;
+ var emptyValue = this.emptyValue_;
+ Polymer.dom(td).appendChild(
+ tr.ui.b.asHTMLOrTextNode(emptyValue, this.ownerDocument));
}
- },
-
- appendNewElement_: function(parent, tagName) {
- var element = parent.ownerDocument.createElement(tagName);
- parent.appendChild(element);
- return element;
- },
-
- getExpandedForTableRow: function(userRow) {
- this.rebuildIfNeeded_();
- var rowInfo = this.tableRowsInfo_.get(userRow);
- if (rowInfo === undefined)
- throw new Error('Row has not been seen, must expand its parents');
- return rowInfo.isExpanded;
- },
-
- getExpandedForUserRow_: function(userRow) {
- if (userRow[this.subRowsPropertyName_] === undefined)
- return false;
- if (userRow[this.subRowsPropertyName_].length === 0)
- return false;
- if (userRow.isExpanded)
- return true;
- if (userRow.isExpanded === false)
- return false;
+ this.bodyDirty_ = false;
+ }
- var rowInfo = this.tableRowsInfo_.get(userRow);
- if (rowInfo && rowInfo.isExpanded)
- return true;
+ if (wasBodyOrHeaderDirty)
+ this.applySizes_();
+
+ if (this.footerDirty_) {
+ Polymer.dom(this.$.foot).textContent = '';
+ this.generateTableRowNodes_(
+ this.$.foot,
+ this.tableFooterRows_, this.tableFooterRowsInfo_, 0,
+ undefined, undefined);
+ if (this.tableFooterRowsInfo_.length) {
+ Polymer.dom(this.$.body).classList.add('has-footer');
+ } else {
+ Polymer.dom(this.$.body).classList.remove('has-footer');
+ }
+ this.footerDirty_ = false;
+ }
+ },
- if (this.defaultExpansionStateCallback_ === undefined)
- return false;
+ appendNewElement_: function(parent, tagName) {
+ var element = parent.ownerDocument.createElement(tagName);
+ Polymer.dom(parent).appendChild(element);
+ return element;
+ },
- var parentUserRow = undefined;
- if (rowInfo && rowInfo.parentRowInfo)
- parentUserRow = rowInfo.parentRowInfo.userRow;
-
- return this.defaultExpansionStateCallback_(
- userRow, parentUserRow);
- },
-
- setExpandedForTableRow: function(userRow, expanded) {
- this.rebuildIfNeeded_();
- var rowInfo = this.tableRowsInfo_.get(userRow);
- if (rowInfo === undefined)
- throw new Error('Row has not been seen, must expand its parents');
- return this.setExpandedForUserRow_(this.$.body, this.tableRowsInfo_,
- userRow, expanded);
- },
-
- setExpandedForUserRow_: function(tableSection, rowInfoMap,
- userRow, expanded) {
- this.rebuildIfNeeded_();
-
- var rowInfo = rowInfoMap.get(userRow);
- if (rowInfo === undefined)
- throw new Error('Row has not been seen, must expand its parents');
-
- rowInfo.isExpanded = !!expanded;
- // If no node, then nothing further needs doing.
- if (rowInfo.htmlNode === undefined)
- return;
+ getExpandedForTableRow: function(userRow) {
+ this.rebuildIfNeeded_();
+ var rowInfo = this.tableRowsInfo_.get(userRow);
+ if (rowInfo === undefined)
+ throw new Error('Row has not been seen, must expand its parents');
+ return rowInfo.isExpanded;
+ },
- // If its detached, then nothing needs doing.
- if (rowInfo.htmlNode.parentElement !== tableSection)
- return;
+ getExpandedForUserRow_: function(userRow) {
+ if (userRow[this.subRowsPropertyName_] === undefined)
+ return false;
+ if (userRow[this.subRowsPropertyName_].length === 0)
+ return false;
+ if (userRow.isExpanded)
+ return true;
+ if ((userRow.isExpanded !== undefined) &&
+ (userRow.isExpanded === false))
+ return false;
- // Otherwise, rebuild.
- var expandButton = rowInfo.htmlNode.querySelector('expand-button');
- if (rowInfo.isExpanded) {
- expandButton.classList.add('button-expanded');
- var lastAddedRow = rowInfo.htmlNode;
- if (rowInfo.userRow[this.subRowsPropertyName_]) {
- this.generateTableRowNodes_(
- tableSection,
- rowInfo.userRow[this.subRowsPropertyName_], rowInfoMap,
- rowInfo.indentation + 1,
- lastAddedRow, rowInfo);
- }
- } else {
- expandButton.classList.remove('button-expanded');
- this.removeSubNodes_(tableSection, rowInfo, rowInfoMap);
- }
+ var rowInfo = this.tableRowsInfo_.get(userRow);
+ if (rowInfo && rowInfo.isExpanded)
+ return true;
- this.maybeUpdateSelectedRow_();
- },
+ if (this.defaultExpansionStateCallback_ === undefined)
+ return false;
- get selectionMode() {
- return this.selectionMode_;
- },
+ var parentUserRow = undefined;
+ if (rowInfo && rowInfo.parentRowInfo)
+ parentUserRow = rowInfo.parentRowInfo.userRow;
- set selectionMode(selectionMode) {
- if (!tr.b.dictionaryContainsValue(SelectionMode, selectionMode))
- throw new Error('Invalid selection mode ' + selectionMode);
- this.rebuildIfNeeded_();
- this.selectionMode_ = selectionMode;
- this.didSelectionStateChange_();
- },
+ return this.defaultExpansionStateCallback_(
+ userRow, parentUserRow);
+ },
- get rowHighlightStyle() {
- return this.rowHighlightStyle_;
- },
-
- set rowHighlightStyle(rowHighlightStyle) {
- if (!tr.b.dictionaryContainsValue(HighlightStyle, rowHighlightStyle))
- throw new Error('Invalid row highlight style ' + rowHighlightStyle);
- this.rebuildIfNeeded_();
- this.rowHighlightStyle_ = rowHighlightStyle;
- this.didSelectionStateChange_();
- },
-
- get resolvedRowHighlightStyle() {
- if (this.rowHighlightStyle_ !== HighlightStyle.DEFAULT)
- return this.rowHighlightStyle_;
- switch (this.selectionMode_) {
- case SelectionMode.NONE:
- return HighlightStyle.NONE;
- case SelectionMode.ROW:
- return HighlightStyle.DARK;
- case SelectionMode.CELL:
- return HighlightStyle.LIGHT;
- default:
- throw new Error('Invalid selection mode ' + selectionMode);
- }
- },
+ setExpandedForTableRow: function(userRow, expanded) {
+ this.rebuildIfNeeded_();
+ var rowInfo = this.tableRowsInfo_.get(userRow);
+ if (rowInfo === undefined)
+ throw new Error('Row has not been seen, must expand its parents');
+ return this.setExpandedForUserRow_(this.$.body, this.tableRowsInfo_,
+ userRow, expanded);
+ },
- get cellHighlightStyle() {
- return this.cellHighlightStyle_;
- },
-
- set cellHighlightStyle(cellHighlightStyle) {
- if (!tr.b.dictionaryContainsValue(HighlightStyle, cellHighlightStyle))
- throw new Error('Invalid cell highlight style ' + cellHighlightStyle);
- this.rebuildIfNeeded_();
- this.cellHighlightStyle_ = cellHighlightStyle;
- this.didSelectionStateChange_();
- },
-
- get resolvedCellHighlightStyle() {
- if (this.cellHighlightStyle_ !== HighlightStyle.DEFAULT)
- return this.cellHighlightStyle_;
- switch (this.selectionMode_) {
- case SelectionMode.NONE:
- case SelectionMode.ROW:
- return HighlightStyle.NONE;
- case SelectionMode.CELL:
- return HighlightStyle.DARK;
- default:
- throw new Error('Invalid selection mode ' + selectionMode);
+ setExpandedForUserRow_: function(tableSection, rowInfoMap,
+ userRow, expanded) {
+ this.rebuildIfNeeded_();
+
+ var rowInfo = rowInfoMap.get(userRow);
+ if (rowInfo === undefined)
+ throw new Error('Row has not been seen, must expand its parents');
+
+ rowInfo.isExpanded = !!expanded;
+ // If no node, then nothing further needs doing.
+ if (rowInfo.htmlNode === undefined)
+ return;
+
+ // If its detached, then nothing needs doing.
+ if (rowInfo.htmlNode.parentElement !== tableSection)
+ return;
+
+ // Otherwise, rebuild.
+ var expandButton =
+ Polymer.dom(rowInfo.htmlNode).querySelector('expand-button');
+ if (rowInfo.isExpanded) {
+ Polymer.dom(expandButton).classList.add('button-expanded');
+ var lastAddedRow = rowInfo.htmlNode;
+ if (rowInfo.userRow[this.subRowsPropertyName_]) {
+ this.generateTableRowNodes_(
+ tableSection,
+ rowInfo.userRow[this.subRowsPropertyName_], rowInfoMap,
+ rowInfo.indentation + 1,
+ lastAddedRow, rowInfo);
}
- },
+ } else {
+ Polymer.dom(expandButton).classList.remove('button-expanded');
+ this.removeSubNodes_(tableSection, rowInfo, rowInfoMap);
+ }
- setHighlightStyle_: function(highlightAttribute, resolvedHighlightStyle) {
- switch (resolvedHighlightStyle) {
- case HighlightStyle.NONE:
- this.$.body.removeAttribute(highlightAttribute);
- break;
- case HighlightStyle.LIGHT:
- this.$.body.setAttribute(highlightAttribute, 'light');
- break;
- case HighlightStyle.DARK:
- this.$.body.setAttribute(highlightAttribute, 'dark');
- break;
- default:
- throw new Error('Invalid resolved highlight style ' +
- resolvedHighlightStyle);
- }
- },
+ this.maybeUpdateSelectedRow_();
+ },
- didSelectionStateChange_: function() {
- this.setHighlightStyle_('row-highlight-style',
- this.resolvedRowHighlightStyle);
- this.setHighlightStyle_('cell-highlight-style',
- this.resolvedCellHighlightStyle);
+ get selectionMode() {
+ return this.selectionMode_;
+ },
- for (var i = 0; i < this.$.body.children.length; i++)
- this.updateTabIndexForTableRowNode_(this.$.body.children[i]);
- this.maybeUpdateSelectedRow_();
- },
+ set selectionMode(selectionMode) {
+ if (!tr.b.dictionaryContainsValue(SelectionMode, selectionMode))
+ throw new Error('Invalid selection mode ' + selectionMode);
+ this.rebuildIfNeeded_();
+ this.selectionMode_ = selectionMode;
+ this.didSelectionStateChange_();
+ },
- maybeUpdateSelectedRow_: function() {
- if (this.selectedTableRowInfo_ === undefined)
- return;
+ get rowHighlightStyle() {
+ return this.rowHighlightStyle_;
+ },
- // Selection may be off.
- if (this.selectionMode_ === SelectionMode.NONE) {
- this.removeSelectedState_();
- this.selectedTableRowInfo_ = undefined;
- return;
- }
+ set rowHighlightStyle(rowHighlightStyle) {
+ if (!tr.b.dictionaryContainsValue(HighlightStyle, rowHighlightStyle))
+ throw new Error('Invalid row highlight style ' + rowHighlightStyle);
+ this.rebuildIfNeeded_();
+ this.rowHighlightStyle_ = rowHighlightStyle;
+ this.didSelectionStateChange_();
+ },
- // selectedUserRow may not be visible
- function isVisible(rowInfo) {
- if (!rowInfo.htmlNode)
- return false;
- return !!rowInfo.htmlNode.parentElement;
- }
- if (isVisible(this.selectedTableRowInfo_)) {
- this.updateSelectedState_();
- return;
- }
+ get resolvedRowHighlightStyle() {
+ if (this.rowHighlightStyle_ !== HighlightStyle.DEFAULT)
+ return this.rowHighlightStyle_;
+ switch (this.selectionMode_) {
+ case SelectionMode.NONE:
+ return HighlightStyle.NONE;
+ case SelectionMode.ROW:
+ return HighlightStyle.DARK;
+ case SelectionMode.CELL:
+ return HighlightStyle.LIGHT;
+ default:
+ throw new Error('Invalid selection mode ' + selectionMode);
+ }
+ },
- this.removeSelectedState_();
- var curRowInfo = this.selectedTableRowInfo_;
- while (curRowInfo && !isVisible(curRowInfo))
- curRowInfo = curRowInfo.parentRowInfo;
+ get cellHighlightStyle() {
+ return this.cellHighlightStyle_;
+ },
- this.selectedTableRowInfo_ = curRowInfo;
- if (this.selectedTableRowInfo_)
- this.updateSelectedState_();
- },
+ set cellHighlightStyle(cellHighlightStyle) {
+ if (!tr.b.dictionaryContainsValue(HighlightStyle, cellHighlightStyle))
+ throw new Error('Invalid cell highlight style ' + cellHighlightStyle);
+ this.rebuildIfNeeded_();
+ this.cellHighlightStyle_ = cellHighlightStyle;
+ this.didSelectionStateChange_();
+ },
- didTableRowInfoGetClicked_: function(rowInfo, columnIndex) {
- switch (this.selectionMode_) {
- case SelectionMode.NONE:
- return;
+ get resolvedCellHighlightStyle() {
+ if (this.cellHighlightStyle_ !== HighlightStyle.DEFAULT)
+ return this.cellHighlightStyle_;
+ switch (this.selectionMode_) {
+ case SelectionMode.NONE:
+ case SelectionMode.ROW:
+ return HighlightStyle.NONE;
+ case SelectionMode.CELL:
+ return HighlightStyle.DARK;
+ default:
+ throw new Error('Invalid selection mode ' + selectionMode);
+ }
+ },
- case SelectionMode.CELL:
- if (!this.doesColumnIndexSupportSelection(columnIndex))
- return;
- if (this.selectedColumnIndex !== columnIndex)
- this.selectedColumnIndex = columnIndex;
- // Fall through.
+ setHighlightStyle_: function(highlightAttribute, resolvedHighlightStyle) {
+ switch (resolvedHighlightStyle) {
+ case HighlightStyle.NONE:
+ Polymer.dom(this.$.body).removeAttribute(highlightAttribute);
+ break;
+ case HighlightStyle.LIGHT:
+ Polymer.dom(this.$.body).setAttribute(highlightAttribute, 'light');
+ break;
+ case HighlightStyle.DARK:
+ Polymer.dom(this.$.body).setAttribute(highlightAttribute, 'dark');
+ break;
+ default:
+ throw new Error('Invalid resolved highlight style ' +
+ resolvedHighlightStyle);
+ }
+ },
- case SelectionMode.ROW:
- if (this.selectedTableRowInfo_ !== rowInfo)
- this.selectedTableRow = rowInfo.userRow;
- }
- },
-
- get selectedTableRow() {
- if (!this.selectedTableRowInfo_)
- return undefined;
- return this.selectedTableRowInfo_.userRow;
- },
-
- set selectedTableRow(userRow) {
- this.rebuildIfNeeded_();
- if (this.selectionMode_ === SelectionMode.NONE)
- throw new Error('Selection is off.');
-
- var rowInfo;
- if (userRow === undefined) {
- rowInfo = undefined;
- } else {
- rowInfo = this.tableRowsInfo_.get(userRow);
- if (!rowInfo)
- throw new Error('Row has not been seen, must expand its parents.');
- }
+ didSelectionStateChange_: function() {
+ this.setHighlightStyle_('row-highlight-style',
+ this.resolvedRowHighlightStyle);
+ this.setHighlightStyle_('cell-highlight-style',
+ this.resolvedCellHighlightStyle);
- var e = this.prepareToChangeSelection_();
- this.selectedTableRowInfo_ = rowInfo;
+ this.removeSelectedState_();
- if (this.selectedTableRowInfo_ === undefined) {
+ switch (this.selectionMode_) {
+ case SelectionMode.ROW:
+ // TODO: Replace this.selectionMode_ with a proper Polymer attribute.
+ Polymer.dom(this.$.body).setAttribute('selection-mode', 'row');
+ Polymer.dom(this.$.body).setAttribute('tabindex', 0);
this.selectedColumnIndex_ = undefined;
- this.removeSelectedState_();
- } else {
- switch (this.selectionMode_) {
- case SelectionMode.ROW:
- this.selectedColumnIndex_ = undefined;
- break;
+ break;
+ case SelectionMode.CELL:
+ Polymer.dom(this.$.body).setAttribute('selection-mode', 'cell');
+ Polymer.dom(this.$.body).setAttribute('tabindex', 0);
+ if (this.selectedTableRowInfo_ &&
+ this.selectedColumnIndex_ === undefined) {
+ var i = this.getFirstSelectableColumnIndex_();
+ if (i === -1) {
+ // No column is selectable.
+ this.selectedTableRowInfo_ = undefined;
+ } else {
+ this.selectedColumnIndex_ = i;
+ }
+ }
+ break;
+ case SelectionMode.NONE:
+ Polymer.dom(this.$.body).removeAttribute('selection-mode');
+ Polymer.dom(this.$.body).removeAttribute('tabindex');
+ this.$.body.blur(); // Remove focus (if applicable).
+ this.selectedTableRowInfo_ = undefined;
+ this.selectedColumnIndex_ = undefined;
+ break;
+ default:
+ throw new Error('Invalid selection mode ' + this.selectionMode_);
+ }
- case SelectionMode.CELL:
- if (this.selectedColumnIndex_ === undefined) {
- var i = this.getFirstSelectableColumnIndex_();
- if (i == -1)
- throw new Error('Cannot find a selectable column.');
- this.selectedColumnIndex_ = i;
- }
- break;
+ this.maybeUpdateSelectedRow_();
+ },
- default:
- throw new Error('Invalid selection mode ' + this.selectionMode_);
- }
- this.updateSelectedState_();
- }
+ maybeUpdateSelectedRow_: function() {
+ if (this.selectedTableRowInfo_ === undefined)
+ return;
- this.dispatchEvent(e);
- },
+ // selectedUserRow may not be visible
+ function isVisible(rowInfo) {
+ if (!rowInfo.htmlNode)
+ return false;
+ return !!rowInfo.htmlNode.parentElement;
+ }
+ if (isVisible(this.selectedTableRowInfo_)) {
+ this.updateSelectedState_();
+ return;
+ }
- updateTabIndexForTableRowNode_: function(row) {
- if (this.selectionMode_ === SelectionMode.ROW)
- row.tabIndex = 0;
- else
- row.removeAttribute('tabIndex');
+ this.removeSelectedState_();
+ var curRowInfo = this.selectedTableRowInfo_;
+ while (curRowInfo && !isVisible(curRowInfo))
+ curRowInfo = curRowInfo.parentRowInfo;
- var enableCellTab = this.selectionMode_ === SelectionMode.CELL;
- for (var i = 0; i < this.tableColumns_.length; i++) {
- var cell = row.children[i];
- if (enableCellTab && this.doesColumnIndexSupportSelection(i))
- cell.tabIndex = 0;
- else
- cell.removeAttribute('tabIndex');
- }
- },
+ this.selectedTableRowInfo_ = curRowInfo;
+ if (this.selectedTableRowInfo_)
+ this.updateSelectedState_();
+ else
+ this.selectedColumnIndex_ = undefined;
+ },
- prepareToChangeSelection_: function() {
- var e = new tr.b.Event('selection-changed');
- var previousSelectedRowInfo = this.selectedTableRowInfo_;
- if (previousSelectedRowInfo)
- e.previousSelectedTableRow = previousSelectedRowInfo.userRow;
- else
- e.previousSelectedTableRow = undefined;
+ didTableRowInfoGetClicked_: function(rowInfo, columnIndex) {
+ switch (this.selectionMode_) {
+ case SelectionMode.NONE:
+ return;
- this.removeSelectedState_();
+ case SelectionMode.CELL:
+ if (!this.doesColumnIndexSupportSelection(columnIndex))
+ return;
+ if (this.selectedColumnIndex !== columnIndex)
+ this.selectedColumnIndex = columnIndex;
+ // Fall through.
- return e;
- },
+ case SelectionMode.ROW:
+ if (this.selectedTableRowInfo_ !== rowInfo)
+ this.selectedTableRow = rowInfo.userRow;
+ }
+ },
- removeSelectedState_: function() {
- this.setSelectedState_(false);
- },
+ dispatchStepIntoEvent_: function(rowInfo, columnIndex) {
+ var e = new tr.b.Event('step-into');
+ e.tableRow = rowInfo.userRow;
+ e.tableColumn = this.tableColumns_[columnIndex];
+ e.columnIndex = columnIndex;
+ this.dispatchEvent(e);
+ },
- updateSelectedState_: function() {
- this.setSelectedState_(true);
- },
+ /**
+ * If the selectionMode is CELL and a cell is selected,
+ * return an object containing the row, column, and value of the selected
+ * cell.
+ *
+ * @return {undefined|!Object}
+ */
+ get selectedCell() {
+ var row = this.selectedTableRow;
+ var columnIndex = this.selectedColumnIndex;
+ if (row === undefined || columnIndex === undefined ||
+ this.tableColumns_.length <= columnIndex)
+ return undefined;
+ var column = this.tableColumns_[columnIndex];
+ return {
+ row: row,
+ column: column,
+ value: column.value(row)
+ };
+ },
- setSelectedState_: function(select) {
- if (this.selectedTableRowInfo_ === undefined)
- return;
+ /**
+ * If a column is selected, return the object describing the selected
+ * column.
+ *
+ * Columns can be selected independently of rows and cells. So it is
+ * possible to select column 0 and cell [0,0], or column 1 and cell [0,0],
+ * for example. See |selectedCell| for how to access the selected cell when
+ * the selectionMode is CELL.
+ *
+ * |selectedTableColumn| is entirely independent of |selectedColumnIndex|.
+ * When the table selectionMode is CELL, use |selectedTableRow| and
+ * |selectedColumnIndex| to find the selected cell.
+ * When one or more columns have |selectable:true|, then use
+ * |selectedTableColumn| to find the selected column, which may be either
+ * the same as or different from |selectedColumnIndex|, if a cell is also
+ * selected.
+ *
+ * @return {number|undefined}
+ */
+ get selectedTableColumnIndex() {
+ var cols = Polymer.dom(this.$.cols).children;
+ for (var i = 0; i < cols.length; ++i) {
+ if (cols[i].getAttribute('selected')) {
+ return i;
+ }
+ }
+ return undefined;
+ },
- // Row selection.
- var rowNode = this.selectedTableRowInfo_.htmlNode;
- if (select)
- rowNode.setAttribute('selected', true);
+ /**
+ * @param {number|undefined} index
+ */
+ set selectedTableColumnIndex(selectedIndex) {
+ var cols = Polymer.dom(this.$.cols).children;
+ for (var i = 0; i < cols.length; ++i) {
+ if (i === selectedIndex)
+ cols[i].setAttribute('selected', true);
else
- rowNode.removeAttribute('selected');
+ cols[i].removeAttribute('selected');
+ }
+ },
- // Cell selection (if applicable).
- var cellNode = rowNode.children[this.selectedColumnIndex_];
- if (!cellNode)
- return;
- if (select)
- cellNode.setAttribute('selected', true);
- else
- cellNode.removeAttribute('selected');
- },
+ get selectedTableRow() {
+ if (!this.selectedTableRowInfo_)
+ return undefined;
+ return this.selectedTableRowInfo_.userRow;
+ },
- doesColumnIndexSupportSelection: function(columnIndex) {
- var columnInfo = this.tableColumns_[columnIndex];
- var scs = columnInfo.supportsCellSelection;
- if (scs === false)
- return false;
- return true;
- },
+ set selectedTableRow(userRow) {
+ this.rebuildIfNeeded_();
+ if (this.selectionMode_ === SelectionMode.NONE)
+ throw new Error('Selection is off.');
+
+ var rowInfo;
+ if (userRow === undefined) {
+ rowInfo = undefined;
+ } else {
+ rowInfo = this.tableRowsInfo_.get(userRow);
+ if (!rowInfo)
+ throw new Error('Row has not been seen, must expand its parents.');
+ }
- getFirstSelectableColumnIndex_: function() {
- for (var i = 0; i < this.tableColumns_.length; i++) {
- if (this.doesColumnIndexSupportSelection(i))
- return i;
- }
- return -1;
- },
+ var e = this.prepareToChangeSelection_();
- getSelectableNodeGivenTableRowNode_: function(htmlNode) {
+ if (!rowInfo) {
+ this.selectedColumnIndex_ = undefined;
+ } else {
switch (this.selectionMode_) {
case SelectionMode.ROW:
- return htmlNode;
+ this.selectedColumnIndex_ = undefined;
+ break;
case SelectionMode.CELL:
- return htmlNode.children[this.selectedColumnIndex_];
+ if (this.selectedColumnIndex_ === undefined) {
+ var i = this.getFirstSelectableColumnIndex_();
+ if (i === -1)
+ throw new Error('Cannot find a selectable column.');
+ this.selectedColumnIndex_ = i;
+ }
+ break;
default:
throw new Error('Invalid selection mode ' + this.selectionMode_);
}
- },
-
- get selectedColumnIndex() {
- if (this.selectionMode_ !== SelectionMode.CELL)
- return undefined;
- return this.selectedColumnIndex_;
- },
-
- set selectedColumnIndex(selectedColumnIndex) {
- this.rebuildIfNeeded_();
- if (this.selectionMode_ === SelectionMode.NONE)
- throw new Error('Selection is off.');
- if (selectedColumnIndex < 0 ||
- selectedColumnIndex >= this.tableColumns_.length)
- throw new Error('Invalid index');
- if (!this.doesColumnIndexSupportSelection(selectedColumnIndex))
- throw new Error('Selection is not supported on this column');
-
- var e = this.prepareToChangeSelection_();
- this.selectedColumnIndex_ = selectedColumnIndex;
- if (this.selectedColumnIndex_ === undefined)
- this.selectedTableRowInfo_ = undefined;
- this.updateSelectedState_();
+ }
- this.dispatchEvent(e);
- },
+ this.selectedTableRowInfo_ = rowInfo;
+ this.updateSelectedState_();
+ this.dispatchEvent(e);
+ },
- onKeyDown_: function(e) {
- if (this.selectionMode_ === SelectionMode.NONE)
- return;
- if (this.selectedTableRowInfo_ === undefined)
- return;
+ prepareToChangeSelection_: function() {
+ var e = new tr.b.Event('selection-changed');
+ var previousSelectedRowInfo = this.selectedTableRowInfo_;
+ if (previousSelectedRowInfo)
+ e.previousSelectedTableRow = previousSelectedRowInfo.userRow;
+ else
+ e.previousSelectedTableRow = undefined;
- var code_to_command_names = {
- 13: 'ENTER',
- 37: 'ARROW_LEFT',
- 38: 'ARROW_UP',
- 39: 'ARROW_RIGHT',
- 40: 'ARROW_DOWN'
- };
- var cmdName = code_to_command_names[e.keyCode];
- if (cmdName === undefined)
- return;
+ this.removeSelectedState_();
- e.stopPropagation();
- e.preventDefault();
- this.performKeyCommand_(cmdName);
- },
-
- performKeyCommand_: function(cmdName) {
- this.rebuildIfNeeded_();
-
- var rowInfo = this.selectedTableRowInfo_;
- var htmlNode = rowInfo.htmlNode;
- if (cmdName === 'ARROW_UP') {
- var prev = htmlNode.previousElementSibling;
- if (prev) {
- tr.ui.b.scrollIntoViewIfNeeded(prev);
- this.selectedTableRow = prev.rowInfo.userRow;
- this.focusSelected_();
- return;
- }
+ return e;
+ },
+
+ removeSelectedState_: function() {
+ this.setSelectedState_(false);
+ },
+
+ updateSelectedState_: function() {
+ this.setSelectedState_(true);
+ },
+
+ setSelectedState_: function(select) {
+ if (this.selectedTableRowInfo_ === undefined)
+ return;
+
+ // Row selection.
+ var rowNode = this.selectedTableRowInfo_.htmlNode;
+ if (select)
+ Polymer.dom(rowNode).setAttribute('selected', true);
+ else
+ Polymer.dom(rowNode).removeAttribute('selected');
+
+ // Cell selection (if applicable).
+ var cellNode = Polymer.dom(rowNode).children[this.selectedColumnIndex_];
+ if (!cellNode)
+ return;
+ if (select)
+ Polymer.dom(cellNode).setAttribute('selected', true);
+ else
+ Polymer.dom(cellNode).removeAttribute('selected');
+ },
+
+ doesColumnIndexSupportSelection: function(columnIndex) {
+ var columnInfo = this.tableColumns_[columnIndex];
+ var scs = columnInfo.supportsCellSelection;
+ if (scs === false)
+ return false;
+ return true;
+ },
+
+ getFirstSelectableColumnIndex_: function() {
+ for (var i = 0; i < this.tableColumns_.length; i++) {
+ if (this.doesColumnIndexSupportSelection(i))
+ return i;
+ }
+ return -1;
+ },
+
+ getSelectableNodeGivenTableRowNode_: function(htmlNode) {
+ switch (this.selectionMode_) {
+ case SelectionMode.ROW:
+ return htmlNode;
+
+ case SelectionMode.CELL:
+ return Polymer.dom(htmlNode).children[this.selectedColumnIndex_];
+
+ default:
+ throw new Error('Invalid selection mode ' + this.selectionMode_);
+ }
+ },
+
+ get selectedColumnIndex() {
+ if (this.selectionMode_ !== SelectionMode.CELL)
+ return undefined;
+ return this.selectedColumnIndex_;
+ },
+
+ set selectedColumnIndex(selectedColumnIndex) {
+ this.rebuildIfNeeded_();
+ if (this.selectionMode_ === SelectionMode.NONE)
+ throw new Error('Selection is off.');
+ if (selectedColumnIndex < 0 ||
+ selectedColumnIndex >= this.tableColumns_.length)
+ throw new Error('Invalid index');
+ if (!this.doesColumnIndexSupportSelection(selectedColumnIndex))
+ throw new Error('Selection is not supported on this column');
+
+ var e = this.prepareToChangeSelection_();
+ if (this.selectedColumnIndex_ === undefined) {
+ this.selectedTableRowInfo_ = undefined;
+ } else if (!this.selectedTableRowInfo_) {
+ if (this.tableRows_.length === 0)
+ throw new Error('No available row to be selected');
+ this.selectedTableRowInfo_ =
+ this.tableRowsInfo_.get(this.tableRows_[0]);
+ }
+ this.selectedColumnIndex_ = selectedColumnIndex;
+ this.updateSelectedState_();
+ this.dispatchEvent(e);
+ },
+
+ onKeyDown_: function(e) {
+ if (this.selectionMode_ === SelectionMode.NONE)
+ return;
+
+ var CODE_TO_COMMAND_NAMES = {
+ 13: 'ENTER',
+ 32: 'SPACE',
+ 37: 'ARROW_LEFT',
+ 38: 'ARROW_UP',
+ 39: 'ARROW_RIGHT',
+ 40: 'ARROW_DOWN'
+ };
+ var cmdName = CODE_TO_COMMAND_NAMES[e.keyCode];
+ if (cmdName === undefined)
+ return;
+
+ e.stopPropagation();
+ e.preventDefault();
+ this.performKeyCommand_(cmdName);
+ },
+
+ onFocus_: function(e) {
+ if (this.selectionMode_ === SelectionMode.NONE ||
+ this.selectedTableRowInfo_ ||
+ this.tableRows_.length === 0) {
+ return;
+ }
+
+ if (this.selectionMode_ === SelectionMode.CELL &&
+ this.getFirstSelectableColumnIndex_() === -1) {
+ // If there are no selectable columns in cell selection mode, don't do
+ // anything.
+ return;
+ }
+
+ this.selectedTableRow = this.tableRows_[0];
+ },
+
+ focus: function() {
+ this.$.body.focus();
+ },
+
+ blur: function() {
+ this.$.body.blur();
+ },
+
+ get isFocused() {
+ return this.root.activeElement === this.$.body;
+ },
+
+ performKeyCommand_: function(cmdName) {
+ this.rebuildIfNeeded_();
+
+ switch (cmdName) {
+ case 'ARROW_UP':
+ this.selectPreviousOrFirstRowIfPossible_();
return;
- }
- if (cmdName === 'ARROW_DOWN') {
- var next = htmlNode.nextElementSibling;
- if (next) {
- tr.ui.b.scrollIntoViewIfNeeded(next);
- this.selectedTableRow = next.rowInfo.userRow;
- this.focusSelected_();
- return;
- }
+ case 'ARROW_DOWN':
+ this.selectNextOrFirstRowIfPossible_();
return;
- }
- if (cmdName === 'ARROW_RIGHT') {
+ case 'ARROW_RIGHT':
switch (this.selectionMode_) {
+ case SelectionMode.NONE:
+ return; // No action.
case SelectionMode.ROW:
- if (rowInfo.userRow[this.subRowsPropertyName_] === undefined)
- return;
- if (rowInfo.userRow[this.subRowsPropertyName_].length === 0)
- return;
-
- if (!rowInfo.isExpanded)
- this.setExpandedForTableRow(rowInfo.userRow, true);
- this.selectedTableRow =
- htmlNode.nextElementSibling.rowInfo.userRow;
- this.focusSelected_();
+ this.expandRowAndSelectChildRowIfPossible_();
return;
-
case SelectionMode.CELL:
- var newIndex = this.selectedColumnIndex_ + 1;
- if (newIndex >= this.tableColumns_.length)
- return;
- if (!this.doesColumnIndexSupportSelection(newIndex))
- return;
- this.selectedColumnIndex = newIndex;
- this.focusSelected_();
+ this.selectNextSelectableCellToTheRightIfPossible_();
return;
-
default:
throw new Error('Invalid selection mode ' + this.selectionMode_);
}
- }
- if (cmdName === 'ARROW_LEFT') {
+ case 'ARROW_LEFT':
switch (this.selectionMode_) {
+ case SelectionMode.NONE:
+ return; // No action.
case SelectionMode.ROW:
- if (rowInfo.isExpanded) {
- this.setExpandedForTableRow(rowInfo.userRow, false);
- this.focusSelected_();
- return;
- }
-
- // Not expanded. Select parent...
- var parentRowInfo = rowInfo.parentRowInfo;
- if (parentRowInfo) {
- this.selectedTableRow = parentRowInfo.userRow;
- this.focusSelected_();
- return;
- }
+ this.collapseRowOrSelectParentRowIfPossible_();
return;
-
case SelectionMode.CELL:
- var newIndex = this.selectedColumnIndex_ - 1;
- if (newIndex < 0)
- return;
- if (!this.doesColumnIndexSupportSelection(newIndex))
- return;
- this.selectedColumnIndex = newIndex;
- this.focusSelected_();
+ this.selectNextSelectableCellToTheLeftIfPossible_();
return;
-
default:
throw new Error('Invalid selection mode ' + this.selectionMode_);
}
+
+ case 'SPACE':
+ this.toggleRowExpansionStateIfPossible_();
+ return;
+
+ case 'ENTER':
+ this.stepIntoSelectionIfPossible_();
+ return;
+
+ default:
+ throw new Error('Unrecognized command ' + cmdName);
+ }
+ },
+
+ selectPreviousOrFirstRowIfPossible_: function() {
+ var prev = this.selectedTableRowInfo_ ?
+ this.selectedTableRowInfo_.htmlNode.previousElementSibling :
+ this.$.body.firstChild;
+ if (!prev)
+ return;
+ if (this.selectionMode_ === SelectionMode.CELL &&
+ this.getFirstSelectableColumnIndex_() === -1) {
+ // If there are no selectable columns in cell selection mode, don't do
+ // anything.
+ return;
+ }
+ tr.ui.b.scrollIntoViewIfNeeded(prev);
+ this.selectedTableRow = prev.rowInfo.userRow;
+ },
+
+ selectNextOrFirstRowIfPossible_: function() {
+ this.getFirstSelectableColumnIndex_
+ var next = this.selectedTableRowInfo_ ?
+ this.selectedTableRowInfo_.htmlNode.nextElementSibling :
+ this.$.body.firstChild;
+ if (!next)
+ return;
+ if (this.selectionMode_ === SelectionMode.CELL &&
+ this.getFirstSelectableColumnIndex_() === -1) {
+ // If there are no selectable columns in cell selection mode, don't do
+ // anything.
+ return;
+ }
+ tr.ui.b.scrollIntoViewIfNeeded(next);
+ this.selectedTableRow = next.rowInfo.userRow;
+ },
+
+ expandRowAndSelectChildRowIfPossible_: function() {
+ var selectedRowInfo = this.selectedTableRowInfo_;
+ if (!selectedRowInfo ||
+ selectedRowInfo.userRow[this.subRowsPropertyName_] === undefined ||
+ selectedRowInfo.userRow[this.subRowsPropertyName_].length === 0) {
+ return;
+ }
+ if (!selectedRowInfo.isExpanded)
+ this.setExpandedForTableRow(selectedRowInfo.userRow, true);
+ this.selectedTableRow =
+ selectedRowInfo.htmlNode.nextElementSibling.rowInfo.userRow;
+ },
+
+ collapseRowOrSelectParentRowIfPossible_: function() {
+ var selectedRowInfo = this.selectedTableRowInfo_;
+ if (!selectedRowInfo)
+ return;
+ if (selectedRowInfo.isExpanded) {
+ // If the node is expanded, collapse it.
+ this.setExpandedForTableRow(selectedRowInfo.userRow, false);
+ } else {
+ // If the node is not expanded, select its parent.
+ var parentRowInfo = selectedRowInfo.parentRowInfo;
+ if (parentRowInfo)
+ this.selectedTableRow = parentRowInfo.userRow;
+ }
+ },
+
+ selectNextSelectableCellToTheRightIfPossible_: function() {
+ if (!this.selectedTableRowInfo_ ||
+ this.selectedColumnIndex_ === undefined) {
+ return;
+ }
+ for (var i = this.selectedColumnIndex_ + 1; i < this.tableColumns_.length;
+ i++) {
+ if (this.doesColumnIndexSupportSelection(i)) {
+ this.selectedColumnIndex = i;
+ return;
}
+ }
+ },
- if (cmdName === 'ENTER') {
- if (rowInfo.userRow[this.subRowsPropertyName_] === undefined)
- return;
- if (rowInfo.userRow[this.subRowsPropertyName_].length === 0)
- return;
- this.setExpandedForTableRow(rowInfo.userRow, !rowInfo.isExpanded);
- this.focusSelected_();
+ selectNextSelectableCellToTheLeftIfPossible_: function() {
+ if (!this.selectedTableRowInfo_ ||
+ this.selectedColumnIndex_ === undefined) {
+ return;
+ }
+ for (var i = this.selectedColumnIndex_ - 1; i >= 0; i--) {
+ if (this.doesColumnIndexSupportSelection(i)) {
+ this.selectedColumnIndex = i;
return;
}
+ }
+ },
+
+ toggleRowExpansionStateIfPossible_: function() {
+ var selectedRowInfo = this.selectedTableRowInfo_;
+ if (!selectedRowInfo ||
+ selectedRowInfo.userRow[this.subRowsPropertyName_] === undefined ||
+ selectedRowInfo.userRow[this.subRowsPropertyName_].length === 0) {
+ return;
+ }
+ this.setExpandedForTableRow(selectedRowInfo.userRow,
+ !selectedRowInfo.isExpanded);
+ },
- throw new Error('Unrecognized command ' + cmdName);
- },
+ stepIntoSelectionIfPossible_: function() {
+ if (!this.selectedTableRowInfo_)
+ return;
+ this.dispatchStepIntoEvent_(this.selectedTableRowInfo_,
+ this.selectedColumnIndex_);
+ },
- focusSelected_: function() {
- if (!this.selectedTableRowInfo_)
- return;
- var node = this.getSelectableNodeGivenTableRowNode_(
- this.selectedTableRowInfo_.htmlNode);
- node.focus();
- },
-
- dispatchSortingChangedEvent_: function() {
- var e = new tr.b.Event('sort-column-changed');
- e.sortColumnIndex = this.sortColumnIndex_;
- e.sortDescending = this.sortDescending_;
- this.dispatchEvent(e);
- }
- });
- })();
- </script>
-</polymer-element>
-<polymer-element name="tr-ui-b-table-header-cell" on-tap="onTap_">
+ dispatchSortingChangedEvent_: function() {
+ var e = new tr.b.Event('sort-column-changed');
+ e.sortColumnIndex = this.sortColumnIndex_;
+ e.sortDescending = this.sortDescending_;
+ this.dispatchEvent(e);
+ }
+ });
+})();
+</script>
+
+<dom-module id="tr-ui-b-table-header-cell">
<template>
<style>
:host {
@@ -1380,94 +1623,131 @@ tr.exportTo('tr.ui.b', function() {
flex: 0 1 auto;
}
- side-element {
+ #side {
-webkit-user-select: none;
flex: 0 0 auto;
- padding-left: 4px;
+ padding-left: 2px;
+ padding-right: 2px;
vertical-align: top;
font-size: 15px;
font-family: sans-serif;
- display: inline;
line-height: 85%;
+ margin-left: 5px;
}
- </style>
-
- <span id="title"></span><side-element id="side"></side-element>
- </template>
- <script>
- 'use strict';
+ #side.disabled {
+ color: rgb(140, 140, 140);
+ }
- var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment;
+ #title:empty, #side:empty {
+ display: none;
+ }
+ </style>
- Polymer({
- created: function() {
- this.tapCallback_ = undefined;
- this.cellTitle_ = '';
- this.align_ = undefined;
- },
+ <span id="title"></span>
+ <span id="side"></span>
+ </template>
+</dom-module>
+<script>
+'use strict';
- set cellTitle(value) {
- this.cellTitle_ = value;
+var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment;
- var titleNode = tr.ui.b.asHTMLOrTextNode(
- this.cellTitle_, this.ownerDocument);
+Polymer({
+ is: 'tr-ui-b-table-header-cell',
- this.$.title.innerText = '';
- this.$.title.appendChild(titleNode);
- },
+ created: function() {
+ this.tapCallback_ = undefined;
+ this.cellTitle_ = '';
+ this.align_ = undefined;
+ this.selectable_ = false;
+ this.column_ = undefined;
+ },
- get cellTitle() {
- return this.cellTitle_;
- },
+ ready: function() {
+ this.addEventListener('click', this.onTap_.bind(this));
+ },
- set align(align) {
- switch (align) {
- case undefined:
- case ColumnAlignment.LEFT:
- this.style.justifyContent = '';
- break;
+ set column(column) {
+ this.column_ = column;
+ this.align = column.align;
+ this.cellTitle = column.title;
+ },
- case ColumnAlignment.RIGHT:
- this.style.justifyContent = 'flex-end';
- break;
+ get column() {
+ return this.column_;
+ },
- default:
- throw new Error('Invalid alignment of column (title=\'' +
- this.cellTitle_ + '\'): ' + align);
- }
- this.align_ = align;
- },
+ set cellTitle(value) {
+ this.cellTitle_ = value;
- get align() {
- return this.align_;
- },
+ var titleNode = tr.ui.b.asHTMLOrTextNode(
+ this.cellTitle_, this.ownerDocument);
- clearSideContent: function() {
- this.$.side.textContent = '';
- },
+ this.$.title.innerText = '';
- set sideContent(content) {
- this.$.side.textContent = content;
- },
+ Polymer.dom(this.$.title).appendChild(titleNode);
+ },
- get sideContent() {
- return this.$.side.textContent;
- },
+ get cellTitle() {
+ return this.cellTitle_;
+ },
- set tapCallback(callback) {
- this.style.cursor = 'pointer';
- this.tapCallback_ = callback;
- },
+ set align(align) {
+ switch (align) {
+ case undefined:
+ case ColumnAlignment.LEFT:
+ this.style.justifyContent = '';
+ break;
- get tapCallback() {
- return this.tapCallback_;
- },
+ case ColumnAlignment.RIGHT:
+ this.style.justifyContent = 'flex-end';
+ break;
- onTap_: function() {
- if (this.tapCallback_)
- this.tapCallback_();
+ default:
+ throw new Error('Invalid alignment of column (title=\'' +
+ this.cellTitle_ + '\'): ' + align);
}
- });
+ this.align_ = align;
+ },
+
+ get align() {
+ return this.align_;
+ },
+
+ clearSideContent: function() {
+ Polymer.dom(this.$.side).textContent = '';
+ },
+
+ set sideContent(content) {
+ Polymer.dom(this.$.side).textContent = content;
+ this.$.side.style.display = content ? 'inline' : 'none';
+ },
+
+ get sideContent() {
+ return Polymer.dom(this.$.side).textContent;
+ },
+
+ set sideContentDisabled(sideContentDisabled) {
+ this.$.side.classList.toggle('disabled', sideContentDisabled);
+ },
+
+ get sideContentDisabled() {
+ return this.$.side.classList.contains('disabled');
+ },
+
+ set tapCallback(callback) {
+ this.style.cursor = 'pointer';
+ this.tapCallback_ = callback;
+ },
+
+ get tapCallback() {
+ return this.tapCallback_;
+ },
+
+ onTap_: function() {
+ if (this.tapCallback_)
+ this.tapCallback_();
+ }
+});
</script>
-</polymer-element>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html
index f6ba5eb35dd..d822c251262 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html
@@ -8,8 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<polymer-element name="tr-ui-b-table-header-cell"
- on-tap="onTap_">
+<dom-module id='tr-ui-b-table-header-cell'>
<template>
<style>
:host {
@@ -35,11 +34,17 @@ found in the LICENSE file.
<span id="title"></span><side-element id="side"></side-element>
</template>
-
+</dom-module>
<script>
'use strict';
Polymer({
+ is: 'tr-ui-b-table-header-cell',
+
+ listeners: {
+ 'tap': 'onTap_'
+ },
+
created: function() {
this.tapCallback_ = undefined;
this.cellTitle_ = '';
@@ -52,7 +57,7 @@ found in the LICENSE file.
tr.ui.b.asHTMLOrTextNode(this.cellTitle_, this.ownerDocument);
this.$.title.innerText = '';
- this.$.title.appendChild(titleNode);
+ Polymer.dom(this.$.title).appendChild(titleNode);
},
get cellTitle() {
@@ -60,15 +65,15 @@ found in the LICENSE file.
},
clearSideContent: function() {
- this.$.side.textContent = '';
+ Polymer.dom(this.$.side).textContent = '';
},
set sideContent(content) {
- this.$.side.textContent = content;
+ Polymer.dom(this.$.side).textContent = content;
},
get sideContent() {
- return this.$.side.textContent;
+ return Polymer.dom(this.$.side).textContent;
},
set tapCallback(callback) {
@@ -86,4 +91,3 @@ found in the LICENSE file.
}
});
</script>
-</polymer-element>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html
index 0c3504fc318..8778646c562 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html
@@ -12,7 +12,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var THIS_DOC = document._currentScript.ownerDocument;
+ var THIS_DOC = document.currentScript.ownerDocument;
var SelectionMode = tr.ui.b.TableFormat.SelectionMode;
var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle;
var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment;
@@ -23,6 +23,16 @@ tr.b.unittest.testSuite(function() {
return element.getAttribute('selected') === 'true';
}
+ function simulateDoubleClick(element) {
+ // See https://developer.mozilla.org/en/docs/Web/API/MouseEvent#Example.
+ var event = new MouseEvent('dblclick', {
+ bubbles: true,
+ cancelable: true,
+ view: window
+ });
+ return element.dispatchEvent(event);
+ }
+
test('instantiateEmptyTable_withoutEmptyValue', function() {
var columns = [
{
@@ -51,7 +61,7 @@ tr.b.unittest.testSuite(function() {
// Check that the first column has a non-empty header.
var firstColumnTitle = tr.b.findDeepElementMatchingPredicate(
firstColumnHeader, function(element) {
- return element.textContent === 'First Column';
+ return Polymer.dom(element).textContent === 'First Column';
});
assert.isDefined(firstColumnTitle);
@@ -328,7 +338,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(table);
var button = THIS_DOC.createElement('button');
- button.textContent = 'Sort By Col 0';
+ Polymer.dom(button).textContent = 'Sort By Col 0';
button.addEventListener('click', function() {
table.sortDescending = !table.sortDescending;
table.sortColumnIndex = 0;
@@ -374,18 +384,20 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(table);
var a1El = tr.b.findDeepElementMatchingPredicate(table, function(element) {
- return element.textContent == 'a1';
+ return Polymer.dom(element).textContent === 'a1';
});
assert.isDefined(a1El);
var bToplevelEl = tr.b.findDeepElementMatchingPredicate(
table,
function(element) {
- return element.textContent == 'bToplevel';
+ return Polymer.dom(element).textContent === 'bToplevel';
});
assert.isDefined(bToplevelEl);
- var expandButton = bToplevelEl.parentElement.querySelector('expand-button');
- assert.isTrue(expandButton.classList.contains('button-expanded'));
+ var expandButton = Polymer.dom(bToplevelEl.parentElement)
+ .querySelector('expand-button');
+ assert.isTrue(Polymer.dom(expandButton).classList.contains(
+ 'button-expanded'));
});
@@ -692,7 +704,7 @@ tr.b.unittest.testSuite(function() {
var r2 = table.$.body.children[2];
assert.equal(r2.rowInfo.userRow, rows[0].subRows[2]);
- assert.isFalse(r0.hasAttribute('tabIndex'));
+ assert.isFalse(table.$.body.hasAttribute('tabindex'));
});
function createSimpleOneColumnNestedTable() {
@@ -742,6 +754,69 @@ tr.b.unittest.testSuite(function() {
return table;
}
+ function createMultiColumnNestedTable() {
+ var table = document.createElement('tr-ui-b-table');
+
+ var columns = [
+ {
+ title: 'Title',
+ value: function(row) { return row.value; },
+ cmp: function(rowA, rowB) {
+ return rowA.value.toString().localeCompare(
+ rowB.value.toString());
+ },
+ width: '150px',
+ supportsCellSelection: false
+ },
+ {
+ title: 'A',
+ value: function(row) { return row.a; },
+ width: '25%'
+ },
+ {
+ title: 'B',
+ value: function(row) { return row.b; },
+ width: '25%'
+ },
+ {
+ title: 'C',
+ value: function(row) { return row.c; },
+ width: '25%',
+ supportsCellSelection: false
+ },
+ {
+ title: 'D',
+ value: function(row) { return row.d; },
+ width: '25%'
+ }
+ ];
+
+ var rows = [
+ {
+ value: 'R1',
+ a: 1, b: 2, c: 3, d: 4,
+ subRows: [
+ {
+ value: 'R1.1',
+ a: 2, b: 3, c: 4, d: 1,
+ },
+ {
+ value: 'R1.2',
+ a: 3, b: 4, c: 1, d: 2,
+ }
+ ]
+ },
+ {
+ value: 'R2',
+ a: 3, b: 4, c: 1, d: 2
+ }
+ ];
+
+ table.tableColumns = columns;
+ table.tableRows = rows;
+ return table;
+ }
+
test('expandAfterRebuild', function() {
var table = createSimpleOneColumnNestedTable();
table.rebuild();
@@ -759,32 +834,38 @@ tr.b.unittest.testSuite(function() {
});
test('tableSelection', function() {
- var table = createSimpleOneColumnNestedTable();
+ var table = createMultiColumnNestedTable();
var rows = table.tableRows;
table.selectionMode = SelectionMode.ROW;
table.selectedTableRow = rows[0];
+ assert.isUndefined(table.selectedColumnIndex);
table.setExpandedForTableRow(rows[0], true);
table.selectedTableRow = rows[0].subRows[1];
- assert.equal(table.selectedTableRow, rows[0].subRows[1]);
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[1]);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ table.selectionMode = SelectionMode.CELL;
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[1]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
table.setExpandedForTableRow(rows[0], false);
- assert.equal(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
table.selectionMode = SelectionMode.NONE;
- assert.equal(table.selectedTableRow, undefined);
+ assert.strictEqual(table.selectedTableRow, undefined);
table.selectionMode = SelectionMode.ROW;
table.setExpandedForTableRow(rows[0].subRows[1], true);
this.addHTMLOutput(table);
- var r0 = table.$.body.children[0];
- assert.isTrue(r0.hasAttribute('tabIndex'));
+ assert.isTrue(table.$.body.hasAttribute('tabindex'));
});
- test('keyMovement', function() {
+ test('keyMovement_rows', function() {
var table = createSimpleOneColumnNestedTable();
table.selectionMode = SelectionMode.ROW;
this.addHTMLOutput(table);
@@ -800,11 +881,11 @@ tr.b.unittest.testSuite(function() {
// Enter on collapsed row should expand.
table.selectedTableRow = rows[0];
- table.performKeyCommand_('ENTER');
+ table.performKeyCommand_('SPACE');
assert.equal(table.selectedTableRow, rows[0]);
assert.isTrue(table.getExpandedForTableRow(rows[0]));
- table.performKeyCommand_('ENTER');
+ table.performKeyCommand_('SPACE');
assert.isFalse(table.getExpandedForTableRow(rows[0]));
// Arrow right on collapsed row should expand.
@@ -838,6 +919,315 @@ tr.b.unittest.testSuite(function() {
assert.isFalse(table.getExpandedForTableRow(rows[1]));
});
+ test('keyMovement_cells', function() {
+ var table = createMultiColumnNestedTable();
+ table.selectionMode = SelectionMode.CELL;
+ this.addHTMLOutput(table);
+
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ var rows = table.tableRows;
+ table.selectedTableRow = rows[1];
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ table.performKeyCommand_('ARROW_LEFT');
+ assert.strictEqual(table.selectedTableRow, rows[1]);
+ // No-op (leftmost selectable cell already selected).
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ table.performKeyCommand_('ARROW_UP');
+ // No-op (top row already selected).
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ table.performKeyCommand_('ARROW_UP');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ table.performKeyCommand_('ARROW_RIGHT');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 2);
+ // Right arrow should NOT expand nested rows in cell selection mode.
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_RIGHT');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 4);
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_RIGHT');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ // No-op (rightmost selectable cell already selected).
+ assert.strictEqual(table.selectedColumnIndex, 4);
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('SPACE');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 4);
+ // Space on collapsed row should expand it.
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_DOWN');
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 4);
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_LEFT');
+ // Left arrow should NOT move to parent row.
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 2);
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_LEFT');
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_LEFT');
+ assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]);
+ // No-op (leftmost selectable cell already selected).
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_UP');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_LEFT');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ // No-op (leftmost selectable cell already selected).
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ // Left arrow should NOT collapse nested rows in cell selection mode.
+ assert.isTrue(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('SPACE');
+ assert.strictEqual(table.selectedTableRow, rows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ // Space on expanded row should collapse it.
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_DOWN');
+ assert.strictEqual(table.selectedTableRow, rows[1]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+
+ table.performKeyCommand_('ARROW_DOWN');
+ // No-op (bottom row already selected).
+ assert.strictEqual(table.selectedTableRow, rows[1]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ assert.isFalse(table.getExpandedForTableRow(rows[0]));
+ });
+
+ test('focus_empty', function() {
+ var table = createSimpleOneColumnNestedTable();
+ table.tableRows = [];
+ table.emptyValue = 'This table is left intentionally empty';
+ this.addHTMLOutput(table);
+
+ assert.isFalse(table.$.body.hasAttribute('tabindex'));
+ assert.isFalse(table.isFocused);
+
+ for (var selectionMode of [SelectionMode.ROW, SelectionMode.CELL]) {
+ table.selectionMode = selectionMode;
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually focus.
+ table.focus();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually unfocus.
+ table.blur();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually focus again.
+ table.focus();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Unfocus via removing selection mode.
+ table.selectionMode = SelectionMode.NONE;
+ assert.isFalse(table.$.body.hasAttribute('tabindex'));
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+ }
+
+ // Re-enable selection mode (for interactive testing).
+ table.selectionMode = SelectionMode.ROW;
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+ });
+
+ test('focus_rows', function() {
+ var table = createSimpleOneColumnNestedTable();
+ table.selectionMode = SelectionMode.ROW;
+ this.addHTMLOutput(table);
+
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually focus.
+ table.focus();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually unfocus.
+ table.blur();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Trigger focus via clicking.
+ table.$.body.children[1].children[0].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[1]);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Unfocus via removing selection mode.
+ table.selectionMode = SelectionMode.NONE;
+ assert.isFalse(table.$.body.hasAttribute('tabindex'));
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Re-enable selection mode.
+ table.selectionMode = SelectionMode.ROW;
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Programatically select row (should NOT steal focus).
+ table.selectedTableRow = table.tableRows[0];
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Trigger focus on the already selected row by clicking.
+ table.$.body.children[0].children[0].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.isUndefined(table.selectedColumnIndex);
+ });
+
+ test('focus_cells', function() {
+ var table = createMultiColumnNestedTable();
+ table.selectionMode = SelectionMode.CELL;
+ this.addHTMLOutput(table);
+
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually focus.
+ table.focus();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ // Manually unfocus.
+ table.blur();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ // Trigger focus via clicking.
+ table.$.body.children[1].children[4].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[1]);
+ assert.strictEqual(table.selectedColumnIndex, 4);
+
+ // Unfocus via removing selection mode.
+ table.selectionMode = SelectionMode.NONE;
+ assert.isFalse(table.$.body.hasAttribute('tabindex'));
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Re-enable selection mode.
+ table.selectionMode = SelectionMode.CELL;
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Clicking on an unselectable cell should NOT trigger focus.
+ table.$.body.children[1].children[0].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Programatically select cell (should NOT steal focus).
+ table.selectedTableRow = table.tableRows[0];
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+
+ // Trigger focus on the already selected cell by clicking.
+ table.$.body.children[0].children[1].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.strictEqual(table.selectedTableRow, table.tableRows[0]);
+ assert.strictEqual(table.selectedColumnIndex, 1);
+ });
+
+ test('focus_allCellsUnselectable', function() {
+ var table = createMultiColumnNestedTable();
+ table.selectionMode = SelectionMode.CELL;
+ for (var c of table.tableColumns)
+ c.supportsCellSelection = false;
+ table.tableColumns = table.tableColumns;
+ this.addHTMLOutput(table);
+
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isFalse(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Manually focus (no automatic selection).
+ table.focus();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+
+ // Trigger focus via clicking (no selection).
+ table.$.body.children[1].children[2].click();
+ assert.strictEqual(table.$.body.getAttribute('tabindex'), '0');
+ assert.isTrue(table.isFocused);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+ });
+
test('RightArrowKeyWhenTableSorted', function() {
var table = createSimpleOneColumnNestedTable();
table.selectionMode = SelectionMode.ROW;
@@ -1014,6 +1404,10 @@ tr.b.unittest.testSuite(function() {
table.selectedTableRow = table.tableRows[0];
assert.equal(table.selectedColumnIndex, 1);
+ var selectedCell = table.selectedCell;
+ assert.strictEqual(selectedCell.row, table.tableRows[0]);
+ assert.strictEqual(selectedCell.column, columns[1]);
+ assert.strictEqual(selectedCell.value, '1');
table.performKeyCommand_('ARROW_DOWN');
table.performKeyCommand_('ARROW_RIGHT');
@@ -1021,11 +1415,16 @@ tr.b.unittest.testSuite(function() {
table.performKeyCommand_('ARROW_LEFT');
assert.equal(table.selectedTableRow, table.tableRows[1]);
assert.equal(table.selectedColumnIndex, 2);
+ selectedCell = table.selectedCell;
+ assert.strictEqual(selectedCell.row, table.tableRows[1]);
+ assert.strictEqual(selectedCell.column, columns[2]);
+ assert.strictEqual(selectedCell.value, 4);
table.selectedTableRow = undefined;
- assert.equal(table.selectedTableRow, undefined);
- assert.equal(table.selectedColumnIndex, undefined);
- assert.equal(table.selectedColumnIndex, undefined);
+ assert.isUndefined(table.selectedTableRow);
+ assert.isUndefined(table.selectedColumnIndex);
+ assert.isUndefined(table.selectedColumnIndex);
+ assert.isUndefined(table.selectedCell);
});
test('cellSelectionNested', function() {
@@ -1161,8 +1560,10 @@ tr.b.unittest.testSuite(function() {
var firstColumnHeader = table.$.head.children[0].children[0].children[0];
var secondColumnHeader = table.$.head.children[0].children[1].children[0];
- assert.equal(firstColumnHeader.cellTitle.textContent, 'First Column');
- assert.equal(secondColumnHeader.cellTitle.textContent, 'Second Column');
+ assert.equal(Polymer.dom(firstColumnHeader.cellTitle).textContent,
+ 'First Column');
+ assert.equal(Polymer.dom(secondColumnHeader.cellTitle).textContent,
+ 'Second Column');
});
test('align', function() {
@@ -1215,7 +1616,8 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(table);
- assert.equal(2, table.$.body.children[1].children[0].textContent);
+ assert.equal(
+ 2, Polymer.dom(table.$.body.children[1].children[0]).textContent);
});
test('shouldNotRenderUndefined', function() {
@@ -1241,7 +1643,7 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(table);
// check that we don't have 'undefined' anywhere
- assert.isTrue(table.$.body.innerHTML.indexOf('undefined') < 0);
+ assert.isTrue(Polymer.dom(table.$.body).innerHTML.indexOf('undefined') < 0);
});
test('customizeTableRowCallback', function() {
@@ -1367,7 +1769,7 @@ tr.b.unittest.testSuite(function() {
var cRow = tr.b.findDeepElementMatchingPredicate(
table, function(element) {
- return element.textContent === 'C';
+ return Polymer.dom(element).textContent === 'C';
});
assert.equal(cRow, undefined);
@@ -1392,7 +1794,7 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(callbackCalled);
cRow = tr.b.findDeepElementMatchingPredicate(table, function(element) {
- return element.textContent === 'C';
+ return Polymer.dom(element).textContent === 'C';
});
assert.isDefined(cRow);
});
@@ -1457,5 +1859,226 @@ tr.b.unittest.testSuite(function() {
// Check that 'A' is still expanded.
assert.isDefined(tr.b.findDeepElementMatchingPredicate(table, isB));
});
+
+ test('shouldPreserveSortWhenColumnsChange', function() {
+ var name = {
+ title: 'Name',
+ value: function(row) { return row.name; },
+ };
+
+ var count = {
+ title: 'Count',
+ value: function(row) { return row.count; },
+ cmp: (rowA, rowB) => rowA.a - rowB.a,
+ };
+
+ var otherCount = {
+ title: 'Count',
+ value: function(row) { return row.count; },
+ cmp: (rowA, rowB) => rowA.a - rowB.a,
+ };
+
+ var table = document.createElement('tr-ui-b-table');
+ table.tableColumns = [count];
+ table.sortColumnIndex = 0;
+ table.sortDescending = true;
+ table.rebuild();
+
+ this.addHTMLOutput(table);
+
+ table.tableColumns = [name, count];
+ table.rebuild();
+ assert.strictEqual(1, table.sortColumnIndex);
+ assert.isTrue(table.sortDescending);
+
+ table.sortDescending = false;
+ table.tableColumns = [otherCount, name];
+ table.rebuild();
+ assert.strictEqual(0, table.sortColumnIndex);
+ assert.isFalse(table.sortDescending);
+
+ table.tableColumns = [name];
+ table.rebuild();
+ assert.isUndefined(table.sortColumnIndex);
+ });
+
+ test('userCanModifySortOrder', function() {
+ var table = document.createElement('tr-ui-b-table');
+ table.tableColumns = [
+ {
+ title: 'Name',
+ value: row => row.name
+ },
+ {
+ title: 'colA',
+ value: row => row.a,
+ cmp: (rowA, rowB) => rowA.a - rowB.a
+ },
+ {
+ title: 'colB',
+ value: row => row.b,
+ cmp: (rowA, rowB) => rowA.b - rowB.b
+ }
+ ];
+ table.tableRows = [
+ {name: 'A', a: 42, b: 0},
+ {name: 'B', a: 89, b: 100},
+ {name: 'C', a: 65, b: -273.15}
+ ];
+ table.userCanModifySortOrder = false;
+ table.sortColumnIndex = 2;
+ table.sortDescending = true;
+ table.rebuild();
+ this.addHTMLOutput(table);
+
+ var toggleButton = document.createElement('button');
+ Polymer.dom(toggleButton).textContent =
+ 'Toggle table.userCanModifySortOrder';
+ toggleButton.addEventListener('click', function() {
+ table.userCanModifySortOrder = !table.userCanModifySortOrder;
+ });
+ this.addHTMLOutput(toggleButton);
+
+ var unsetButton = document.createElement('button');
+ Polymer.dom(unsetButton).textContent = 'Unset sort order';
+ unsetButton.addEventListener('click', function() {
+ table.sortColumnIndex = undefined;
+ });
+ this.addHTMLOutput(unsetButton);
+ });
+
+ test('columnSelection', function() {
+ var table = document.createElement('tr-ui-b-table');
+ table.tableColumns = [
+ {
+ title: 'Name',
+ value: (row) => row.name
+ },
+ {
+ title: 'colA',
+ selectable: true,
+ value: (row) => row.a,
+ cmp: (rowA, rowB) => rowA.a - rowB.a
+ },
+ {
+ title: 'colB',
+ selectable: true,
+ value: (row) => row.b,
+ cmp: (rowA, rowB) => rowA.b - rowB.b
+ }
+ ];
+ table.tableRows = [
+ {name: 'foo', a: 42, b: -42},
+ {name: 'bar', a: 57, b: 133}
+ ];
+ table.rebuild();
+ table.selectionMode = SelectionMode.CELL;
+ this.addHTMLOutput(table);
+
+ table.selectedTableColumnIndex = 1;
+ var cols = tr.b.findDeepElementMatchingPredicate(table,
+ e => e.tagName === 'COLGROUP').children;
+ assert.isNull(cols[0].getAttribute('selected'));
+ assert.strictEqual(cols[1].getAttribute('selected'), 'true');
+ assert.isNull(cols[2].getAttribute('selected'));
+ assert.strictEqual(1, table.selectedTableColumnIndex);
+
+ table.selectedTableColumnIndex = undefined;
+ cols = tr.b.findDeepElementMatchingPredicate(table,
+ e => e.tagName === 'COLGROUP').children;
+ assert.isNull(cols[0].getAttribute('selected'));
+ assert.isNull(cols[1].getAttribute('selected'));
+ assert.isNull(cols[2].getAttribute('selected'));
+ assert.isUndefined(table.selectedTableColumnIndex);
+
+ table.selectedTableColumnIndex = 2;
+ cols = tr.b.findDeepElementMatchingPredicate(table,
+ e => e.tagName === 'COLGROUP').children;
+ assert.isNull(cols[0].getAttribute('selected'));
+ assert.isNull(cols[1].getAttribute('selected'));
+ assert.strictEqual(cols[2].getAttribute('selected'), 'true');
+ assert.strictEqual(2, table.selectedTableColumnIndex);
+ });
+
+ test('stepInto', function() {
+ var columns = [
+ {
+ title: 'Title',
+ value: function(row) { return row.a; },
+ width: '150px',
+ supportsCellSelection: false
+ },
+ {
+ title: 'Col1',
+ value: function(row) { return row.b; },
+ width: '33%'
+ },
+ {
+ title: 'Col2',
+ value: function(row) { return row.b * 2; },
+ width: '33%'
+ },
+ {
+ title: 'Col3',
+ value: function(row) { return row.b * 3; },
+ width: '33%'
+ }
+ ];
+ var rows = [
+ {
+ a: 'first',
+ b: '1'
+ },
+ {
+ a: 'second',
+ b: '2'
+ }
+ ];
+
+ var table = document.createElement('tr-ui-b-table');
+
+ var firedStepIntoEvents = [];
+ table.addEventListener('step-into', e => firedStepIntoEvents.push(e));
+
+ table.cellHighlightStyle = HighlightStyle.DARK;
+ table.tableColumns = columns;
+ table.tableRows = rows;
+ table.rebuild();
+ this.addHTMLOutput(table);
+
+ assert.lengthOf(firedStepIntoEvents, 0);
+
+ // Double click.
+ simulateDoubleClick(table.$.body.children[0].children[1]);
+ assert.lengthOf(firedStepIntoEvents, 1);
+ assert.strictEqual(firedStepIntoEvents[0].tableRow, rows[0]);
+ assert.strictEqual(firedStepIntoEvents[0].tableColumn, columns[1]);
+ assert.strictEqual(firedStepIntoEvents[0].columnIndex, 1);
+
+ simulateDoubleClick(table.$.body.children[1].children[3]);
+ assert.lengthOf(firedStepIntoEvents, 2);
+ assert.strictEqual(firedStepIntoEvents[1].tableRow, rows[1]);
+ assert.strictEqual(firedStepIntoEvents[1].tableColumn, columns[3]);
+ assert.strictEqual(firedStepIntoEvents[1].columnIndex, 3);
+
+ // Shift+Enter in cell selection mode.
+ table.selectionMode = SelectionMode.CELL;
+ table.selectedTableRow = rows[0];
+ table.selectedColumnIndex = 2;
+ table.performKeyCommand_('ENTER');
+ assert.lengthOf(firedStepIntoEvents, 3);
+ assert.strictEqual(firedStepIntoEvents[2].tableRow, rows[0]);
+ assert.strictEqual(firedStepIntoEvents[2].tableColumn, columns[2]);
+ assert.strictEqual(firedStepIntoEvents[2].columnIndex, 2);
+
+ // Shift+Enter in row selection mode.
+ table.selectionMode = SelectionMode.ROW;
+ table.selectedTableRow = rows[1];
+ table.performKeyCommand_('ENTER');
+ assert.lengthOf(firedStepIntoEvents, 4);
+ assert.strictEqual(firedStepIntoEvents[3].tableRow, rows[1]);
+ assert.isUndefined(firedStepIntoEvents[3].tableColumn);
+ assert.isUndefined(firedStepIntoEvents[3].columnIndex);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html b/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html
index 5fe8c74e86b..85ca3e440ab 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html
@@ -33,7 +33,7 @@ tr.exportTo('tr.ui.b', function() {
// Valid only during mousedown.
this.isMovingLeftEdge_ = false;
- };
+ }
TimingTool.prototype = {
@@ -189,7 +189,7 @@ tr.exportTo('tr.ui.b', function() {
else
ir.setMinAndMax(b, a);
- if (ir.min == newWorldX) {
+ if (ir.min === newWorldX) {
this.isMovingLeftEdge_ = true;
ir.leftSelected = true;
ir.rightSelected = false;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html
index 9d2405d8480..74b7774255a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
</script>
-<polymer-element name='tr-ui-b-toolbar-button' noscript>
+<dom-module id='tr-ui-b-toolbar-button'>
<template>
<style>
:host {
@@ -38,4 +38,8 @@ found in the LICENSE file.
<content></content>
</div>
</template>
-</polymer-element>
+</dom-module>
+<script>
+ 'use strict';
+ Polymer({ is: 'tr-ui-b-toolbar-button' });
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html
index 78f94081163..25d2dfe85a3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html
@@ -4,8 +4,8 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/toolbar_button.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/toolbar_button.html">
<script>
'use strict';
@@ -15,7 +15,7 @@ tr.b.unittest.testSuite(function() {
el.style.width = '100px';
el.style.height = '40px';
- el.textContent = 'blahblah';
+ Polymer.dom(el).textContent = 'blahblah';
this.addHTMLOutput(el);
});
@@ -25,14 +25,14 @@ tr.b.unittest.testSuite(function() {
el.style.width = '100px';
el.style.height = '40px';
- el.appendChild(tr.ui.b.createSpan({textContent: 'blahblah'}));
+ Polymer.dom(el).appendChild(tr.ui.b.createSpan({textContent: 'blahblah'}));
this.addHTMLOutput(el);
});
test('puny', function() {
var el = document.createElement('tr-ui-b-toolbar-button');
- el.textContent = 'M';
+ Polymer.dom(el).textContent = 'M';
this.addHTMLOutput(el);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html b/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html
index 20c1bd4471d..8e27b45ecea 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html
@@ -20,8 +20,8 @@ tr.exportTo('tr.ui.b', function() {
*/
function decorate(source, constr) {
var elements;
- if (typeof source == 'string')
- elements = tr.doc.querySelectorAll(source);
+ if (typeof source === 'string')
+ elements = Polymer.dom(tr.doc).querySelectorAll(source);
else
elements = [source];
@@ -72,7 +72,7 @@ tr.exportTo('tr.ui.b', function() {
* constructor.
*/
function define(className, opt_parentConstructor, opt_tagNS) {
- if (typeof className == 'function') {
+ if (typeof className === 'function') {
throw new Error('Passing functions as className is deprecated. Please ' +
'use (className, opt_parentConstructor) to subclass');
}
@@ -108,7 +108,7 @@ tr.exportTo('tr.ui.b', function() {
*/
function f() {
if (opt_parentConstructor &&
- f.prototype.__proto__ != opt_parentConstructor.prototype) {
+ f.prototype.__proto__ !== opt_parentConstructor.prototype) {
throw new Error(
className + ' prototye\'s __proto__ field is messed up. ' +
'It MUST be the prototype of ' + opt_parentConstructor.tagName);
@@ -148,17 +148,17 @@ tr.exportTo('tr.ui.b', function() {
}
function elementIsChildOf(el, potentialParent) {
- if (el == potentialParent)
+ if (el === potentialParent)
return false;
var cur = el;
- while (cur.parentNode) {
- if (cur == potentialParent)
+ while (Polymer.dom(cur).parentNode) {
+ if (cur === potentialParent)
return true;
- cur = cur.parentNode;
+ cur = Polymer.dom(cur).parentNode;
}
return false;
- };
+ }
return {
decorate: decorate,
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html
index 9db0b9f396f..4cace3aa243 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html
@@ -191,18 +191,18 @@ tr.b.unittest.testSuite(function() {
var svgNS = 'http://www.w3.org/2000/svg';
var cls = tr.ui.b.define('svg', undefined, svgNS);
cls.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
- this.setAttribute('width', 200);
- this.setAttribute('height', 200);
- this.setAttribute('viewPort', '0 0 200 200');
+ Polymer.dom(this).setAttribute('width', 200);
+ Polymer.dom(this).setAttribute('height', 200);
+ Polymer.dom(this).setAttribute('viewPort', '0 0 200 200');
var rectEl = document.createElementNS(svgNS, 'rect');
- rectEl.setAttribute('x', 10);
- rectEl.setAttribute('y', 10);
- rectEl.setAttribute('width', 180);
- rectEl.setAttribute('height', 180);
- this.appendChild(rectEl);
+ Polymer.dom(rectEl).setAttribute('x', 10);
+ Polymer.dom(rectEl).setAttribute('y', 10);
+ Polymer.dom(rectEl).setAttribute('width', 180);
+ Polymer.dom(rectEl).setAttribute('height', 180);
+ Polymer.dom(this).appendChild(rectEl);
}
};
var el = new cls();
@@ -215,18 +215,18 @@ tr.b.unittest.testSuite(function() {
var svgNS = 'http://www.w3.org/2000/svg';
var cls = tr.ui.b.define('svg', undefined, svgNS);
cls.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
- this.setAttribute('width', 200);
- this.setAttribute('height', 200);
- this.setAttribute('viewPort', '0 0 200 200');
+ Polymer.dom(this).setAttribute('width', 200);
+ Polymer.dom(this).setAttribute('height', 200);
+ Polymer.dom(this).setAttribute('viewPort', '0 0 200 200');
var rectEl = document.createElementNS(svgNS, 'rect');
- rectEl.setAttribute('x', 10);
- rectEl.setAttribute('y', 10);
- rectEl.setAttribute('width', 180);
- rectEl.setAttribute('height', 180);
- this.appendChild(rectEl);
+ Polymer.dom(rectEl).setAttribute('x', 10);
+ Polymer.dom(rectEl).setAttribute('y', 10);
+ Polymer.dom(rectEl).setAttribute('width', 180);
+ Polymer.dom(rectEl).setAttribute('height', 180);
+ Polymer.dom(this).appendChild(rectEl);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html
index a205d1db1b7..cdb9ab36570 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/base/rect.html">
<script>
@@ -13,10 +14,11 @@ found in the LICENSE file.
tr.exportTo('tr.ui.b', function() {
function instantiateTemplate(selector, doc) {
doc = doc || document;
- var el = doc.querySelector(selector);
+ var el = Polymer.dom(doc).querySelector(selector);
if (!el)
throw new Error('Element not found');
- return el.createInstance();
+ return doc.importNode(el.content, true);
+// return el.createInstance();
}
function windowRectForElement(element) {
@@ -57,7 +59,19 @@ tr.exportTo('tr.ui.b', function() {
undefined, {minimumFractionDigits: 3, maximumFractionDigits: 3});
}
+ /**
+ * Returns true if |name| is the name of an unknown HTML element. Registered
+ * polymer elements are known, so this returns false. Typos of registered
+ * polymer element names are unknown, so this returns true for typos.
+ *
+ * @return {boolean}
+ */
+ function isUnknownElementName(name) {
+ return document.createElement(name) instanceof HTMLUnknownElement;
+ }
+
return {
+ isUnknownElementName: isUnknownElementName,
toThreeDigitLocaleString: toThreeDigitLocaleString,
instantiateTemplate: instantiateTemplate,
windowRectForElement: windowRectForElement,
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html
index 7e82132fe8d..f24cd2be811 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html
@@ -7,16 +7,16 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/utils.html">
-<polymer-element name="instantiate-template-polymer-element-test">
+<dom-module id='instantiate-template-polymer-element-test'>
<template></template>
- <script>
- 'use strict';
- Polymer({
- testProperty: 'Test'
- });
- </script>
-</polymer-element>
-
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'instantiate-template-polymer-element-test',
+ testProperty: 'Test'
+});
+</script>
<template id="instantiate-template-polymer-test">
<instantiate-template-polymer-element-test>
</instantiate-template-polymer-element-test>
@@ -31,12 +31,11 @@ found in the LICENSE file.
<instantiate-template-polymer-element-test>
</instantiate-template-polymer-element-test>
</template>
-
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var THIS_DOC = document._currentScript.ownerDocument;
+ var THIS_DOC = document.currentScript.ownerDocument;
test('instantiateTemplatePolymer', function() {
var e = tr.ui.b.instantiateTemplate(
@@ -54,13 +53,14 @@ tr.b.unittest.testSuite(function() {
assert.equal(outerElement.children[1].testProperty, 'Test');
// Make sure we can still instantiate inner templates, if we need them.
- var innerElement = outerElement.children[0].createInstance();
+ var innerElement = THIS_DOC.importNode(
+ outerElement.children[0].content, true);
assert.equal(innerElement.children.length, 2);
assert.equal(innerElement.children[0].testProperty, 'Test');
assert.equal(
innerElement.children[1].getAttribute('test-attribute'),
'TestAttribute');
- assert.equal(innerElement.children[1].textContent, 'Foo');
+ assert.equal(Polymer.dom(innerElement.children[1]).textContent, 'Foo');
});
test('extractUrlStringAcceptsBothVersions', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html
index 9996e4db952..371cfafefa3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html
@@ -6,6 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/guid.html">
+<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/selection_state.html">
@@ -137,9 +138,11 @@ tr.exportTo('tr.ui.b', function() {
this.viewSpecificBrushingStates_ = viewSpecificBrushingStates;
},
- get causesDimming_() {
- return this.findMatches_.length > 0 ||
- this.analysisViewRelatedEvents_.length > 0;
+ get dimmedEvents_() {
+ var dimmedEvents = new EventSet();
+ dimmedEvents.addEventSet(this.findMatches);
+ dimmedEvents.addEventSet(this.analysisViewRelatedEvents_);
+ return dimmedEvents;
},
get brightenedEvents_() {
@@ -149,41 +152,70 @@ tr.exportTo('tr.ui.b', function() {
return brightenedEvents;
},
- applyToModelSelectionState: function(model) {
+ /**
+ * This function sets the SelectionStates according to these rules:
+ *
+ * - Events in ONE of findMatches or analysisViewRelatedEvents
+ * are set to SelectionState.BRIGHTENED0.
+ * - Events in BOTH of findMatches and analysisViewRelatedEvents
+ * are set to SelectionState.BRIGHTENED1.
+ * - Events in ONE of selection or analysisLinkHoveredEvents
+ * are set to SelectionState.DIMMED1.
+ * - Events in BOTH selection and analysisLinkHoveredEvents
+ * are set to SelectionState.DIMMED2.
+ * - Events not in any of the above are set to SelectionState.NONE
+ * if there are no events in selection or analysisLinkHoveredEvents
+ * (i.e. model is "default bright") or SelectionState.DIMMED0 (i.e.
+ * model is "default dimmed").
+ *
+ * It is up to the caller to assure that all of the SelectionStates
+ * are the same before calling this function. Normally,
+ * this is done by calling unapplyFromModelSelectionState on the
+ * old brushing state first.
+ */
+ applyToEventSelectionStates: function(model) {
this.appliedToModel_ = model;
- if (!this.causesDimming_) {
- this.brightenedEvents_.forEach(function(e) {
- var score;
- score = 0;
- if (this.selection_.contains(e))
- score++;
- if (this.analysisLinkHoveredEvents_.contains(e))
- score++;
- e.selectionState = SelectionState.getFromBrighteningLevel(score);
- }, this);
- return;
+ var dimmedEvents = this.dimmedEvents_;
+
+ // It's possible for this to get called with an undefined model pointer.
+ // If so, skip adjusting the defaults.
+ if (model) {
+ var newDefaultState = (
+ dimmedEvents.length ? SelectionState.DIMMED0 : SelectionState.NONE);
+
+ // Since all the states are the same, we can get the current default
+ // state by looking at the first element.
+ var currentDefaultState = tr.b.getFirstElement(
+ model.getDescendantEvents()).selectionState;
+
+ // If the default state was changed, then we have to iterate through
+ // and reset all the events to the new default state.
+ if (currentDefaultState !== newDefaultState)
+ for (var e of model.getDescendantEvents())
+ e.selectionState = newDefaultState;
}
- var brightenedEvents = this.brightenedEvents_;
- for (var e of model.getDescendantEvents()) {
- var score;
- if (brightenedEvents.contains(e)) {
- score = 0;
- if (this.selection_.contains(e))
- score++;
- if (this.analysisLinkHoveredEvents_.contains(e))
- score++;
- e.selectionState = SelectionState.getFromBrighteningLevel(score);
- } else {
- score = 0;
- if (this.findMatches_.contains(e))
- score++;
- if (this.analysisViewRelatedEvents_.contains(e))
- score++;
- e.selectionState = SelectionState.getFromDimmingLevel(score);
- }
+ // Now we apply the other rules above.
+ var score;
+ for (var e of dimmedEvents) {
+ score = 0;
+ if (this.findMatches_.contains(e))
+ score++;
+ if (this.analysisViewRelatedEvents_.contains(e))
+ score++;
+ e.selectionState = SelectionState.getFromDimmingLevel(score);
}
+
+ for (var e of this.brightenedEvents_) {
+ score = 0;
+ if (this.selection_.contains(e))
+ score++;
+ if (this.analysisLinkHoveredEvents_.contains(e))
+ score++;
+ e.selectionState = SelectionState.getFromBrighteningLevel(score);
+ }
+
},
transferModelOwnershipToClone: function(that) {
@@ -194,20 +226,27 @@ tr.exportTo('tr.ui.b', function() {
this.appliedToModel_ = undefined;
},
- unapplyFromModelSelectionState: function() {
+ /**
+ * Unapplies this brushing state from the model selection state.
+ * Resets all the SelectionStates to their default value (DIMMED0 or NONE)
+ * and returns the default selection states. The caller should store this
+ * value and pass it into applyFromModelSelectionStat when that is called.
+ */
+ unapplyFromEventSelectionStates: function() {
if (!this.appliedToModel_)
throw new Error('Not applied');
var model = this.appliedToModel_;
this.appliedToModel_ = undefined;
- if (!this.causesDimming_) {
- for (var e of this.brightenedEvents_)
- e.selectionState = SelectionState.NONE;
- return;
- }
+ var dimmedEvents = this.dimmedEvents_;
+ var defaultState = (
+ dimmedEvents.length ? SelectionState.DIMMED0 : SelectionState.NONE);
- for (var e of model.getDescendantEvents())
- e.selectionState = SelectionState.NONE;
+ for (var e of this.brightenedEvents_)
+ e.selectionState = defaultState;
+ for (var e of dimmedEvents)
+ e.selectionState = defaultState;
+ return defaultState;
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html
index c3b9e83952b..faa01567f4a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html
@@ -7,11 +7,11 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/event_target.html">
<link rel="import" href="/tracing/base/task.html">
-<link rel="import" href="/tracing/ui/brushing_state.html">
-<link rel="import" href="/tracing/ui/timeline_viewport.html">
-<link rel="import" href="/tracing/ui/base/ui_state.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/model/selection_state.html">
+<link rel="import" href="/tracing/ui/base/ui_state.html">
+<link rel="import" href="/tracing/ui/brushing_state.html">
+<link rel="import" href="/tracing/ui/timeline_viewport.html">
<script>
'use strict';
@@ -76,14 +76,14 @@ tr.exportTo('tr.c', function() {
modelWillChange: function() {
if (this.currentBrushingState_.isAppliedToModel)
- this.currentBrushingState_.unapplyFromModelSelectionState();
+ this.currentBrushingState_.unapplyFromEventSelectionStates();
},
modelDidChange: function() {
this.selections_ = {};
this.currentBrushingState_ = new BrushingState();
- this.currentBrushingState_.applyToModelSelectionState(this.model);
+ this.currentBrushingState_.applyToEventSelectionStates(this.model);
var e = new tr.b.Event('model-changed', false, false);
this.dispatchEvent(e);
@@ -153,12 +153,11 @@ tr.exportTo('tr.c', function() {
}
if (this.currentBrushingState_.isAppliedToModel)
- this.currentBrushingState_.unapplyFromModelSelectionState();
+ this.currentBrushingState_.unapplyFromEventSelectionStates();
this.currentBrushingState_ = newBrushingState;
- if (this.model)
- this.currentBrushingState_.applyToModelSelectionState(this.model);
+ this.currentBrushingState_.applyToEventSelectionStates(this.model);
this.dispatchChangeEvent_();
},
@@ -291,8 +290,8 @@ tr.exportTo('tr.c', function() {
// Possibly inside a shadow DOM.
var currentNode = currentElement;
- while (currentNode.parentNode)
- currentNode = currentNode.parentNode;
+ while (Polymer.dom(currentNode).parentNode)
+ currentNode = Polymer.dom(currentNode).parentNode;
currentElement = currentNode.host;
}
return undefined;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html
index 1f44f5962b6..b8a8b0d63fd 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html
@@ -130,7 +130,7 @@ tr.b.unittest.testSuite(function() {
function addChildDiv(element) {
var child = element.ownerDocument.createElement('div');
- element.appendChild(child);
+ Polymer.dom(element).appendChild(child);
return child;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html
index d0480738bd7..25606f6cb6b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html
@@ -40,9 +40,9 @@ tr.b.unittest.testSuite(function() {
var bs = new tr.ui.b.BrushingState();
bs.selection = new EventSet([m.sA]);
- bs.applyToModelSelectionState(m);
+ bs.applyToEventSelectionStates(m);
assert.equal(m.sA.selectionState, SelectionState.SELECTED);
- bs.unapplyFromModelSelectionState();
+ bs.unapplyFromEventSelectionStates();
assert.equal(m.sA.selectionState, SelectionState.NONE);
});
@@ -54,10 +54,10 @@ tr.b.unittest.testSuite(function() {
bs.selection = new EventSet([m.sA]);
bs.analysisLinkHoveredEvents = new EventSet([m.sA, m.sB]);
- bs.applyToModelSelectionState(m);
+ bs.applyToEventSelectionStates(m);
assert.equal(m.sA.selectionState, SelectionState.BRIGHTENED1);
assert.equal(m.sB.selectionState, SelectionState.BRIGHTENED0);
- bs.unapplyFromModelSelectionState();
+ bs.unapplyFromEventSelectionStates();
assert.equal(m.sA.selectionState, SelectionState.NONE);
});
@@ -68,14 +68,14 @@ tr.b.unittest.testSuite(function() {
bs.selection = new EventSet([m.sA]);
bs.findMatches = new EventSet([m.sA, m.sB]);
- bs.applyToModelSelectionState(m);
+ bs.applyToEventSelectionStates(m);
assert.equal(m.sA.selectionState, SelectionState.BRIGHTENED0);
assert.equal(m.sB.selectionState, SelectionState.DIMMED1);
assert.equal(m.sC.selectionState, SelectionState.DIMMED0);
- bs.unapplyFromModelSelectionState();
- assert.equal(m.sA.selectionState, SelectionState.NONE);
- assert.equal(m.sB.selectionState, SelectionState.NONE);
- assert.equal(m.sC.selectionState, SelectionState.NONE);
+ bs.unapplyFromEventSelectionStates();
+ assert.equal(m.sA.selectionState, SelectionState.DIMMED0);
+ assert.equal(m.sB.selectionState, SelectionState.DIMMED0);
+ assert.equal(m.sC.selectionState, SelectionState.DIMMED0);
});
test('brushingTransfer', function() {
@@ -86,13 +86,13 @@ tr.b.unittest.testSuite(function() {
var bs2 = bs.clone();
- bs.applyToModelSelectionState(m);
+ bs.applyToEventSelectionStates(m);
assert.equal(m.sA.selectionState, SelectionState.SELECTED);
bs.transferModelOwnershipToClone(bs2);
assert.isFalse(bs.isAppliedToModel);
assert.isTrue(bs2.isAppliedToModel);
- bs2.unapplyFromModelSelectionState();
+ bs2.unapplyFromEventSelectionStates();
assert.equal(m.sA.selectionState, SelectionState.NONE);
assert.equal(m.sB.selectionState, SelectionState.NONE);
assert.equal(m.sC.selectionState, SelectionState.NONE);
@@ -104,7 +104,7 @@ tr.b.unittest.testSuite(function() {
var bs = new tr.ui.b.BrushingState();
bs.selection = new EventSet([m.sA]);
bs.findMatches = new EventSet([m.sB]);
- bs.applyToModelSelectionState = new EventSet([m.sC]);
+ bs.applyToEventSelectionStates = new EventSet([m.sC]);
// Clone equality, but with shared refs.
var bs2 = bs.clone();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html
index 1df923b4d42..8e579d90921 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html
@@ -4,6 +4,8 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
+
<link rel="stylesheet" href="/tracing/ui/extras/about_tracing/common.css">
<link rel="import" href="/tracing/ui/extras/about_tracing/profiling_view.html">
<link rel="import" href="/tracing/ui/extras/full_config.html">
@@ -16,7 +18,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
document.addEventListener('DOMContentLoaded', function() {
window.profilingView = new tr.ui.e.about_tracing.ProfilingView();
profilingView.timelineView.globalMode = true;
- document.body.appendChild(profilingView);
+ Polymer.dom(document.body).appendChild(profilingView);
});
return {};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html
index accff574c54..58d4e913e34 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html
@@ -69,31 +69,33 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
/**
* ProfilingView
* @constructor
- * @extends {HTMLUnknownElement}
+ * @extends {HTMLDivElement}
*/
var ProfilingView = tr.ui.b.define('x-profiling-view');
var THIS_DOC = document.currentScript.ownerDocument;
ProfilingView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function(tracingControllerClient) {
- this.appendChild(tr.ui.b.instantiateTemplate('#profiling-view-template',
- THIS_DOC));
+ Polymer.dom(this).appendChild(
+ tr.ui.b.instantiateTemplate('#profiling-view-template', THIS_DOC));
- this.timelineView_ = this.querySelector('tr-ui-timeline-view');
- this.infoBarGroup_ = this.querySelector('tr-ui-b-info-bar-group');
+ this.timelineView_ =
+ Polymer.dom(this).querySelector('tr-ui-timeline-view');
+ this.infoBarGroup_ =
+ Polymer.dom(this).querySelector('tr-ui-b-info-bar-group');
// Detach the buttons. We will reattach them to the timeline view.
// TODO(nduca): Make timeline-view have a content select="x-buttons"
// that pulls in any buttons.
- this.recordButton_ = this.querySelector('#record-button');
- this.loadButton_ = this.querySelector('#load-button');
- this.saveButton_ = this.querySelector('#save-button');
+ this.recordButton_ = Polymer.dom(this).querySelector('#record-button');
+ this.loadButton_ = Polymer.dom(this).querySelector('#load-button');
+ this.saveButton_ = Polymer.dom(this).querySelector('#save-button');
- var buttons = this.querySelector('x-timeline-view-buttons');
- buttons.parentElement.removeChild(buttons);
- this.timelineView_.leftControls.appendChild(buttons);
+ var buttons = Polymer.dom(this).querySelector('x-timeline-view-buttons');
+ Polymer.dom(buttons.parentElement).removeChild(buttons);
+ Polymer.dom(this.timelineView_.leftControls).appendChild(buttons);
this.initButtons_();
this.timelineView_.hotkeyController.addHotKey(new tr.ui.b.HotKey({
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html
index 2284b0fa3e7..a72ddfeba07 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html
@@ -72,18 +72,18 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
var bufferPercentFullDiv;
function startTracing() {
progressDlg = new tr.ui.b.Overlay();
- progressDlg.textContent = 'Recording...';
+ Polymer.dom(progressDlg).textContent = 'Recording...';
progressDlg.userCanClose = false;
bufferPercentFullDiv = document.createElement('div');
- progressDlg.appendChild(bufferPercentFullDiv);
+ Polymer.dom(progressDlg).appendChild(bufferPercentFullDiv);
var stopButton = document.createElement('button');
- stopButton.textContent = 'Stop';
+ Polymer.dom(stopButton).textContent = 'Stop';
progressDlg.clickStopButton = function() {
stopButton.click();
};
- progressDlg.appendChild(stopButton);
+ Polymer.dom(progressDlg).appendChild(stopButton);
var recordingOptions = {
categoryFilter: selectionDlg.categoryFilter(),
@@ -141,21 +141,21 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
updateBufferPercentFull);
}
- function updateBufferPercentFull(percent_full) {
+ function updateBufferPercentFull(percentFull) {
if (!bufferPercentFullDiv)
return;
- percent_full = Math.round(100 * parseFloat(percent_full));
- var newText = 'Buffer usage: ' + percent_full + '%';
- if (bufferPercentFullDiv.textContent != newText)
- bufferPercentFullDiv.textContent = newText;
+ percentFull = Math.round(100 * parseFloat(percentFull));
+ var newText = 'Buffer usage: ' + percentFull + '%';
+ if (Polymer.dom(bufferPercentFullDiv).textContent !== newText)
+ Polymer.dom(bufferPercentFullDiv).textContent = newText;
window.setTimeout(getBufferPercentFull, 500);
}
// Thats it! We're done.
return finalPromise;
- };
+ }
function endRecording(tracingControllerClient) {
return tracingControllerClient.endRecording();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
index 79ce154dba8..71a333bf60d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
@@ -29,6 +29,7 @@ found in the LICENSE file.
max-width: 0;
opacity: 0;
overflow: hidden;
+ display: none;
}
.categories-selection {
@@ -228,24 +229,25 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
tr.ui.b.Overlay.prototype.decorate.call(this);
this.title = 'Record a new trace...';
- this.classList.add('record-dialog-overlay');
+ Polymer.dom(this).classList.add('record-dialog-overlay');
var node =
tr.ui.b.instantiateTemplate('#record-selection-dialog-template',
THIS_DOC);
- this.appendChild(node);
+ Polymer.dom(this).appendChild(node);
this.recordButtonEl_ = document.createElement('button');
- this.recordButtonEl_.textContent = 'Record';
+ Polymer.dom(this.recordButtonEl_).textContent = 'Record';
this.recordButtonEl_.addEventListener(
'click',
this.onRecordButtonClicked_.bind(this));
this.recordButtonEl_.style.fontSize = '110%';
- this.buttons.appendChild(this.recordButtonEl_);
+ Polymer.dom(this.buttons).appendChild(this.recordButtonEl_);
- this.categoriesView_ = this.querySelector('.categories-column-view');
- this.presetsEl_ = this.querySelector('.category-presets');
- this.presetsEl_.appendChild(tr.ui.b.createOptionGroup(
+ this.categoriesView_ = Polymer.dom(this).querySelector(
+ '.categories-column-view');
+ this.presetsEl_ = Polymer.dom(this).querySelector('.category-presets');
+ Polymer.dom(this.presetsEl_).appendChild(tr.ui.b.createOptionGroup(
this, 'currentlyChosenPreset',
'about_tracing.record_selection_dialog_preset',
DEFAULT_PRESETS[0].categoryFilter,
@@ -266,30 +268,37 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
undefined, undefined,
'recordSelectionDialog.useSampling', DEFAULT_SAMPLING_TRACING,
'State sampling');
- this.tracingModesContainerEl_ = this.querySelector('.tracing-modes');
- this.tracingModesContainerEl_.appendChild(this.tracingRecordModeSltr_);
- this.tracingModesContainerEl_.appendChild(this.systemTracingBn_);
- this.tracingModesContainerEl_.appendChild(this.samplingTracingBn_);
-
+ this.tracingModesContainerEl_ = Polymer.dom(this).querySelector(
+ '.tracing-modes');
+ Polymer.dom(this.tracingModesContainerEl_).appendChild(
+ this.tracingRecordModeSltr_);
+ Polymer.dom(this.tracingModesContainerEl_).appendChild(
+ this.systemTracingBn_);
+ Polymer.dom(this.tracingModesContainerEl_).appendChild(
+ this.samplingTracingBn_);
this.enabledCategoriesContainerEl_ =
- this.querySelector('.default-enabled-categories .categories');
+ Polymer.dom(this).querySelector(
+ '.default-enabled-categories .categories');
this.disabledCategoriesContainerEl_ =
- this.querySelector('.default-disabled-categories .categories');
+ Polymer.dom(this).querySelector(
+ '.default-disabled-categories .categories');
this.createGroupSelectButtons_(
- this.querySelector('.default-enabled-categories'));
+ Polymer.dom(this).querySelector('.default-enabled-categories'));
this.createGroupSelectButtons_(
- this.querySelector('.default-disabled-categories'));
+ Polymer.dom(this).querySelector('.default-disabled-categories'));
this.createDefaultDisabledWarningDialog_(
- this.querySelector('.warning-default-disabled-categories'));
+ Polymer.dom(this).querySelector(
+ '.warning-default-disabled-categories'));
this.editCategoriesOpened_ = false;
// TODO(chrishenry): When used with tr.ui.b.Overlay (such as in
// chrome://tracing, this does not yet look quite right due to
// the 10px overlay content padding (but it's good enough).
- this.infoBarGroup_ = this.querySelector('tr-ui-b-info-bar-group');
+ this.infoBarGroup_ = Polymer.dom(this).querySelector(
+ 'tr-ui-b-info-bar-group');
this.addEventListener('visible-change', this.onVisibleChange_.bind(this));
},
@@ -370,7 +379,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
},
updateManualSelectionView_: function() {
- var classList = this.categoriesView_.classList;
+ var classList = Polymer.dom(this.categoriesView_).classList;
if (!this.usingPreset_()) {
classList.remove('categories-column-view-hidden');
} else {
@@ -382,7 +391,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
},
updateCategoryColumnView_: function(shouldReadFromSettings) {
- var categorySet = this.querySelectorAll('.categories');
+ var categorySet = Polymer.dom(this).querySelectorAll('.categories');
for (var i = 0; i < categorySet.length; ++i) {
var categoryGroup = categorySet[i].children;
for (var j = 0; j < categoryGroup.length; ++j) {
@@ -415,26 +424,31 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
},
changeEditCategoriesState_: function(editCategoriesState) {
- var presetOptionsGroup = this.querySelector('.labeled-option-group');
+ var presetOptionsGroup = Polymer.dom(this).querySelector(
+ '.labeled-option-group');
if (!presetOptionsGroup)
return;
this.editCategoriesOpened_ = editCategoriesState;
if (this.editCategoriesOpened_)
- presetOptionsGroup.classList.add('categories-expanded');
+ Polymer.dom(presetOptionsGroup).classList.add('categories-expanded');
else
- presetOptionsGroup.classList.remove('categories-expanded');
+ Polymer.dom(presetOptionsGroup).classList.remove(
+ 'categories-expanded');
},
updatePresetDescription_: function() {
- var description = this.querySelector('.category-description');
+ var description = Polymer.dom(this).querySelector(
+ '.category-description');
if (this.usingPreset_()) {
description.innerText = this.currentlyChosenPreset_;
- description.classList.remove('category-description-hidden');
+ Polymer.dom(description).classList.remove(
+ 'category-description-hidden');
} else {
description.innerText = '';
- if (!description.classList.contains('category-description-hidden'))
- description.classList.add('category-description-hidden');
+ if (!Polymer.dom(description).classList.contains(
+ 'category-description-hidden'))
+ Polymer.dom(description).classList.add('category-description-hidden');
}
},
@@ -443,7 +457,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
var categories = [];
var allCategories = this.allCategories_();
for (var category in allCategories) {
- var disabled = category.indexOf('disabled-by-default-') == 0;
+ var disabled = category.indexOf('disabled-by-default-') === 0;
if (this.currentlyChosenPreset_.indexOf(category) >= 0) {
if (disabled)
categories.push(category);
@@ -456,17 +470,17 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
}
var categories = this.unselectedCategories_();
- var categories_length = categories.length;
- var negated_categories = [];
- for (var i = 0; i < categories_length; ++i) {
+ var categoriesLength = categories.length;
+ var negatedCategories = [];
+ for (var i = 0; i < categoriesLength; ++i) {
// Skip any category with a , as it will cause issues when we negate.
// Both sides should have been added as separate categories, these can
// only come from settings.
if (categories[i].match(/,/))
continue;
- negated_categories.push('-' + categories[i]);
+ negatedCategories.push('-' + categories[i]);
}
- categories = negated_categories.join(',');
+ categories = negatedCategories.join(',');
var disabledCategories = this.enabledDisabledByDefaultCategories_();
disabledCategories = disabledCategories.join(',');
@@ -490,9 +504,9 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
},
collectInputs_: function(inputs, isChecked) {
- var inputs_length = inputs.length;
+ var inputsLength = inputs.length;
var categories = [];
- for (var i = 0; i < inputs_length; ++i) {
+ for (var i = 0; i < inputsLength; ++i) {
var input = inputs[i];
if (input.checked === isChecked)
categories.push(input.value);
@@ -502,13 +516,15 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
unselectedCategories_: function() {
var inputs =
- this.enabledCategoriesContainerEl_.querySelectorAll('input');
+ Polymer.dom(this.enabledCategoriesContainerEl_).querySelectorAll(
+ 'input');
return this.collectInputs_(inputs, false);
},
enabledDisabledByDefaultCategories_: function() {
var inputs =
- this.disabledCategoriesContainerEl_.querySelectorAll('input');
+ Polymer.dom(this.disabledCategoriesContainerEl_).querySelectorAll(
+ 'input');
return this.collectInputs_(inputs, true);
},
@@ -518,8 +534,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
},
buildInputs_: function(inputs, checkedDefault, parent) {
- var inputs_length = inputs.length;
- for (var i = 0; i < inputs_length; i++) {
+ var inputsLength = inputs.length;
+ for (var i = 0; i < inputsLength; i++) {
var category = inputs[i];
var inputEl = document.createElement('input');
@@ -532,14 +548,15 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
inputEl.onclick = this.updateSetting_.bind(this);
var labelEl = document.createElement('label');
- labelEl.textContent = category.replace('disabled-by-default-', '');
- labelEl.setAttribute('for', category);
+ Polymer.dom(labelEl).textContent =
+ category.replace('disabled-by-default-', '');
+ Polymer.dom(labelEl).setAttribute('for', category);
var divEl = document.createElement('div');
- divEl.appendChild(inputEl);
- divEl.appendChild(labelEl);
+ Polymer.dom(divEl).appendChild(inputEl);
+ Polymer.dom(divEl).appendChild(labelEl);
- parent.appendChild(divEl);
+ Polymer.dom(parent).appendChild(divEl);
}
},
@@ -560,8 +577,9 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
- this.enabledCategoriesContainerEl_.innerHTML = ''; // Clear old categories
- this.disabledCategoriesContainerEl_.innerHTML = '';
+ // Clear old categories
+ Polymer.dom(this.enabledCategoriesContainerEl_).innerHTML = '';
+ Polymer.dom(this.disabledCategoriesContainerEl_).innerHTML = '';
this.recordButtonEl_.focus();
@@ -569,7 +587,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
var categories = [];
var disabledCategories = [];
for (var category in allCategories) {
- if (category.indexOf('disabled-by-default-') == 0)
+ if (category.indexOf('disabled-by-default-') === 0)
disabledCategories.push(category);
else
categories.push(category);
@@ -577,7 +595,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
disabledCategories = disabledCategories.sort(ignoreCaseCompare);
categories = categories.sort(ignoreCaseCompare);
- if (this.categories_.length == 0) {
+ if (this.categories_.length === 0) {
this.infoBarGroup_.addMessage(
'No categories found; recording will use default categories.');
}
@@ -603,15 +621,16 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
var categoryEl = this.querySelector(
'#category-preset-Manually-select-settings');
categoryEl.checked = true;
- var description = this.querySelector('.category-description');
+ var description = Polymer.dom(this).querySelector(
+ '.category-description');
description.innerText = '';
- description.classList.add('category-description-hidden');
+ Polymer.dom(description).classList.add('category-description-hidden');
}
},
createGroupSelectButtons_: function(parent) {
var flipInputs = function(dir) {
- var inputs = parent.querySelectorAll('input');
+ var inputs = Polymer.dom(parent).querySelectorAll('input');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked === dir)
continue;
@@ -621,13 +640,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
}
};
- var allBtn = parent.querySelector('.all-btn');
+ var allBtn = Polymer.dom(parent).querySelector('.all-btn');
allBtn.onclick = function(evt) {
flipInputs(true);
evt.preventDefault();
};
- var noneBtn = parent.querySelector('.none-btn');
+ var noneBtn = Polymer.dom(parent).querySelector('.none-btn');
noneBtn.onclick = function(evt) {
flipInputs(false);
evt.preventDefault();
@@ -639,11 +658,11 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
for (var i = 0; i < messages.length; ++i) {
var messageDiv = document.createElement('div');
- messageDiv.textContent = messages[i];
- contentDiv.appendChild(messageDiv);
+ Polymer.dom(messageDiv).textContent = messages[i];
+ Polymer.dom(contentDiv).appendChild(messageDiv);
}
- this.warningOverlay_.textContent = '';
- this.warningOverlay_.appendChild(contentDiv);
+ Polymer.dom(this.warningOverlay_).textContent = '';
+ Polymer.dom(this.warningOverlay_).appendChild(contentDiv);
},
createDefaultDisabledWarningDialog_: function(warningLink) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html
index 1142f6e6035..7dfc4e0a7cf 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantitate', function() {
var showButton = document.createElement('button');
- showButton.textContent = 'Show record selection dialog';
+ Polymer.dom(showButton).textContent = 'Show record selection dialog';
this.addHTMLOutput(showButton);
showButton.addEventListener('click', function(e) {
@@ -49,7 +49,7 @@ tr.b.unittest.testSuite(function() {
var expected =
['"cc"', '"cc.debug"', '"disabled-by-default-one"', '"three"', '"two"'];
- var labels = dlg.querySelectorAll('.categories input');
+ var labels = Polymer.dom(dlg).querySelectorAll('.categories input');
var results = [];
for (var i = 0; i < labels.length; i++) {
results.push('"' + labels[i].value + '"');
@@ -66,7 +66,7 @@ tr.b.unittest.testSuite(function() {
dlg.currentlyChosenPreset = [];
dlg.updateForm_();
- var checkboxes = dlg.querySelectorAll('.categories input');
+ var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input');
assert.equal(checkboxes.length, 3);
assert.equal(checkboxes[0].id, 'three');
assert.equal(checkboxes[0].value, 'three');
@@ -80,11 +80,11 @@ tr.b.unittest.testSuite(function() {
assert.equal(dlg.categoryFilter(), '');
- var labels = dlg.querySelectorAll('.categories label');
+ var labels = Polymer.dom(dlg).querySelectorAll('.categories label');
assert.equal(labels.length, 3);
- assert.equal(labels[0].textContent, 'three');
- assert.equal(labels[1].textContent, 'two');
- assert.equal(labels[2].textContent, 'one');
+ assert.equal(Polymer.dom(labels[0]).textContent, 'three');
+ assert.equal(Polymer.dom(labels[1]).textContent, 'two');
+ assert.equal(Polymer.dom(labels[2]).textContent, 'one');
});
test('recordSelectionDialog_UpdateForm_Settings', function() {
@@ -97,7 +97,7 @@ tr.b.unittest.testSuite(function() {
dlg.currentlyChosenPreset = [];
dlg.updateForm_();
- var checkboxes = dlg.querySelectorAll('.categories input');
+ var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input');
assert.equal(checkboxes.length, 3);
assert.equal(checkboxes[0].id, 'three');
assert.equal(checkboxes[0].value, 'three');
@@ -111,11 +111,11 @@ tr.b.unittest.testSuite(function() {
assert.equal(dlg.categoryFilter(), '-three');
- var labels = dlg.querySelectorAll('.categories label');
+ var labels = Polymer.dom(dlg).querySelectorAll('.categories label');
assert.equal(labels.length, 3);
- assert.equal(labels[0].textContent, 'three');
- assert.equal(labels[1].textContent, 'two');
- assert.equal(labels[2].textContent, 'one');
+ assert.equal(Polymer.dom(labels[0]).textContent, 'three');
+ assert.equal(Polymer.dom(labels[1]).textContent, 'two');
+ assert.equal(Polymer.dom(labels[2]).textContent, 'one');
});
test('recordSelectionDialog_UpdateForm_DisabledByDefault', function() {
@@ -128,7 +128,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(dlg.categoryFilter(), '');
var inputs =
- dlg.querySelector('input#disabled-by-default-bar').click();
+ Polymer.dom(dlg).querySelector('input#disabled-by-default-bar').click();
assert.equal(dlg.categoryFilter(), 'disabled-by-default-bar');
@@ -158,27 +158,32 @@ tr.b.unittest.testSuite(function() {
dlg.updateForm_();
// Enables the three option, two already enabled.
- dlg.querySelector('.default-enabled-categories .all-btn').click();
+ Polymer.dom(dlg).querySelector('.default-enabled-categories .all-btn')
+ .click();
assert.equal(dlg.categoryFilter(), '');
assert.isTrue(tr.b.Settings.get('three', false, 'categories'));
// Disables three and two.
- dlg.querySelector('.default-enabled-categories .none-btn').click();
+ Polymer.dom(dlg).querySelector('.default-enabled-categories .none-btn')
+ .click();
assert.equal(dlg.categoryFilter(), '-three,-two');
assert.isFalse(tr.b.Settings.get('two', false, 'categories'));
assert.isFalse(tr.b.Settings.get('three', false, 'categories'));
// Turn categories back on so they can be ignored.
- dlg.querySelector('.default-enabled-categories .all-btn').click();
+ Polymer.dom(dlg).querySelector('.default-enabled-categories .all-btn')
+ .click();
// Enables disabled category.
- dlg.querySelector('.default-disabled-categories .all-btn').click();
+ Polymer.dom(dlg).querySelector('.default-disabled-categories .all-btn')
+ .click();
assert.equal(dlg.categoryFilter(), 'disabled-by-default-one');
assert.isTrue(
tr.b.Settings.get('disabled-by-default-one', false, 'categories'));
// Turn disabled by default back off.
- dlg.querySelector('.default-disabled-categories .none-btn').click();
+ Polymer.dom(dlg).querySelector('.default-disabled-categories .none-btn')
+ .click();
assert.equal(dlg.categoryFilter(), '');
assert.isFalse(
tr.b.Settings.get('disabled-by-default-one', false, 'categories'));
@@ -209,11 +214,11 @@ tr.b.unittest.testSuite(function() {
assert.isFalse(dlg.useSampling);
// Make sure the manual settings are not visible.
- var classList = dlg.categoriesView_.classList;
+ var classList = Polymer.dom(dlg.categoriesView_).classList;
assert.isTrue(classList.contains('categories-column-view-hidden'));
// Verify manual settings do not modify the checkboxes.
- var checkboxes = dlg.querySelectorAll('.categories input');
+ var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input');
assert.equal(checkboxes.length, 3);
assert.equal(checkboxes[0].id, 'three');
assert.equal(checkboxes[0].value, 'three');
@@ -297,7 +302,7 @@ tr.b.unittest.testSuite(function() {
assert.isFalse(dlg.useSampling);
// Make sure the manual settings are not visible.
- var classList = dlg.categoriesView_.classList;
+ var classList = Polymer.dom(dlg.categoriesView_).classList;
assert.isTrue(classList.contains('categories-column-view-hidden'));
// Switch to manual settings and verify the default values are not returned.
@@ -346,7 +351,7 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(dlg.useSampling);
// Make sure the manual settings are not visible.
- var classList = dlg.categoriesView_.classList;
+ var classList = Polymer.dom(dlg.categoriesView_).classList;
assert.isTrue(classList.contains('categories-column-view-hidden'));
// Switch to manual settings and verify the default values are not returned.
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html
index c7c68cc8483..a33e614813e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html
@@ -20,13 +20,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
data = null;
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
- if (method != 'POST' && data !== null)
+ if (method !== 'POST' && data !== null)
throw new Error('Non-POST should have data==null');
req.open(method, path, true);
req.onreadystatechange = function(e) {
- if (req.readyState == 4) {
+ if (req.readyState === 4) {
window.setTimeout(function() {
- if (req.status == 200 && req.responseText != '##ERROR##') {
+ if (req.status === 200 && req.responseText !== '##ERROR##') {
resolve(req.responseText);
} else {
reject(new Error('Error occured at ' + path));
@@ -58,8 +58,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
captureMonitoring: function() {
return beginXhr('GET', '/json/capture_monitoring_compressed').then(
function(data) {
- var decoded_size = Base64.getDecodedBufferLength(data);
- var buffer = new ArrayBuffer(decoded_size);
+ var decodedSize = Base64.getDecodedBufferLength(data);
+ var buffer = new ArrayBuffer(decodedSize);
Base64.DecodeToTypedArray(data, new DataView(buffer));
return buffer;
}
@@ -93,8 +93,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() {
endRecording: function() {
return beginXhr('GET', '/json/end_recording_compressed').then(
function(data) {
- var decoded_size = Base64.getDecodedBufferLength(data);
- var buffer = new ArrayBuffer(decoded_size);
+ var decodedSize = Base64.getDecodedBufferLength(data);
+ var buffer = new ArrayBuffer(decodedSize);
Base64.DecodeToTypedArray(data, new DataView(buffer));
return buffer;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html
index 55a028ce4c3..37403d8f7fd 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html
@@ -134,66 +134,73 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'tr-ui-e-chrome-cc-display-item-debugger');
DisplayItemDebugger.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
var node = tr.ui.b.instantiateTemplate(
'#tr-ui-e-chrome-cc-display-item-debugger-template', THIS_DOC);
- this.appendChild(node);
+ Polymer.dom(this).appendChild(node);
this.pictureAsImageData_ = undefined;
this.zoomScaleValue_ = 1;
- this.sizeInfo_ = this.querySelector('.size');
- this.rasterArea_ = this.querySelector('raster-area');
- this.rasterCanvas_ = this.rasterArea_.querySelector('canvas');
+ this.sizeInfo_ = Polymer.dom(this).querySelector('.size');
+ this.rasterArea_ = Polymer.dom(this).querySelector('raster-area');
+ this.rasterCanvas_ =
+ Polymer.dom(this.rasterArea_).querySelector('canvas');
this.rasterCtx_ = this.rasterCanvas_.getContext('2d');
this.trackMouse_();
- this.displayItemInfo_ = this.querySelector('display-item-info');
+ this.displayItemInfo_ =
+ Polymer.dom(this).querySelector('display-item-info');
this.displayItemInfo_.addEventListener(
'click', this.onDisplayItemInfoClick_.bind(this), false);
this.displayItemListView_ = new tr.ui.b.ListView();
this.displayItemListView_.addEventListener('selection-changed',
this.onDisplayItemListSelection_.bind(this));
- this.displayItemInfo_.appendChild(this.displayItemListView_);
+ Polymer.dom(this.displayItemInfo_).appendChild(this.displayItemListView_);
- this.displayListFilename_ = this.querySelector('.dlfilename');
- this.displayListExportButton_ = this.querySelector('.dlexport');
+ this.displayListFilename_ =
+ Polymer.dom(this).querySelector('.dlfilename');
+ this.displayListExportButton_ =
+ Polymer.dom(this).querySelector('.dlexport');
this.displayListExportButton_.addEventListener(
'click', this.onExportDisplayListClicked_.bind(this));
- this.skpFilename_ = this.querySelector('.skpfilename');
- this.skpExportButton_ = this.querySelector('.skpexport');
+ this.skpFilename_ = Polymer.dom(this).querySelector('.skpfilename');
+ this.skpExportButton_ = Polymer.dom(this).querySelector('.skpexport');
this.skpExportButton_.addEventListener(
'click', this.onExportSkPictureClicked_.bind(this));
- var leftPanel = this.querySelector('left-panel');
+ var leftPanel = Polymer.dom(this).querySelector('left-panel');
var middleDragHandle = document.createElement('tr-ui-b-drag-handle');
middleDragHandle.horizontal = false;
middleDragHandle.target = leftPanel;
- var rightPanel = this.querySelector('right-panel');
+ var rightPanel = Polymer.dom(this).querySelector('right-panel');
this.infoBar_ = document.createElement('tr-ui-b-info-bar');
- this.rasterArea_.insertBefore(this.infoBar_, this.rasterCanvas_);
+ Polymer.dom(this.rasterArea_).insertBefore(
+ this.infoBar_, this.rasterCanvas_);
- this.insertBefore(middleDragHandle, rightPanel);
+ Polymer.dom(this).insertBefore(middleDragHandle, rightPanel);
this.picture_ = undefined;
this.pictureOpsListView_ = new tr.ui.e.chrome.cc.PictureOpsListView();
- rightPanel.insertBefore(this.pictureOpsListView_, this.rasterArea_);
+ Polymer.dom(rightPanel).insertBefore(
+ this.pictureOpsListView_, this.rasterArea_);
this.pictureOpsListDragHandle_ =
document.createElement('tr-ui-b-drag-handle');
this.pictureOpsListDragHandle_.horizontal = false;
this.pictureOpsListDragHandle_.target = this.pictureOpsListView_;
- rightPanel.insertBefore(this.pictureOpsListDragHandle_, this.rasterArea_);
+ Polymer.dom(rightPanel).insertBefore(
+ this.pictureOpsListDragHandle_, this.rasterArea_);
},
get picture() {
@@ -209,7 +216,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var listItem = document.createElement(
'tr-ui-e-chrome-cc-display-item-list-item');
listItem.data = item;
- this.displayItemListView_.appendChild(listItem);
+ Polymer.dom(this.displayItemListView_).appendChild(listItem);
}.bind(this));
},
@@ -266,7 +273,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.updateContentsPending_ = false;
if (this.picture_) {
- this.sizeInfo_.textContent = '(' +
+ Polymer.dom(this.sizeInfo_).textContent = '(' +
this.picture_.layerRect.width + ' x ' +
this.picture_.layerRect.height + ')';
}
@@ -281,7 +288,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.infoBar_.message = 'Cannot rasterize...';
this.infoBar_.addButton('More info...', function(e) {
var overlay = new tr.ui.b.Overlay();
- overlay.textContent = this.pictureAsImageData_.error;
+ Polymer.dom(overlay).textContent = this.pictureAsImageData_.error;
overlay.visible = true;
e.stopPropagation();
return false;
@@ -346,7 +353,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
},
onDisplayItemInfoClick_: function(e) {
- if (e && e.target == this.displayItemInfo_) {
+ if (e && e.target === this.displayItemInfo_) {
this.displayItemListView_.selectedElement = undefined;
}
},
@@ -355,12 +362,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (showOpsList) {
this.pictureOpsListView_.picture = this.picture_;
if (this.pictureOpsListView_.numOps > 0) {
- this.pictureOpsListView_.classList.add('hasPictureOps');
- this.pictureOpsListDragHandle_.classList.add('hasPictureOps');
+ Polymer.dom(this.pictureOpsListView_).classList.add('hasPictureOps');
+ Polymer.dom(this.pictureOpsListDragHandle_).classList.add(
+ 'hasPictureOps');
}
} else {
- this.pictureOpsListView_.classList.remove('hasPictureOps');
- this.pictureOpsListDragHandle_.classList.remove('hasPictureOps');
+ Polymer.dom(this.pictureOpsListView_).classList.remove('hasPictureOps');
+ Polymer.dom(this.pictureOpsListDragHandle_).classList.remove(
+ 'hasPictureOps');
}
},
@@ -368,7 +377,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.mouseModeSelector_ = document.createElement(
'tr-ui-b-mouse-mode-selector');
this.mouseModeSelector_.targetElement = this.rasterArea_;
- this.rasterArea_.appendChild(this.mouseModeSelector_);
+ Polymer.dom(this.rasterArea_).appendChild(this.mouseModeSelector_);
this.mouseModeSelector_.supportedModeMask =
tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html
index b34495a6b41..696489f33d6 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<!--
An element displaying basic information about a display item in a list view.
-->
-<polymer-element name="tr-ui-e-chrome-cc-display-item-list-item">
+<dom-module id='tr-ui-e-chrome-cc-display-item-list-item'>
<template>
<style>
:host {
@@ -51,9 +51,8 @@ An element displaying basic information about a display item in a list view.
</style>
<div class="header">
{{name}}
- <template if="{{richDetails && richDetails.skp64}}">
- <a class="extra"
- href="data:application/octet-stream;base64,{{richDetails.skp64}}"
+ <template is="dom-if" if="{{_computeIf(richDetails)}}">
+ <a class="extra" href$="{{_computeHref(richDetails)}}"
download="drawing.skp" on-click="{{stopPropagation}}">SKP</a>
</template>
</div>
@@ -61,13 +60,13 @@ An element displaying basic information about a display item in a list view.
<template if="{{rawDetails}}">
<div class="raw-details">{{rawDetails}}</div>
</template>
- <template if="{{richDetails}}" bind="{{richDetails}}">
+ <template is="dom-if" if="{{richDetails}}" bind="{{richDetails}}">
<dl>
- <template if="{{cullRect}}" bind="{{cullRect}}">
+ <template is="dom-if" if="{{cullRect}}" bind="{{cullRect}}">
<dt>Cull rect</dt>
<dd>{{x}},{{y}} {{width}}&times;{{height}}</dd>
</template>
- <template if="{{visualRect}}" bind="{{visualRect}}">
+ <template is="dom-if" if="{{visualRect}}" bind="{{visualRect}}">
<dt>Visual rect</dt>
<dd>{{x}},{{y}} {{width}}&times;{{height}}</dd>
</template>
@@ -75,50 +74,63 @@ An element displaying basic information about a display item in a list view.
</template>
</div>
</template>
- <script>
- 'use strict';
- (function() {
- // Extracts the "type" and "details" parts of the unstructured (plaintext)
- // display item format, even if the details span multiple lines.
- // For example, given "FooDisplayItem type=hello\nworld", produces
- // "FooDisplayItem" as the first capture and "type=hello\nworld" as the
- // second. Either capture could be the empty string, but this regex will
- // still successfully match.
- var DETAILS_SPLIT_REGEX = /^(\S*)\s*([\S\s]*)$/;
+<script>
+'use strict';
+(function() {
+ // Extracts the "type" and "details" parts of the unstructured (plaintext)
+ // display item format, even if the details span multiple lines.
+ // For example, given "FooDisplayItem type=hello\nworld", produces
+ // "FooDisplayItem" as the first capture and "type=hello\nworld" as the
+ // second. Either capture could be the empty string, but this regex will
+ // still successfully match.
+ var DETAILS_SPLIT_REGEX = /^(\S*)\s*([\S\s]*)$/;
- Polymer({
- created: function() {
- this.name = '';
- this.rawDetails = '';
- this.richDetails = undefined;
- this.data_ = undefined;
- },
+ Polymer({
+ is: 'tr-ui-e-chrome-cc-display-item-list-item',
- get data() {
- return this.data_;
- },
+ created: function() {
+ // TODO(charliea): Why is setAttribute necessary here but not below? We
+ // should reach out to the Polymer team to figure out.
+ Polymer.dom(this).setAttribute('name', '');
+ Polymer.dom(this).setAttribute('rawDetails', '');
+ Polymer.dom(this).setAttribute('richDetails', undefined);
+ Polymer.dom(this).setAttribute('data_', undefined);
+ },
- set data(data) {
- this.data_ = data;
+ get data() {
+ return this.data_;
+ },
- if (!data) {
- this.name = 'DATA MISSING';
- this.rawDetails = '';
- this.richDetails = undefined;
- } else if (typeof data === 'string') {
- var match = data.match(DETAILS_SPLIT_REGEX);
- this.name = match[1];
- this.rawDetails = match[2];
- this.richDetails = undefined;
- } else {
- this.name = data.name;
- this.rawDetails = '';
- this.richDetails = data;
- }
- },
+ set data(data) {
+ this.data_ = data;
- stopPropagation: function(e) { e.stopPropagation(); }
- });
- })();
- </script>
-</polymer-element>
+ if (!data) {
+ this.name = 'DATA MISSING';
+ this.rawDetails = '';
+ this.richDetails = undefined;
+ } else if (typeof data === 'string') {
+ var match = data.match(DETAILS_SPLIT_REGEX);
+ this.name = match[1];
+ this.rawDetails = match[2];
+ this.richDetails = undefined;
+ } else {
+ this.name = data.name;
+ this.rawDetails = '';
+ this.richDetails = data;
+ }
+ },
+
+ stopPropagation: function(e) {
+ e.stopPropagation();
+ },
+
+ _computeIf: function(richDetails) {
+ return richDetails && richDetails.skp64;
+ },
+
+ _computeHref: function(richDetails) {
+ return 'data:application/octet-stream;base64,' + richDetails.skp64;
+ }
+ });
+})();
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html
index c66327afc57..c4f9c6b0152 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html
@@ -28,9 +28,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-chrome-cc-display-item-list-view');
+ Polymer.dom(this).classList.add(
+ 'tr-ui-e-chrome-cc-display-item-list-view');
this.displayItemDebugger_ = new tr.ui.e.chrome.cc.DisplayItemDebugger();
- this.appendChild(this.displayItemDebugger_);
+ Polymer.dom(this).appendChild(this.displayItemDebugger_);
},
updateContents: function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html
index 780fe03d86c..c02e129d3b5 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html
@@ -7,14 +7,15 @@ found in the LICENSE file.
<link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/layer_picker.css">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/extras/chrome/cc/constants.html">
<link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html">
<link rel="import" href="/tracing/extras/chrome/cc/util.html">
-<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
<link rel="import" href="/tracing/model/event.html">
+<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
+<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/drag_handle.html">
<link rel="import" href="/tracing/ui/base/list_view.html">
-<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html">
<script>
@@ -22,7 +23,6 @@ found in the LICENSE file.
tr.exportTo('tr.ui.e.chrome.cc', function() {
var constants = tr.e.cc.constants;
- var bytesToRoundedMegabytes = tr.e.cc.bytesToRoundedMegabytes;
var RENDER_PASS_QUADS =
Math.max(constants.ACTIVE_TREE, constants.PENDING_TREE) + 1;
@@ -41,14 +41,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.itemList_ = new tr.ui.b.ListView();
- this.appendChild(this.controls_);
+ Polymer.dom(this).appendChild(this.controls_);
- this.appendChild(this.itemList_);
+ Polymer.dom(this).appendChild(this.itemList_);
this.itemList_.addEventListener(
'selection-changed', this.onItemSelectionChanged_.bind(this));
- this.controls_.appendChild(tr.ui.b.createSelector(
+ Polymer.dom(this.controls_).appendChild(tr.ui.b.createSelector(
this, 'whichTree',
'layerPicker.whichTree', constants.ACTIVE_TREE,
[{label: 'Active tree', value: constants.ACTIVE_TREE},
@@ -60,10 +60,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this, 'showPureTransformLayers',
'layerPicker.showPureTransformLayers', false,
'Transform layers');
- showPureTransformLayers.classList.add('show-transform-layers');
+ Polymer.dom(showPureTransformLayers).classList.add(
+ 'show-transform-layers');
showPureTransformLayers.title =
'When checked, pure transform layers are shown';
- this.controls_.appendChild(showPureTransformLayers);
+ Polymer.dom(this.controls_).appendChild(showPureTransformLayers);
},
get lthiSnapshot() {
@@ -81,7 +82,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
set whichTree(whichTree) {
this.whichTree_ = whichTree;
- this.renderPassQuads_ = (whichTree == RENDER_PASS_QUADS);
+ this.renderPassQuads_ = (whichTree === RENDER_PASS_QUADS);
this.updateContents_();
tr.b.dispatchSimpleEvent(this, 'selection-change', false);
},
@@ -141,8 +142,8 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
function isPureTransformLayer(layer) {
if (layer.args.compositingReasons &&
- layer.args.compositingReasons.length != 1 &&
- layer.args.compositingReasons[0] != 'No reasons given')
+ layer.args.compositingReasons.length !== 1 &&
+ layer.args.compositingReasons[0] !== 'No reasons given')
return false;
if (layer.args.drawsContent)
@@ -172,7 +173,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (showPureTransformLayers || !isPureTransformLayer(layer))
layerInfos.push(info);
- };
+ }
tree.iterLayers(visitLayer);
return layerInfos;
},
@@ -197,14 +198,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var id = renderPassInfo.id;
var item = this.createElementWithDepth_(renderPassInfo.depth);
- var labelEl = item.appendChild(tr.ui.b.createSpan());
+ var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan());
- labelEl.textContent = renderPassInfo.name + ' ' + id;
+ Polymer.dom(labelEl).textContent = renderPassInfo.name + ' ' + id;
item.renderPass = renderPass;
item.renderPassId = id;
- this.itemList_.appendChild(item);
+ Polymer.dom(this.itemList_).appendChild(item);
- if (id == selectedRenderPassId) {
+ if (id === selectedRenderPassId) {
renderPass.selectionState =
tr.model.SelectionState.SELECTED;
}
@@ -226,26 +227,27 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var id = layer.layerId;
var item = this.createElementWithDepth_(layerInfo.depth);
- var labelEl = item.appendChild(tr.ui.b.createSpan());
+ var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan());
- labelEl.textContent = layerInfo.name + ' ' + id;
+ Polymer.dom(labelEl).textContent = layerInfo.name + ' ' + id;
- var notesEl = item.appendChild(tr.ui.b.createSpan());
+ var notesEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan());
if (layerInfo.isMaskLayer)
- notesEl.textContent += '(mask)';
+ Polymer.dom(notesEl).textContent += '(mask)';
if (layerInfo.isReplicaLayer)
- notesEl.textContent += '(replica)';
+ Polymer.dom(notesEl).textContent += '(replica)';
- if (layer.gpuMemoryUsageInBytes !== undefined) {
- var rounded = bytesToRoundedMegabytes(layer.gpuMemoryUsageInBytes);
- if (rounded !== 0)
- notesEl.textContent += ' (' + rounded + ' MB)';
- }
+ if ((layer.gpuMemoryUsageInBytes !== undefined) &&
+ (layer.gpuMemoryUsageInBytes > 0)) {
+ var gpuUsageStr = tr.b.Unit.byName.sizeInBytes.format(
+ layer.gpuMemoryUsageInBytes);
+ Polymer.dom(notesEl).textContent += ' (' + gpuUsageStr + ' MiB)';
+ }
item.layer = layer;
- this.itemList_.appendChild(item);
+ Polymer.dom(this.itemList_).appendChild(item);
- if (layer.layerId == selectedLayerId) {
+ if (layer.layerId === selectedLayerId) {
layer.selectionState = tr.model.SelectionState.SELECTED;
item.selected = true;
}
@@ -258,10 +260,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
createElementWithDepth_: function(depth) {
var item = document.createElement('div');
- var indentEl = item.appendChild(tr.ui.b.createSpan());
+ var indentEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan());
indentEl.style.whiteSpace = 'pre';
- for (var i = 0; i < depth; i++)
- indentEl.textContent = indentEl.textContent + ' ';
+ for (var i = 0; i < depth; i++) {
+ Polymer.dom(indentEl).textContent =
+ Polymer.dom(indentEl).textContent + ' ';
+ }
return item;
},
@@ -308,7 +312,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
},
set selection(selection) {
- if (this.selection_ == selection)
+ if (this.selection_ === selection)
return;
this.selection_ = selection;
this.updateContents_();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html
index d808bc5e869..97a8bfe75e9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html
@@ -9,11 +9,11 @@ found in the LICENSE file.
href="/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.css">
<link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html">
-<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_picker.html">
-<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_view.html">
<link rel="import" href="/tracing/extras/chrome/cc/tile.html">
<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html">
<link rel="import" href="/tracing/ui/base/drag_handle.html">
+<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_picker.html">
+<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_view.html">
<script>
'use strict';
@@ -31,7 +31,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-chrome-cc-lthi-s-view');
+ Polymer.dom(this).classList.add('tr-ui-e-chrome-cc-lthi-s-view');
this.selection_ = undefined;
@@ -48,9 +48,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.dragHandle_.horizontal = false;
this.dragHandle_.target = this.layerView_;
- this.appendChild(this.layerPicker_);
- this.appendChild(this.dragHandle_);
- this.appendChild(this.layerView_);
+ Polymer.dom(this).appendChild(this.layerPicker_);
+ Polymer.dom(this).appendChild(this.dragHandle_);
+ Polymer.dom(this).appendChild(this.layerView_);
// Make sure we have the current values from layerView_ and layerPicker_,
// since those might have been created before we added the listener.
@@ -85,7 +85,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
},
set selection(selection) {
- if (this.selection_ == selection)
+ if (this.selection_ === selection)
return;
this.selection_ = selection;
this.layerPicker_.selection = selection;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html
index a54deecabfc..100741e8bb1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html
@@ -9,6 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/quad.html">
<link rel="import" href="/tracing/base/raf.html">
<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/extras/chrome/cc/debug_colors.html">
<link rel="import" href="/tracing/extras/chrome/cc/picture.html">
<link rel="import" href="/tracing/extras/chrome/cc/render_pass.html">
@@ -87,8 +88,6 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
{label: 'Coverage Rects', value: 'coverage'}];
}
- var bytesToRoundedMegabytes = tr.e.cc.bytesToRoundedMegabytes;
-
/**
* @constructor
@@ -121,21 +120,21 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var node = tr.ui.b.instantiateTemplate(
'#tr-ui-e-chrome-cc-layer-tree-quad-stack-view-template', THIS_DOC);
- this.appendChild(node);
- this.appendChild(this.controls_);
- this.appendChild(this.infoBar_);
- this.appendChild(this.quadStackView_);
+ Polymer.dom(this).appendChild(node);
+ Polymer.dom(this).appendChild(this.controls_);
+ Polymer.dom(this).appendChild(this.infoBar_);
+ Polymer.dom(this).appendChild(this.quadStackView_);
this.tileRectsSelector_ = tr.ui.b.createSelector(
this, 'howToShowTiles',
'layerView.howToShowTiles', 'none',
createTileRectsSelectorBaseOptions());
- this.controls_.appendChild(this.tileRectsSelector_);
+ Polymer.dom(this.controls_).appendChild(this.tileRectsSelector_);
var tileHeatmapText = tr.ui.b.createSpan({
textContent: 'Tile heatmap:'
});
- this.controls_.appendChild(tileHeatmapText);
+ Polymer.dom(this.controls_).appendChild(tileHeatmapText);
var tileHeatmapSelector = tr.ui.b.createSelector(
this, 'tileHeatmapType',
@@ -147,7 +146,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
{label: 'Is using GPU memory',
value: TILE_HEATMAP_TYPE.USING_GPU_MEMORY}
]);
- this.controls_.appendChild(tileHeatmapSelector);
+ Polymer.dom(this.controls_).appendChild(tileHeatmapSelector);
var showOtherLayersCheckbox = tr.ui.b.createCheckBox(
this, 'showOtherLayers',
@@ -155,7 +154,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Other layers/passes');
showOtherLayersCheckbox.title =
'When checked, show all layers, selected or not.';
- this.controls_.appendChild(showOtherLayersCheckbox);
+ Polymer.dom(this.controls_).appendChild(showOtherLayersCheckbox);
var showInvalidationsCheckbox = tr.ui.b.createCheckBox(
this, 'showInvalidations',
@@ -163,7 +162,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Invalidations');
showInvalidationsCheckbox.title =
'When checked, compositing invalidations are highlighted in red';
- this.controls_.appendChild(showInvalidationsCheckbox);
+ Polymer.dom(this.controls_).appendChild(showInvalidationsCheckbox);
var showUnrecordedRegionCheckbox = tr.ui.b.createCheckBox(
this, 'showUnrecordedRegion',
@@ -171,7 +170,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Unrecorded area');
showUnrecordedRegionCheckbox.title =
'When checked, unrecorded areas are highlighted in yellow';
- this.controls_.appendChild(showUnrecordedRegionCheckbox);
+ Polymer.dom(this.controls_).appendChild(showUnrecordedRegionCheckbox);
var showBottlenecksCheckbox = tr.ui.b.createCheckBox(
this, 'showBottlenecks',
@@ -179,7 +178,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Bottlenecks');
showBottlenecksCheckbox.title =
'When checked, scroll bottlenecks are highlighted';
- this.controls_.appendChild(showBottlenecksCheckbox);
+ Polymer.dom(this.controls_).appendChild(showBottlenecksCheckbox);
var showLayoutRectsCheckbox = tr.ui.b.createCheckBox(
this, 'showLayoutRects',
@@ -187,7 +186,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Layout rects');
showLayoutRectsCheckbox.title =
'When checked, shows rects for regions where layout happened';
- this.controls_.appendChild(showLayoutRectsCheckbox);
+ Polymer.dom(this.controls_).appendChild(showLayoutRectsCheckbox);
var showContentsCheckbox = tr.ui.b.createCheckBox(
this, 'showContents',
@@ -195,7 +194,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Contents');
showContentsCheckbox.title =
'When checked, show the rendered contents inside the layer outlines';
- this.controls_.appendChild(showContentsCheckbox);
+ Polymer.dom(this.controls_).appendChild(showContentsCheckbox);
var showAnimationBoundsCheckbox = tr.ui.b.createCheckBox(
this, 'showAnimationBounds',
@@ -203,7 +202,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Animation Bounds');
showAnimationBoundsCheckbox.title = 'When checked, show a border around' +
' a layer showing the extent of its animation.';
- this.controls_.appendChild(showAnimationBoundsCheckbox);
+ Polymer.dom(this.controls_).appendChild(showAnimationBoundsCheckbox);
var showInputEventsCheckbox = tr.ui.b.createCheckBox(
this, 'showInputEvents',
@@ -211,14 +210,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'Input events');
showInputEventsCheckbox.title = 'When checked, input events are ' +
'displayed as circles.';
- this.controls_.appendChild(showInputEventsCheckbox);
+ Polymer.dom(this.controls_).appendChild(showInputEventsCheckbox);
this.whatRasterizedLink_ = document.createElement('a');
- this.whatRasterizedLink_.classList.add('what-rasterized');
- this.whatRasterizedLink_.textContent = 'What rasterized?';
+ Polymer.dom(this.whatRasterizedLink_).classList.add('what-rasterized');
+ Polymer.dom(this.whatRasterizedLink_).textContent = 'What rasterized?';
this.whatRasterizedLink_.addEventListener(
'click', this.onWhatRasterizedLinkClicked_.bind(this));
- this.appendChild(this.whatRasterizedLink_);
+ Polymer.dom(this).appendChild(this.whatRasterizedLink_);
},
get layerTreeImpl() {
@@ -383,7 +382,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var selectableQuads = e.quads.filter(function(q) {
return q.selectionToSetIfClicked !== undefined;
});
- if (selectableQuads.length == 0) {
+ if (selectableQuads.length === 0) {
this.selection = undefined;
return;
}
@@ -391,7 +390,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
// Sort the quads low to high on stackingGroupId.
selectableQuads.sort(function(x, y) {
var z = x.stackingGroupId - y.stackingGroupId;
- if (z != 0)
+ if (z !== 0)
return z;
return x.selectionToSetIfClicked.specicifity -
y.selectionToSetIfClicked.specicifity;
@@ -440,18 +439,20 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var thisTreeUsageInBytes = this.layerTreeImpl_.gpuMemoryUsageInBytes;
var otherTreeUsageInBytes = lthi.gpuMemoryUsageInBytes -
thisTreeUsageInBytes;
- message += bytesToRoundedMegabytes(thisTreeUsageInBytes) +
- 'MB on this tree';
+ message += tr.b.convertUnit(thisTreeUsageInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on this tree';
if (otherTreeUsageInBytes) {
- message += ', ' +
- bytesToRoundedMegabytes(otherTreeUsageInBytes) +
- 'MB on the other tree';
+ message += ', ' + tr.b.convertUnit(otherTreeUsageInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on the other tree';
}
} else {
if (this.layerTreeImpl_) {
var thisTreeUsageInBytes = this.layerTreeImpl_.gpuMemoryUsageInBytes;
- message += bytesToRoundedMegabytes(thisTreeUsageInBytes) +
- 'MB on this tree';
+ message += tr.b.convertUnit(thisTreeUsageInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on this tree';
if (this.layerTreeImpl_.otherTree) {
// Older Chromes don't report enough data to know how much memory is
@@ -461,7 +462,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
// plus one tree, to guess the unique on the other tree, etc. Newer
// chromes report memory per tile, which allows LTHI to compute the
// total tile memory usage, letting us figure things out properly.
- message += ', ???MB on other tree. ';
+ message += ', ??? MiB on other tree. ';
}
}
}
@@ -469,10 +470,13 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (lthi.args.tileManagerBasicState) {
var tmgs = lthi.args.tileManagerBasicState.globalState;
message += ' (softMax=' +
- bytesToRoundedMegabytes(tmgs.softMemoryLimitInBytes) +
- 'MB, hardMax=' +
- bytesToRoundedMegabytes(tmgs.hardMemoryLimitInBytes) + 'MB, ' +
- tmgs.memoryLimitPolicy + ')';
+ tr.b.convertUnit(tmgs.softMemoryLimitInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, hardMax=' +
+ tr.b.convertUnit(tmgs.hardMemoryLimitInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, ' +
+ tmgs.memoryLimitPolicy + ')';
} else {
// Old Chromes do not have a globalState on the LTHI dump.
@@ -495,10 +499,13 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var newest = didManageTilesSlices[didManageTilesSlices.length - 1];
var tmgs = newest.args.state.global_state;
message += ' (softMax=' +
- bytesToRoundedMegabytes(tmgs.soft_memory_limit_in_bytes) +
- 'MB, hardMax=' +
- bytesToRoundedMegabytes(tmgs.hard_memory_limit_in_bytes) + 'MB, ' +
- tmgs.memory_limit_policy + ')';
+ tr.b.convertUnit(tmgs.softMemoryLimitInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, hardMax=' +
+ tr.b.convertUnit(tmgs.hardMemoryLimitInBytes,
+ tr.b.UnitScale.Binary.NONE,
+ tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, ' +
+ tmgs.memoryLimitPolicy + ')';
}
}
@@ -530,12 +537,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
}
// Then create a new selector and replace the old one.
- var new_selector = tr.ui.b.createSelector(
+ var newSelector = tr.ui.b.createSelector(
this, 'howToShowTiles',
'layerView.howToShowTiles', 'none',
data);
- this.controls_.replaceChild(new_selector, this.tileRectsSelector_);
- this.tileRectsSelector_ = new_selector;
+ this.controls_.replaceChild(newSelector, this.tileRectsSelector_);
+ this.tileRectsSelector_ = newSelector;
},
computePictureLoadingStatus_: function() {
@@ -614,7 +621,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
}
if (this.showInputEvents && this.layerTreeImpl.tracedInputLatencies &&
this.inputEventImageData_ === undefined) {
- var image = this.querySelector('#input-event');
+ var image = Polymer.dom(this).querySelector('#input-event');
if (!image.src) {
this.loadDataForImageElement_(image, function(imageData) {
this.inputEventImageData_ = imageData;
@@ -858,11 +865,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
},
getValueForHeatmap_: function(tile, heatmapType) {
- if (heatmapType == TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) {
- return tile.scheduledPriority == 0 ?
+ if (heatmapType === TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) {
+ return tile.scheduledPriority === 0 ?
undefined :
tile.scheduledPriority;
- } else if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
+ } else if (heatmapType === TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
if (tile.isSolidColor)
return 0.5;
return tile.isUsingGpuMemory ? 0 : 1;
@@ -871,7 +878,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
getMinMaxForHeatmap_: function(tiles, heatmapType) {
var range = new tr.b.Range();
- if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
+ if (heatmapType === TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
range.addValue(0);
range.addValue(1);
return range;
@@ -926,7 +933,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
// TODO(vmpstr): Make the stiching of tiles and layers a part of
// tile construction (issue 346)
- if (layer.layerId != tile.layerId)
+ if (layer.layerId !== tile.layerId)
continue;
tiles.push(tile);
@@ -1030,7 +1037,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
// Generate quads back-to-front.
var layer = layers[layers.length - i];
alreadyVisitedLayerIds[layer.layerId] = true;
- if (layer.objectInstance.name == 'cc::NinePatchLayerImpl')
+ if (layer.objectInstance.name === 'cc::NinePatchLayerImpl')
continue;
var layerQuad = layer.layerQuad.clone();
@@ -1044,7 +1051,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
layerQuad.stackingGroupId = nextStackingGroupId++;
layerQuad.selectionToSetIfClicked = new cc.LayerSelection(layer);
layerQuad.layer = layer;
- if (this.showOtherLayers && this.selectedLayer == layer)
+ if (this.showOtherLayers && this.selectedLayer === layer)
layerQuad.upperBorderColor = 'rgb(156,189,45)';
if (this.showAnimationBounds)
@@ -1088,7 +1095,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
}
this.layerTreeImpl.iterLayers(function(layer, depth, isMask, isReplica) {
- if (!this.showOtherLayers && this.selectedLayer != layer)
+ if (!this.showOtherLayers && this.selectedLayer !== layer)
return;
if (alreadyVisitedLayerIds[layer.layerId])
return;
@@ -1124,16 +1131,16 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.infoBar_.message = 'Some problems were encountered...';
this.infoBar_.addButton('More info...', function(e) {
var overlay = new tr.ui.b.Overlay();
- overlay.textContent = '';
+ Polymer.dom(overlay).textContent = '';
infoBarMessages.forEach(function(message) {
var title = document.createElement('h3');
- title.textContent = message.header;
+ Polymer.dom(title).textContent = message.header;
var details = document.createElement('div');
- details.textContent = message.details;
+ Polymer.dom(details).textContent = message.details;
- overlay.appendChild(title);
- overlay.appendChild(details);
+ Polymer.dom(overlay).appendChild(title);
+ Polymer.dom(overlay).appendChild(details);
});
overlay.visible = true;
@@ -1160,7 +1167,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (tile === undefined)
continue;
- if (tile.containingSnapshot == lthi)
+ if (tile.containingSnapshot === lthi)
tasks.push(event);
}
return tasks;
@@ -1169,10 +1176,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
updateWhatRasterizedLinkState_: function() {
var tasks = this.getWhatRasterized_();
if (tasks.length) {
- this.whatRasterizedLink_.textContent = tasks.length + ' raster tasks';
+ Polymer.dom(this.whatRasterizedLink_).textContent =
+ tasks.length + ' raster tasks';
this.whatRasterizedLink_.style.display = '';
} else {
- this.whatRasterizedLink_.textContent = '';
+ Polymer.dom(this.whatRasterizedLink_).textContent = '';
this.whatRasterizedLink_.style.display = 'none';
}
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html
index ab2a403283b..9bd34e084b6 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html
@@ -31,7 +31,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var LayerView = tr.ui.b.define('tr-ui-e-chrome-cc-layer-view');
LayerView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.layerTreeQuadStackView_ =
@@ -44,9 +44,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.dragBar_.target = this.analysisEl_;
- this.appendChild(this.layerTreeQuadStackView_);
- this.appendChild(this.dragBar_);
- this.appendChild(this.analysisEl_);
+ Polymer.dom(this).appendChild(this.layerTreeQuadStackView_);
+ Polymer.dom(this).appendChild(this.dragBar_);
+ Polymer.dom(this).appendChild(this.analysisEl_);
this.layerTreeQuadStackView_.addEventListener('selection-change',
function() {
@@ -84,22 +84,22 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (selection) {
this.dragBar_.style.display = '';
this.analysisEl_.style.display = '';
- this.analysisEl_.textContent = '';
+ Polymer.dom(this.analysisEl_).textContent = '';
var layer = selection.layer;
if (layer && layer.args && layer.args.pictures) {
- this.analysisEl_.appendChild(
+ Polymer.dom(this.analysisEl_).appendChild(
this.createPictureBtn_(layer.args.pictures));
}
var analysis = selection.createAnalysis();
- this.analysisEl_.appendChild(analysis);
+ Polymer.dom(this.analysisEl_).appendChild(analysis);
} else {
this.dragBar_.style.display = 'none';
this.analysisEl_.style.display = 'none';
- var analysis = this.analysisEl_.firstChild;
+ var analysis = Polymer.dom(this.analysisEl_).firstChild;
if (analysis)
- this.analysisEl_.removeChild(analysis);
+ Polymer.dom(this.analysisEl_).removeChild(analysis);
this.layerTreeQuadStackView_.style.height =
window.getComputedStyle(this).height;
}
@@ -120,7 +120,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
selection.push(snapshot);
return selection;
};
- link.textContent = 'View in Picture Debugger';
+ Polymer.dom(link).textContent = 'View in Picture Debugger';
return link;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html
index 28d51d16d93..7240a75f386 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html
@@ -9,8 +9,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/extras/chrome/cc/picture.html">
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
<link rel="import" href="/tracing/ui/base/drag_handle.html">
-<link rel="import" href="/tracing/ui/base/info_bar.html">
<link rel="import" href="/tracing/ui/base/hotkey_controller.html">
+<link rel="import" href="/tracing/ui/base/info_bar.html">
<link rel="import" href="/tracing/ui/base/list_view.html">
<link rel="import" href="/tracing/ui/base/mouse_mode_selector.html">
<link rel="import" href="/tracing/ui/base/overlay.html">
@@ -120,24 +120,25 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var PictureDebugger = tr.ui.b.define('tr-ui-e-chrome-cc-picture-debugger');
PictureDebugger.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
var node = tr.ui.b.instantiateTemplate(
'#tr-ui-e-chrome-cc-picture-debugger-template', THIS_DOC);
- this.appendChild(node);
+ Polymer.dom(this).appendChild(node);
this.pictureAsImageData_ = undefined;
this.showOverdraw_ = false;
this.zoomScaleValue_ = 1;
- this.sizeInfo_ = this.querySelector('.size');
- this.rasterArea_ = this.querySelector('raster-area');
- this.rasterCanvas_ = this.rasterArea_.querySelector('canvas');
+ this.sizeInfo_ = Polymer.dom(this).querySelector('.size');
+ this.rasterArea_ = Polymer.dom(this).querySelector('raster-area');
+ this.rasterCanvas_ = Polymer.dom(this.rasterArea_)
+ .querySelector('canvas');
this.rasterCtx_ = this.rasterCanvas_.getContext('2d');
- this.filename_ = this.querySelector('.filename');
+ this.filename_ = Polymer.dom(this).querySelector('.filename');
this.drawOpsChartSummaryView_ =
new tr.ui.e.chrome.cc.PictureOpsChartSummaryView();
@@ -145,7 +146,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.drawOpsChartView_.addEventListener(
'selection-changed', this.onChartBarClicked_.bind(this));
- this.exportButton_ = this.querySelector('.export');
+ this.exportButton_ = Polymer.dom(this).querySelector('.export');
this.exportButton_.addEventListener(
'click', this.onSaveAsSkPictureClicked_.bind(this));
@@ -161,31 +162,31 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'pictureView.showSummaryChart', false,
'Show timing summary');
- var pictureInfo = this.querySelector('picture-info');
- pictureInfo.appendChild(overdrawCheckbox);
- pictureInfo.appendChild(chartCheckbox);
+ var pictureInfo = Polymer.dom(this).querySelector('picture-info');
+ Polymer.dom(pictureInfo).appendChild(overdrawCheckbox);
+ Polymer.dom(pictureInfo).appendChild(chartCheckbox);
this.drawOpsView_ = new tr.ui.e.chrome.cc.PictureOpsListView();
this.drawOpsView_.addEventListener(
'selection-changed', this.onChangeDrawOps_.bind(this));
- var leftPanel = this.querySelector('left-panel');
- leftPanel.appendChild(this.drawOpsChartSummaryView_);
- leftPanel.appendChild(this.drawOpsView_);
+ var leftPanel = Polymer.dom(this).querySelector('left-panel');
+ Polymer.dom(leftPanel).appendChild(this.drawOpsChartSummaryView_);
+ Polymer.dom(leftPanel).appendChild(this.drawOpsView_);
var middleDragHandle = document.createElement('tr-ui-b-drag-handle');
middleDragHandle.horizontal = false;
middleDragHandle.target = leftPanel;
- var rightPanel = this.querySelector('right-panel');
+ var rightPanel = Polymer.dom(this).querySelector('right-panel');
rightPanel.replaceChild(
- this.drawOpsChartView_,
- rightPanel.querySelector('tr-ui-e-chrome-cc-picture-ops-chart-view'));
+ this.drawOpsChartView_, Polymer.dom(rightPanel)
+ .querySelector('tr-ui-e-chrome-cc-picture-ops-chart-view'));
this.infoBar_ = document.createElement('tr-ui-b-info-bar');
- this.rasterArea_.appendChild(this.infoBar_);
+ Polymer.dom(this.rasterArea_).appendChild(this.infoBar_);
- this.insertBefore(middleDragHandle, rightPanel);
+ Polymer.dom(this).insertBefore(middleDragHandle, rightPanel);
this.picture_ = undefined;
@@ -208,7 +209,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
e.stopPropagation();
}
}));
- this.appendChild(hkc);
+ Polymer.dom(this).appendChild(hkc);
// Add a mutation observer so that when the view is resized we can
// update the chart summary view.
@@ -315,7 +316,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.updateContentsPending_ = false;
if (this.picture_) {
- this.sizeInfo_.textContent = '(' +
+ Polymer.dom(this.sizeInfo_).textContent = '(' +
this.picture_.layerRect.width + ' x ' +
this.picture_.layerRect.height + ')';
}
@@ -333,7 +334,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.infoBar_.message = 'Cannot rasterize...';
this.infoBar_.addButton('More info...', function(e) {
var overlay = new tr.ui.b.Overlay();
- overlay.textContent = this.pictureAsImageData_.error;
+ Polymer.dom(overlay).textContent = this.pictureAsImageData_.error;
overlay.visible = true;
e.stopPropagation();
return false;
@@ -432,7 +433,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.mouseModeSelector_ = document.createElement(
'tr-ui-b-mouse-mode-selector');
this.mouseModeSelector_.targetElement = this.rasterArea_;
- this.rasterArea_.appendChild(this.mouseModeSelector_);
+ Polymer.dom(this.rasterArea_).appendChild(this.mouseModeSelector_);
this.mouseModeSelector_.supportedModeMask =
tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html
index 5ac0efb3d71..c9d60769fdc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html
@@ -39,7 +39,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
'tr-ui-e-chrome-cc-picture-ops-chart-summary-view');
PictureOpsChartSummaryView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.picture_ = undefined;
@@ -49,7 +49,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.chart_ = document.createElement('canvas');
this.chartCtx_ = this.chart_.getContext('2d');
- this.appendChild(this.chart_);
+ Polymer.dom(this).appendChild(this.chart_);
this.opsTimingData_ = [];
@@ -78,7 +78,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.picture_ = picture;
this.pictureDataProcessed_ = false;
- if (this.classList.contains('hidden'))
+ if (Polymer.dom(this).classList.contains('hidden'))
return;
this.processPictureData_();
@@ -87,12 +87,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
},
hide: function() {
- this.classList.add('hidden');
+ Polymer.dom(this).classList.add('hidden');
},
show: function() {
- this.classList.remove('hidden');
+ Polymer.dom(this).classList.remove('hidden');
if (this.pictureDataProcessed_)
return;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html
index a62f128e6b9..fe71fc87735 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html
@@ -38,7 +38,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
tr.ui.b.define('tr-ui-e-chrome-cc-picture-ops-chart-view');
PictureOpsChartView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.picture_ = undefined;
@@ -49,7 +49,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this.chart_ = document.createElement('canvas');
this.chartCtx_ = this.chart_.getContext('2d');
- this.appendChild(this.chart_);
+ Polymer.dom(this).appendChild(this.chart_);
this.selectedOpIndex_ = undefined;
this.chartWidth_ = 0;
@@ -69,8 +69,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
this, 'usePercentileScale',
'PictureOpsChartView.usePercentileScale', false,
'Limit to 95%-ile');
- this.usePercentileScaleCheckbox_.classList.add('use-percentile-scale');
- this.appendChild(this.usePercentileScaleCheckbox_);
+ Polymer.dom(this.usePercentileScaleCheckbox_).classList.add(
+ 'use-percentile-scale');
+ Polymer.dom(this).appendChild(this.usePercentileScaleCheckbox_);
},
get dimensionsHaveChanged() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html
index 1bae14a635f..806a54c5c30 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html
@@ -8,8 +8,8 @@ found in the LICENSE file.
<link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/picture_ops_list_view.css">
<link rel="import" href="/tracing/extras/chrome/cc/constants.html">
-<link rel="import" href="/tracing/ui/base/list_view.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/list_view.html">
<link rel="import" href="/tracing/ui/base/utils.html">
<link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html">
@@ -34,11 +34,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
tr.ui.b.define('tr-ui-e-chrome-cc-picture-ops-list-view');
PictureOpsListView.prototype = {
- __proto__: HTMLUnknownElement.prototype,
+ __proto__: HTMLDivElement.prototype,
decorate: function() {
this.opsList_ = new tr.ui.b.ListView();
- this.appendChild(this.opsList_);
+ Polymer.dom(this).appendChild(this.opsList_);
this.selectedOp_ = undefined;
this.selectedOpIndex_ = undefined;
@@ -75,21 +75,21 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
var op = ops[i];
var item = document.createElement('div');
item.opIndex = op.opIndex;
- item.textContent = i + ') ' + op.cmd_string;
+ Polymer.dom(item).textContent = i + ') ' + op.cmd_string;
// Display the element info associated with the op, if available.
if (op.elementInfo.tag || op.elementInfo.id || op.elementInfo.class) {
var elementInfo = document.createElement('span');
- elementInfo.classList.add('elementInfo');
+ Polymer.dom(elementInfo).classList.add('elementInfo');
var tag = op.elementInfo.tag ? op.elementInfo.tag : 'unknown';
var id = op.elementInfo.id ? 'id=' + op.elementInfo.id : undefined;
var className = op.elementInfo.class ? 'class=' +
op.elementInfo.class : undefined;
- elementInfo.textContent =
+ Polymer.dom(elementInfo).textContent =
'<' + tag + (id ? ' ' : '') +
(id ? id : '') + (className ? ' ' : '') +
(className ? className : '') + '>';
- item.appendChild(elementInfo);
+ Polymer.dom(item).appendChild(elementInfo);
}
// Display the Skia params.
@@ -97,20 +97,20 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
// (https://github.com/google/trace-viewer/issues/782)
if (op.info.length > 0) {
var infoItem = document.createElement('div');
- infoItem.textContent = JSON.stringify(op.info);
- item.appendChild(infoItem);
+ Polymer.dom(infoItem).textContent = JSON.stringify(op.info);
+ Polymer.dom(item).appendChild(infoItem);
}
// Display the op timing, if available.
if (op.cmd_time && op.cmd_time >= 0.0001) {
var time = document.createElement('span');
- time.classList.add('time');
+ Polymer.dom(time).classList.add('time');
var rounded = op.cmd_time.toFixed(4);
- time.textContent = '(' + rounded + 'ms)';
- item.appendChild(time);
+ Polymer.dom(time).textContent = '(' + rounded + 'ms)';
+ Polymer.dom(item).appendChild(time);
}
- this.opsList_.appendChild(item);
+ Polymer.dom(this.opsList_).appendChild(item);
}
},
@@ -134,9 +134,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
beforeSelectedOp = false;
this.selectedOpIndex_ = op.opIndex;
} else if (beforeSelectedOp) {
- op.setAttribute('beforeSelection', 'beforeSelection');
+ Polymer.dom(op).setAttribute('beforeSelection', 'beforeSelection');
} else {
- op.removeAttribute('beforeSelection');
+ Polymer.dom(op).removeAttribute('beforeSelection');
}
}
@@ -204,15 +204,15 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
elementInfo = {};
annotationGroup.forEach(function(annotation) {
annotation.info.forEach(function(info) {
- if (info.indexOf(ANNOTATION_TAG) != -1)
+ if (info.indexOf(ANNOTATION_TAG) !== -1)
elementInfo.tag = info.substring(
info.indexOf(ANNOTATION_TAG) +
ANNOTATION_TAG.length).toLowerCase();
- else if (info.indexOf(ANNOTATION_ID) != -1)
+ else if (info.indexOf(ANNOTATION_ID) !== -1)
elementInfo.id = info.substring(
info.indexOf(ANNOTATION_ID) +
ANNOTATION_ID.length);
- else if (info.indexOf(ANNOTATION_CLASS) != -1)
+ else if (info.indexOf(ANNOTATION_CLASS) !== -1)
elementInfo.class = info.substring(
info.indexOf(ANNOTATION_CLASS) +
ANNOTATION_CLASS.length);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html
index 74acef3e37b..ccb0b04e88e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html
@@ -28,9 +28,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-chrome-cc-picture-snapshot-view');
+ Polymer.dom(this).classList.add(
+ 'tr-ui-e-chrome-cc-picture-snapshot-view');
this.pictureDebugger_ = new tr.ui.e.chrome.cc.PictureDebugger();
- this.appendChild(this.pictureDebugger_);
+ Polymer.dom(this).appendChild(this.pictureDebugger_);
},
updateContents: function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html
index 2838c5b63ed..7dd256e40c7 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html
@@ -52,7 +52,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
if (!referenceSnapshot) {
referenceSnapshot = tile.containingSnapshot;
} else {
- if (tile.containingSnapshot != referenceSnapshot) {
+ if (tile.containingSnapshot !== referenceSnapshot) {
return {
ok: false,
why: 'Raster tasks are from different compositor instances'
@@ -77,7 +77,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
get associatedLayerId() {
var tile0 = this.tiles_[0];
var allSameLayer = this.tiles_.every(function(tile) {
- tile.layerId == tile0.layerId;
+ tile.layerId === tile0.layerId;
});
if (allSameLayer)
return tile0.layerId;
@@ -105,7 +105,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
});
var analysis;
- if (sel.length == 1)
+ if (sel.length === 1)
analysis = document.createElement('tr-ui-a-single-event-sub-view');
else
analysis = document.createElement('tr-ui-e-chrome-cc-raster-task-view');
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
index ee8e91c3c77..652bbc9b7cf 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = m.processes[1];
var rasterTasks = p.threads[1].sliceGroup.slices.filter(function(slice) {
- return slice.title == 'RasterTask';
+ return slice.title === 'RasterTask';
});
var selection = new tr.model.EventSet();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html
index b4020840303..7ab2cbda14b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html
@@ -4,15 +4,16 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/extras/chrome/cc/raster_task.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-e-chrome-cc-raster-task-view">
+<dom-module id='tr-ui-e-chrome-cc-raster-task-view'>
<template>
<style>
:host {
@@ -22,6 +23,9 @@ found in the LICENSE file.
#heading {
flex: 0 0 auto;
}
+ tr-ui-b-table {
+ font-size: 12px;
+ }
</style>
<div id="heading">
@@ -30,187 +34,187 @@ found in the LICENSE file.
</div>
<tr-ui-b-table id="content"></tr-ui-b-table>
</template>
-
- <script>
- 'use strict';
- Polymer({
- created: function() {
- this.selection_ = undefined;
- },
-
- set selection(selection) {
- this.selection_ = selection;
-
- this.updateContents_();
- },
-
- updateColumns_: function(hadCpuDurations) {
- var timeSpanConfig = {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: this.ownerDocument
- };
-
- var columns = [
- {
- title: 'Layer',
- value: function(row) {
- if (row.isTotals)
- return 'Totals';
- if (row.layer) {
- var linkEl = document.createElement('tr-ui-a-analysis-link');
- linkEl.setSelectionAndContent(
- function() {
- return new tr.ui.e.chrome.cc.LayerSelection(costs.layer);
- },
- 'Layer ' + row.layerId);
- return linkEl;
- } else {
- return 'Layer ' + row.layerId;
- }
- },
- width: '250px'
- },
- {
- title: 'Num Tiles',
- value: function(row) { return row.numTiles; },
- cmp: function(a, b) { return a.numTiles - b.numTiles; }
- },
- {
- title: 'Num Analysis Tasks',
- value: function(row) { return row.numAnalysisTasks; },
- cmp: function(a, b) {
- return a.numAnalysisTasks - b.numAnalysisTasks;
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-e-chrome-cc-raster-task-view',
+
+ created: function() {
+ this.selection_ = undefined;
+ },
+
+ set selection(selection) {
+ this.selection_ = selection;
+
+ this.updateContents_();
+ },
+
+ updateColumns_: function(hadCpuDurations) {
+ var timeSpanConfig = {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ ownerDocument: this.ownerDocument
+ };
+
+ var columns = [
+ {
+ title: 'Layer',
+ value: function(row) {
+ if (row.isTotals)
+ return 'Totals';
+ if (row.layer) {
+ var linkEl = document.createElement('tr-ui-a-analysis-link');
+ linkEl.setSelectionAndContent(
+ function() {
+ return new tr.ui.e.chrome.cc.LayerSelection(costs.layer);
+ },
+ 'Layer ' + row.layerId);
+ return linkEl;
+ } else {
+ return 'Layer ' + row.layerId;
}
},
- {
- title: 'Num Raster Tasks',
- value: function(row) { return row.numRasterTasks; },
- cmp: function(a, b) { return a.numRasterTasks - b.numRasterTasks; }
- },
- {
- title: 'Wall Duration (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.duration, timeSpanConfig);
- },
- cmp: function(a, b) { return a.duration - b.duration; }
+ width: '250px'
+ },
+ {
+ title: 'Num Tiles',
+ value: function(row) { return row.numTiles; },
+ cmp: function(a, b) { return a.numTiles - b.numTiles; }
+ },
+ {
+ title: 'Num Analysis Tasks',
+ value: function(row) { return row.numAnalysisTasks; },
+ cmp: function(a, b) {
+ return a.numAnalysisTasks - b.numAnalysisTasks;
}
- ];
-
- if (hadCpuDurations) {
- columns.push({
- title: 'CPU Duration (ms)',
- value: function(row) {
- return tr.v.ui.createScalarSpan(row.cpuDuration, timeSpanConfig);
- },
- cmp: function(a, b) { return a.cpuDuration - b.cpuDuration; }
- });
+ },
+ {
+ title: 'Num Raster Tasks',
+ value: function(row) { return row.numRasterTasks; },
+ cmp: function(a, b) { return a.numRasterTasks - b.numRasterTasks; }
+ },
+ {
+ title: 'Wall Duration (ms)',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.duration, timeSpanConfig);
+ },
+ cmp: function(a, b) { return a.duration - b.duration; }
}
+ ];
- var colWidthPercentage;
- if (columns.length == 1)
- colWidthPercentage = '100%';
- else
- colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
+ if (hadCpuDurations) {
+ columns.push({
+ title: 'CPU Duration (ms)',
+ value: function(row) {
+ return tr.v.ui.createScalarSpan(row.cpuDuration, timeSpanConfig);
+ },
+ cmp: function(a, b) { return a.cpuDuration - b.cpuDuration; }
+ });
+ }
- for (var i = 1; i < columns.length; i++)
- columns[i].width = colWidthPercentage;
+ var colWidthPercentage;
+ if (columns.length === 1)
+ colWidthPercentage = '100%';
+ else
+ colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
- this.$.content.tableColumns = columns;
- this.$.content.sortColumnIndex = columns.length - 1;
- },
+ for (var i = 1; i < columns.length; i++)
+ columns[i].width = colWidthPercentage;
- updateContents_: function() {
- var table = this.$.content;
+ this.$.content.tableColumns = columns;
+ this.$.content.sortColumnIndex = columns.length - 1;
+ },
- if (this.selection_.length === 0) {
- this.$.link.setSelectionAndContent(undefined, '');
- table.tableRows = [];
- table.footerRows = [];
- table.rebuild();
- return;
- }
+ updateContents_: function() {
+ var table = this.$.content;
- // LTHI link.
- var lthi = tr.e.cc.getTileFromRasterTaskSlice(
- this.selection_[0]).containingSnapshot;
- this.$.link.setSelectionAndContent(function() {
- return new tr.model.EventSet(lthi);
- }, lthi.userFriendlyName);
-
- // Get costs by layer.
- var costsByLayerId = {};
- function getCurrentCostsForLayerId(tile) {
- var layerId = tile.layerId;
- var lthi = tile.containingSnapshot;
- var layer;
- if (lthi.activeTree)
- layer = lthi.activeTree.findLayerWithId(layerId);
- if (layer === undefined && lthi.pendingTree)
- layer = lthi.pendingTree.findLayerWithId(layerId);
- if (costsByLayerId[layerId] === undefined) {
- costsByLayerId[layerId] = {
- layerId: layerId,
- layer: layer,
- numTiles: 0,
- numAnalysisTasks: 0,
- numRasterTasks: 0,
- duration: 0,
- cpuDuration: 0
- };
- }
- return costsByLayerId[layerId];
+ if (this.selection_.length === 0) {
+ this.$.link.setSelectionAndContent(undefined, '');
+ table.tableRows = [];
+ table.footerRows = [];
+ table.rebuild();
+ return;
+ }
+ // LTHI link.
+ var lthi = tr.e.cc.getTileFromRasterTaskSlice(
+ tr.b.getFirstElement(this.selection_)).containingSnapshot;
+ this.$.link.setSelectionAndContent(function() {
+ return new tr.model.EventSet(lthi);
+ }, lthi.userFriendlyName);
+
+ // Get costs by layer.
+ var costsByLayerId = {};
+ function getCurrentCostsForLayerId(tile) {
+ var layerId = tile.layerId;
+ var lthi = tile.containingSnapshot;
+ var layer;
+ if (lthi.activeTree)
+ layer = lthi.activeTree.findLayerWithId(layerId);
+ if (layer === undefined && lthi.pendingTree)
+ layer = lthi.pendingTree.findLayerWithId(layerId);
+ if (costsByLayerId[layerId] === undefined) {
+ costsByLayerId[layerId] = {
+ layerId: layerId,
+ layer: layer,
+ numTiles: 0,
+ numAnalysisTasks: 0,
+ numRasterTasks: 0,
+ duration: 0,
+ cpuDuration: 0
+ };
}
+ return costsByLayerId[layerId];
+ }
- var totalDuration = 0;
- var totalCpuDuration = 0;
- var totalNumAnalyzeTasks = 0;
- var totalNumRasterizeTasks = 0;
- var hadCpuDurations = false;
-
- var tilesThatWeHaveSeen = {};
-
- this.selection_.forEach(function(slice) {
- var tile = tr.e.cc.getTileFromRasterTaskSlice(slice);
- var curCosts = getCurrentCostsForLayerId(tile);
+ var totalDuration = 0;
+ var totalCpuDuration = 0;
+ var totalNumAnalyzeTasks = 0;
+ var totalNumRasterizeTasks = 0;
+ var hadCpuDurations = false;
- if (!tilesThatWeHaveSeen[tile.objectInstance.id]) {
- tilesThatWeHaveSeen[tile.objectInstance.id] = true;
- curCosts.numTiles += 1;
- }
+ var tilesThatWeHaveSeen = {};
- if (tr.e.cc.isSliceDoingAnalysis(slice)) {
- curCosts.numAnalysisTasks += 1;
- totalNumAnalyzeTasks += 1;
- } else {
- curCosts.numRasterTasks += 1;
- totalNumRasterizeTasks += 1;
- }
- curCosts.duration += slice.duration;
- totalDuration += slice.duration;
- if (slice.cpuDuration !== undefined) {
- curCosts.cpuDuration += slice.cpuDuration;
- totalCpuDuration += slice.cpuDuration;
- hadCpuDurations = true;
- }
- });
+ this.selection_.forEach(function(slice) {
+ var tile = tr.e.cc.getTileFromRasterTaskSlice(slice);
+ var curCosts = getCurrentCostsForLayerId(tile);
- // Apply to the table.
- this.updateColumns_(hadCpuDurations);
- table.tableRows = tr.b.dictionaryValues(costsByLayerId);
- table.rebuild();
+ if (!tilesThatWeHaveSeen[tile.objectInstance.id]) {
+ tilesThatWeHaveSeen[tile.objectInstance.id] = true;
+ curCosts.numTiles += 1;
+ }
- // Footer.
- table.footerRows = [
- {
- isTotals: true,
- numTiles: tr.b.dictionaryLength(tilesThatWeHaveSeen),
- numAnalysisTasks: totalNumAnalyzeTasks,
- numRasterTasks: totalNumRasterizeTasks,
- duration: totalDuration,
- cpuDuration: totalCpuDuration
- }
- ];
- }
- });
- </script>
-</polymer-element>
+ if (tr.e.cc.isSliceDoingAnalysis(slice)) {
+ curCosts.numAnalysisTasks += 1;
+ totalNumAnalyzeTasks += 1;
+ } else {
+ curCosts.numRasterTasks += 1;
+ totalNumRasterizeTasks += 1;
+ }
+ curCosts.duration += slice.duration;
+ totalDuration += slice.duration;
+ if (slice.cpuDuration !== undefined) {
+ curCosts.cpuDuration += slice.cpuDuration;
+ totalCpuDuration += slice.cpuDuration;
+ hadCpuDurations = true;
+ }
+ });
+
+ // Apply to the table.
+ this.updateColumns_(hadCpuDurations);
+ table.tableRows = tr.b.dictionaryValues(costsByLayerId);
+ table.rebuild();
+
+ // Footer.
+ table.footerRows = [
+ {
+ isTotals: true,
+ numTiles: tr.b.dictionaryLength(tilesThatWeHaveSeen),
+ numAnalysisTasks: totalNumAnalyzeTasks,
+ numRasterTasks: totalNumRasterizeTasks,
+ duration: totalDuration,
+ cpuDuration: totalCpuDuration
+ }
+ ];
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
index be771775cb7..cb3d11d4953 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
@@ -29,7 +29,7 @@ tr.b.unittest.testSuite(function() {
var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = m.processes[1];
var rasterTasks = p.threads[1].sliceGroup.slices.filter(function(slice) {
- return slice.title == 'RasterTask' || slice.title == 'AnalyzeTask';
+ return slice.title === 'RasterTask' || slice.title === 'AnalyzeTask';
});
var selection = new tr.model.EventSet();
@@ -58,7 +58,7 @@ tr.b.unittest.testSuite(function() {
analysisEl.brushingStateController = brushingStateController;
brushingStateController.changeSelectionFromTimeline(selection);
- assert.isDefined(analysisEl.querySelector(
+ assert.isDefined(Polymer.dom(analysisEl).querySelector(
'tr-ui-e-chrome-cc-raster-task-view'));
var sv = tr.b.findDeepElementMatching(
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html
index 2c556c67a7b..16e0bf0f347 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html
@@ -26,10 +26,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-chrome-cc-tile-snapshot-view');
+ Polymer.dom(this).classList.add('tr-ui-e-chrome-cc-tile-snapshot-view');
this.layerTreeView_ =
new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView();
- this.appendChild(this.layerTreeView_);
+ Polymer.dom(this).appendChild(this.layerTreeView_);
},
updateContents: function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html
index 77bb005fcf3..51f3f444a29 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html
@@ -25,9 +25,9 @@ tr.exportTo('tr.ui.e.chrome.gpu', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-chrome-gpu-state-snapshot-view');
+ Polymer.dom(this).classList.add('tr-ui-e-chrome-gpu-state-snapshot-view');
this.screenshotImage_ = document.createElement('img');
- this.appendChild(this.screenshotImage_);
+ Polymer.dom(this).appendChild(this.screenshotImage_);
},
updateContents: function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/layout_tree_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/layout_tree_sub_view.html
index 75a42c01d42..26b38f6d402 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/layout_tree_sub_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/layout_tree_sub_view.html
@@ -5,19 +5,27 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/extras/chrome/layout_tree.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
-<polymer-element name="tr-ui-a-layout-tree-sub-view"
- extends="tr-ui-a-sub-view">
+<dom-module id='tr-ui-a-layout-tree-sub-view'>
<template>
+ <style>
+ tr-ui-b-table {
+ font-size: 12px;
+ }
+ </style>
<div id="content"></div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui.analysis', function() {
- Polymer('tr-ui-a-layout-tree-sub-view', {
+ Polymer({
+ is: 'tr-ui-a-layout-tree-sub-view',
+ behaviors: ['tr-ui-a-sub-view'],
+
set selection(selection) {
this.currentSelection_ = selection;
this.updateContents_();
@@ -28,7 +36,7 @@ tr.exportTo('tr.ui.analysis', function() {
},
updateContents_: function() {
- this.$.content.textContent = '';
+ this.set('$.content.textContent', '');
if (!this.currentSelection_)
return;
@@ -193,11 +201,26 @@ tr.exportTo('tr.ui.analysis', function() {
return snapshot.rootLayoutObject;
});
table.rebuild();
- this.$.content.appendChild(table);
- }
- });
+ Polymer.dom(this.$.content).appendChild(table);
+ },
+ });
return {};
});
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-layout-tree-sub-view',
+ tr.e.chrome.LayoutTreeSnapshot,
+ {
+ multi: false,
+ title: 'Layout Tree',
+ });
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-a-layout-tree-sub-view',
+ tr.e.chrome.LayoutTreeSnapshot,
+ {
+ multi: true,
+ title: 'Layout Trees',
+ });
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html
index cd9fb3f91c4..e2065a701e5 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html
@@ -13,12 +13,21 @@ The chrome config is heavily used:
- telemetry
-->
+<!--
+TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the
+same way that all non-UI files depend on tracing/base/base.html. Enforce this
+dependency with a presubmit.
+-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
+
<link rel="import" href="/tracing/extras/chrome_config.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/extras/chrome/cc/cc.html">
<link rel="import" href="/tracing/ui/extras/chrome/gpu/gpu.html">
+<link rel="import" href="/tracing/ui/extras/chrome/layout_tree_sub_view.html">
<link rel="import" href="/tracing/ui/extras/side_panel/frame_data_side_panel.html">
<link rel="import" href="/tracing/ui/extras/side_panel/input_latency_side_panel.html">
<link rel="import" href="/tracing/ui/extras/side_panel/time_summary_side_panel.html">
<link rel="import" href="/tracing/ui/extras/system_stats/system_stats.html">
+<link rel="import" href="/tracing/ui/extras/v8_config.html">
<link rel="import" href="/tracing/ui/timeline_view.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html
index a515ac4123f..2324a1d9214 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html
@@ -12,106 +12,110 @@ This class tries to (simply) copy the telemetry Results object, but outputs
directly to an HTML table. It takes things that look like Telemetry values,
and updates the table internally.
-->
-<polymer-element name="tr-ui-e-deep-reports-html-results">
+<dom-module id='tr-ui-e-deep-reports-html-results'>
<template>
<style>
:host {
display: flex;
+ font-size: 12px;
}
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.hasColumnNamed_ = {};
- this.pageToRowMap_ = new WeakMap();
- },
-
- ready: function() {
- var table = this.$.table;
- table.tableColumns = [
- {
- title: 'Label',
- value: function(row) { return row.label; },
- width: '350px'
- }
- ];
- this.clear();
- },
-
- clear: function() {
- this.$.table.tableRows = [];
- },
-
- addColumnIfNeeded_: function(columnName) {
- if (this.hasColumnNamed_[columnName])
- return;
- this.hasColumnNamed_[columnName] = true;
-
- var column = {
- title: columnName,
- value: function(row) {
- if (row[columnName] === undefined)
- return '';
- return row[columnName];
- }
- };
-
- var columns = this.$.table.tableColumns;
- columns.push(column);
-
- // Update widths.
- var colWidthPercentage;
- if (columns.length == 1)
- colWidthPercentage = '100%';
- else
- colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
-
- for (var i = 1; i < columns.length; i++)
- columns[i].width = colWidthPercentage;
-
- this.$.table.tableColumns = columns;
- },
-
- getRowForPage_: function(page) {
- if (!this.pageToRowMap_.has(page)) {
- var i = page.url.lastIndexOf('/');
- var baseName = page.url.substring(i + 1);
-
- var link = document.createElement('a');
- link.href = 'trace_viewer.html#' + page.url;
- link.textContent = baseName;
-
- var row = {
- label: link,
- value: '',
- subRows: [],
- isExpanded: true
- };
- this.$.table.tableRows.push(row);
- this.pageToRowMap_.set(page, row);
-
- // Kick table rebuild.
- this.$.table.tableRows = this.$.table.tableRows;
+</dom-module>
+
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-deep-reports-html-results',
+
+ created: function() {
+ this.hasColumnNamed_ = {};
+ this.pageToRowMap_ = new WeakMap();
+ },
+
+ ready: function() {
+ var table = this.$.table;
+ table.tableColumns = [
+ {
+ title: 'Label',
+ value: function(row) { return row.label; },
+ width: '350px'
}
- return this.pageToRowMap_.get(page);
- },
-
- addValue: function(value) {
- /* Value is expected to be a scalar telemetry-style Value. */
- if (value.type !== 'scalar')
- throw new Error('wat');
-
- this.addColumnIfNeeded_(value.name);
- var rowForPage = this.getRowForPage_(value.page);
- rowForPage[value.name] = value.value;
+ ];
+ this.clear();
+ },
+
+ clear: function() {
+ this.$.table.tableRows = [];
+ },
+
+ addColumnIfNeeded_: function(columnName) {
+ if (this.hasColumnNamed_[columnName])
+ return;
+ this.hasColumnNamed_[columnName] = true;
+
+ var column = {
+ title: columnName,
+ value: function(row) {
+ if (row[columnName] === undefined)
+ return '';
+ return row[columnName];
+ }
+ };
+
+ var columns = this.$.table.tableColumns;
+ columns.push(column);
+
+ // Update widths.
+ var colWidthPercentage;
+ if (columns.length === 1)
+ colWidthPercentage = '100%';
+ else
+ colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
+
+ for (var i = 1; i < columns.length; i++)
+ columns[i].width = colWidthPercentage;
+
+ this.$.table.tableColumns = columns;
+ },
+
+ getRowForPage_: function(page) {
+ if (!this.pageToRowMap_.has(page)) {
+ var i = page.url.lastIndexOf('/');
+ var baseName = page.url.substring(i + 1);
+
+ var link = document.createElement('a');
+ link.href = 'trace_viewer.html#' + page.url;
+ Polymer.dom(link).textContent = baseName;
+
+ var row = {
+ label: link,
+ value: '',
+ subRows: [],
+ isExpanded: true
+ };
+ this.$.table.tableRows.push(row);
+ this.pageToRowMap_.set(page, row);
// Kick table rebuild.
this.$.table.tableRows = this.$.table.tableRows;
}
- });
- </script>
-</polymer-element>
+ return this.pageToRowMap_.get(page);
+ },
+
+ addValue: function(value) {
+ /* Value is expected to be a scalar telemetry-style Value. */
+ if (value.type !== 'scalar')
+ throw new Error('wat');
+
+ this.addColumnIfNeeded_(value.name);
+ var rowForPage = this.getRowForPage_(value.page);
+ rowForPage[value.name] = value.value;
+
+ // Kick table rebuild.
+ this.$.table.tableRows = this.$.table.tableRows;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html
index 180f2ce97b4..fa19a804bc5 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html
@@ -5,7 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<polymer-element name="tr-ui-e-drive-comment-element" attributes="comment">
+<dom-module id='tr-ui-e-drive-comment-element'>
<template>
<style>
:host {
@@ -56,16 +56,29 @@ found in the LICENSE file.
<div id="comment-date">{{ createdDate }}</div>
</div>
</div>
- <div id="comment-content">{{ comment.anchor ? '&#9875;&nbsp;' : '' }}
+ <div id="comment-content">{{_computeCommentContentPrefix( comment)}}
{{ comment.content }}</div>
</div>
</template>
- <script>
- 'use strict';
- Polymer({
- commentChanged: function() {
- this.createdDate = new Date(this.comment.createdDate).toLocaleString();
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-e-drive-comment-element',
+
+ properties: {
+ comment: {
+ type: String,
+ observer: '_commentChanged'
}
- });
- </script>
-</polymer-element>
+ },
+
+ _commentChanged: function() {
+ this.createdDate = new Date(this.comment.createdDate).toLocaleString();
+ },
+
+ _computeCommentContentPrefix: function(comment) {
+ return comment.anchor ? '&#9875;&nbsp;' : '';
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html
index 3728481be17..19cc2cc46b1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html
@@ -6,9 +6,9 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/extras/drive/comment_element.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
-<polymer-element name='tr-ui-e-drive-comments-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id='tr-ui-e-drive-comments-side-panel'>
<template>
<style>
:host {
@@ -40,141 +40,146 @@ found in the LICENSE file.
<toolbar id='toolbar'></toolbar>
<result-area id='result_area'>
- <template repeat="{{ comment in comments_ }}">
+ <template is="dom-repeat" items="{{comments_}}" repeat="{{ comment in comments_ }}">
<tr-ui-e-drive-comment-element comment="{{comment}}"
- on-click="{{commentClick}}">
+ on-click="commentClick">
</tr-ui-e-drive-comment-element>
</template>
<div id="comments-textarea-container">
- <textarea id="commentinput" on-focus='{{textAreaFocus}}'
- on-blur='{{textAreaBlur}}'
- on-keypress="{{textareaKeypress}}"></textarea>
+ <textarea id="commentinput" on-focus='textAreaFocus'
+ on-blur='textAreaBlur'
+ on-keypress="textareaKeypress"></textarea>
</div>
</result-area>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.rangeOfInterest_ = new tr.b.Range();
- this.selection_ = undefined;
- this.comments_ = [];
- this.annotationFromComment_ = undefined;
- this.textAreaFocused = false;
- },
-
- setCommentProvider: function(commentProvider) {
- this.commentProvider_ = commentProvider;
- },
-
- attached: function() {
- if (this.commentProvider_ === undefined) {
- this.commentProvider_ =
- new tr.ui.e.drive.analysis.DefaultCommentProvider();
- }
- this.commentProvider_.attachToElement(this);
- },
-
- detached: function() {
- this.commentProvider_.detachFromElement();
- },
-
- commentClick: function(event, detail, sender) {
- var anchor = sender.comment.anchor;
- if (anchor === undefined)
- return;
-
- var uiState =
- JSON.parse(anchor).a[0][tr.ui.e.drive.constants.ANCHOR_NAME];
-
- var myEvent = new CustomEvent('navigateToUIState', { detail:
- new tr.ui.b.UIState(new tr.model.Location(uiState.location.xWorld,
- uiState.location.yComponents),
- uiState.scaleX)
- });
- document.dispatchEvent(myEvent);
-
- if (this.annotationFromComment_)
- this.model.removeAnnotation(this.annotationFromComment_);
- var loc = new tr.model.Location(uiState.location.xWorld,
- uiState.location.yComponents);
-
- var text = sender.comment.author.displayName + ': ' +
- sender.comment.content;
- this.annotationFromComment_ =
- new tr.model.CommentBoxAnnotation(loc, text);
- this.model.addAnnotation(this.annotationFromComment_);
- },
-
- textareaKeypress: function(event, detail, sender) {
- // Check for return key.
- if (event.keyCode === 13 && !event.ctrlKey) {
- this.commentProvider_.addComment(this.$.commentinput.value);
- this.$.commentinput.value = '';
- }
- event.stopPropagation();
- return true;
- },
-
- textAreaFocus: function(event) {
- this.textAreaFocused = true;
- },
-
- textAreaBlur: function(event) {
- this.textAreaFocused = false;
- },
-
- get rangeOfInterest() {
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-drive-comments-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
+ ready: function() {
+ this.rangeOfInterest_ = new tr.b.Range();
+ this.selection_ = undefined;
+ this.comments_ = [];
+ this.annotationFromComment_ = undefined;
+ this.textAreaFocused = false;
+ },
+
+ setCommentProvider: function(commentProvider) {
+ this.commentProvider_ = commentProvider;
+ },
+
+ attached: function() {
+ if (this.commentProvider_ === undefined) {
+ this.commentProvider_ =
+ new tr.ui.e.drive.analysis.DefaultCommentProvider();
+ }
+ this.commentProvider_.attachToElement(this);
+ },
+
+ detached: function() {
+ this.commentProvider_.detachFromElement();
+ },
+
+ commentClick: function(event) {
+ var anchor = event.currentTarget.comment.anchor;
+ if (!anchor)
+ return;
+
+ var uiState =
+ JSON.parse(anchor).a[0][tr.ui.e.drive.constants.ANCHOR_NAME];
+
+ var myEvent = new CustomEvent('navigateToUIState', { detail:
+ new tr.ui.b.UIState(new tr.model.Location(uiState.location.xWorld,
+ uiState.location.yComponents),
+ uiState.scaleX)
+ });
+ document.dispatchEvent(myEvent);
+
+ if (this.annotationFromComment_)
+ this.model.removeAnnotation(this.annotationFromComment_);
+ var loc = new tr.model.Location(uiState.location.xWorld,
+ uiState.location.yComponents);
+
+ var text = sender.comment.author.displayName + ': ' +
+ sender.comment.content;
+ this.annotationFromComment_ =
+ new tr.model.CommentBoxAnnotation(loc, text);
+ this.model.addAnnotation(this.annotationFromComment_);
+ },
+
+ textareaKeypress: function(event) {
+ // Check for return key.
+ if (event.keyCode === 13 && !event.ctrlKey) {
+ this.commentProvider_.addComment(this.$.commentinput.value);
+ this.$.commentinput.value = '';
+ }
+ event.stopPropagation();
+ return true;
+ },
+
+ textAreaFocus: function(event) {
+ this.textAreaFocused = true;
+ },
+
+ textAreaBlur: function(event) {
+ this.textAreaFocused = false;
+ },
+
+ get rangeOfInterest() {
+ return this.rangeOfInterest_;
+ },
+
+ set rangeOfInterest(rangeOfInterest) {
+ this.rangeOfInterest_ = rangeOfInterest;
+ this.updateContents_();
+ },
+
+ get currentRangeOfInterest() {
+ if (this.rangeOfInterest_.isEmpty)
+ return this.model_.bounds;
+ else
return this.rangeOfInterest_;
- },
-
- set rangeOfInterest(rangeOfInterest) {
- this.rangeOfInterest_ = rangeOfInterest;
- this.updateContents_();
- },
-
- get currentRangeOfInterest() {
- if (this.rangeOfInterest_.isEmpty)
- return this.model_.bounds;
- else
- return this.rangeOfInterest_;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- this.updateContents_();
- },
-
- set selection(selection) {
- this.selection_ = selection;
- },
-
- updateContents_: function() {
- this.commentProvider_.updateComments();
- },
-
- supportsModel: function(m) {
- if (m === undefined) {
- return {
- supported: false,
- reason: 'Unknown tracing model'
- };
- }
+ },
+
+ get model() {
+ return this.model_;
+ },
+
+ set model(model) {
+ this.model_ = model;
+ this.updateContents_();
+ },
+
+ set selection(selection) {
+ this.selection_ = selection;
+ },
+
+ updateContents_: function() {
+ this.commentProvider_.updateComments();
+ },
+
+ supportsModel: function(m) {
+ if (m === undefined) {
return {
- supported: true
+ supported: false,
+ reason: 'Unknown tracing model'
};
- },
-
- get textLabel() {
- return 'Comments';
}
- });
-
- </script>
-</polymer-element>
+ return {
+ supported: true
+ };
+ },
+
+ get textLabel() {
+ return 'Comments';
+ }
+});
+
+tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-e-drive-comments-side-panel');
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html
index 2c44cea24ff..4b31b5fc68d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html
@@ -10,9 +10,9 @@ found in the LICENSE file.
<script type="text/javascript" src="https://apis.google.com/js/api.js"></script>
<link rel="import" href="/components/polymer/polymer.html">
+ <link rel="import" href="/tracing/ui/extras/drive/drive_comment_provider.html">
<link rel="import" href="/tracing/ui/extras/full_config.html">
<link rel="import" href="/tracing/ui/timeline_view.html">
- <link rel="import" href="/tracing/ui/extras/drive/drive_comment_provider.html">
<style>
body {
@@ -196,7 +196,7 @@ found in the LICENSE file.
// Use the Google API Loader script to load the google.picker script.
onAPIClientLoaded_ = function() {
var driveState = parseGETParameter('state');
- if (driveState != null) {
+ if (driveState !== null) {
var driveStateJson = JSON.parse(driveState);
fileIdToLoad_ = String(driveStateJson.ids);
}
@@ -209,7 +209,7 @@ found in the LICENSE file.
setTimeout(onRepeatAuthApiLoad, 30000);
}, 30000);
}});
- }
+ };
function onAuthApiLoad(tryImmediate, resultCallback) {
window.gapi.auth.authorize(
@@ -222,12 +222,12 @@ found in the LICENSE file.
function onPickerApiLoad() {
pickerApiLoaded_ = true;
- if (fileIdToLoad_ == null)
+ if (fileIdToLoad_ === null)
createPicker();
}
function onAuthResultSuccess() {
- if (fileIdToLoad_ == null)
+ if (fileIdToLoad_ === null)
createPicker();
else
loadFileFromDrive(fileIdToLoad_);
@@ -261,7 +261,7 @@ found in the LICENSE file.
}
function pickerCallback(data) {
- if (data.action == google.picker.Action.PICKED) {
+ if (data.action === google.picker.Action.PICKED) {
loadFileFromDrive(data.docs[0].id);
}
}
@@ -287,11 +287,11 @@ found in the LICENSE file.
downloadingOverlay.title = 'Downloading...';
downloadingOverlay.userCanClose = false;
downloadingOverlay.msgEl = document.createElement('div');
- downloadingOverlay.appendChild(downloadingOverlay.msgEl);
+ Polymer.dom(downloadingOverlay).appendChild(downloadingOverlay.msgEl);
downloadingOverlay.msgEl.style.margin = '20px';
downloadingOverlay.update = function(msg) {
- this.msgEl.textContent = msg;
- }
+ Polymer.dom(this.msgEl).textContent = msg;
+ };
downloadingOverlay.visible = true;
var accessToken = gapi.auth.getToken().access_token;
@@ -317,7 +317,7 @@ found in the LICENSE file.
var allCollaborators = driveDocument_.getCollaborators();
var collaboratorCount = allCollaborators.length;
var collabspan = document.getElementById('collabs');
- collabspan.innerHTML = '';
+ Polymer.dom(collabspan).innerHTML = '';
var imageList = [];
for (var i = 0; i < collaboratorCount; i++) {
var user = allCollaborators[i];
@@ -328,7 +328,7 @@ found in the LICENSE file.
img.height = 30;
img.width = 30;
img.className = 'collaborator-img';
- collabspan.appendChild(img);
+ Polymer.dom(collabspan).appendChild(img);
imageList.push({'image': img, 'name': user.displayName});
}
for (i = 0; i < imageList.length; i++) {
@@ -338,18 +338,18 @@ found in the LICENSE file.
var collabTooltipContent = tr.ui.b.createDiv({
className: 'collaborator-tooltip-content'
});
- collabTooltipContent.textContent = imageList[i].name;
- collabTooltip.appendChild(collabTooltipContent);
- collabspan.appendChild(collabTooltip);
+ Polymer.dom(collabTooltipContent).textContent = imageList[i].name;
+ Polymer.dom(collabTooltip).appendChild(collabTooltipContent);
+ Polymer.dom(collabspan).appendChild(collabTooltip);
var collabTooltipArrow = tr.ui.b.createDiv({
className: 'collaborator-tooltip-arrow'});
- collabTooltip.appendChild(collabTooltipArrow);
+ Polymer.dom(collabTooltip).appendChild(collabTooltipArrow);
var collabTooltipArrowBefore = tr.ui.b.createDiv({
className: 'collaborator-tooltip-arrow-before'});
- collabTooltipArrow.appendChild(collabTooltipArrowBefore);
+ Polymer.dom(collabTooltipArrow).appendChild(collabTooltipArrowBefore);
var collabTooltipArrowAfter = tr.ui.b.createDiv({
className: 'collaborator-tooltip-arrow-after'});
- collabTooltipArrow.appendChild(collabTooltipArrowAfter);
+ Polymer.dom(collabTooltipArrow).appendChild(collabTooltipArrowAfter);
var rect = imageList[i].image.getBoundingClientRect();
collabTooltip.style.top = (rect.bottom - 6) + 'px';
@@ -414,7 +414,7 @@ found in the LICENSE file.
},
function(err) {
var downloadingOverlay = new tr.ui.b.Overlay();
- downloadingOverlay.textContent =
+ Polymer.dom(downloadingOverlay).textContent =
tr.b.normalizeException(err).message;
downloadingOverlay.title = 'Import error';
downloadingOverlay.visible = true;
@@ -434,7 +434,7 @@ found in the LICENSE file.
}
function onLoad() {
- timelineViewEl_ = document.querySelector('x-timeline-view');
+ timelineViewEl_ = Polymer.dom(document).querySelector('x-timeline-view');
timelineViewEl_.globalMode = true;
var navbar = document.getElementById('navbar');
timelineViewEl_.style.top = navbar.offsetHeight + 'px';
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html
index f27fbafd1ce..6d1e29d4e20 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html
@@ -5,6 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<!--
+TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the
+same way that all non-UI files depend on tracing/base/base.html. Enforce this
+dependency with a presubmit.
+-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
+
<!-- The full config is all the configs slammed together. -->
<link rel="import" href="/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html">
<link rel="import" href="/tracing/ui/extras/chrome_config.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html
index b804717a76a..a36021dd7b3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/tracks/highlighter.html">
<link rel="import" href="/tracing/ui/timeline_track_view.html">
<link rel="import" href="/tracing/ui/timeline_viewport.html">
+<link rel="import" href="/tracing/ui/tracks/highlighter.html">
<link rel="import" href="/tracing/ui/tracks/model_track.html">
<script>
@@ -81,7 +81,7 @@ tr.exportTo('tr.ui.e.highlighter', function() {
var stripes = VSyncHighlighter.generateStripes(
this.times_, viewLWorld, viewRWorld);
- if (stripes.length == 0) {
+ if (stripes.length === 0) {
return;
}
@@ -93,7 +93,7 @@ tr.exportTo('tr.ui.e.highlighter', function() {
var opacity =
(VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT - clampedStripeDensity) /
VSyncHighlighter.VSYNC_DENSITY_RANGE;
- if (opacity == 0) {
+ if (opacity === 0) {
return;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html
index 0197474ce45..ba6ae9990d8 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html
@@ -5,7 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/extras/lean_config.html">
+<!--
+TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the same way that
+all non-UI files depend on tracing/base/base.html. Enforce this dependency with a presubmit.
+-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
+
+<link rel="import" href="/tracing/extras/lean_config.html" data-suppress-import-order>
<!--
The lean config is just enough to import uncompressed, trace-event-formatted
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html
index 5cc5b6dc241..0988f6367cc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html
@@ -7,13 +7,13 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/statistics.html">
<link rel="import" href="/tracing/model/event_set.html">
-<link rel="import" href="/tracing/ui/base/table.html">
-<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/line_chart.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
-<polymer-element name='tr-ui-e-s-alerts-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id='tr-ui-e-s-alerts-side-panel'>
<template>
<style>
:host {
@@ -24,6 +24,9 @@ found in the LICENSE file.
flex-direction: column;
display: flex;
}
+ tr-ui-b-table {
+ font-size: 12px;
+ }
</style>
<div id='content'>
@@ -31,131 +34,138 @@ found in the LICENSE file.
<result-area id='result_area'></result-area>
</div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.rangeOfInterest_ = new tr.b.Range();
- this.selection_ = undefined;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- this.updateContents_();
- },
-
- set selection(selection) {
- },
-
- set rangeOfInterest(rangeOfInterest) {
- },
-
- /**
- * Fires a selection event selecting all alerts of the specified
- * type.
- */
- selectAlertsOfType: function(alertTypeString) {
- var alertsOfType = this.model_.alerts.filter(function(alert) {
- return alert.title === alertTypeString;
- });
-
- var event = new tr.model.RequestSelectionChangeEvent();
- event.selection = new tr.model.EventSet(alertsOfType);
- this.dispatchEvent(event);
- },
-
- /**
- * Returns a map for the specified alerts where each key is the
- * alert type string and each value is a list of alerts with that
- * type.
- */
- alertsByType_: function(alerts) {
- var alertsByType = {};
- alerts.forEach(function(alert) {
- if (!alertsByType[alert.title])
- alertsByType[alert.title] = [];
-
- alertsByType[alert.title].push(alert);
- });
- return alertsByType;
- },
-
- alertsTableRows_: function(alertsByType) {
- return Object.keys(alertsByType).map(function(key) {
- return {
- alertType: key,
- count: alertsByType[key].length
- };
- });
- },
-
- alertsTableColumns_: function() {
- return [
- {
- title: 'Alert type',
- value: function(row) { return row.alertType; },
- width: '180px'
- },
- {
- title: 'Count',
- width: '100%',
- value: function(row) { return row.count; }
- }
- ];
- },
-
- createAlertsTable_: function(alerts) {
- var alertsByType = this.alertsByType_(alerts);
-
- var table = document.createElement('tr-ui-b-table');
- table.tableColumns = this.alertsTableColumns_();
- table.tableRows = this.alertsTableRows_(alertsByType);
- table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
- table.addEventListener('selection-changed', function(e) {
- var row = table.selectedTableRow;
- if (row)
- this.selectAlertsOfType(row.alertType);
- }.bind(this));
-
- return table;
- },
-
- updateContents_: function() {
- this.$.result_area.textContent = '';
- if (this.model_ === undefined)
- return;
-
- var panel = this.createAlertsTable_(this.model_.alerts);
- this.$.result_area.appendChild(panel);
- },
-
- supportsModel: function(m) {
- if (m == undefined) {
- return {
- supported: false,
- reason: 'Unknown tracing model'
- };
- } else if (m.alerts.length === 0) {
- return {
- supported: false,
- reason: 'No alerts in tracing model'
- };
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-s-alerts-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
+
+ ready: function() {
+ this.rangeOfInterest_ = new tr.b.Range();
+ this.selection_ = undefined;
+ },
+
+ get model() {
+ return this.model_;
+ },
+
+ set model(model) {
+ this.model_ = model;
+ this.updateContents_();
+ },
+
+ set selection(selection) {
+ },
+
+ set rangeOfInterest(rangeOfInterest) {
+ },
+
+ /**
+ * Fires a selection event selecting all alerts of the specified
+ * type.
+ */
+ selectAlertsOfType: function(alertTypeString) {
+ var alertsOfType = this.model_.alerts.filter(function(alert) {
+ return alert.title === alertTypeString;
+ });
+
+ var event = new tr.model.RequestSelectionChangeEvent();
+ event.selection = new tr.model.EventSet(alertsOfType);
+ this.dispatchEvent(event);
+ },
+
+ /**
+ * Returns a map for the specified alerts where each key is the
+ * alert type string and each value is a list of alerts with that
+ * type.
+ */
+ alertsByType_: function(alerts) {
+ var alertsByType = {};
+ alerts.forEach(function(alert) {
+ if (!alertsByType[alert.title])
+ alertsByType[alert.title] = [];
+
+ alertsByType[alert.title].push(alert);
+ });
+ return alertsByType;
+ },
+
+ alertsTableRows_: function(alertsByType) {
+ return Object.keys(alertsByType).map(function(key) {
+ return {
+ alertType: key,
+ count: alertsByType[key].length
+ };
+ });
+ },
+
+ alertsTableColumns_: function() {
+ return [
+ {
+ title: 'Alert type',
+ value: function(row) { return row.alertType; },
+ width: '180px'
+ },
+ {
+ title: 'Count',
+ width: '100%',
+ value: function(row) { return row.count; }
}
-
+ ];
+ },
+
+ createAlertsTable_: function(alerts) {
+ var alertsByType = this.alertsByType_(alerts);
+
+ var table = document.createElement('tr-ui-b-table');
+ table.tableColumns = this.alertsTableColumns_();
+ table.tableRows = this.alertsTableRows_(alertsByType);
+ table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ table.addEventListener('selection-changed', function(e) {
+ var row = table.selectedTableRow;
+ if (row)
+ this.selectAlertsOfType(row.alertType);
+ }.bind(this));
+
+ return table;
+ },
+
+ updateContents_: function() {
+ Polymer.dom(this.$.result_area).textContent = '';
+ if (this.model_ === undefined)
+ return;
+
+ var panel = this.createAlertsTable_(this.model_.alerts);
+ Polymer.dom(this.$.result_area).appendChild(panel);
+ },
+
+ supportsModel: function(m) {
+ if (m === undefined) {
return {
- supported: true
+ supported: false,
+ reason: 'Unknown tracing model'
+ };
+ } else if (m.alerts.length === 0) {
+ return {
+ supported: false,
+ reason: 'No alerts in tracing model'
};
- },
-
- get textLabel() {
- return 'Alerts';
}
- });
- </script>
-</polymer-element>
+
+ return {
+ supported: true
+ };
+ },
+
+ get textLabel() {
+ return 'Alerts';
+ }
+});
+
+tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-e-s-alerts-side-panel');
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html
index 2ca6250b69e..83ce91aca62 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html
@@ -37,7 +37,7 @@ tr.b.unittest.testSuite(function() {
new tr.model.Alert(ALERT_INFO_2, 3)
];
- var predicted_alerts = new tr.model.EventSet([alerts[0], alerts[1]]);
+ var predictedAlerts = new tr.model.EventSet([alerts[0], alerts[1]]);
panel.model = createModelWithAlerts(alerts);
panel.style.height = '100px';
this.addHTMLOutput(panel);
@@ -45,7 +45,7 @@ tr.b.unittest.testSuite(function() {
var selectionChanged = false;
panel.addEventListener('requestSelectionChange', function(e) {
selectionChanged = true;
- assert.isTrue(e.selection.equals(predicted_alerts));
+ assert.isTrue(e.selection.equals(predictedAlerts));
});
panel.selectAlertsOfType(ALERT_INFO_1.title);
@@ -56,6 +56,6 @@ tr.b.unittest.testSuite(function() {
var m = new tr.Model();
m.alerts = alerts;
return m;
- };
+ }
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
index ebaff275896..f8ed34df15c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
@@ -5,17 +5,17 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/extras/chrome/blame_context/frame_tree_node.html">
<link rel="import" href="/tracing/extras/chrome/blame_context/render_frame.html">
<link rel="import" href="/tracing/extras/chrome/blame_context/top_level.html">
<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name='tr-ui-e-s-frame-data-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id='tr-ui-e-s-frame-data-side-panel'>
<template>
<style>
:host {
@@ -26,13 +26,21 @@ found in the LICENSE file.
table-container {
display: flex;
overflow: auto;
+ font-size: 12px;
}
</style>
+ <div>
+ Organize by:
+ <select id="select">
+ <option value="none">None</option>
+ <option value="tree">Frame Tree</option>
+ </select>
+ </div>
<table-container>
<tr-ui-b-table id="table"></tr-ui-b-table>
</table-container>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -49,12 +57,24 @@ tr.exportTo('tr.ui.e.s', function() {
/**
* @constructor
+ * If |context| is provided, creates a row for the given context.
+ * Otherwise, creates an empty Row template which can be used for aggregating
+ * data from a group of subrows.
*/
function Row(context) {
- this.type = context.objectInstance.blameContextType;
+ this.subRows = undefined;
+ this.contexts = [];
+ this.type = undefined;
+ this.renderer = 'N/A';
+ this.url = undefined;
+ this.time = 0;
+ this.eventsOfInterest = new tr.model.EventSet();
+
+ if (context === undefined)
+ return;
- this.contexts = [context];
- this.renderer = undefined;
+ this.type = context.objectInstance.blameContextType;
+ this.contexts.push(context);
if (context instanceof FrameTreeNodeSnapshot) {
if (context.renderFrame) {
this.contexts.push(context.renderFrame);
@@ -69,24 +89,89 @@ tr.exportTo('tr.ui.e.s', function() {
} else {
throw new Error('Unknown context type');
}
+ this.eventsOfInterest.addEventSet(this.contexts);
// TODO(xiaochengh): Handle the case where a subframe has a trivial url
// (e.g., about:blank), but inherits the origin of its parent. This is not
// needed now, but will be required if we want to group rows by origin.
this.url = context.url;
-
- // To be computed in batch later for efficiency.
- this.eventsOfInterest = new tr.model.EventSet(this.contexts);
- this.time = 0;
}
- Polymer('tr-ui-e-s-frame-data-side-panel', {
+ var groupFunctions = {
+ none: rows => rows,
+
+ // Group the rows according to the frame tree structure.
+ // Example: consider frame tree a(b, c(d)), where each frame has 1ms time
+ // attributed to it. The resulting table should look like:
+ // Type | Time | URL
+ // --------------+------+-----
+ // Frame Tree | 4 | a
+ // +- Frame | 1 | a
+ // +- Subframe | 1 | b
+ // +- Frame Tree | 2 | c
+ // +- Frame | 1 | c
+ // +- Subframe | 1 | d
+ tree: function(rows, rowMap) {
+ // Finds the parent of a specific row. When there is conflict between the
+ // browser's dump of the frame tree and the renderers', use the browser's.
+ var getParentRow = function(row) {
+ var pivot;
+ row.contexts.forEach(function(context) {
+ if (context instanceof tr.e.chrome.FrameTreeNodeSnapshot)
+ pivot = context;
+ });
+ if (pivot && pivot.parentContext)
+ return rowMap[pivot.parentContext.guid];
+ return undefined;
+ };
+
+ var rootRows = [];
+ rows.forEach(function(row) {
+ var parentRow = getParentRow(row);
+ if (parentRow === undefined) {
+ rootRows.push(row);
+ return;
+ }
+ if (parentRow.subRows === undefined)
+ parentRow.subRows = [];
+ parentRow.subRows.push(row);
+ });
+
+ var aggregateAllDescendants = function(row) {
+ if (!row.subRows) {
+ if (getParentRow(row))
+ row.type = 'Subframe';
+ return row;
+ }
+ var result = new Row();
+ result.type = 'Frame Tree';
+ result.renderer = row.renderer;
+ result.url = row.url;
+ result.subRows = [row];
+ row.subRows.forEach(
+ subRow => result.subRows.push(aggregateAllDescendants(subRow)));
+ result.subRows.forEach(function(subRow) {
+ result.time += subRow.time;
+ result.eventsOfInterest.addEventSet(subRow.eventsOfInterest);
+ });
+ row.subRows = undefined;
+ return result;
+ };
+
+ return rootRows.map(rootRow => aggregateAllDescendants(rootRow));
+ }
+
+ // TODO(xiaochengh): Add grouping by site and probably more...
+ };
+
+ Polymer({
+ is: 'tr-ui-e-s-frame-data-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
ready: function() {
this.model_ = undefined;
this.rangeOfInterest_ = new tr.b.Range();
- // TODO(xiaochengh): Design proper grouping of the rows (by renderer
- // pid, frame tree topology, site, ...) in a follow-up patch.
this.$.table.showHeader = true;
this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
this.$.table.tableColumns = this.createFrameDataTableColumns_();
@@ -94,6 +179,10 @@ tr.exportTo('tr.ui.e.s', function() {
this.$.table.addEventListener('selection-changed', function(e) {
this.selectEventSet_(this.$.table.selectedTableRow.eventsOfInterest);
}.bind(this));
+
+ this.$.select.addEventListener('change', function(e) {
+ this.updateContents_();
+ }.bind(this));
},
selectEventSet_: function(eventSet) {
@@ -121,7 +210,7 @@ tr.exportTo('tr.ui.e.s', function() {
{
title: 'Time',
value: row => tr.v.ui.createScalarSpan(row.time, {
- unit: tr.v.Unit.byName.timeStampInMs,
+ unit: tr.b.Unit.byName.timeStampInMs,
ownerDocument: this.ownerDocument
}),
cmp: (a, b) => a.time - b.time
@@ -173,7 +262,11 @@ tr.exportTo('tr.ui.e.s', function() {
}, this);
}, this);
- return rows;
+ // Apply grouping to rows.
+ var select = this.$.select;
+ var groupOption = select.options[select.selectedIndex].value;
+ var groupFunction = groupFunctions[groupOption];
+ return groupFunction(rows, rowMap);
},
updateContents_: function() {
@@ -239,5 +332,9 @@ tr.exportTo('tr.ui.e.s', function() {
this.updateContents_();
}
});
+
+ tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-e-s-frame-data-side-panel');
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html
index 4b3a9a5917b..7375c09e050 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html
@@ -11,9 +11,9 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/line_chart.html">
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
-<polymer-element name='tr-ui-e-s-input-latency-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id='tr-ui-e-s-input-latency-side-panel'>
<template>
<style>
:host {
@@ -36,291 +36,299 @@ found in the LICENSE file.
<toolbar id='toolbar'></toolbar>
<result-area id='result_area'></result-area>
</template>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-s-input-latency-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
+
+ ready: function() {
+ this.rangeOfInterest_ = new tr.b.Range();
+ this.frametimeType_ = tr.model.helpers.IMPL_FRAMETIME_TYPE;
+ this.latencyChart_ = undefined;
+ this.frametimeChart_ = undefined;
+ this.selectedProcessId_ = undefined;
+ this.mouseDownIndex_ = undefined;
+ this.curMouseIndex_ = undefined;
+ },
+
+ get model() {
+ return this.model_;
+ },
+
+ set model(model) {
+ this.model_ = model;
+ if (this.model_) {
+ this.modelHelper_ = this.model_.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+ } else {
+ this.modelHelper_ = undefined;
+ }
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.rangeOfInterest_ = new tr.b.Range();
- this.frametimeType_ = tr.model.helpers.IMPL_FRAMETIME_TYPE;
- this.latencyChart_ = undefined;
- this.frametimeChart_ = undefined;
- this.selectedProcessId_ = undefined;
- this.mouseDownIndex_ = undefined;
- this.curMouseIndex_ = undefined;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- if (this.model_) {
- this.modelHelper_ = this.model_.getOrCreateHelper(
- tr.model.helpers.ChromeModelHelper);
- } else {
- this.modelHelper_ = undefined;
- }
-
- this.updateToolbar_();
- this.updateContents_();
- },
-
- get frametimeType() {
- return this.frametimeType_;
- },
-
- set frametimeType(type) {
- if (this.frametimeType_ === type)
- return;
- this.frametimeType_ = type;
- this.updateContents_();
- },
-
- get selectedProcessId() {
- return this.selectedProcessId_;
- },
-
- set selectedProcessId(process) {
- if (this.selectedProcessId_ === process)
- return;
- this.selectedProcessId_ = process;
- this.updateContents_();
- },
-
- set selection(selection) {
- if (this.latencyChart_ === undefined)
- return;
- this.latencyChart_.brushedRange = selection.bounds;
- },
-
- // This function is for testing purpose.
- setBrushedIndices: function(mouseDownIndex, curIndex) {
- this.mouseDownIndex_ = mouseDownIndex;
- this.curMouseIndex_ = curIndex;
- this.updateBrushedRange_();
- },
-
- updateBrushedRange_: function() {
- if (this.latencyChart_ === undefined)
- return;
-
- var r = new tr.b.Range();
- if (this.mouseDownIndex_ === undefined) {
- this.latencyChart_.brushedRange = r;
- return;
- }
- r = this.latencyChart_.computeBrushRangeFromIndices(
- this.mouseDownIndex_, this.curMouseIndex_);
+ this.updateToolbar_();
+ this.updateContents_();
+ },
+
+ get frametimeType() {
+ return this.frametimeType_;
+ },
+
+ set frametimeType(type) {
+ if (this.frametimeType_ === type)
+ return;
+ this.frametimeType_ = type;
+ this.updateContents_();
+ },
+
+ get selectedProcessId() {
+ return this.selectedProcessId_;
+ },
+
+ set selectedProcessId(process) {
+ if (this.selectedProcessId_ === process)
+ return;
+ this.selectedProcessId_ = process;
+ this.updateContents_();
+ },
+
+ set selection(selection) {
+ if (this.latencyChart_ === undefined)
+ return;
+ this.latencyChart_.brushedRange = selection.bounds;
+ },
+
+ // This function is for testing purpose.
+ setBrushedIndices: function(mouseDownIndex, curIndex) {
+ this.mouseDownIndex_ = mouseDownIndex;
+ this.curMouseIndex_ = curIndex;
+ this.updateBrushedRange_();
+ },
+
+ updateBrushedRange_: function() {
+ if (this.latencyChart_ === undefined)
+ return;
+
+ var r = new tr.b.Range();
+ if (this.mouseDownIndex_ === undefined) {
this.latencyChart_.brushedRange = r;
+ return;
+ }
+ r = this.latencyChart_.computeBrushRangeFromIndices(
+ this.mouseDownIndex_, this.curMouseIndex_);
+ this.latencyChart_.brushedRange = r;
+
+ // Based on the brushed range, update the selection of LatencyInfo in
+ // the timeline view by sending a selectionChange event.
+ var latencySlices = [];
+ for (var thread of this.model_.getAllThreads())
+ for (var event of thread.getDescendantEvents())
+ if (event.title.indexOf('InputLatency:') === 0)
+ latencySlices.push(event);
+ latencySlices = tr.model.helpers.getSlicesIntersectingRange(
+ r, latencySlices);
+
+ var event = new tr.model.RequestSelectionChangeEvent();
+ event.selection = new tr.model.EventSet(latencySlices);
+ this.latencyChart_.dispatchEvent(event);
+ },
+
+ registerMouseEventForLatencyChart_: function() {
+ this.latencyChart_.addEventListener('item-mousedown', function(e) {
+ this.mouseDownIndex_ = e.index;
+ this.curMouseIndex_ = e.index;
+ this.updateBrushedRange_();
+ }.bind(this));
- // Based on the brushed range, update the selection of LatencyInfo in
- // the timeline view by sending a selectionChange event.
- var latencySlices = [];
- for (var thread of this.model_.getAllThreads())
- for (var event of thread.getDescendantEvents())
- if (event.title.indexOf('InputLatency:') === 0)
- latencySlices.push(event);
- latencySlices = tr.model.helpers.getSlicesIntersectingRange(
- r, latencySlices);
-
- var event = new tr.model.RequestSelectionChangeEvent();
- event.selection = new tr.model.EventSet(latencySlices);
- this.latencyChart_.dispatchEvent(event);
- },
-
- registerMouseEventForLatencyChart_: function() {
- this.latencyChart_.addEventListener('item-mousedown', function(e) {
- this.mouseDownIndex_ = e.index;
- this.curMouseIndex_ = e.index;
- this.updateBrushedRange_();
- }.bind(this));
-
- this.latencyChart_.addEventListener('item-mousemove', function(e) {
- if (e.button == undefined)
- return;
- this.curMouseIndex_ = e.index;
- this.updateBrushedRange_();
- }.bind(this));
-
- this.latencyChart_.addEventListener('item-mouseup', function(e) {
- this.curMouseIndex = e.index;
- this.updateBrushedRange_();
- }.bind(this));
- },
-
- updateToolbar_: function() {
- var browserProcess = this.modelHelper_.browserProcess;
- var labels = [];
-
- if (browserProcess !== undefined) {
- var label_str = 'Browser: ' + browserProcess.pid;
- labels.push({label: label_str, value: browserProcess.pid});
- }
-
- tr.b.iterItems(this.modelHelper_.rendererHelpers,
- function(pid, rendererHelper) {
- var rendererProcess = rendererHelper.process;
- var label_str = 'Renderer: ' + rendererProcess.userFriendlyName;
- labels.push({label: label_str, value: rendererProcess.userFriendlyName
- });
- }, this);
-
- if (labels.length === 0)
- return;
-
- this.selectedProcessId_ = labels[0].value;
- var toolbarEl = this.$.toolbar;
- toolbarEl.appendChild(tr.ui.b.createSelector(
- this, 'frametimeType',
- 'inputLatencySidePanel.frametimeType', this.frametimeType_,
- [{label: 'Main Thread Frame Times',
- value: tr.model.helpers.MAIN_FRAMETIME_TYPE},
- {label: 'Impl Thread Frame Times',
- value: tr.model.helpers.IMPL_FRAMETIME_TYPE}
- ]));
- toolbarEl.appendChild(tr.ui.b.createSelector(
- this, 'selectedProcessId',
- 'inputLatencySidePanel.selectedProcessId',
- this.selectedProcessId_,
- labels));
- },
-
- get currentRangeOfInterest() {
- if (this.rangeOfInterest_.isEmpty)
- return this.model_.bounds;
- else
- return this.rangeOfInterest_;
- },
-
- createLatencyLineChart: function(data, title) {
- var chart = new tr.ui.b.LineChart();
- var width = 600;
- if (document.body.clientWidth != undefined)
- width = document.body.clientWidth * 0.5;
- chart.setSize({width: width, height: chart.height});
- chart.chartTitle = title;
- chart.data = data;
- return chart;
- },
-
- updateContents_: function() {
- var resultArea = this.$.result_area;
- this.latencyChart_ = undefined;
- this.frametimeChart_ = undefined;
- resultArea.textContent = '';
-
- if (this.modelHelper_ === undefined)
+ this.latencyChart_.addEventListener('item-mousemove', function(e) {
+ if (e.button === undefined)
return;
+ this.curMouseIndex_ = e.index;
+ this.updateBrushedRange_();
+ }.bind(this));
- var rangeOfInterest = this.currentRangeOfInterest;
-
- var chromeProcess;
- if (this.modelHelper_.rendererHelpers[this.selectedProcessId_])
- chromeProcess = this.modelHelper_.rendererHelpers[
- this.selectedProcessId_
- ];
- else
- chromeProcess = this.modelHelper_.browserHelper;
+ this.latencyChart_.addEventListener('item-mouseup', function(e) {
+ this.curMouseIndex = e.index;
+ this.updateBrushedRange_();
+ }.bind(this));
+ },
- var frameEvents = chromeProcess.getFrameEventsInRange(
- this.frametimeType, rangeOfInterest);
+ updateToolbar_: function() {
+ var browserProcess = this.modelHelper_.browserProcess;
+ var labels = [];
- var frametimeData = tr.model.helpers.getFrametimeDataFromEvents(
- frameEvents);
- var averageFrametime = tr.b.Statistics.mean(frametimeData, function(d) {
- return d.frametime;
- });
-
- var latencyEvents = this.modelHelper_.browserHelper.
- getLatencyEventsInRange(
- rangeOfInterest);
-
- var latencyData = [];
- latencyEvents.forEach(function(event) {
- if (event.inputLatency === undefined)
- return;
- latencyData.push({
- x: event.start,
- latency: event.inputLatency / 1000
- });
- });
+ if (browserProcess !== undefined) {
+ var labelStr = 'Browser: ' + browserProcess.pid;
+ labels.push({label: labelStr, value: browserProcess.pid});
+ }
- var averageLatency = tr.b.Statistics.mean(latencyData, function(d) {
- return d.latency;
+ tr.b.iterItems(this.modelHelper_.rendererHelpers,
+ function(pid, rendererHelper) {
+ var rendererProcess = rendererHelper.process;
+ var labelStr = 'Renderer: ' + rendererProcess.userFriendlyName;
+ labels.push({label: labelStr, value: rendererProcess.userFriendlyName
});
-
- // Create summary.
- var latencySummaryText = document.createElement('div');
- latencySummaryText.appendChild(tr.ui.b.createSpan({
- textContent: 'Average Latency ' + averageLatency + ' ms',
- bold: true}));
- resultArea.appendChild(latencySummaryText);
-
- var frametimeSummaryText = document.createElement('div');
- frametimeSummaryText.appendChild(tr.ui.b.createSpan({
- textContent: 'Average Frame Time ' + averageFrametime + ' ms',
- bold: true}));
- resultArea.appendChild(frametimeSummaryText);
-
- if (latencyData.length !== 0) {
- this.latencyChart_ = this.createLatencyLineChart(
- latencyData, 'Latency Over Time');
- this.registerMouseEventForLatencyChart_();
- resultArea.appendChild(this.latencyChart_);
- }
-
- if (frametimeData.length != 0) {
- this.frametimeChart_ = this.createLatencyLineChart(
- frametimeData, 'Frame Times');
- resultArea.appendChild(this.frametimeChart_);
- }
- },
-
- get rangeOfInterest() {
+ }, this);
+
+ if (labels.length === 0)
+ return;
+
+ this.selectedProcessId_ = labels[0].value;
+ var toolbarEl = this.$.toolbar;
+ Polymer.dom(toolbarEl).appendChild(tr.ui.b.createSelector(
+ this, 'frametimeType',
+ 'inputLatencySidePanel.frametimeType', this.frametimeType_,
+ [{label: 'Main Thread Frame Times',
+ value: tr.model.helpers.MAIN_FRAMETIME_TYPE},
+ {label: 'Impl Thread Frame Times',
+ value: tr.model.helpers.IMPL_FRAMETIME_TYPE}
+ ]));
+ Polymer.dom(toolbarEl).appendChild(tr.ui.b.createSelector(
+ this, 'selectedProcessId',
+ 'inputLatencySidePanel.selectedProcessId',
+ this.selectedProcessId_,
+ labels));
+ },
+
+ // TODO(charliea): Delete this function in favor of rangeOfInterest.
+ get currentRangeOfInterest() {
+ if (this.rangeOfInterest_.isEmpty)
+ return this.model_.bounds;
+ else
return this.rangeOfInterest_;
- },
+ },
+
+ createLatencyLineChart: function(data, title) {
+ var chart = new tr.ui.b.LineChart();
+ var width = 600;
+ if (document.body.clientWidth !== undefined)
+ width = document.body.clientWidth * 0.5;
+ chart.setSize({width: width, height: chart.height});
+ chart.chartTitle = title;
+ chart.data = data;
+ return chart;
+ },
+
+ updateContents_: function() {
+ var resultArea = this.$.result_area;
+ this.latencyChart_ = undefined;
+ this.frametimeChart_ = undefined;
+ Polymer.dom(resultArea).textContent = '';
+
+ if (this.modelHelper_ === undefined)
+ return;
+
+ var rangeOfInterest = this.currentRangeOfInterest;
+
+ var chromeProcess;
+ if (this.modelHelper_.rendererHelpers[this.selectedProcessId_])
+ chromeProcess = this.modelHelper_.rendererHelpers[
+ this.selectedProcessId_
+ ];
+ else
+ chromeProcess = this.modelHelper_.browserHelper;
+
+ var frameEvents = chromeProcess.getFrameEventsInRange(
+ this.frametimeType, rangeOfInterest);
+
+ var frametimeData = tr.model.helpers.getFrametimeDataFromEvents(
+ frameEvents);
+ var averageFrametime = tr.b.Statistics.mean(frametimeData, function(d) {
+ return d.frametime;
+ });
+
+ var latencyEvents = this.modelHelper_.browserHelper.
+ getLatencyEventsInRange(
+ rangeOfInterest);
+
+ var latencyData = [];
+ latencyEvents.forEach(function(event) {
+ if (event.inputLatency === undefined)
+ return;
+ latencyData.push({
+ x: event.start,
+ latency: event.inputLatency / 1000
+ });
+ });
+
+ var averageLatency = tr.b.Statistics.mean(latencyData, function(d) {
+ return d.latency;
+ });
+
+ // Create summary.
+ var latencySummaryText = document.createElement('div');
+ Polymer.dom(latencySummaryText).appendChild(tr.ui.b.createSpan({
+ textContent: 'Average Latency ' + averageLatency + ' ms',
+ bold: true}));
+ Polymer.dom(resultArea).appendChild(latencySummaryText);
+
+ var frametimeSummaryText = document.createElement('div');
+ Polymer.dom(frametimeSummaryText).appendChild(tr.ui.b.createSpan({
+ textContent: 'Average Frame Time ' + averageFrametime + ' ms',
+ bold: true}));
+ Polymer.dom(resultArea).appendChild(frametimeSummaryText);
+
+ if (latencyData.length !== 0) {
+ this.latencyChart_ = this.createLatencyLineChart(
+ latencyData, 'Latency Over Time');
+ this.registerMouseEventForLatencyChart_();
+ Polymer.dom(resultArea).appendChild(this.latencyChart_);
+ }
- set rangeOfInterest(rangeOfInterest) {
- this.rangeOfInterest_ = rangeOfInterest;
- this.updateContents_();
- },
+ if (frametimeData.length !== 0) {
+ this.frametimeChart_ = this.createLatencyLineChart(
+ frametimeData, 'Frame Times');
+ Polymer.dom(resultArea).appendChild(this.frametimeChart_);
+ }
+ },
- supportsModel: function(m) {
- if (m == undefined) {
- return {
- supported: false,
- reason: 'Unknown tracing model'
- };
- }
+ get rangeOfInterest() {
+ return this.rangeOfInterest_;
+ },
- if (!tr.model.helpers.ChromeModelHelper.supportsModel(m)) {
- return {
- supported: false,
- reason: 'No Chrome browser or renderer process found'
- };
- }
+ set rangeOfInterest(rangeOfInterest) {
+ this.rangeOfInterest_ = rangeOfInterest;
+ this.updateContents_();
+ },
- var modelHelper = m.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);
- if (modelHelper.browserHelper &&
- modelHelper.browserHelper.hasLatencyEvents) {
- return {
- supported: true
- };
- }
+ supportsModel: function(m) {
+ if (m === undefined) {
+ return {
+ supported: false,
+ reason: 'Unknown tracing model'
+ };
+ }
+ if (!tr.model.helpers.ChromeModelHelper.supportsModel(m)) {
return {
supported: false,
- reason: 'No InputLatency events trace. Consider enabling ' +
- 'benchmark" and "input" category when recording the trace'
+ reason: 'No Chrome browser or renderer process found'
};
- },
+ }
- get textLabel() {
- return 'Input Latency';
+ var modelHelper = m.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);
+ if (modelHelper.browserHelper &&
+ modelHelper.browserHelper.hasLatencyEvents) {
+ return {
+ supported: true
+ };
}
- });
- </script>
-</polymer-element>
+
+ return {
+ supported: false,
+ reason: 'No InputLatency events trace. Consider enabling ' +
+ 'benchmark" and "input" category when recording the trace'
+ };
+ },
+
+ get textLabel() {
+ return 'Input Latency';
+ }
+});
+
+tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-e-s-input-latency-side-panel');
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
index 51021bd4aa3..417c171b977 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
@@ -64,14 +64,14 @@ tr.b.unittest.testSuite(function() {
test('brushedRangeChange', function() {
var events = [];
for (var i = 0; i < 10; i++) {
- var start_ts = i * 10000;
- var end_ts = start_ts + 1000 * (i % 2);
+ var startTs = i * 10000;
+ var endTs = startTs + 1000 * (i % 2);
events.push(
{
'cat': 'benchmark',
'pid': 3507,
'tid': 3507,
- 'ts': start_ts,
+ 'ts': startTs,
'ph': 'S',
'name': 'InputLatency',
'id': i
@@ -81,7 +81,7 @@ tr.b.unittest.testSuite(function() {
'cat': 'benchmark',
'pid': 3507,
'tid': 3507,
- 'ts': end_ts,
+ 'ts': endTs,
'ph': 'T',
'name': 'InputLatency',
'args': {'step': 'GestureScrollUpdate'},
@@ -92,16 +92,16 @@ tr.b.unittest.testSuite(function() {
'cat': 'benchmark',
'pid': 3507,
'tid': 3507,
- 'ts': end_ts,
+ 'ts': endTs,
'ph': 'F',
'name': 'InputLatency',
'args': {
'data': {
'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT': {
- 'time': start_ts
+ 'time': startTs
},
'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT': {
- 'time': end_ts
+ 'time': endTs
}
}
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
index a0b6d9df6b6..7391d050ced 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
@@ -7,15 +7,14 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/pie_chart.html">
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name="tr-ui-e-s-time-summary-side-panel"
- extends="tr-ui-side-panel">
+<dom-module id='tr-ui-e-s-time-summary-side-panel'>
<template>
<style>
:host {
@@ -38,401 +37,404 @@ found in the LICENSE file.
<toolbar id='toolbar'></toolbar>
<result-area id='result_area'></result-area>
</template>
-
- <script>
- 'use strict';
- (function() {
- var GROUP_BY_PROCESS_NAME = 'process';
- var GROUP_BY_THREAD_NAME = 'thread';
-
- var WALL_TIME_GROUPING_UNIT = 'Wall time';
- var CPU_TIME_GROUPING_UNIT = 'CPU time';
+</dom-module>
+<script>
+'use strict';
+(function() {
+ var GROUP_BY_PROCESS_NAME = 'process';
+ var GROUP_BY_THREAD_NAME = 'thread';
+
+ var WALL_TIME_GROUPING_UNIT = 'Wall time';
+ var CPU_TIME_GROUPING_UNIT = 'CPU time';
+
+ /**
+ * @constructor
+ */
+ function ResultsForGroup(model, name) {
+ this.model = model;
+ this.name = name;
+ this.topLevelSlices = [];
+ this.allSlices = [];
+ }
+
+ ResultsForGroup.prototype = {
+ get wallTime() {
+ var wallSum = tr.b.Statistics.sum(
+ this.topLevelSlices, function(x) { return x.duration; });
+ return wallSum;
+ },
+
+ get cpuTime() {
+ var cpuDuration = 0;
+ for (var i = 0; i < this.topLevelSlices.length; i++) {
+ var x = this.topLevelSlices[i];
+ // Only report thread-duration if we have it for all events.
+ //
+ // A thread_duration of 0 is valid, so this only returns 0 if it is
+ // None.
+ if (x.cpuDuration === undefined) {
+ if (x.duration === undefined)
+ continue;
+ return 0;
+ }
+ cpuDuration += x.cpuDuration;
+ }
+ return cpuDuration;
+ },
+
+ appendGroupContents: function(group) {
+ if (group.model !== this.model)
+ throw new Error('Models must be the same');
+
+ group.allSlices.forEach(function(slice) {
+ this.allSlices.push(slice);
+ }, this);
+ group.topLevelSlices.forEach(function(slice) {
+ this.topLevelSlices.push(slice);
+ }, this);
+ },
+
+ appendThreadSlices: function(rangeOfInterest, thread) {
+ var tmp = this.getSlicesIntersectingRange(
+ rangeOfInterest, thread.sliceGroup.slices);
+ tmp.forEach(function(slice) {
+ this.allSlices.push(slice);
+ }, this);
+ tmp = this.getSlicesIntersectingRange(
+ rangeOfInterest, thread.sliceGroup.topLevelSlices);
+ tmp.forEach(function(slice) {
+ this.topLevelSlices.push(slice);
+ }, this);
+ },
+
+ getSlicesIntersectingRange: function(rangeOfInterest, slices) {
+ var slicesInFilterRange = [];
+ for (var i = 0; i < slices.length; i++) {
+ var slice = slices[i];
+ if (rangeOfInterest.intersectsExplicitRangeInclusive(
+ slice.start, slice.end))
+ slicesInFilterRange.push(slice);
+ }
+ return slicesInFilterRange;
+ }
+ };
+
+ Polymer({
+ is: 'tr-ui-e-s-time-summary-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
+ ready: function() {
+ this.rangeOfInterest_ = new tr.b.Range();
+ this.selection_ = undefined;
+ this.groupBy_ = GROUP_BY_PROCESS_NAME;
+ this.groupingUnit_ = CPU_TIME_GROUPING_UNIT;
+ this.showCpuIdleTime_ = true;
+ this.chart_ = undefined;
+
+ var toolbarEl = this.$.toolbar;
+ this.groupBySelector_ = tr.ui.b.createSelector(
+ this, 'groupBy',
+ 'timeSummarySidePanel.groupBy', this.groupBy_,
+ [{label: 'Group by process', value: GROUP_BY_PROCESS_NAME},
+ {label: 'Group by thread', value: GROUP_BY_THREAD_NAME}
+ ]);
+ Polymer.dom(toolbarEl).appendChild(this.groupBySelector_);
+
+ this.groupingUnitSelector_ = tr.ui.b.createSelector(
+ this, 'groupingUnit',
+ 'timeSummarySidePanel.groupingUnit', this.groupingUnit_,
+ [{label: 'Wall time', value: WALL_TIME_GROUPING_UNIT},
+ {label: 'CPU time', value: CPU_TIME_GROUPING_UNIT}
+ ]);
+ Polymer.dom(toolbarEl).appendChild(this.groupingUnitSelector_);
+
+ this.showCpuIdleTimeCheckbox_ = tr.ui.b.createCheckBox(
+ this, 'showCpuIdleTime',
+ 'timeSummarySidePanel.showCpuIdleTime', this.showCpuIdleTime_,
+ 'Show CPU idle time');
+ Polymer.dom(toolbarEl).appendChild(this.showCpuIdleTimeCheckbox_);
+ this.updateShowCpuIdleTimeCheckboxVisibility_();
+ },
/**
- * @constructor
+ * This function takes an array of groups and merges smaller groups into
+ * the provided 'Other' group item such that the remaining items are ready
+ * for pie-chart consumption. Otherwise, the pie chart gets overwhelmed
+ * with tons of little slices.
*/
- function ResultsForGroup(model, name) {
- this.model = model;
- this.name = name;
- this.topLevelSlices = [];
- this.allSlices = [];
- }
-
- ResultsForGroup.prototype = {
- get wallTime() {
- var wallSum = tr.b.Statistics.sum(
- this.topLevelSlices, function(x) { return x.duration; });
- return wallSum;
- },
-
- get cpuTime() {
- var cpuDuration = 0;
- for (var i = 0; i < this.topLevelSlices.length; i++) {
- var x = this.topLevelSlices[i];
- // Only report thread-duration if we have it for all events.
- //
- // A thread_duration of 0 is valid, so this only returns 0 if it is
- // None.
- if (x.cpuDuration === undefined) {
- if (x.duration === undefined)
- continue;
- return 0;
- }
- cpuDuration += x.cpuDuration;
- }
- return cpuDuration;
- },
-
- appendGroupContents: function(group) {
- if (group.model != this.model)
- throw new Error('Models must be the same');
-
- group.allSlices.forEach(function(slice) {
- this.allSlices.push(slice);
- }, this);
- group.topLevelSlices.forEach(function(slice) {
- this.topLevelSlices.push(slice);
- }, this);
- },
-
- appendThreadSlices: function(rangeOfInterest, thread) {
- var tmp = this.getSlicesIntersectingRange(
- rangeOfInterest, thread.sliceGroup.slices);
- tmp.forEach(function(slice) {
- this.allSlices.push(slice);
- }, this);
- tmp = this.getSlicesIntersectingRange(
- rangeOfInterest, thread.sliceGroup.topLevelSlices);
- tmp.forEach(function(slice) {
- this.topLevelSlices.push(slice);
- }, this);
- },
-
- getSlicesIntersectingRange: function(rangeOfInterest, slices) {
- var slicesInFilterRange = [];
- for (var i = 0; i < slices.length; i++) {
- var slice = slices[i];
- if (rangeOfInterest.intersectsExplicitRangeInclusive(
- slice.start, slice.end))
- slicesInFilterRange.push(slice);
- }
- return slicesInFilterRange;
+ trimPieChartData: function(groups, otherGroup, getValue, opt_extraValue) {
+ // Copy the array so it can be mutated.
+ groups = groups.filter(function(d) {
+ return getValue(d) !== 0;
+ });
+
+ // Figure out total array range.
+ var sum = tr.b.Statistics.sum(groups, getValue);
+ if (opt_extraValue !== undefined)
+ sum += opt_extraValue;
+
+ // Sort by value.
+ function compareByValue(a, b) {
+ return getValue(a) - getValue(b);
+ }
+ groups.sort(compareByValue);
+
+ // Now start fusing elements until none are less than threshold in size.
+ var thresshold = 0.1 * sum;
+ while (groups.length > 1) {
+ var group = groups[0];
+ if (getValue(group) >= thresshold)
+ break;
+
+ var v = getValue(group);
+ if (v + getValue(otherGroup) > thresshold)
+ break;
+
+ // Remove the group from the list and add it to the 'Other' group.
+ groups.splice(0, 1);
+ otherGroup.appendGroupContents(group);
}
- };
-
- Polymer({
- ready: function() {
- this.rangeOfInterest_ = new tr.b.Range();
- this.selection_ = undefined;
- this.groupBy_ = GROUP_BY_PROCESS_NAME;
- this.groupingUnit_ = CPU_TIME_GROUPING_UNIT;
- this.showCpuIdleTime_ = true;
- this.chart_ = undefined;
-
- var toolbarEl = this.$.toolbar;
- this.groupBySelector_ = tr.ui.b.createSelector(
- this, 'groupBy',
- 'timeSummarySidePanel.groupBy', this.groupBy_,
- [{label: 'Group by process', value: GROUP_BY_PROCESS_NAME},
- {label: 'Group by thread', value: GROUP_BY_THREAD_NAME}
- ]);
- toolbarEl.appendChild(this.groupBySelector_);
-
- this.groupingUnitSelector_ = tr.ui.b.createSelector(
- this, 'groupingUnit',
- 'timeSummarySidePanel.groupingUnit', this.groupingUnit_,
- [{label: 'Wall time', value: WALL_TIME_GROUPING_UNIT},
- {label: 'CPU time', value: CPU_TIME_GROUPING_UNIT}
- ]);
- toolbarEl.appendChild(this.groupingUnitSelector_);
-
- this.showCpuIdleTimeCheckbox_ = tr.ui.b.createCheckBox(
- this, 'showCpuIdleTime',
- 'timeSummarySidePanel.showCpuIdleTime', this.showCpuIdleTime_,
- 'Show CPU idle time');
- toolbarEl.appendChild(this.showCpuIdleTimeCheckbox_);
- this.updateShowCpuIdleTimeCheckboxVisibility_();
- },
-
- /**
- * This function takes an array of groups and merges smaller groups into
- * the provided 'Other' group item such that the remaining items are ready
- * for pie-chart consumption. Otherwise, the pie chart gets overwhelmed
- * with tons of little slices.
- */
- trimPieChartData: function(groups, otherGroup, getValue, opt_extraValue) {
- // Copy the array so it can be mutated.
- groups = groups.filter(function(d) {
- return getValue(d) != 0;
- });
-
- // Figure out total array range.
- var sum = tr.b.Statistics.sum(groups, getValue);
- if (opt_extraValue !== undefined)
- sum += opt_extraValue;
-
- // Sort by value.
- function compareByValue(a, b) {
- return getValue(a) - getValue(b);
- }
- groups.sort(compareByValue);
-
- // Now start fusing elements until none are less than threshold in size.
- var thresshold = 0.1 * sum;
- while (groups.length > 1) {
- var group = groups[0];
- if (getValue(group) >= thresshold)
- break;
-
- var v = getValue(group);
- if (v + getValue(otherGroup) > thresshold)
- break;
-
- // Remove the group from the list and add it to the 'Other' group.
- groups.splice(0, 1);
- otherGroup.appendGroupContents(group);
- }
-
- // Final return.
- if (getValue(otherGroup) > 0)
- groups.push(otherGroup);
-
- groups.sort(compareByValue);
- return groups;
- },
+ // Final return.
+ if (getValue(otherGroup) > 0)
+ groups.push(otherGroup);
- generateResultsForGroup: function(model, name) {
- return new ResultsForGroup(model, name);
- },
+ groups.sort(compareByValue);
- createPieChartFromResultGroups: function(
- groups, title, getValue, opt_extraData) {
- var chart = new tr.ui.b.PieChart();
+ return groups;
+ },
- function pushDataForGroup(data, resultsForGroup, value) {
- data.push({
- label: resultsForGroup.name,
- value: value,
- valueText: tr.v.Unit.byName.timeDurationInMs.format(value),
- resultsForGroup: resultsForGroup
- });
- }
- chart.addEventListener('item-click', function(clickEvent) {
- var resultsForGroup = clickEvent.data.resultsForGroup;
- if (resultsForGroup === undefined)
- return;
-
- var event = new tr.model.RequestSelectionChangeEvent();
- event.selection = new tr.model.EventSet(resultsForGroup.allSlices);
- event.selection.timeSummaryGroupName = resultsForGroup.name;
- chart.dispatchEvent(event);
- });
+ generateResultsForGroup: function(model, name) {
+ return new ResultsForGroup(model, name);
+ },
+ createPieChartFromResultGroups: function(
+ groups, title, getValue, opt_extraData) {
+ var chart = new tr.ui.b.PieChart();
- // Build chart data.
- var data = [];
- groups.forEach(function(resultsForGroup) {
- var value = getValue(resultsForGroup);
- if (value === 0)
- return;
- pushDataForGroup(data, resultsForGroup, value);
+ function pushDataForGroup(data, resultsForGroup, value) {
+ data.push({
+ label: resultsForGroup.name,
+ value: value,
+ valueText: tr.b.Unit.byName.timeDurationInMs.format(value),
+ resultsForGroup: resultsForGroup
});
- if (opt_extraData)
- data.push.apply(data, opt_extraData);
-
- chart.chartTitle = title;
- chart.data = data;
- return chart;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- this.updateContents_();
- },
-
- get groupBy() {
- return groupBy_;
- },
-
- set groupBy(groupBy) {
- this.groupBy_ = groupBy;
- if (this.groupBySelector_)
- this.groupBySelector_.selectedValue = groupBy;
- this.updateContents_();
- },
-
- get groupingUnit() {
- return groupingUnit_;
- },
-
- set groupingUnit(groupingUnit) {
- this.groupingUnit_ = groupingUnit;
- if (this.groupingUnitSelector_)
- this.groupingUnitSelector_.selectedValue = groupingUnit;
- this.updateShowCpuIdleTimeCheckboxVisibility_();
- this.updateContents_();
- },
-
- get showCpuIdleTime() {
- return this.showCpuIdleTime_;
- },
-
- set showCpuIdleTime(showCpuIdleTime) {
- this.showCpuIdleTime_ = showCpuIdleTime;
- if (this.showCpuIdleTimeCheckbox_)
- this.showCpuIdleTimeCheckbox_.checked = showCpuIdleTime;
- this.updateContents_();
- },
-
- updateShowCpuIdleTimeCheckboxVisibility_: function() {
- if (!this.showCpuIdleTimeCheckbox_)
- return;
- var visible = this.groupingUnit_ == CPU_TIME_GROUPING_UNIT;
- if (visible)
- this.showCpuIdleTimeCheckbox_.style.display = '';
- else
- this.showCpuIdleTimeCheckbox_.style.display = 'none';
- },
-
- getGroupNameForThread_: function(thread) {
- if (this.groupBy_ == GROUP_BY_THREAD_NAME)
- return thread.name ? thread.name : thread.userFriendlyName;
-
- if (this.groupBy_ == GROUP_BY_PROCESS_NAME)
- return thread.parent.userFriendlyName;
- },
-
- updateContents_: function() {
- var resultArea = this.$.result_area;
- this.chart_ = undefined;
- resultArea.textContent = '';
-
- if (this.model_ === undefined)
+ }
+ chart.addEventListener('item-click', function(clickEvent) {
+ var resultsForGroup = clickEvent.data.resultsForGroup;
+ if (resultsForGroup === undefined)
return;
- var rangeOfInterest;
- if (this.rangeOfInterest_.isEmpty)
- rangeOfInterest = this.model_.bounds;
- else
- rangeOfInterest = this.rangeOfInterest_;
-
- var allGroup = this.generateResultsForGroup(this.model_, 'all');
- var resultsByGroupName = {};
- this.model_.getAllThreads().forEach(function(thread) {
- var groupName = this.getGroupNameForThread_(thread);
- if (resultsByGroupName[groupName] === undefined) {
- resultsByGroupName[groupName] = this.generateResultsForGroup(
- this.model_, groupName);
- }
- resultsByGroupName[groupName].appendThreadSlices(
- rangeOfInterest, thread);
-
- allGroup.appendThreadSlices(rangeOfInterest, thread);
- }, this);
-
- // Helper function for working with the produced group.
- var getValueFromGroup = function(group) {
- if (this.groupingUnit_ == WALL_TIME_GROUPING_UNIT)
- return group.wallTime;
- return group.cpuTime;
- }.bind(this);
-
- // Create summary.
- var summaryText = document.createElement('div');
- summaryText.appendChild(tr.ui.b.createSpan({
- textContent: 'Total ' + this.groupingUnit_ + ': ',
- bold: true}));
- summaryText.appendChild(tr.v.ui.createScalarSpan(
- getValueFromGroup(allGroup), {
- unit: tr.v.Unit.byName.timeDurationInMs,
- ownerDocument: this.ownerDocument
- }));
- resultArea.appendChild(summaryText);
-
- // If needed, add in the idle time.
- var extraValue = 0;
- var extraData = [];
- if (this.showCpuIdleTime_ &&
- this.groupingUnit_ === CPU_TIME_GROUPING_UNIT &&
- this.model.kernel.bestGuessAtCpuCount !== undefined) {
- var maxCpuTime = rangeOfInterest.range *
- this.model.kernel.bestGuessAtCpuCount;
- var idleTime = Math.max(0, maxCpuTime - allGroup.cpuTime);
- extraData.push({
- label: 'CPU Idle',
- value: idleTime,
- valueText: tr.v.Unit.byName.timeDurationInMs.format(idleTime)
- });
- extraValue += idleTime;
- }
-
- // Create the actual chart.
- var otherGroup = this.generateResultsForGroup(this.model_, 'Other');
- var groups = this.trimPieChartData(
- tr.b.dictionaryValues(resultsByGroupName),
- otherGroup,
- getValueFromGroup,
- extraValue);
-
- if (groups.length == 0) {
- resultArea.appendChild(tr.ui.b.createSpan({textContent: 'No data'}));
- return undefined;
- }
+ var event = new tr.model.RequestSelectionChangeEvent();
+ event.selection = new tr.model.EventSet(resultsForGroup.allSlices);
+ event.selection.timeSummaryGroupName = resultsForGroup.name;
+ chart.dispatchEvent(event);
+ });
- this.chart_ = this.createPieChartFromResultGroups(
- groups,
- this.groupingUnit_ + ' breakdown by ' + this.groupBy_,
- getValueFromGroup, extraData);
- resultArea.appendChild(this.chart_);
- this.chart_.addEventListener('click', function() {
- var event = new tr.model.RequestSelectionChangeEvent();
- event.selection = new tr.c.EventSet([]);
- this.dispatchEvent(event);
- });
- this.chart_.setSize(this.chart_.getMinSize());
- },
-
- get selection() {
- return selection_;
- },
-
- set selection(selection) {
- this.selection_ = selection;
-
- if (this.chart_ === undefined)
+ // Build chart data.
+ var data = [];
+ groups.forEach(function(resultsForGroup) {
+ var value = getValue(resultsForGroup);
+ if (value === 0)
return;
+ pushDataForGroup(data, resultsForGroup, value);
+ });
+ if (opt_extraData)
+ data.push.apply(data, opt_extraData);
+
+ chart.chartTitle = title;
+ chart.data = data;
+ return chart;
+ },
+
+ get model() {
+ return this.model_;
+ },
+
+ set model(model) {
+ this.model_ = model;
+ this.updateContents_();
+ },
+
+ get groupBy() {
+ return groupBy_;
+ },
+
+ set groupBy(groupBy) {
+ this.groupBy_ = groupBy;
+ if (this.groupBySelector_)
+ this.groupBySelector_.selectedValue = groupBy;
+ this.updateContents_();
+ },
+
+ get groupingUnit() {
+ return groupingUnit_;
+ },
+
+ set groupingUnit(groupingUnit) {
+ this.groupingUnit_ = groupingUnit;
+ if (this.groupingUnitSelector_)
+ this.groupingUnitSelector_.selectedValue = groupingUnit;
+ this.updateShowCpuIdleTimeCheckboxVisibility_();
+ this.updateContents_();
+ },
+
+ get showCpuIdleTime() {
+ return this.showCpuIdleTime_;
+ },
+
+ set showCpuIdleTime(showCpuIdleTime) {
+ this.showCpuIdleTime_ = showCpuIdleTime;
+ if (this.showCpuIdleTimeCheckbox_)
+ this.showCpuIdleTimeCheckbox_.checked = showCpuIdleTime;
+ this.updateContents_();
+ },
+
+ updateShowCpuIdleTimeCheckboxVisibility_: function() {
+ if (!this.showCpuIdleTimeCheckbox_)
+ return;
+ var visible = this.groupingUnit_ === CPU_TIME_GROUPING_UNIT;
+ if (visible)
+ this.showCpuIdleTimeCheckbox_.style.display = '';
+ else
+ this.showCpuIdleTimeCheckbox_.style.display = 'none';
+ },
+
+ getGroupNameForThread_: function(thread) {
+ if (this.groupBy_ === GROUP_BY_THREAD_NAME)
+ return thread.name ? thread.name : thread.userFriendlyName;
+
+ if (this.groupBy_ === GROUP_BY_PROCESS_NAME)
+ return thread.parent.userFriendlyName;
+ },
+
+ updateContents_: function() {
+ var resultArea = this.$.result_area;
+ this.chart_ = undefined;
+ Polymer.dom(resultArea).textContent = '';
+
+ if (this.model_ === undefined)
+ return;
+
+ var rangeOfInterest;
+ if (this.rangeOfInterest_.isEmpty)
+ rangeOfInterest = this.model_.bounds;
+ else
+ rangeOfInterest = this.rangeOfInterest_;
+
+ var allGroup = this.generateResultsForGroup(this.model_, 'all');
+ var resultsByGroupName = {};
+ this.model_.getAllThreads().forEach(function(thread) {
+ var groupName = this.getGroupNameForThread_(thread);
+ if (resultsByGroupName[groupName] === undefined) {
+ resultsByGroupName[groupName] = this.generateResultsForGroup(
+ this.model_, groupName);
+ }
+ resultsByGroupName[groupName].appendThreadSlices(
+ rangeOfInterest, thread);
+
+ allGroup.appendThreadSlices(rangeOfInterest, thread);
+ }, this);
+
+ // Helper function for working with the produced group.
+ var getValueFromGroup = function(group) {
+ if (this.groupingUnit_ === WALL_TIME_GROUPING_UNIT)
+ return group.wallTime;
+ return group.cpuTime;
+ }.bind(this);
+
+ // Create summary.
+ var summaryText = document.createElement('div');
+ Polymer.dom(summaryText).appendChild(tr.ui.b.createSpan({
+ textContent: 'Total ' + this.groupingUnit_ + ': ',
+ bold: true}));
+ Polymer.dom(summaryText).appendChild(tr.v.ui.createScalarSpan(
+ getValueFromGroup(allGroup), {
+ unit: tr.b.Unit.byName.timeDurationInMs,
+ ownerDocument: this.ownerDocument
+ }));
+ Polymer.dom(resultArea).appendChild(summaryText);
+
+ // If needed, add in the idle time.
+ var extraValue = 0;
+ var extraData = [];
+ if (this.showCpuIdleTime_ &&
+ this.groupingUnit_ === CPU_TIME_GROUPING_UNIT &&
+ this.model.kernel.bestGuessAtCpuCount !== undefined) {
+ var maxCpuTime = rangeOfInterest.range *
+ this.model.kernel.bestGuessAtCpuCount;
+ var idleTime = Math.max(0, maxCpuTime - allGroup.cpuTime);
+ extraData.push({
+ label: 'CPU Idle',
+ value: idleTime,
+ valueText: tr.b.Unit.byName.timeDurationInMs.format(idleTime)
+ });
+ extraValue += idleTime;
+ }
- if (selection.timeSummaryGroupName)
- this.chart_.highlightedLegendKey = selection.timeSummaryGroupName;
- else
- this.chart_.highlightedLegendKey = undefined;
- },
-
- get rangeOfInterest() {
- return this.rangeOfInterest_;
- },
-
- set rangeOfInterest(rangeOfInterest) {
- this.rangeOfInterest_ = rangeOfInterest;
- this.updateContents_();
- },
-
- supportsModel: function(model) {
- return {
- supported: false
- };
- },
-
- get textLabel() {
- return 'Time Summary';
+ // Create the actual chart.
+ var otherGroup = this.generateResultsForGroup(this.model_, 'Other');
+ var groups = this.trimPieChartData(
+ tr.b.dictionaryValues(resultsByGroupName),
+ otherGroup,
+ getValueFromGroup,
+ extraValue);
+
+ if (groups.length === 0) {
+ Polymer.dom(resultArea).appendChild(
+ tr.ui.b.createSpan({textContent: 'No data'}));
+ return undefined;
}
- });
- }());
- </script>
-</polymer-element>
+
+ this.chart_ = this.createPieChartFromResultGroups(
+ groups,
+ this.groupingUnit_ + ' breakdown by ' + this.groupBy_,
+ getValueFromGroup, extraData);
+ Polymer.dom(resultArea).appendChild(this.chart_);
+
+ this.chart_.addEventListener('click', function() {
+ var event = new tr.model.RequestSelectionChangeEvent();
+ event.selection = new tr.c.EventSet([]);
+ this.dispatchEvent(event);
+ });
+ this.chart_.setSize(this.chart_.getMinSize());
+ },
+
+ get selection() {
+ return selection_;
+ },
+
+ set selection(selection) {
+ this.selection_ = selection;
+
+ if (this.chart_ === undefined)
+ return;
+
+ if (selection.timeSummaryGroupName)
+ this.chart_.highlightedLegendKey = selection.timeSummaryGroupName;
+ else
+ this.chart_.highlightedLegendKey = undefined;
+ },
+
+ get rangeOfInterest() {
+ return this.rangeOfInterest_;
+ },
+
+ set rangeOfInterest(rangeOfInterest) {
+ this.rangeOfInterest_ = rangeOfInterest;
+ this.updateContents_();
+ },
+
+ supportsModel: function(model) {
+ return {
+ supported: false
+ };
+ },
+
+ get textLabel() {
+ return 'Time Summary';
+ }
+ });
+}());
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html
index 9aa10212de6..2e096b65ec9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html
@@ -9,10 +9,10 @@ found in the LICENSE file.
href="/tracing/ui/extras/system_stats/system_stats_instance_track.css">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
-<link rel="import" href="/tracing/ui/tracks/stacked_bars_track.html">
-<link rel="import" href="/tracing/ui/tracks/object_instance_track.html">
<link rel="import" href="/tracing/ui/base/event_presenter.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/object_instance_track.html">
+<link rel="import" href="/tracing/ui/tracks/stacked_bars_track.html">
<script>
'use strict';
@@ -57,7 +57,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
decorate: function(viewport) {
tr.ui.tracks.StackedBarsTrack.prototype.decorate.call(this, viewport);
- this.classList.add('tr-ui-e-system-stats-instance-track');
+ Polymer.dom(this).classList.add('tr-ui-e-system-stats-instance-track');
this.objectInstance_ = null;
},
@@ -66,7 +66,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
this.objectInstance_ = [];
return;
}
- if (objectInstances.length != 1)
+ if (objectInstances.length !== 1)
throw new Error('Bad object instance count.');
this.objectInstance_ = objectInstances[0];
if (this.objectInstance_ !== null) {
@@ -83,7 +83,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
var prevSnapshot;
var prevStats;
- if (i == 0) {
+ if (i === 0) {
// Deltas will be zero.
prevSnapshot = snapshots[0];
} else {
@@ -92,7 +92,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
prevStats = prevSnapshot.getStats();
var timeIntervalSeconds = (snapshot.ts - prevSnapshot.ts) / 1000;
// Prevent divide by zero.
- if (timeIntervalSeconds == 0)
+ if (timeIntervalSeconds === 0)
timeIntervalSeconds = 1;
this.computeRatesRecursive_(prevStats, stats,
@@ -108,28 +108,28 @@ tr.exportTo('tr.ui.e.system_stats', function() {
stats[statName],
timeIntervalSeconds);
} else {
- if (statName == 'sectors_read') {
+ if (statName === 'sectors_read') {
stats['bytes_read_per_sec'] = (stats['sectors_read'] -
prevStats['sectors_read']) *
512 / timeIntervalSeconds;
}
- if (statName == 'sectors_written') {
+ if (statName === 'sectors_written') {
stats['bytes_written_per_sec'] =
(stats['sectors_written'] -
prevStats['sectors_written']) *
512 / timeIntervalSeconds;
}
- if (statName == 'pgmajfault') {
+ if (statName === 'pgmajfault') {
stats['pgmajfault_per_sec'] = (stats['pgmajfault'] -
prevStats['pgmajfault']) /
timeIntervalSeconds;
}
- if (statName == 'pswpin') {
+ if (statName === 'pswpin') {
stats['bytes_swpin_per_sec'] = (stats['pswpin'] -
prevStats['pswpin']) *
1000 / timeIntervalSeconds;
}
- if (statName == 'pswpout') {
+ if (statName === 'pswpout') {
stats['bytes_swpout_per_sec'] = (stats['pswpout'] -
prevStats['pswpout']) *
1000 / timeIntervalSeconds;
@@ -237,7 +237,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
// Compute the edges for the column graph bar.
var right;
- if (i != objectSnapshots.length - 1) {
+ if (i !== objectSnapshots.length - 1) {
right = objectSnapshots[i + 1].ts;
} else {
// If this is the last snaphot of multiple snapshots, use the width of
@@ -267,7 +267,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
maxStats,
currentY);
- if (i == lowIndex)
+ if (i === lowIndex)
this.drawStatNames_(leftView, height, currentY, '', maxStats);
}
ctx.lineWidth = 1;
@@ -332,7 +332,7 @@ tr.exportTo('tr.ui.e.system_stats', function() {
} else {
var fullname = statName;
- if (prefix != '')
+ if (prefix !== '')
fullname = prefix + ' :: ' + statName;
ctx.fillText(fullname, leftView - 10, currentY - height / 4);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html
index 684887c2f0d..b13eaa921d6 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html
@@ -49,11 +49,11 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new SystemStatsInstanceTrack(viewport);
track.objectInstances = objectInstances;
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html
index 11421e91453..ba093134da3 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html
@@ -24,20 +24,20 @@ tr.exportTo('tr.ui.e.system_stats', function() {
__proto__: tr.ui.analysis.ObjectSnapshotView.prototype,
decorate: function() {
- this.classList.add('tr-ui-e-system-stats-snapshot-view');
+ Polymer.dom(this).classList.add('tr-ui-e-system-stats-snapshot-view');
},
updateContents: function() {
var snapshot = this.objectSnapshot_;
if (!snapshot || !snapshot.getStats()) {
- this.textContent = 'No system stats snapshot found.';
+ Polymer.dom(this).textContent = 'No system stats snapshot found.';
return;
}
// Clear old snapshot view.
- this.textContent = '';
+ Polymer.dom(this).textContent = '';
var stats = snapshot.getStats();
- this.appendChild(this.buildList_(stats));
+ Polymer.dom(this).appendChild(this.buildList_(stats));
},
isFloat: function(n) {
@@ -55,16 +55,16 @@ tr.exportTo('tr.ui.e.system_stats', function() {
for (var statName in stats) {
var statText = document.createElement('li');
- statText.textContent = '' + statName + ': ';
- statList.appendChild(statText);
+ Polymer.dom(statText).textContent = '' + statName + ': ';
+ Polymer.dom(statList).appendChild(statText);
if (stats[statName] instanceof Object) {
- statList.appendChild(this.buildList_(stats[statName]));
+ Polymer.dom(statList).appendChild(this.buildList_(stats[statName]));
} else {
if (this.isFloat(stats[statName]))
- statText.textContent += stats[statName].toFixed(2);
+ Polymer.dom(statText).textContent += stats[statName].toFixed(2);
else
- statText.textContent += stats[statName];
+ Polymer.dom(statText).textContent += stats[statName];
}
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html
index 3ba4626e1c3..5045dd13d34 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html
@@ -5,6 +5,13 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<!--
+TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the
+same way that all non-UI files depend on tracing/base/base.html. Enforce this
+dependency with a presubmit.
+-->
+<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order>
+
<link rel="import" href="/tracing/extras/systrace_config.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/extras/highlighter/vsync_highlighter.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html
new file mode 100644
index 00000000000..a33ec56e07f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html
@@ -0,0 +1,556 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/v8/v8_gc_stats_thread_slice.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+
+<dom-module id='tr-ui-e-v8-gc-objects-stats-table'>
+ <template>
+ <style>
+ tr-ui-b-table {
+ flex: 0 0 auto;
+ align-self: stretch;
+ margin-top: 1em;
+ font-size: 12px;
+ }
+ </style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</dom-module>
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.e.v8', function() {
+
+ // The constant variables below should be consistent with
+ // https://github.com/mlippautz/v8-heap-stats/blob/master/app/utils.js#L120
+ var InstanceTypeGroups = {
+ Rest: [
+ "ACCESSOR_INFO_TYPE",
+ "ACCESSOR_PAIR_TYPE",
+ "ACCESS_CHECK_INFO_TYPE",
+ "ALLOCATION_MEMENTO_TYPE",
+ "ALLOCATION_SITE_TYPE",
+ "CALL_HANDLER_INFO_TYPE",
+ "CELL_TYPE",
+ "FIXED_INT8_ARRAY_TYPE",
+ "FIXED_UINT8_ARRAY_TYPE",
+ "FIXED_UINT8_CLAMPED_ARRAY_TYPE",
+ "FIXED_INT16_ARRAY_TYPE",
+ "FIXED_UINT16_ARRAY_TYPE",
+ "FIXED_INT32_ARRAY_TYPE",
+ "FIXED_UINT32_ARRAY_TYPE",
+ "FIXED_FLOAT32_ARRAY_TYPE",
+ "FIXED_FLOAT64_ARRAY_TYPE",
+ "FIXED_DOUBLE_ARRAY_TYPE",
+ "FOREIGN_TYPE",
+ "FUNCTION_TEMPLATE_INFO_TYPE",
+ "HEAP_NUMBER_TYPE",
+ "INTERCEPTOR_INFO_TYPE",
+ "MUTABLE_HEAP_NUMBER_TYPE",
+ "OBJECT_TEMPLATE_INFO_TYPE",
+ "ODDBALL_TYPE",
+ "PROPERTY_CELL_TYPE",
+ "PROTOTYPE_INFO_TYPE",
+ "SCRIPT_TYPE",
+ "SYMBOL_TYPE",
+ "TRANSITION_ARRAY_TYPE",
+ "TYPE_FEEDBACK_INFO_TYPE"
+ ],
+ Strings: [
+ "CONS_ONE_BYTE_STRING_TYPE",
+ "CONS_STRING_TYPE",
+ "EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE",
+ "EXTERNAL_ONE_BYTE_STRING_TYPE",
+ "EXTERNAL_INTERNALIZED_STRING_TYPE",
+ "EXTERNAL_STRING_TYPE",
+ "INTERNALIZED_STRING_TYPE",
+ "ONE_BYTE_INTERNALIZED_STRING_TYPE",
+ "ONE_BYTE_STRING_TYPE",
+ "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE",
+ "SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE",
+ "SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE",
+ "SHORT_EXTERNAL_STRING_TYPE",
+ "SLICED_ONE_BYTE_STRING_TYPE",
+ "SLICED_STRING_TYPE",
+ "STRING_TYPE"
+ ],
+ JS_OTHER: [
+ "JS_API_OBJECT_TYPE",
+ "JS_ARGUMENTS_TYPE",
+ "JS_ARRAY_BUFFER_TYPE",
+ "JS_ARRAY_TYPE",
+ "JS_BOUND_FUNCTION_TYPE",
+ "JS_ERROR_TYPE",
+ "JS_DATE_TYPE",
+ "JS_FUNCTION_TYPE",
+ "JS_GLOBAL_OBJECT_TYPE",
+ "JS_GLOBAL_PROXY_TYPE",
+ "JS_MAP_ITERATOR_TYPE",
+ "JS_MAP_TYPE",
+ "JS_MESSAGE_OBJECT_TYPE",
+ "JS_PROMISE_TYPE",
+ "JS_REGEXP_TYPE",
+ "JS_SPECIAL_API_OBJECT_TYPE",
+ "JS_TYPED_ARRAY_TYPE",
+ "JS_VALUE_TYPE",
+ "JS_WEAK_MAP_TYPE"
+ ],
+ FIXED_ARRAY_TYPE: [
+ "*FIXED_ARRAY_CODE_STUBS_TABLE_SUB_TYPE",
+ "*FIXED_ARRAY_COMPILATION_CACHE_TABLE_SUB_TYPE",
+ "*FIXED_ARRAY_CONTEXT_SUB_TYPE",
+ "*FIXED_ARRAY_COPY_ON_WRITE_SUB_TYPE",
+ "*FIXED_ARRAY_DEOPTIMIZATION_DATA_SUB_TYPE",
+ "*FIXED_ARRAY_DESCRIPTOR_ARRAY_SUB_TYPE",
+ "*FIXED_ARRAY_EMBEDDED_OBJECT_SUB_TYPE",
+ "*FIXED_ARRAY_ENUM_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_ENUM_INDICES_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_DEPENDENT_CODE_SUB_TYPE",
+ "*FIXED_ARRAY_DICTIONARY_ELEMENTS_SUB_TYPE",
+ "*FIXED_ARRAY_DICTIONARY_PROPERTIES_SUB_TYPE",
+ "*FIXED_ARRAY_EMPTY_PROPERTIES_DICTIONARY_SUB_TYPE",
+ "*FIXED_ARRAY_FAST_ELEMENTS_SUB_TYPE",
+ "*FIXED_ARRAY_FAST_PROPERTIES_SUB_TYPE",
+ "*FIXED_ARRAY_HANDLER_TABLE_SUB_TYPE",
+ "*FIXED_ARRAY_INTRINSIC_FUNCTION_NAMES_SUB_TYPE",
+ "*FIXED_ARRAY_JS_COLLECTION_SUB_TYPE",
+ "*FIXED_ARRAY_JS_WEAK_COLLECTION_SUB_TYPE",
+ "*FIXED_ARRAY_LITERALS_ARRAY_SUB_TYPE",
+ "*FIXED_ARRAY_MAP_CODE_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE",
+ "*FIXED_ARRAY_NUMBER_STRING_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_OBJECT_TO_CODE_SUB_TYPE",
+ "*FIXED_ARRAY_OPTIMIZED_CODE_LITERALS_TUB_TYPE",
+ "*FIXED_ARRAY_OPTIMIZED_CODE_MAP_SUB_TYPE",
+ "*FIXED_ARRAY_PROTOTYPE_USERS_SUB_TYPE",
+ "*FIXED_ARRAY_REGEXP_MULTIPLE_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_RETAINED_MAPS_SUB_TYPE",
+ "*FIXED_ARRAY_SCOPE_INFO_SUB_TYPE",
+ "*FIXED_ARRAY_SCRIPT_LIST_SUB_TYPE",
+ "*FIXED_ARRAY_SERIALIZED_TEMPLATES_SUB_TYPE",
+ "*FIXED_ARRAY_SHARED_FUNCTION_INFOS_SUB_TYPE",
+ "*FIXED_ARRAY_SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_STRING_SPLIT_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_STRING_TABLE_SUB_TYPE",
+ "*FIXED_ARRAY_TEMPLATE_INFO_SUB_TYPE",
+ "*FIXED_ARRAY_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE",
+ "*FIXED_ARRAY_TYPE_FEEDBACK_VECTOR_SUB_TYPE",
+ "*FIXED_ARRAY_TYPE_FEEDBACK_METADATA_SUB_TYPE",
+ "*FIXED_ARRAY_WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE",
+ "*FIXED_ARRAY_UNKNOWN_SUB_TYPE"
+ ],
+ CODE_TYPE: [
+ "*CODE_FUNCTION",
+ "*CODE_OPTIMIZED_FUNCTION",
+ "*CODE_BYTECODE_HANDLER",
+ "*CODE_STUB",
+ "*CODE_HANDLER",
+ "*CODE_BUILTIN",
+ "*CODE_REGEXP",
+ "*CODE_WASM_FUNCTION",
+ "*CODE_WASM_TO_JS_FUNCTION",
+ "*CODE_JS_TO_WASM_FUNCTION",
+ "*CODE_LOAD_IC",
+ "*CODE_LOAD_GLOBAL_IC",
+ "*CODE_KEYED_LOAD_IC",
+ "*CODE_CALL_IC",
+ "*CODE_STORE_IC",
+ "*CODE_KEYED_STORE_IC",
+ "*CODE_BINARY_OP_IC",
+ "*CODE_COMPARE_IC",
+ "*CODE_TO_BOOLEAN_IC"
+ ],
+ CONTEXT_EXTENSION_TYPE: [
+ 'CONTEXT_EXTENSION_TYPE'
+ ],
+ MAP_TYPE: [
+ 'MAP_TYPE'
+ ],
+ BYTE_ARRAY_TYPE: [
+ 'BYTE_ARRAY_TYPE'
+ ],
+ SHARED_FUNCTION_INFO_TYPE: [
+ 'SHARED_FUNCTION_INFO_TYPE'
+ ],
+ WEAK_CELL_TYPE: [
+ 'WEAK_CELL_TYPE'
+ ],
+ JS_OBJECT_TYPE: [
+ 'JS_OBJECT_TYPE'
+ ],
+ JS_CONTEXT_EXTENSION_OBJECT_TYPE: [
+ 'JS_CONTEXT_EXTENSION_OBJECT_TYPE'
+ ]
+ };
+
+ var InstanceSubTypeNames = {
+ FIXED_ARRAY_TYPE: {
+ keyToName: key => key.slice("*FIXED_ARRAY_".length)
+ .slice(0, -("_SUB_TYPE".length)),
+ nameToKey: name => "*FIXED_ARRAY_" + name + "_SUB_TYPE"
+ },
+ CODE_TYPE: {
+ keyToName: key => key.slice("*CODE_".length),
+ nameToKey: name => "*CODE_" + name
+ },
+ Strings: {
+ keyToName: key => key,
+ nameToKey: name => name
+ },
+ Rest: {
+ keyToName: key => key,
+ nameToKey: name => name
+ },
+ JS_OTHER: {
+ keyToName: key => key,
+ nameToKey: name => name
+ }
+ };
+
+ class Entry {
+ constructor(title, count, overall, overAllocated, histogram,
+ overAllocatedHistogram) {
+ this.title_ = title;
+ this.overall_ = overall;
+ this.count_ = count;
+ this.overAllocated_ = overAllocated;
+ this.histogram_ = histogram;
+ this.overAllocatedHistogram_ = overAllocatedHistogram;
+ this.bucketSize_ = this.histogram_.length;
+ this.overallPercent_ = 100;
+ this.overAllocatedPercent_ = 100;
+ }
+
+ get title() {
+ return this.title_;
+ }
+
+ get overall() {
+ return this.overall_;
+ }
+
+ get count() {
+ return this.count_;
+ }
+
+ get overAllocated() {
+ return this.overAllocated_;
+ }
+
+ get histogram() {
+ return this.histogram_;
+ }
+
+ get overAllocatedHistogram() {
+ return this.overAllocatedHistogram_;
+ }
+
+ get bucketSize() {
+ return this.bucketSize_;
+ }
+
+ get overallPercent() {
+ return this.overallPercent_;
+ }
+
+ set overallPercent(value) {
+ this.overallPercent_ = value;
+ }
+
+ get overAllocatedPercent() {
+ return this.overAllocatedPercent_;
+ }
+
+ set overAllocatedPercent(value) {
+ this.overAllocatedPercent_ = value;
+ }
+
+ setFromObject(obj) {
+ this.count_ = obj.count;
+ this.overall_ = obj.overall;
+ this.overAllocated_ = obj.over_allocated;
+ this.histogram_ = obj.histogram;
+ this.overAllocatedHistogram_ = obj.over_allocated_histogram;
+ }
+ }
+
+ class GroupedEntry extends Entry {
+ constructor(title, count, overall, overAllocated, histogram,
+ overAllocatedHistogram) {
+ super(title, count, overall, overAllocated, histogram,
+ overAllocatedHistogram);
+ this.histogram_.fill(0);
+ this.overAllocatedHistogram_.fill(0);
+ this.entries_ = new Map();
+ }
+
+ get subRows() {
+ return Array.from(this.entries_.values());
+ }
+
+ getEntryFromTitle(title) {
+ return this.entries_.get(title);
+ }
+
+ add(entry) {
+ this.count_ += entry.count;
+ this.overall_ += entry.overall;
+ this.overAllocated_ += entry.overAllocated;
+ if (this.bucketSize_ === entry.bucketSize) {
+ for (var i = 0; i < this.bucketSize_; ++i) {
+ this.histogram_[i] += entry.histogram[i];
+ this.overAllocatedHistogram_[i] += entry.overAllocatedHistogram[i];
+ }
+ }
+ this.entries_.set(entry.title, entry);
+ }
+
+ accumulateUnknown(title) {
+ var unknownCount = this.count_;
+ var unknownOverall = this.overall_;
+ var unknownOverAllocated = this.overAllocated_;
+ var unknownHistogram = tr.b.deepCopy(this.histogram_);
+ var unknownOverAllocatedHistogram =
+ tr.b.deepCopy(this.overAllocatedHistogram_);
+ for (var entry of this.entries_.values()) {
+ unknownCount -= entry.count;
+ unknownOverall -= entry.overall;
+ unknownOverAllocated -= entry.overAllocated;
+ for (var i = 0; i < this.bucketSize_; ++i) {
+ unknownHistogram[i] -= entry.histogram[i];
+ unknownOverAllocatedHistogram[i] -= entry.overAllocatedHistogram[i];
+ }
+ }
+ this.entries_.set(title, new Entry(title, unknownCount, unknownOverall,
+ unknownOverAllocated, unknownHistogram,
+ unknownOverAllocatedHistogram));
+ }
+
+ calculatePercentage() {
+ for (var entry of this.entries_.values()) {
+ if (this.overall_ > 0) {
+ entry.overallPercent =
+ (entry.overall / this.overall_ * 100).toFixed(3);
+ } else {
+ entry.overallPercent = 0;
+ }
+
+ if (this.overAllocated_ > 0) {
+ entry.overAllocatedPercent =
+ (entry.overAllocated / this.overAllocated_ * 100).toFixed(3);
+ } else {
+ entry.overAllocatedPercent = 0;
+ }
+
+ if (entry instanceof GroupedEntry) entry.calculatePercentage();
+ }
+ }
+ }
+
+ Polymer({
+ is: 'tr-ui-e-v8-gc-objects-stats-table',
+
+ ready: function() {
+ this.isolateEntries_ = [];
+ },
+
+ constructTable_: function() {
+ this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ this.$.table.tableColumns = [
+ {
+ title: 'Component',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.title;
+ return typeEl;
+ },
+ showExpandButtons: true
+ },
+ {
+ title: 'Overall Memory (KB)',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = (row.overall / 1024).toFixed(3);
+ return typeEl;
+ },
+ cmp: function(a, b) {
+ return a.overall - b.overall;
+ }
+ },
+ {
+ title: 'Over Allocated Memory (KB)',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = (row.overAllocated / 1024).toFixed(3);
+ return typeEl;
+ },
+ cmp: function(a, b) {
+ return a.overAllocated - b.overAllocated;
+ }
+ },
+ {
+ title: 'Overall Count',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.count;
+ return typeEl;
+ },
+ cmp: function(a, b) {
+ return a.count - b.count;
+ }
+ },
+ {
+ title: 'Overall Memory Percent',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.overallPercent + '%';
+ return typeEl;
+ },
+ cmp: function(a, b) {
+ return a.overall - b.overall;
+ }
+ },
+ {
+ title: 'Overall Allocated Memory Percent',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.overAllocatedPercent + '%';
+ return typeEl;
+ },
+ cmp: function(a, b) {
+ return a.overAllocated - b.overAllocated;
+ }
+ }
+ ];
+
+ this.$.table.sortColumnIndex = 1;
+ this.$.table.sortDescending = true;
+ },
+
+ buildSubEntry_: function(objects, groupEntry, keyToName) {
+ var typeGroup = InstanceTypeGroups[groupEntry.title];
+ for (var instanceType of typeGroup) {
+ var e = objects[instanceType];
+ delete objects[instanceType];
+ if (e === undefined) continue;
+ var title = instanceType;
+ if (keyToName !== undefined) title = keyToName(title);
+ groupEntry.add(new Entry(title, e.count, e.overall, e.over_allocated,
+ e.histogram, e.over_allocated_histogram));
+ }
+ },
+
+ buildOthers_: function(objects, groupEntry) {
+ for (var title of Object.getOwnPropertyNames(objects)) {
+ if (title === 'END') continue;
+ var obj = objects[title];
+ groupEntry.add(new Entry(title, obj.count, obj.overall,
+ obj.over_allocated, obj.histogram,
+ obj.over_allocated_histogram))
+ }
+ },
+
+ build_: function(objects, objectEntry, bucketSize) {
+ var fixedArrayObject = objects['FIXED_ARRAY_TYPE'];
+ if (fixedArrayObject === undefined)
+ throw new Error('Fixed Array Object not found.');
+
+ var groupEntries = {
+ restEntry: new GroupedEntry('Rest', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ stringEntry: new GroupedEntry('Strings', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ jsEntry: new GroupedEntry('JS_OTHER', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ fixedArrayEntry: new GroupedEntry('FIXED_ARRAY_TYPE', 0, 0, 0,
+ new Array(bucketSize),
+ new Array(bucketSize)),
+ codeEntry: new GroupedEntry('CODE_TYPE', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ contextExtensionEntry: new GroupedEntry('CONTEXT_EXTENSION_TYPE', 0, 0,
+ 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ mapEntry: new GroupedEntry('MAP_TYPE', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize)),
+ byteArrayEntry: new GroupedEntry('BYTE_ARRAY_TYPE', 0, 0, 0,
+ new Array(bucketSize),
+ new Array(bucketSize)),
+ sharedFunctionInfoEntry: new GroupedEntry('SHARED_FUNCTION_INFO_TYPE',
+ 0, 0, 0,
+ new Array(bucketSize),
+ new Array(bucketSize)),
+ weakCellEntry: new GroupedEntry('WEAK_CELL_TYPE', 0, 0, 0,
+ new Array(bucketSize),
+ new Array(bucketSize)),
+ jsObjectEntry: new GroupedEntry('JS_OBJECT_TYPE', 0, 0, 0,
+ new Array(bucketSize),
+ new Array(bucketSize)),
+ jsContextExtensionObjectEntry: new GroupedEntry(
+ 'JS_CONTEXT_EXTENSION_OBJECT_TYPE', 0, 0, 0, new Array(bucketSize),
+ new Array(bucketSize))
+ };
+ for (var name of Object.getOwnPropertyNames(groupEntries)) {
+ var groupEntry = groupEntries[name];
+ var keyToName = undefined;
+ if (InstanceSubTypeNames[groupEntry.title] !== undefined) {
+ keyToName = InstanceSubTypeNames[groupEntry.title].keyToName;
+ }
+ this.buildSubEntry_(objects, groupEntry, keyToName);
+ if (name === 'fixedArrayEntry') {
+ groupEntry.setFromObject(fixedArrayObject);
+ groupEntry.accumulateUnknown('UNKNOWN');
+ }
+ objectEntry.add(groupEntry);
+ }
+ },
+
+ set selection(slices) {
+ slices.sortEvents(function(a, b) {
+ return b.start - a.start;
+ });
+ var previous = undefined;
+ for (let slice of slices) {
+ if (!slice instanceof tr.e.v8.V8GCStatsThreadSlice) continue;
+ var liveObjects = slice.liveObjects;
+ var deadObjects = slice.deadObjects;
+ var isolate = liveObjects.isolate;
+
+ var isolateEntry =
+ new GroupedEntry(
+ 'Isolate_' + isolate + ' at ' + slice.start.toFixed(3) + ' ms',
+ 0, 0, 0, [], []);
+ var liveEntry = new GroupedEntry('live objects', 0, 0, 0, [], []);
+ var deadEntry = new GroupedEntry('dead objects', 0, 0, 0, [], []);
+
+ var liveBucketSize = liveObjects.bucket_sizes.length;
+ var deadBucketSize = deadObjects.bucket_sizes.length;
+
+ this.build_(tr.b.deepCopy(liveObjects.type_data), liveEntry,
+ liveBucketSize);
+ isolateEntry.add(liveEntry);
+
+ this.build_(tr.b.deepCopy(deadObjects.type_data), deadEntry,
+ deadBucketSize);
+ isolateEntry.add(deadEntry);
+
+ isolateEntry.calculatePercentage();
+ this.isolateEntries_.push(isolateEntry);
+ }
+ this.updateTable_();
+ },
+
+ updateTable_: function() {
+ this.constructTable_();
+ this.$.table.tableRows = this.isolateEntries_;
+ this.$.table.rebuild();
+ },
+ });
+
+ return {};
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html
new file mode 100644
index 00000000000..02c5c0e27d6
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html">
+
+<dom-module id='tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view'>
+ <template>
+ <style>
+ </style>
+ <tr-ui-e-v8-gc-objects-stats-table id="gcObjectsStats">
+ </tr-ui-e-v8-gc-objects-stats-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ get selection() {
+ return this.$.content.selection;
+ },
+
+ set selection(selection) {
+ this.$.gcObjectsStats.selection = selection;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view',
+ tr.e.v8.V8GCStatsThreadSlice,
+ {
+ multi: true,
+ title: 'V8 GC Stats slices'
+ }
+);
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html
new file mode 100644
index 00000000000..a2dfecbfb04
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html">
+
+<dom-module id='tr-ui-e-multi-v8-thread-slice-sub-view'>
+ <template>
+ <tr-ui-a-multi-thread-slice-sub-view id="content"></tr-ui-a-multi-thread-slice-sub-view>
+ <tr-ui-e-v8-runtime-call-stats-table id="runtimeCallStats"></tr-ui-e-v8-runtime-call-stats-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-e-multi-v8-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ get selection() {
+ return this.$.content.selection;
+ },
+
+ set selection(selection) {
+ this.$.runtimeCallStats.slices = selection;
+ this.$.content.selection = selection;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-e-multi-v8-thread-slice-sub-view',
+ tr.e.v8.V8ThreadSlice,
+ {
+ multi: true,
+ title: 'V8 slices'
+ }
+);
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html
new file mode 100644
index 00000000000..7bf81d1d043
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html">
+<link rel="import" href="/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+
+ function createModel() {
+ var m = tr.c.TestUtils.newModel(function(m) {
+ m.p1 = m.getOrCreateProcess(1);
+ m.t2 = m.p1.getOrCreateThread(2);
+
+ m.s1 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 0,
+ end: 10,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ CompileFullCode: [3, 345],
+ LoadIC_Miss: [5, 567],
+ ParseLazy: [8, 890]
+ }}}));
+ m.s2 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 11,
+ end: 15,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ HandleApiCall: [1, 123],
+ OptimizeCode: [7, 789]
+ }}}));
+ });
+ return m;
+ }
+
+ test('selectMultiV8ThreadSlices', function() {
+ var m = createModel();
+
+ var viewEl =
+ document.createElement('tr-ui-e-multi-v8-thread-slice-sub-view');
+ var selection = new tr.model.EventSet();
+ selection.push(m.s1);
+ selection.push(m.s2);
+ viewEl.selection = selection;
+ this.addHTMLOutput(viewEl);
+ var rows = viewEl.$.runtimeCallStats.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 2714,
+ 567,
+ 789,
+ 345,
+ 890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 123
+ ]);
+ });
+
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html
new file mode 100644
index 00000000000..d09d0f1f754
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html
@@ -0,0 +1,230 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+
+<dom-module id='tr-ui-e-v8-runtime-call-stats-table'>
+ <template>
+ <style>
+ #table {
+ flex: 0 0 auto;
+ align-self: stretch;
+ margin-top: 1em;
+ font-size: 12px;
+ }
+ </style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</dom-module>
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.e.v8', function() {
+
+ function handleCodeSearch_(event) {
+ if (event.target.parentNode === undefined) return;
+ var name = event.target.parentNode.entryName;
+ var url = 'https://cs.chromium.org/search/?sq=package:chromium&type=cs&q=';
+ if (name.startsWith('API_')) name = name.substring(4);
+ url += encodeURIComponent(name) + '+file:src/v8/src';
+ window.open(url, '_blank');
+ }
+
+ var Entry = function(name, count, time) {
+ this.name_ = name;
+ this.count_ = count;
+ this.time_ = time;
+ };
+
+ Entry.prototype = {
+ __proto__: Object.prototype,
+
+ get name() {
+ return this.name_;
+ },
+
+ get count() {
+ return this.count_;
+ },
+
+ get time() {
+ return this.time_;
+ },
+
+ accumulate: function(count, time) {
+ this.count_ += count;
+ this.time_ += time;
+ },
+
+ reset: function() {
+ this.count_ = 0;
+ this.time_ = 0;
+ }
+ };
+
+ var GroupedEntry = function(name, matchRegex) {
+ Entry.call(this, name, 0, 0);
+ this.regex_ = matchRegex;
+ this.entries_ = new Map();
+ };
+
+ GroupedEntry.prototype = {
+ __proto__: Entry.prototype,
+
+ match: function(name) {
+ return this.regex_ && !(!name.match(this.regex_));
+ },
+
+ add: function(entry) {
+ var value = this.entries_.get(entry.name);
+ if (value !== undefined)
+ value.accumulate(entry.count, entry.time);
+ else
+ this.entries_.set(entry.name, entry);
+ this.count_ += entry.count;
+ this.time_ += entry.time;
+ },
+
+ get subRows() {
+ return Array.from(this.entries_.values());
+ },
+
+ reset: function(entry) {
+ this.time_ = 0;
+ this.count_ = 0;
+ this.entries_.clear();
+ }
+ };
+
+ Polymer({
+ is: 'tr-ui-e-v8-runtime-call-stats-table',
+
+ ready: function() {
+ this.table_ = this.$.table;
+ this.totalTime_ = 0;
+ },
+
+ constructTable_: function() {
+ var totalTime = this.totalTime_;
+ this.table_.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
+ this.table_.tableColumns = [
+ {
+ title: 'Name',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.name;
+ if (!(row instanceof GroupedEntry)) {
+ typeEl.title = 'click ? for code search';
+ typeEl.entryName = row.name;
+ var codeSearchEl = document.createElement('span');
+ codeSearchEl.innerText = '?';
+ codeSearchEl.style.float = 'right';
+ codeSearchEl.style.borderRadius = '5px';
+ codeSearchEl.style.backgroundColor = '#EEE';
+ codeSearchEl.addEventListener('click',
+ handleCodeSearch_.bind(this));
+ typeEl.appendChild(codeSearchEl);
+ }
+ return typeEl;
+ },
+ width: '200px',
+ showExpandButtons: true
+ },
+ {
+ title: 'Time',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = (row.time / 1000.0).toFixed(3) + ' ms';
+ return typeEl;
+ },
+ width: '100px',
+ cmp: function(a, b) {
+ return a.time - b.time;
+ }
+ },
+ {
+ title: 'Count',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = row.count;
+ return typeEl;
+ },
+ width: '100px',
+ cmp: function(a, b) {
+ return a.count - b.count;
+ }
+ },
+ {
+ title: 'Percent',
+ value: function(row) {
+ var typeEl = document.createElement('span');
+ typeEl.innerText = (row.time / totalTime * 100).toFixed(3) + '%';
+ return typeEl;
+ },
+ width: '100px',
+ cmp: function(a, b) {
+ return a.time - b.time;
+ }
+ }
+ ];
+
+ this.table_.sortColumnIndex = 1;
+ this.table_.sortDescending = true;
+ },
+
+ set slices(slices) {
+ var groups = new Array(
+ new GroupedEntry('Total'),
+ new GroupedEntry('IC', /.*IC.*/),
+ new GroupedEntry('Optimize',
+ /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/),
+ new GroupedEntry('Compile', /.*Compile.*/),
+ new GroupedEntry('Parse', /.*Parse.*/),
+ new GroupedEntry('Callback', /.*Callback$/),
+ new GroupedEntry('API', /.*API.*/),
+ new GroupedEntry('GC', /GC|AllocateInTargetSpace/),
+ new GroupedEntry('JavaScript', /JS_Execution/),
+ new GroupedEntry('Runtime', /.*/)
+ );
+
+ slices.forEach(function(slice) {
+ if (!(slice instanceof tr.e.v8.V8ThreadSlice)) return;
+ try {
+ var runtimeCallStats = JSON.parse(slice.runtimeCallStats);
+ } catch (e) {
+ var runtimeCallStats = slice.runtimeCallStats;
+ }
+ if (runtimeCallStats !== undefined) {
+ Object.getOwnPropertyNames(runtimeCallStats).forEach(
+ function(runtimeCallStatName) {
+ for (var i = 1; i < groups.length; ++i) {
+ if (groups[i].match(runtimeCallStatName)) {
+ var runtimeCallStat = runtimeCallStats[runtimeCallStatName];
+ if (runtimeCallStat.length !== 2) break;
+ var entry = new Entry(runtimeCallStatName, runtimeCallStat[0],
+ runtimeCallStat[1]);
+ groups[0].accumulate(runtimeCallStat[0], runtimeCallStat[1]);
+ groups[i].add(entry);
+ break;
+ }
+ }
+ }, this);
+ }
+ }, this);
+ this.totalTime_ = groups[0].time;
+ if (this.totalTime_ > 0) {
+ this.constructTable_();
+ this.table_.tableRows = groups;
+ this.table_.rebuild();
+ }
+ }
+ });
+
+ return {};
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html
new file mode 100644
index 00000000000..71696479d72
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html">
+<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var apiObjectGet = [1, 123];
+ var functionCallback = [2, 234];
+ var compileFullCode = [3, 345];
+ var allocateInTargetSpace = [4, 456];
+ var loadIcMiss = [5, 567];
+ var jsExecution = [6, 678];
+ var optimizeCode = [7, 789];
+ var parseLazy = [8, 890];
+ var handleApiCall = [9, 901];
+
+ function createModel() {
+ var m = tr.c.TestUtils.newModel(function(m) {
+ m.p1 = m.getOrCreateProcess(1);
+ m.t2 = m.p1.getOrCreateThread(2);
+
+ m.s1 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 0,
+ end: 10,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ JS_Execution: jsExecution,
+ HandleApiCall: handleApiCall,
+ CompileFullCode: compileFullCode,
+ LoadIC_Miss: loadIcMiss,
+ ParseLazy: parseLazy,
+ OptimizeCode: optimizeCode,
+ FunctionCallback: functionCallback,
+ AllocateInTargetSpace: allocateInTargetSpace,
+ API_Object_Get: apiObjectGet
+ }}}));
+ m.s2 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 11,
+ end: 15,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ JS_Execution: jsExecution,
+ HandleApiCall: handleApiCall,
+ CompileFullCode: compileFullCode,
+ LoadIC_Miss: loadIcMiss,
+ ParseLazy: parseLazy,
+ OptimizeCode: optimizeCode,
+ FunctionCallback: functionCallback,
+ AllocateInTargetSpace: allocateInTargetSpace,
+ API_Object_Get: apiObjectGet
+ }}}));
+ m.s3 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 11,
+ end: 15,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ LoadIC_LoadCallback: [1, 111],
+ StoreIC_StoreCallback: [2, 222],
+ }}}));
+ });
+ return m;
+ }
+
+ test('SingleSliceSelection', function() {
+ var m = createModel();
+
+ var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table');
+ viewEl.slices = [m.s1];
+ this.addHTMLOutput(viewEl);
+ tr.b.forceAllPendingTasksToRunForTest();
+ var rows = viewEl.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 4983,
+ loadIcMiss[1],
+ optimizeCode[1],
+ compileFullCode[1],
+ parseLazy[1],
+ functionCallback[1],
+ apiObjectGet[1],
+ allocateInTargetSpace[1],
+ jsExecution[1],
+ handleApiCall[1]
+ ]);
+ });
+
+ test('MultiSliceSelection', function() {
+ var m = createModel();
+
+ var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table');
+ viewEl.slices = [m.s1, m.s2];
+ this.addHTMLOutput(viewEl);
+ tr.b.forceAllPendingTasksToRunForTest();
+ var rows = viewEl.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 9966,
+ loadIcMiss[1] * 2,
+ optimizeCode[1] * 2,
+ compileFullCode[1] * 2,
+ parseLazy[1] * 2,
+ functionCallback[1] * 2,
+ apiObjectGet[1] * 2,
+ allocateInTargetSpace[1] * 2,
+ jsExecution[1] * 2,
+ handleApiCall[1] * 2
+ ]);
+
+ assert.deepEqual(rows.map(r => r.entries_.size), [
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]);
+ });
+
+ test('groupCorrectly', function() {
+ var m = createModel();
+
+ var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table');
+ viewEl.slices = [m.s3];
+ this.addHTMLOutput(viewEl);
+ tr.b.forceAllPendingTasksToRunForTest();
+ var rows = viewEl.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 333,
+ 333,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ]);
+
+ assert.deepEqual(rows.map(r => r.entries_.size), [
+ 0,
+ 2,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ]);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html
new file mode 100644
index 00000000000..6926ffa2e72
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html">
+
+<dom-module id='tr-ui-e-single-v8-gc-stats-thread-slice-sub-view'>
+ <template>
+ <tr-ui-a-single-event-sub-view id="content"></tr-ui-a-single-event-sub-view>
+ <tr-ui-e-v8-gc-objects-stats-table id="gcObjectsStats"></tr-ui-e-v8-gc-objects-stats-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-e-single-v8-gc-stats-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ get selection() {
+ return this.$.content.selection;
+ },
+
+ set selection(selection) {
+ this.$.content.selection = selection;
+ this.$.gcObjectsStats.selection = selection;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-e-single-v8-gc-stats-thread-slice-sub-view',
+ tr.e.v8.V8GCStatsThreadSlice,
+ {
+ multi: false,
+ title: 'V8 GC stats slice'
+ }
+);
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html
new file mode 100644
index 00000000000..8162d201fbe
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html">
+
+<dom-module id='tr-ui-e-single-v8-thread-slice-sub-view'>
+ <template>
+ <tr-ui-a-single-thread-slice-sub-view id="content"></tr-ui-a-single-thread-slice-sub-view>
+ <tr-ui-e-v8-runtime-call-stats-table id="runtimeCallStats"></tr-ui-e-v8-runtime-call-stats-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-e-single-v8-thread-slice-sub-view',
+ behaviors: [tr.ui.analysis.AnalysisSubView],
+
+ get selection() {
+ return this.$.content.selection;
+ },
+
+ set selection(selection) {
+ this.$.runtimeCallStats.slices = selection;
+ this.$.content.selection = selection;
+ }
+});
+
+tr.ui.analysis.AnalysisSubView.register(
+ 'tr-ui-e-single-v8-thread-slice-sub-view',
+ tr.e.v8.V8ThreadSlice,
+ {
+ multi: false,
+ title: 'V8 slice'
+ }
+);
+
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html
new file mode 100644
index 00000000000..a23d18a1682
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html">
+<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+
+ function createModel() {
+ var m = tr.c.TestUtils.newModel(function(m) {
+ m.p1 = m.getOrCreateProcess(1);
+ m.t2 = m.p1.getOrCreateThread(2);
+
+ m.s1 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 0,
+ end: 10,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ CompileFullCode: [3, 345],
+ LoadIC_Miss: [5, 567],
+ ParseLazy: [8, 890]
+ }}}));
+ m.s2 = m.t2.sliceGroup.pushSlice(
+ newSliceEx(
+ {title: 'V8.Execute',
+ start: 11,
+ end: 15,
+ type: tr.e.v8.V8ThreadSlice,
+ cat: 'v8',
+ args: {'runtime-call-stats':
+ {
+ HandleApiCall: [1, 123],
+ OptimizeCode: [7, 789]
+ }}}));
+ });
+ return m;
+ }
+
+ test('selectV8ThreadSlice', function() {
+ var m = createModel();
+
+ var viewEl =
+ document.createElement('tr-ui-e-single-v8-thread-slice-sub-view');
+ var selection1 = new tr.model.EventSet();
+ selection1.push(m.s1);
+ viewEl.selection = selection1;
+ this.addHTMLOutput(viewEl);
+ var rows = viewEl.$.runtimeCallStats.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 1802,
+ 567,
+ 0,
+ 345,
+ 890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ]);
+
+ var selection2 = new tr.model.EventSet();
+ selection2.push(m.s2);
+ viewEl.selection = selection2;
+ rows = viewEl.$.runtimeCallStats.$.table.tableRows;
+ assert.lengthOf(rows, 10);
+ assert.deepEqual(rows.map(r => r.time), [
+ 912,
+ 0,
+ 789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 123
+ ]);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html
new file mode 100644
index 00000000000..ac9794d1de7
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2013 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+
+<link rel="import" href="/tracing/extras/v8_config.html">
+<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html">
+<link rel="import" href="/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html">
+<link rel="import" href="/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html">
+<link rel="import" href="/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html">
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_control.html b/chromium/third_party/catapult/tracing/tracing/ui/find_control.html
index 6f2c636b281..0660438b199 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/find_control.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/find_control.html
@@ -9,7 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/find_controller.html">
<link rel="import" href="/tracing/ui/timeline_track_view.html">
-<polymer-element name="tr-ui-find-control">
+<dom-module id='tr-ui-find-control'>
<template>
<style>
:host {
@@ -64,110 +64,111 @@ found in the LICENSE file.
</style>
<input type='text' id='filter'
- on-input="{{ filterTextChanged }}"
- on-keydown="{{ filterKeyDown }}"
- on-blur="{{ filterBlur }}"
- on-focus="{{ filterFocus }}"
- on-mouseup="{{ filterMouseUp }}" />
+ on-input="filterTextChanged"
+ on-keydown="filterKeyDown"
+ on-blur="filterBlur"
+ on-focus="filterFocus"
+ on-mouseup="filterMouseUp" />
<div id="spinner"></div>
- <tr-ui-b-toolbar-button on-click="{{ findPrevious }}">
+ <tr-ui-b-toolbar-button on-click="findPrevious">
&larr;
</tr-ui-b-toolbar-button>
- <tr-ui-b-toolbar-button on-click="{{ findNext }}">
+ <tr-ui-b-toolbar-button on-click="findNext">
&rarr;
</tr-ui-b-toolbar-button>
<div id="hitCount">0 of 0</div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- filterKeyDown: function(e) {
- if (e.keyCode === 27) {
- var hkc = tr.b.getHotkeyControllerForElement(this);
- if (hkc) {
- hkc.childRequestsBlur(this);
- } else {
- this.blur();
- }
- e.preventDefault();
- e.stopPropagation();
- return;
- } else if (e.keyCode === 13) {
- if (e.shiftKey)
- this.findPrevious();
- else
- this.findNext();
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-find-control',
+
+ filterKeyDown: function(e) {
+ if (e.keyCode === 27) {
+ var hkc = tr.b.getHotkeyControllerForElement(this);
+ if (hkc) {
+ hkc.childRequestsBlur(this);
+ } else {
+ this.blur();
}
- },
-
- filterBlur: function(e) {
- this.updateHitCountEl();
- },
-
- filterFocus: function(e) {
- this.$.filter.select();
- },
-
- // Prevent that the input text is deselected after focusing the find
- // control with the mouse.
- filterMouseUp: function(e) {
e.preventDefault();
- },
-
- get controller() {
- return this.controller_;
- },
-
- set controller(c) {
- this.controller_ = c;
- this.updateHitCountEl();
- },
-
- focus: function() {
- this.$.filter.focus();
- },
-
- get hasFocus() {
- return this === document.activeElement;
- },
-
- filterTextChanged: function() {
- this.$.hitCount.textContent = '';
- this.$.spinner.style.visibility = 'visible';
- this.controller.startFiltering(this.$.filter.value).then(function() {
- this.$.spinner.style.visibility = 'hidden';
- this.updateHitCountEl();
- }.bind(this));
- },
-
- findNext: function() {
- if (this.controller)
- this.controller.findNext();
- this.updateHitCountEl();
- },
-
- findPrevious: function() {
- if (this.controller)
- this.controller.findPrevious();
+ e.stopPropagation();
+ return;
+ } else if (e.keyCode === 13) {
+ if (e.shiftKey)
+ this.findPrevious();
+ else
+ this.findNext();
+ }
+ },
+
+ filterBlur: function(e) {
+ this.updateHitCountEl();
+ },
+
+ filterFocus: function(e) {
+ this.$.filter.select();
+ },
+
+ // Prevent that the input text is deselected after focusing the find
+ // control with the mouse.
+ filterMouseUp: function(e) {
+ e.preventDefault();
+ },
+
+ get controller() {
+ return this.controller_;
+ },
+
+ set controller(c) {
+ this.controller_ = c;
+ this.updateHitCountEl();
+ },
+
+ focus: function() {
+ this.$.filter.focus();
+ },
+
+ get hasFocus() {
+ return this === document.activeElement;
+ },
+
+ filterTextChanged: function() {
+ Polymer.dom(this.$.hitCount).textContent = '';
+ this.$.spinner.style.visibility = 'visible';
+ this.controller.startFiltering(this.$.filter.value).then(function() {
+ this.$.spinner.style.visibility = 'hidden';
this.updateHitCountEl();
- },
-
- updateHitCountEl: function() {
- if (!this.controller || this.$.filter.value.length === 0) {
- this.$.hitCount.textContent = '';
- return;
- }
+ }.bind(this));
+ },
+
+ findNext: function() {
+ if (this.controller)
+ this.controller.findNext();
+ this.updateHitCountEl();
+ },
+
+ findPrevious: function() {
+ if (this.controller)
+ this.controller.findPrevious();
+ this.updateHitCountEl();
+ },
+
+ updateHitCountEl: function() {
+ if (!this.controller || this.$.filter.value.length === 0) {
+ Polymer.dom(this.$.hitCount).textContent = '';
+ return;
+ }
- var n = this.controller.filterHits.length;
- var i = n === 0 ? -1 : this.controller.currentHitIndex;
- this.$.hitCount.textContent = (i + 1) + ' of ' + n;
- },
+ var n = this.controller.filterHits.length;
+ var i = n === 0 ? -1 : this.controller.currentHitIndex;
+ Polymer.dom(this.$.hitCount).textContent = (i + 1) + ' of ' + n;
+ },
- setText: function(string) {
- this.$.filter.value = string;
- }
- });
- </script>
-</polymer-element>
+ setText: function(string) {
+ this.$.filter.value = string;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html
index 4247676856b..223b9621d1a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html
@@ -82,7 +82,7 @@ tr.exportTo('tr.ui', function() {
} catch (e) {
this.enqueueOperation_(function() {
var overlay = new tr.ui.b.Overlay();
- overlay.textContent = e.message;
+ Polymer.dom(overlay).textContent = e.message;
overlay.title = 'UI State Navigation Error';
overlay.visible = true;
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html
index f6509f88cbc..fed4812a985 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html
@@ -221,7 +221,7 @@ tr.b.unittest.testSuite(function() {
container.id = 'track_view_container';
var timeline = document.createElement('tr-ui-timeline-view');
- timeline.appendChild(container);
+ Polymer.dom(timeline).appendChild(container);
// This is for testing only, have to make sure things link up right.
timeline.trackViewContainer_ = container;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html b/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html
index 5164a80d7bb..72c30ca4579 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html
@@ -4,43 +4,44 @@ Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/perf_insights/mre/mre_result.html">
<link rel="import" href="/tracing/extras/full_config.html">
<link rel="import" href="/tracing/importer/import.html">
<link rel="import" href="/tracing/metrics/all_metrics.html">
<link rel="import" href="/tracing/metrics/metric_map_function.html">
<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/file.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name="tracing-ui-metrics-debugger-app">
- <template>
- <style>
- pre {
- overflow: auto;
- }
- #bar {
- display: flex;
- flex-direction: row;
- padding: 1px 6px;
- }
- </style>
+<dom-module id='tracing-ui-metrics-debugger-app'>
+ <style>
+ pre {
+ overflow: auto;
+ }
+ #bar {
+ display: flex;
+ flex-direction: row;
+ padding: 1px 6px;
+ }
+ </style>
- <top-left-controls id="top_left_controls"></top-left-controls>
- <input id="load_trace" type="file"/>
- <button id="run_metric">Run metric</button>
- <div id="trace_info"></div>
- <pre id="map_results">
- </pre>
+ <template>
+ <top-left-controls id="top_left_controls"></top-left-controls>
+ <input id="load_trace" type="file"/>
+ <button id="run_metric">Run metric</button>
+ <div id="trace_info"></div>
+ <pre id="map_results">
+ </pre>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui', function() {
- Polymer('tracing-ui-metrics-debugger-app', {
+ Polymer({
+ is: 'tracing-ui-metrics-debugger-app',
created: function() {
this.metrics_ = [];
tr.metrics.MetricRegistry.getAllRegisteredTypeInfos().forEach(
@@ -62,7 +63,8 @@ tr.exportTo('tr.ui', function() {
this.settingsKey_,
this.metrics_[0].value,
this.metrics_);
- this.$.top_left_controls.appendChild(metricSelector);
+ Polymer.dom(this.$.top_left_controls).appendChild(
+ metricSelector);
this.$.load_trace.addEventListener('change', function(event) {
var file = event.target.files[0];
@@ -80,13 +82,14 @@ tr.exportTo('tr.ui', function() {
tr.ui.b.Overlay.showError('You must load a trace first!');
return;
}
- var result = new pi.mre.MreResult();
+ var result = new tr.mre.MreResult();
var model = this.activeTrace_.model;
- var options = {metric: this.currentMetricName_};
+ var options = {metrics: [this.currentMetricName_]};
try {
tr.metrics.metricMapFunction(result, model, options);
- this.$.map_results.textContent = 'Metric result:\n' +
- JSON.stringify(result.asDict(), undefined, 2);
+ this.set(
+ '$.map_results.textContent',
+ 'Metric result:\n' + JSON.stringify(result.asDict(), undefined, 2));
} catch (err) {
tr.ui.b.Overlay.showError('Error running metric:\n' + err.stack);
console.error(err);
@@ -117,8 +120,8 @@ tr.exportTo('tr.ui', function() {
filename: filename,
model: model,
};
- this.$.trace_info.textContent = 'Trace file ' + filename +
- ' is loaded.';
+ Polymer.dom(this.$.trace_info).textContent = 'Trace file ' +
+ filename + ' is loaded.';
}.bind(this),
function(err) {
tr.ui.b.Overlay.showError('Trace import error: ' + err);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html b/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html
index 208cc35577e..22d8bd183ac 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html
@@ -7,8 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/extras/tquery/tquery.html">
-<polymer-element
- name="tr-ui-scripting-control">
+<dom-module id='tr-ui-scripting-control'>
<template>
<style>
:host {
@@ -64,125 +63,130 @@ found in the LICENSE file.
</style>
<div id="root" class="root hidden" tabindex="0"
- on-focus="{{ onConsoleFocus }}">
+ on-focus="onConsoleFocus">
<div id='history'></div>
<div id='prompt'
- on-keypress="{{ promptKeyPress }}"
- on-keydown="{{ promptKeyDown }}"
- on-blur="{{ onConsoleBlur }}"></div>
+ on-keypress="promptKeyPress"
+ on-keydown="promptKeyDown"
+ on-blur="onConsoleBlur"></div>
</div>
</template>
-
- <script>
- 'use strict';
-
- Polymer({
- _isEnterKey: function(event) {
- // Check if in IME.
- return event.keyCode !== 229 && event.keyIdentifier === 'Enter';
- },
-
- _setFocused: function(focused) {
- var promptEl = this.$.prompt;
- if (focused) {
- promptEl.focus();
- this.$.root.classList.add('focused');
- // Move cursor to the end of any existing text.
- if (promptEl.innerText.length > 0) {
- var sel = window.getSelection();
- sel.collapse(promptEl.firstChild, promptEl.innerText.length);
- }
- } else {
- promptEl.blur();
- this.$.root.classList.remove('focused');
- // Workaround for crbug.com/89026 to ensure the prompt doesn't retain
- // keyboard focus.
- var parent = promptEl.parentElement;
- var nextEl = promptEl.nextSibling;
- promptEl.remove();
- parent.insertBefore(promptEl, nextEl);
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-scripting-control',
+
+ _isEnterKey: function(event) {
+ // Check if in IME.
+ // Remove keyIdentifier after reference build rolls past M51 when
+ // KeyboardEvent.key was added.
+ return event.keyCode !== 229 &&
+ (event.key === 'Enter' || event.keyIdentifier === 'Enter');
+ },
+
+ _setFocused: function(focused) {
+ var promptEl = this.$.prompt;
+ if (focused) {
+ promptEl.focus();
+ Polymer.dom(this.$.root).classList.add('focused');
+ // Move cursor to the end of any existing text.
+ if (promptEl.innerText.length > 0) {
+ var sel = window.getSelection();
+ sel.collapse(
+ Polymer.dom(promptEl).firstChild, promptEl.innerText.length);
}
- },
+ } else {
+ promptEl.blur();
+ Polymer.dom(this.$.root).classList.remove('focused');
+ // Workaround for crbug.com/89026 to ensure the prompt doesn't retain
+ // keyboard focus.
+ var parent = promptEl.parentElement;
+ var nextEl = Polymer.dom(promptEl).nextSibling;
+ promptEl.remove();
+ Polymer.dom(parent).insertBefore(promptEl, nextEl);
+ }
+ },
+
+ onConsoleFocus: function(e) {
+ e.stopPropagation();
+ this._setFocused(true);
+ },
+
+ onConsoleBlur: function(e) {
+ e.stopPropagation();
+ this._setFocused(false);
+ },
+
+ promptKeyDown: function(e) {
+ e.stopPropagation();
+ if (!this._isEnterKey(e))
+ return;
+ e.preventDefault();
+ var promptEl = this.$.prompt;
+ var command = promptEl.innerText;
+ if (command.length === 0)
+ return;
+ promptEl.innerText = '';
+ this.addLine_(String.fromCharCode(187) + ' ' + command);
+
+ try {
+ var result = this.controller_.executeCommand(command);
+ } catch (e) {
+ result = e.stack || e.stackTrace;
+ }
- onConsoleFocus: function(e) {
- e.stopPropagation();
+ if (result instanceof tr.e.tquery.TQuery) {
+ // TODO(skyostil): Show a cool spinner.
+ result.ready().then(function(selection) {
+ this.addLine_(selection.length + ' matches');
+ this.controller_.brushingStateController.
+ showScriptControlSelection(selection);
+ }.bind(this));
+ } else {
+ this.addLine_(result);
+ }
+ promptEl.scrollIntoView();
+ },
+
+ addLine_: function(line) {
+ var historyEl = this.$.history;
+ if (historyEl.innerText.length !== 0)
+ historyEl.innerText += '\n';
+ historyEl.innerText += line;
+ },
+
+ promptKeyPress: function(e) {
+ e.stopPropagation();
+ },
+
+ toggleVisibility: function() {
+ var root = this.$.root;
+ if (!this.visible) {
+ Polymer.dom(root).classList.remove('hidden');
this._setFocused(true);
- },
-
- onConsoleBlur: function(e) {
- e.stopPropagation();
+ } else {
+ Polymer.dom(root).classList.add('hidden');
this._setFocused(false);
- },
-
- promptKeyDown: function(e) {
- e.stopPropagation();
- if (!this._isEnterKey(e))
- return;
- e.preventDefault();
- var promptEl = this.$.prompt;
- var command = promptEl.innerText;
- if (command.length === 0)
- return;
- promptEl.innerText = '';
- this.addLine_(String.fromCharCode(187) + ' ' + command);
-
- try {
- var result = this.controller_.executeCommand(command);
- } catch (e) {
- result = e.stack || e.stackTrace;
- }
-
- if (result instanceof tr.e.tquery.TQuery) {
- // TODO(skyostil): Show a cool spinner.
- result.ready().then(function(selection) {
- this.addLine_(selection.length + ' matches');
- this.controller_.brushingStateController.
- showScriptControlSelection(selection);
- }.bind(this));
- } else {
- this.addLine_(result);
- }
- promptEl.scrollIntoView();
- },
-
- addLine_: function(line) {
- var historyEl = this.$.history;
- if (historyEl.innerText.length !== 0)
- historyEl.innerText += '\n';
- historyEl.innerText += line;
- },
-
- promptKeyPress: function(e) {
- e.stopPropagation();
- },
-
- toggleVisibility: function() {
- var root = this.$.root;
- if (!this.visible) {
- root.classList.remove('hidden');
- this._setFocused(true);
- } else {
- root.classList.add('hidden');
- this._setFocused(false);
- }
- },
-
- get hasFocus() {
- return this === document.activeElement;
- },
-
- get visible() {
- var root = this.$.root;
- return !root.classList.contains('hidden');
- },
-
- get controller() {
- return this.controller_;
- },
-
- set controller(c) {
- this.controller_ = c;
}
- });
- </script>
-</polymer-element>
+ },
+
+ get hasFocus() {
+ return this === document.activeElement;
+ },
+
+ get visible() {
+ var root = this.$.root;
+ return !Polymer.dom(root).classList.contains('hidden');
+ },
+
+ get controller() {
+ return this.controller_;
+ },
+
+ set controller(c) {
+ this.controller_ = c;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html
index 6e96d27da06..a2e80c29966 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html
@@ -6,16 +6,16 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/base/grouping_table.html">
<link rel="import" href="/tracing/ui/base/grouping_table_groupby_picker.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
<link rel="import" href="/tracing/value/numeric.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<polymer-element name='tr-ui-sp-file-size-stats-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id='tr-ui-sp-file-size-stats-side-panel'>
<template>
<style>
:host {
@@ -49,13 +49,16 @@ found in the LICENSE file.
<tr-ui-b-grouping-table id="table"></tr-ui-b-grouping-table>
</table-container>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
(function() {
- Polymer('tr-ui-sp-file-size-stats-side-panel', {
+ Polymer({
+ is: 'tr-ui-sp-file-size-stats-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
ready: function() {
this.model_ = undefined;
this.selection_ = new tr.model.EventSet();
@@ -133,7 +136,7 @@ found in the LICENSE file.
title: 'Title',
value: function(row) {
var titleEl = document.createElement('span');
- titleEl.textContent = row.title;
+ Polymer.dom(titleEl).textContent = row.title;
titleEl.style.textOverflow = 'ellipsis';
return titleEl;
},
@@ -160,7 +163,7 @@ found in the LICENSE file.
title: 'Bytes',
align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT,
value: function(row) {
- var value = new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes,
+ var value = new tr.v.ScalarNumeric(tr.b.Unit.byName.sizeInBytes,
row.rowStats.totalEventSizeinBytes);
var spanEl = tr.v.ui.createScalarSpan(value);
return spanEl;
@@ -208,5 +211,9 @@ found in the LICENSE file.
this.$.table.rebuild();
}
});
+
+ tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-sp-file-size-stats-side-panel');
+ });
})();
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html
index 724ca970eac..94990b467f2 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html
@@ -6,33 +6,46 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/metrics/metric_map_function.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/mre/mre_result.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
-<link rel="import" href="/tracing/value/ui/value_set_table.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
<link rel="import" href="/tracing/value/ui/value_set_view.html">
<link rel="import" href="/tracing/value/value_set.html">
-<polymer-element name='tr-ui-sp-metrics-side-panel'
- extends='tr-ui-side-panel'>
+<dom-module id="tr-ui-sp-metrics-side-panel">
<template>
<style>
:host {
display: flex;
flex-direction: column;
}
+ div#error {
+ color: red;
+ }
+ #results {
+ font-size: 12px;
+ }
</style>
<top-left-controls id="top_left_controls"></top-left-controls>
+
<tr-v-ui-value-set-view id="results"></tr-v-ui-value-set-view>
+
+ <div id="error"></div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui', function() {
- Polymer('tr-ui-sp-metrics-side-panel', {
+ Polymer({
+ is: 'tr-ui-sp-metrics-side-panel',
+ behaviors: [tr.ui.behaviors.SidePanel],
+
ready: function() {
this.model_ = undefined;
@@ -57,7 +70,7 @@ tr.exportTo('tr.ui', function() {
this.settingsKey_,
this.currentMetricName_,
this.metrics_);
- this.$.top_left_controls.appendChild(metricSelector);
+ Polymer.dom(this.$.top_left_controls).appendChild(metricSelector);
metricSelector.addEventListener('change',
this.onMetricChange_.bind(this));
this.currentMetricTypeInfo_ =
@@ -66,7 +79,7 @@ tr.exportTo('tr.ui', function() {
this.recomputeButton_ = tr.ui.b.createButton(
'Recompute', this.onRecompute_, this);
- this.$.top_left_controls.appendChild(this.recomputeButton_);
+ Polymer.dom(this.$.top_left_controls).appendChild(this.recomputeButton_);
},
/**
@@ -155,24 +168,15 @@ tr.exportTo('tr.ui', function() {
},
updateContents_: function() {
- this.style.width = '';
- tr.b.requestAnimationFrame(function() {
- var width = this.$.results.getBoundingClientRect().width + 15;
- this.style.width = width + 'px';
- }, this);
+ Polymer.dom(this.$.error).textContent = '';
+ this.$.results.style.display = 'none';
if (!this.model_) {
- this.$.results.values = new tr.v.ValueSet([
- new tr.v.FailureValue('missing', {
- description: 'Missing model',
- stack: ''
- })
- ]);
+ Polymer.dom(this.$.error).textContent = 'Missing model';
return;
}
- var values = new tr.v.ValueSet();
- var options = {};
+ var options = {metrics: [this.currentMetricName_]};
if (this.currentMetricTypeInfo_ &&
this.currentMetricTypeInfo_.metadata.supportsRangeOfInterest &&
@@ -182,15 +186,13 @@ tr.exportTo('tr.ui', function() {
var startDate = new Date();
try {
- this.currentMetricTypeInfo_.constructor(values, this.model_, options);
+ var values = tr.metrics.runMetrics(this.model_, options);
} catch (err) {
- console.error(err.stack);
- this.$.results.values = new tr.v.ValueSet([
- new tr.v.FailureValue('error', {
- description: err.message,
- stack: err.stack
- })
- ]);
+ console.warn(
+ this.currentMetricName_ +
+ ' could not be computed for the current model:\n' +
+ err.stack);
+ Polymer.dom(this.$.error).textContent = err.message;
return;
}
@@ -199,10 +201,16 @@ tr.exportTo('tr.ui', function() {
this.metricLatenciesMs_.shift();
this.recomputeButton_.style.background = '';
+
+ this.$.results.style.display = '';
this.$.results.values = values;
}
});
+ tr.ui.side_panel.SidePanelRegistry.register(function() {
+ return document.createElement('tr-ui-sp-metrics-side-panel');
+ });
+
return {};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html
index 1fc54ed4f0e..fd39923d190 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html
@@ -1,25 +1,18 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
+Copyright 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/base/ui.html">
-<polymer-element name='tr-ui-side-panel'>
- <template>
- <style>
- :host {
- overflow: auto;
- }
- </style>
- </template>
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- },
+<script>
+'use strict';
+
+tr.exportTo('tr.ui.behaviors', function() {
+
+ var SidePanel = {
get rangeOfInterest() {
throw new Error('Not implemented');
@@ -48,6 +41,11 @@ found in the LICENSE file.
supportsModel: function(m) {
throw new Error('Not implemented');
}
- });
- </script>
-</polymer-element>
+ };
+
+ return {
+ SidePanel: SidePanel
+ };
+
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html
index 0f3b5219ef6..2f2067f2e84 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html
@@ -6,10 +6,10 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/range.html">
-<link rel='import' href='/tracing/ui/base/polymer_utils.html'>
<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
-<polymer-element name='tr-ui-side-panel-container' is='HTMLUnknownElement'>
+<dom-module id='tr-ui-side-panel-container'>
<template>
<style>
:host {
@@ -18,12 +18,14 @@ found in the LICENSE file.
background-color: white;
}
+ :host([expanded]) > #side_panel_drag_handle,
:host([expanded]) > active-panel-container {
-webkit-flex: 1 1 auto;
border-left: 1px solid black;
display: -webkit-flex;
}
+ :host(:not([expanded])) > #side_panel_drag_handle,
:host(:not([expanded])) > active-panel-container {
display: none;
}
@@ -64,189 +66,192 @@ found in the LICENSE file.
border-left: none;
padding: 14px 2px 14px 1px;
}
+
+ #active_panel_container {
+ overflow: auto;
+ }
</style>
+ <tr-ui-b-drag-handle id="side_panel_drag_handle"></tr-ui-b-drag-handle>
<active-panel-container id='active_panel_container'>
- <tr-ui-b-drag-handle id="side_panel_drag_handle"></tr-ui-b-drag-handle>
</active-panel-container>
<tab-strip id='tab_strip'></tab-strip>
</template>
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-ui-side-panel-container',
+
+ ready: function() {
+ this.activePanelContainer_ = this.$.active_panel_container;
+ this.tabStrip_ = this.$.tab_strip;
+
+ this.dragHandle_ = this.$.side_panel_drag_handle;
+ this.dragHandle_.horizontal = false;
+ this.dragHandle_.target = this.activePanelContainer_;
+ this.rangeOfInterest_ = new tr.b.Range();
+ this.brushingStateController_ = undefined;
+ this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
+ this.onModelChanged_ = this.onModelChanged_.bind(this);
+ },
+
+ get brushingStateController() {
+ return this.brushingStateController_;
+ },
+
+ set brushingStateController(brushingStateController) {
+ if (this.brushingStateController) {
+ this.brushingStateController_.removeEventListener(
+ 'change', this.onSelectionChanged_);
+ this.brushingStateController_.removeEventListener(
+ 'model-changed', this.onModelChanged_);
+ }
+ this.brushingStateController_ = brushingStateController;
+ if (this.brushingStateController) {
+ this.brushingStateController_.addEventListener(
+ 'change', this.onSelectionChanged_);
+ this.brushingStateController_.addEventListener(
+ 'model-changed', this.onModelChanged_);
+ }
+ },
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- this.activePanelContainer_ = this.$.active_panel_container;
- this.tabStrip_ = this.$.tab_strip;
-
- this.dragHandle_ = this.$.side_panel_drag_handle;
- this.dragHandle_.horizontal = false;
- this.rangeOfInterest_ = new tr.b.Range();
- this.brushingStateController_ = undefined;
- this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
- this.onModelChanged_ = this.onModelChanged_.bind(this);
- },
-
- get brushingStateController() {
- return this.brushingStateController_;
- },
-
- set brushingStateController(brushingStateController) {
- if (this.brushingStateController) {
- this.brushingStateController_.removeEventListener(
- 'change', this.onSelectionChanged_);
- this.brushingStateController_.removeEventListener(
- 'model-changed', this.onModelChanged_);
- }
- this.brushingStateController_ = brushingStateController;
- if (this.brushingStateController) {
- this.brushingStateController_.addEventListener(
- 'change', this.onSelectionChanged_);
- this.brushingStateController_.addEventListener(
- 'model-changed', this.onModelChanged_);
- }
- },
-
- get selection() {
- return this.brushingStateController_.selection;
- },
+ onSelectionChanged_: function() {
+ if (this.activePanel)
+ this.activePanel.selection = this.selection;
+ },
- onSelectionChanged_: function() {
- if (this.activePanel)
- this.activePanel.selection = this.selection;
- },
+ get model() {
+ return this.brushingStateController_.model;
+ },
- get model() {
- return this.brushingStateController_.model;
- },
+ onModelChanged_: function() {
+ this.activePanelType_ = undefined;
+ this.updateContents_();
+ },
- onModelChanged_: function() {
- this.activePanelType_ = undefined;
- this.updateContents_();
- },
+ get expanded() {
+ this.hasAttribute('expanded');
+ },
- get expanded() {
- this.hasAttribute('expanded');
- },
+ get activePanel() {
+ return this.activePanelContainer_.children[0];
+ },
- get activePanel() {
- if (this.activePanelContainer_.children.length < 2)
- return undefined;
- return this.activePanelContainer_.children[1];
- },
+ get activePanelType() {
+ return this.activePanelType_;
+ },
- get activePanelType() {
- return this.activePanelType_;
- },
+ set activePanelType(panelType) {
+ if (this.model === undefined)
+ throw new Error('Cannot activate panel without a model');
- set activePanelType(panelType) {
- if (this.model === undefined)
- throw new Error('Cannot activate panel without a model');
+ var panel = undefined;
+ if (panelType)
+ panel = document.createElement(panelType);
- var panel = undefined;
- if (panelType)
- panel = document.createElement(panelType);
+ if (panel !== undefined && !panel.supportsModel(this.model))
+ throw new Error('Cannot activate panel: does not support this model');
- if (panel !== undefined && !panel.supportsModel(this.model))
- throw new Error('Cannot activate panel: does not support this model');
+ if (this.activePanelType) {
+ Polymer.dom(this.getLabelElementForPanelType_(
+ this.activePanelType)).removeAttribute('selected');
+ }
- if (this.activePanelType) {
- this.getLabelElementForPanelType_(
- this.activePanelType).removeAttribute('selected');
- }
+ if (this.activePanelType) {
+ this.getLabelElementForPanelType_(
+ this.activePanelType).removeAttribute('selected');
+ }
- if (this.activePanel)
- this.activePanelContainer_.removeChild(this.activePanel);
+ if (this.activePanel)
+ this.activePanelContainer_.removeChild(this.activePanel);
- if (panelType === undefined) {
- this.removeAttribute('expanded');
- this.activePanelType_ = undefined;
- return;
- }
+ if (panelType === undefined) {
+ Polymer.dom(this).removeAttribute('expanded');
+ this.activePanelType_ = undefined;
+ return;
+ }
- this.getLabelElementForPanelType_(panelType).
- setAttribute('selected', true);
- this.setAttribute('expanded', true);
+ Polymer.dom(this.getLabelElementForPanelType_(panelType)).
+ setAttribute('selected', true);
+ Polymer.dom(this).setAttribute('expanded', true);
- this.activePanelContainer_.appendChild(panel);
- this.dragHandle_.target = panel;
- panel.rangeOfInterest = this.rangeOfInterest_;
- panel.selection = this.selection_;
- panel.model = this.model;
+ Polymer.dom(this.activePanelContainer_).appendChild(panel);
+ panel.rangeOfInterest = this.rangeOfInterest_;
+ panel.selection = this.selection_;
+ panel.model = this.model;
- this.activePanelType_ = panelType;
- },
+ this.activePanelType_ = panelType;
+ },
- getPanelTypeForConstructor_: function(constructor) {
- for (var i = 0; i < this.tabStrip_.children.length; i++) {
- if (this.tabStrip_.children[i].panelType.constructor == constructor)
- return this.tabStrip_.children[i].panelType;
- }
- },
+ getPanelTypeForConstructor_: function(constructor) {
+ for (var i = 0; i < this.tabStrip_.children.length; i++) {
+ if (this.tabStrip_.children[i].panelType.constructor === constructor)
+ return this.tabStrip_.children[i].panelType;
+ }
+ },
- getLabelElementForPanelType_: function(panelType) {
- for (var i = 0; i < this.tabStrip_.children.length; i++) {
- if (this.tabStrip_.children[i].panelType == panelType)
- return this.tabStrip_.children[i];
- }
- return undefined;
- },
-
- updateContents_: function() {
- var previouslyActivePanelType = this.activePanelType;
-
- this.tabStrip_.textContent = '';
- var supportedPanelTypes = [];
-
- var panelTypes =
- tr.ui.b.getPolymerElementsThatSubclass('tr-ui-side-panel');
- panelTypes.forEach(function(panelType) {
- var labelEl = document.createElement('tab-strip-label');
- var panel = document.createElement(panelType);
-
- labelEl.textContent = panel.textLabel;
- labelEl.panelType = panelType;
-
- var supported = panel.supportsModel(this.model);
- if (this.model && supported.supported) {
- supportedPanelTypes.push(panelType);
- labelEl.setAttribute('enabled', true);
- labelEl.addEventListener('click', function() {
- this.activePanelType =
- this.activePanelType === panelType ? undefined : panelType;
- }.bind(this));
- } else {
- labelEl.title = 'Not supported for the current trace: ' +
- supported.reason;
- labelEl.style.display = 'none';
- }
- this.tabStrip_.appendChild(labelEl);
- }, this);
-
- // Restore the active panel, or collapse
- if (previouslyActivePanelType &&
- supportedPanelTypes.indexOf(previouslyActivePanelType) != -1) {
- this.activePanelType = previouslyActivePanelType;
- this.setAttribute('expanded', true);
+ getLabelElementForPanelType_: function(panelType) {
+ for (var i = 0; i < this.tabStrip_.children.length; i++) {
+ if (this.tabStrip_.children[i].panelType === panelType)
+ return this.tabStrip_.children[i];
+ }
+ return undefined;
+ },
+
+ updateContents_: function() {
+ var previouslyActivePanelType = this.activePanelType;
+
+ Polymer.dom(this.tabStrip_).textContent = '';
+ var supportedPanelTypes = [];
+
+ for (var panelTypeInfo of
+ tr.ui.side_panel.SidePanelRegistry.getAllRegisteredTypeInfos()) {
+ var labelEl = document.createElement('tab-strip-label');
+ var panel = panelTypeInfo.constructor();
+ var panelType = panel.tagName;
+
+ Polymer.dom(labelEl).textContent = panel.textLabel;
+ labelEl.panelType = panelType;
+
+ var supported = panel.supportsModel(this.model);
+ if (this.model && supported.supported) {
+ supportedPanelTypes.push(panelType);
+ Polymer.dom(labelEl).setAttribute('enabled', true);
+ labelEl.addEventListener('click', function(panelType) {
+ this.activePanelType =
+ this.activePanelType === panelType ? undefined : panelType;
+ }.bind(this, panelType));
} else {
if (this.activePanel)
this.activePanelContainer_.removeChild(this.activePanel);
this.removeAttribute('expanded');
}
- },
-
- get rangeOfInterest() {
- return this.rangeOfInterest_;
- },
+ Polymer.dom(this.tabStrip_).appendChild(labelEl);
+ }
- set rangeOfInterest(range) {
- if (range == undefined)
- throw new Error('Must not be undefined');
- this.rangeOfInterest_ = range;
+ // Restore the active panel, or collapse
+ if (previouslyActivePanelType &&
+ supportedPanelTypes.indexOf(previouslyActivePanelType) !== -1) {
+ this.activePanelType = previouslyActivePanelType;
+ Polymer.dom(this).setAttribute('expanded', true);
+ } else {
if (this.activePanel)
- this.activePanel.rangeOfInterest = range;
+ Polymer.dom(this.activePanelContainer_).removeChild(this.activePanel);
+ Polymer.dom(this).removeAttribute('expanded');
}
- });
- </script>
-</polymer-element>
-
+ },
+
+ get rangeOfInterest() {
+ return this.rangeOfInterest_;
+ },
+
+ set rangeOfInterest(range) {
+ if (range === undefined)
+ throw new Error('Must not be undefined');
+ this.rangeOfInterest_ = range;
+ if (this.activePanel)
+ this.activePanel.rangeOfInterest = range;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html
new file mode 100644
index 00000000000..ef86dbe06dd
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/extension_registry.html">
+
+<script>
+'use strict';
+
+// TODO(charliea): This can probably be cleaned up so that we don't have to
+// manually wrap the Polymer element names with a function and
+// `document.createElement` at each of the registration sites by creating a
+// new "Polymer" registration mode.
+tr.exportTo('tr.ui.side_panel', function() {
+ /**
+ * SidePanelRegistry is an entity for side panel Polymer elements to register
+ * on so that they'll render a side panel if the model has the correct data.
+ *
+ * Example usage:
+ *
+ * SidePanelRegistry.register(function() {
+ * return document.createElement('my-side-panel');
+ * });
+ *
+ * @constructor
+ */
+ function SidePanelRegistry() {}
+
+ var options = new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);
+ tr.b.decorateExtensionRegistry(SidePanelRegistry, options);
+
+ return {
+ SidePanelRegistry: SidePanelRegistry
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html
new file mode 100644
index 00000000000..9e91ce0494f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var SidePanelRegistry = tr.ui.side_panel.SidePanelRegistry;
+
+ var testOptions = {
+ setUp: function() {
+ SidePanelRegistry.pushCleanStateBeforeTest();
+ },
+
+ tearDown: function() {
+ SidePanelRegistry.popCleanStateAfterTest();
+ },
+ };
+
+ test('register', function() {
+ SidePanelRegistry.register(function() {
+ return document.createElement('div');
+ });
+ SidePanelRegistry.register(function() {
+ return document.createElement('span');
+ });
+
+ var typeInfos = SidePanelRegistry.getAllRegisteredTypeInfos();
+ assert.equal(typeInfos[0].constructor().tagName, 'DIV');
+ assert.equal(typeInfos[1].constructor().tagName, 'SPAN');
+ assert.lengthOf(typeInfos, 2);
+ }, testOptions);
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html
index 49c10e29123..bc1bc4cc12c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html
@@ -57,7 +57,7 @@ tr.exportTo('tr.ui', function() {
},
xPanWorldPosToViewPos: function(worldX, viewX, viewWidth) {
- if (typeof viewX == 'string') {
+ if (typeof viewX === 'string') {
if (viewX === 'left') {
viewX = 0;
} else if (viewX === 'center') {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html
index 7122d9ba51c..a1f5ecff9b1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html
@@ -130,7 +130,7 @@ tr.exportTo('tr.ui', function() {
__proto__: tr.ui.b.Animation.prototype,
get affectsPanY() {
- return this.startPanY != this.goalFocalPointY;
+ return this.startPanY !== this.goalFocalPointY;
},
canTakeOverFor: function(existingAnimation) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html
index 240104d6322..b28d7af8c0e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html
@@ -95,7 +95,7 @@ tr.exportTo('tr.ui', function() {
},
set leftSelected(leftSelected) {
- if (this.leftSelected_ == leftSelected)
+ if (this.leftSelected_ === leftSelected)
return;
this.leftSelected_ = leftSelected;
this.viewport_.dispatchChangeEvent();
@@ -106,7 +106,7 @@ tr.exportTo('tr.ui', function() {
},
set rightSelected(rightSelected) {
- if (this.rightSelected_ == rightSelected)
+ if (this.rightSelected_ === rightSelected)
return;
this.rightSelected_ = rightSelected;
this.viewport_.dispatchChangeEvent();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html
index 36454ffb9e3..c4c84bc9a2f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html
@@ -9,6 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/settings.html">
<link rel="import" href="/tracing/base/task.html">
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/core/filter.html">
<link rel="import" href="/tracing/model/event.html">
<link rel="import" href="/tracing/model/event_set.html">
@@ -22,7 +23,6 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/tracks/drawing_container.html">
<link rel="import" href="/tracing/ui/tracks/model_track.html">
<link rel="import" href="/tracing/ui/tracks/ruler_track.html">
-<link rel="import" href="/tracing/value/unit.html">
<!--
Interactive visualizaiton of Model objects based loosely on gantt charts.
@@ -36,7 +36,7 @@ found in the LICENSE file.
BBBB BB
Thread2: CCCCCC CCCCC
-->
-<polymer-element name='tr-ui-timeline-track-view'>
+<dom-module id='tr-ui-timeline-track-view'>
<template>
<style>
:host {
@@ -72,1079 +72,1080 @@ found in the LICENSE file.
<tv-ui-b-hotkey-controller id='hotkey_controller'>
</tv-ui-b-hotkey-controller>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-timeline-track-view',
- Polymer({
- ready: function() {
- this.displayTransform_ = new tr.ui.TimelineDisplayTransform();
- this.model_ = undefined;
+ ready: function() {
+ this.displayTransform_ = new tr.ui.TimelineDisplayTransform();
+ this.model_ = undefined;
- this.timelineView_ = undefined;
+ this.timelineView_ = undefined;
- this.viewport_ = new tr.ui.TimelineViewport(this);
- this.viewportDisplayTransformAtMouseDown_ = undefined;
- this.brushingStateController_ = undefined;
+ this.viewport_ = new tr.ui.TimelineViewport(this);
+ this.viewportDisplayTransformAtMouseDown_ = undefined;
+ this.brushingStateController_ = undefined;
- this.rulerTrackContainer_ =
- new tr.ui.tracks.DrawingContainer(this.viewport_);
- this.appendChild(this.rulerTrackContainer_);
- this.rulerTrackContainer_.invalidate();
+ this.rulerTrackContainer_ =
+ new tr.ui.tracks.DrawingContainer(this.viewport_);
+ Polymer.dom(this).appendChild(this.rulerTrackContainer_);
+ this.rulerTrackContainer_.invalidate();
- this.rulerTrack_ = new tr.ui.tracks.RulerTrack(this.viewport_);
- this.rulerTrackContainer_.appendChild(this.rulerTrack_);
+ this.rulerTrack_ = new tr.ui.tracks.RulerTrack(this.viewport_);
+ Polymer.dom(this.rulerTrackContainer_).appendChild(this.rulerTrack_);
- this.upperModelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_);
- this.upperModelTrack_.upperMode = true;
- this.rulerTrackContainer_.appendChild(this.upperModelTrack_);
+ this.upperModelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_);
+ this.upperModelTrack_.upperMode = true;
+ Polymer.dom(this.rulerTrackContainer_).appendChild(this.upperModelTrack_);
- this.modelTrackContainer_ =
- new tr.ui.tracks.DrawingContainer(this.viewport_);
- this.appendChild(this.modelTrackContainer_);
- this.modelTrackContainer_.style.display = 'block';
- this.modelTrackContainer_.invalidate();
+ this.modelTrackContainer_ =
+ new tr.ui.tracks.DrawingContainer(this.viewport_);
+ Polymer.dom(this).appendChild(this.modelTrackContainer_);
+ this.modelTrackContainer_.style.display = 'block';
+ this.modelTrackContainer_.invalidate();
- this.viewport_.modelTrackContainer = this.modelTrackContainer_;
+ this.viewport_.modelTrackContainer = this.modelTrackContainer_;
- this.modelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_);
- this.modelTrackContainer_.appendChild(this.modelTrack_);
+ this.modelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_);
+ Polymer.dom(this.modelTrackContainer_).appendChild(this.modelTrack_);
- this.timingTool_ = new tr.ui.b.TimingTool(this.viewport_, this);
+ this.timingTool_ = new tr.ui.b.TimingTool(this.viewport_, this);
- this.initMouseModeSelector();
+ this.initMouseModeSelector();
- this.hideDragBox_();
+ this.hideDragBox_();
- this.initHintText_();
+ this.initHintText_();
- this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
+ this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
- this.onDblClick_ = this.onDblClick_.bind(this);
- this.addEventListener('dblclick', this.onDblClick_);
+ this.onDblClick_ = this.onDblClick_.bind(this);
+ this.addEventListener('dblclick', this.onDblClick_);
- this.onMouseWheel_ = this.onMouseWheel_.bind(this);
- this.addEventListener('mousewheel', this.onMouseWheel_);
+ this.onMouseWheel_ = this.onMouseWheel_.bind(this);
+ this.addEventListener('mousewheel', this.onMouseWheel_);
- this.onMouseDown_ = this.onMouseDown_.bind(this);
- this.addEventListener('mousedown', this.onMouseDown_);
+ this.onMouseDown_ = this.onMouseDown_.bind(this);
+ this.addEventListener('mousedown', this.onMouseDown_);
- this.onMouseMove_ = this.onMouseMove_.bind(this);
- this.addEventListener('mousemove', this.onMouseMove_);
+ this.onMouseMove_ = this.onMouseMove_.bind(this);
+ this.addEventListener('mousemove', this.onMouseMove_);
- this.onTouchStart_ = this.onTouchStart_.bind(this);
- this.addEventListener('touchstart', this.onTouchStart_);
+ this.onTouchStart_ = this.onTouchStart_.bind(this);
+ this.addEventListener('touchstart', this.onTouchStart_);
- this.onTouchMove_ = this.onTouchMove_.bind(this);
- this.addEventListener('touchmove', this.onTouchMove_);
+ this.onTouchMove_ = this.onTouchMove_.bind(this);
+ this.addEventListener('touchmove', this.onTouchMove_);
- this.onTouchEnd_ = this.onTouchEnd_.bind(this);
- this.addEventListener('touchend', this.onTouchEnd_);
+ this.onTouchEnd_ = this.onTouchEnd_.bind(this);
+ this.addEventListener('touchend', this.onTouchEnd_);
- this.addHotKeys_();
+ this.addHotKeys_();
- this.mouseViewPosAtMouseDown_ = {x: 0, y: 0};
- this.lastMouseViewPos_ = {x: 0, y: 0};
+ this.mouseViewPosAtMouseDown_ = {x: 0, y: 0};
+ this.lastMouseViewPos_ = {x: 0, y: 0};
- this.lastTouchViewPositions_ = [];
+ this.lastTouchViewPositions_ = [];
- this.alert_ = undefined;
+ this.alert_ = undefined;
- this.isPanningAndScanning_ = false;
- this.isZooming_ = false;
- },
+ this.isPanningAndScanning_ = false;
+ this.isZooming_ = false;
+ },
- initMouseModeSelector: function() {
- this.mouseModeSelector_ = document.createElement(
- 'tr-ui-b-mouse-mode-selector');
- this.mouseModeSelector_.targetElement = this;
- this.appendChild(this.mouseModeSelector_);
+ initMouseModeSelector: function() {
+ this.mouseModeSelector_ = document.createElement(
+ 'tr-ui-b-mouse-mode-selector');
+ this.mouseModeSelector_.targetElement = this;
+ Polymer.dom(this).appendChild(this.mouseModeSelector_);
- this.mouseModeSelector_.addEventListener('beginpan',
- this.onBeginPanScan_.bind(this));
- this.mouseModeSelector_.addEventListener('updatepan',
- this.onUpdatePanScan_.bind(this));
- this.mouseModeSelector_.addEventListener('endpan',
- this.onEndPanScan_.bind(this));
+ this.mouseModeSelector_.addEventListener('beginpan',
+ this.onBeginPanScan_.bind(this));
+ this.mouseModeSelector_.addEventListener('updatepan',
+ this.onUpdatePanScan_.bind(this));
+ this.mouseModeSelector_.addEventListener('endpan',
+ this.onEndPanScan_.bind(this));
- this.mouseModeSelector_.addEventListener('beginselection',
- this.onBeginSelection_.bind(this));
- this.mouseModeSelector_.addEventListener('updateselection',
- this.onUpdateSelection_.bind(this));
- this.mouseModeSelector_.addEventListener('endselection',
- this.onEndSelection_.bind(this));
+ this.mouseModeSelector_.addEventListener('beginselection',
+ this.onBeginSelection_.bind(this));
+ this.mouseModeSelector_.addEventListener('updateselection',
+ this.onUpdateSelection_.bind(this));
+ this.mouseModeSelector_.addEventListener('endselection',
+ this.onEndSelection_.bind(this));
- this.mouseModeSelector_.addEventListener('beginzoom',
- this.onBeginZoom_.bind(this));
- this.mouseModeSelector_.addEventListener('updatezoom',
- this.onUpdateZoom_.bind(this));
- this.mouseModeSelector_.addEventListener('endzoom',
- this.onEndZoom_.bind(this));
+ this.mouseModeSelector_.addEventListener('beginzoom',
+ this.onBeginZoom_.bind(this));
+ this.mouseModeSelector_.addEventListener('updatezoom',
+ this.onUpdateZoom_.bind(this));
+ this.mouseModeSelector_.addEventListener('endzoom',
+ this.onEndZoom_.bind(this));
- this.mouseModeSelector_.addEventListener('entertiming',
- this.timingTool_.onEnterTiming.bind(this.timingTool_));
- this.mouseModeSelector_.addEventListener('begintiming',
- this.timingTool_.onBeginTiming.bind(this.timingTool_));
- this.mouseModeSelector_.addEventListener('updatetiming',
- this.timingTool_.onUpdateTiming.bind(this.timingTool_));
- this.mouseModeSelector_.addEventListener('endtiming',
- this.timingTool_.onEndTiming.bind(this.timingTool_));
- this.mouseModeSelector_.addEventListener('exittiming',
- this.timingTool_.onExitTiming.bind(this.timingTool_));
+ this.mouseModeSelector_.addEventListener('entertiming',
+ this.timingTool_.onEnterTiming.bind(this.timingTool_));
+ this.mouseModeSelector_.addEventListener('begintiming',
+ this.timingTool_.onBeginTiming.bind(this.timingTool_));
+ this.mouseModeSelector_.addEventListener('updatetiming',
+ this.timingTool_.onUpdateTiming.bind(this.timingTool_));
+ this.mouseModeSelector_.addEventListener('endtiming',
+ this.timingTool_.onEndTiming.bind(this.timingTool_));
+ this.mouseModeSelector_.addEventListener('exittiming',
+ this.timingTool_.onExitTiming.bind(this.timingTool_));
- var m = tr.ui.b.MOUSE_SELECTOR_MODE;
- this.mouseModeSelector_.supportedModeMask =
- m.SELECTION | m.PANSCAN | m.ZOOM | m.TIMING;
- this.mouseModeSelector_.settingsKey =
- 'timelineTrackView.mouseModeSelector';
- this.mouseModeSelector_.setKeyCodeForMode(m.PANSCAN, '2'.charCodeAt(0));
- this.mouseModeSelector_.setKeyCodeForMode(m.SELECTION, '1'.charCodeAt(0));
- this.mouseModeSelector_.setKeyCodeForMode(m.ZOOM, '3'.charCodeAt(0));
- this.mouseModeSelector_.setKeyCodeForMode(m.TIMING, '4'.charCodeAt(0));
+ var m = tr.ui.b.MOUSE_SELECTOR_MODE;
+ this.mouseModeSelector_.supportedModeMask =
+ m.SELECTION | m.PANSCAN | m.ZOOM | m.TIMING;
+ this.mouseModeSelector_.settingsKey =
+ 'timelineTrackView.mouseModeSelector';
+ this.mouseModeSelector_.setKeyCodeForMode(m.PANSCAN, '2'.charCodeAt(0));
+ this.mouseModeSelector_.setKeyCodeForMode(m.SELECTION, '1'.charCodeAt(0));
+ this.mouseModeSelector_.setKeyCodeForMode(m.ZOOM, '3'.charCodeAt(0));
+ this.mouseModeSelector_.setKeyCodeForMode(m.TIMING, '4'.charCodeAt(0));
- this.mouseModeSelector_.setModifierForAlternateMode(
- m.SELECTION, tr.ui.b.MODIFIER.SHIFT);
- this.mouseModeSelector_.setModifierForAlternateMode(
- m.PANSCAN, tr.ui.b.MODIFIER.SPACE);
- },
+ this.mouseModeSelector_.setModifierForAlternateMode(
+ m.SELECTION, tr.ui.b.MODIFIER.SHIFT);
+ this.mouseModeSelector_.setModifierForAlternateMode(
+ m.PANSCAN, tr.ui.b.MODIFIER.SPACE);
+ },
- get brushingStateController() {
- return this.brushingStateController_;
- },
-
- set brushingStateController(brushingStateController) {
- if (this.brushingStateController_) {
- this.brushingStateController_.removeEventListener('change',
- this.onSelectionChanged_);
- }
- this.brushingStateController_ = brushingStateController;
- if (this.brushingStateController_) {
- this.brushingStateController_.addEventListener('change',
- this.onSelectionChanged_);
- }
- },
-
- set timelineView(view) {
- this.timelineView_ = view;
- },
-
- onSelectionChanged_: function() {
- this.showHintText_('Press \'m\' to mark current selection');
- this.viewport_.dispatchChangeEvent();
- },
-
- set selection(selection) {
- throw new Error('DO NOT CALL THIS');
- },
-
- set highlight(highlight) {
- throw new Error('DO NOT CALL THIS');
- },
-
- detach: function() {
- this.modelTrack_.detach();
- this.upperModelTrack_.detach();
-
- this.viewport_.detach();
- },
-
- get viewport() {
- return this.viewport_;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- if (!model)
- throw new Error('Model cannot be undefined');
-
- var modelInstanceChanged = this.model_ !== model;
- this.model_ = model;
- this.modelTrack_.model = model;
- this.upperModelTrack_.model = model;
-
- // Set up a reasonable viewport.
- if (modelInstanceChanged)
- this.viewport_.setWhenPossible(this.setInitialViewport_.bind(this));
- },
-
- get hasVisibleContent() {
- return this.modelTrack_.hasVisibleContent ||
- this.upperModelTrack_.hasVisibleContent;
- },
-
- setInitialViewport_: function() {
- // We need the canvas size to be up-to-date at this point. We maybe in
- // here before the raf fires, so the size may have not been updated since
- // the canvas was resized.
- this.modelTrackContainer_.updateCanvasSizeIfNeeded_();
- var w = this.modelTrackContainer_.canvas.width;
-
- var min;
- var range;
-
- if (this.model_.bounds.isEmpty) {
- min = 0;
- range = 1000;
- } else if (this.model_.bounds.range === 0) {
- min = this.model_.bounds.min;
- range = 1000;
- } else {
- min = this.model_.bounds.min;
- range = this.model_.bounds.range;
- }
-
- var boost = range * 0.15;
- this.displayTransform_.set(this.viewport_.currentDisplayTransform);
- this.displayTransform_.xSetWorldBounds(
- min - boost, min + range + boost, w);
- this.viewport_.setDisplayTransformImmediately(this.displayTransform_);
- },
-
- /**
- * @param {Filter} filter The filter to use for finding matches.
- * @param {Selection} selection The selection to add matches to.
- * @return {Task} which performs the filtering.
- */
- addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) {
- var modelTrack = this.modelTrack_;
- var firstT = modelTrack.addAllEventsMatchingFilterToSelectionAsTask(
- filter, selection);
- var lastT = firstT.after(function() {
- this.upperModelTrack_.addAllEventsMatchingFilterToSelection(
- filter, selection);
-
- }, this);
- return firstT;
- },
-
- onMouseMove_: function(e) {
- // Zooming requires the delta since the last mousemove so we need to avoid
- // tracking it when the zoom interaction is active.
- if (this.isZooming_)
- return;
-
- this.storeLastMousePos_(e);
- },
-
- onTouchStart_: function(e) {
- this.storeLastTouchPositions_(e);
- this.focusElements_();
- },
-
- onTouchMove_: function(e) {
- e.preventDefault();
- this.onUpdateTransformForTouch_(e);
- },
-
- onTouchEnd_: function(e) {
- this.storeLastTouchPositions_(e);
- this.focusElements_();
- },
-
- addHotKeys_: function() {
- this.addKeyDownHotKeys_();
- this.addKeyPressHotKeys_();
- },
-
- addKeyPressHotKeys_: function() {
- var addBinding = function(dict) {
- dict.eventType = 'keypress';
- dict.useCapture = false;
- dict.thisArg = this;
- var binding = new tr.ui.b.HotKey(dict);
- this.$.hotkey_controller.addHotKey(binding);
- }.bind(this);
-
- addBinding({
- keyCodes: ['w'.charCodeAt(0), ','.charCodeAt(0)],
- callback: function(e) {
- this.zoomBy_(1.5, true);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCodes: ['s'.charCodeAt(0), 'o'.charCodeAt(0)],
- callback: function(e) {
- this.zoomBy_(1 / 1.5, true);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'g'.charCodeAt(0),
- callback: function(e) {
- this.onGridToggle_(true);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'G'.charCodeAt(0),
- callback: function(e) {
- this.onGridToggle_(false);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCodes: ['W'.charCodeAt(0), '<'.charCodeAt(0)],
- callback: function(e) {
- this.zoomBy_(10, true);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCodes: ['S'.charCodeAt(0), 'O'.charCodeAt(0)],
- callback: function(e) {
- this.zoomBy_(1 / 10, true);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'a'.charCodeAt(0),
- callback: function(e) {
- this.queueSmoothPan_(this.viewWidth_ * 0.3, 0);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCodes: ['d'.charCodeAt(0), 'e'.charCodeAt(0)],
- callback: function(e) {
- this.queueSmoothPan_(this.viewWidth_ * -0.3, 0);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'A'.charCodeAt(0),
- callback: function(e) {
- this.queueSmoothPan_(viewWidth * 0.5, 0);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'D'.charCodeAt(0),
- callback: function(e) {
- this.queueSmoothPan_(viewWidth * -0.5, 0);
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: '0'.charCodeAt(0),
- callback: function(e) {
- this.setInitialViewport_();
- e.stopPropagation();
- }
- });
-
- addBinding({
- keyCode: 'f'.charCodeAt(0),
- callback: function(e) {
- this.zoomToSelection();
- e.stopPropagation();
- }
- });
+ get brushingStateController() {
+ return this.brushingStateController_;
+ },
+
+ set brushingStateController(brushingStateController) {
+ if (this.brushingStateController_) {
+ this.brushingStateController_.removeEventListener('change',
+ this.onSelectionChanged_);
+ }
+ this.brushingStateController_ = brushingStateController;
+ if (this.brushingStateController_) {
+ this.brushingStateController_.addEventListener('change',
+ this.onSelectionChanged_);
+ }
+ },
+
+ set timelineView(view) {
+ this.timelineView_ = view;
+ },
+
+ onSelectionChanged_: function() {
+ this.showHintText_('Press \'m\' to mark current selection');
+ this.viewport_.dispatchChangeEvent();
+ },
+
+ set selection(selection) {
+ throw new Error('DO NOT CALL THIS');
+ },
+
+ set highlight(highlight) {
+ throw new Error('DO NOT CALL THIS');
+ },
+
+ detach: function() {
+ this.modelTrack_.detach();
+ this.upperModelTrack_.detach();
+
+ this.viewport_.detach();
+ },
+
+ get viewport() {
+ return this.viewport_;
+ },
+
+ get model() {
+ return this.model_;
+ },
+
+ set model(model) {
+ if (!model)
+ throw new Error('Model cannot be undefined');
+
+ var modelInstanceChanged = this.model_ !== model;
+ this.model_ = model;
+ this.modelTrack_.model = model;
+ this.upperModelTrack_.model = model;
+
+ // Set up a reasonable viewport.
+ if (modelInstanceChanged)
+ this.viewport_.setWhenPossible(this.setInitialViewport_.bind(this));
+ },
+
+ get hasVisibleContent() {
+ return this.modelTrack_.hasVisibleContent ||
+ this.upperModelTrack_.hasVisibleContent;
+ },
+
+ setInitialViewport_: function() {
+ // We need the canvas size to be up-to-date at this point. We maybe in
+ // here before the raf fires, so the size may have not been updated since
+ // the canvas was resized.
+ this.modelTrackContainer_.updateCanvasSizeIfNeeded_();
+ var w = this.modelTrackContainer_.canvas.width;
+
+ var min;
+ var range;
+
+ if (this.model_.bounds.isEmpty) {
+ min = 0;
+ range = 1000;
+ } else if (this.model_.bounds.range === 0) {
+ min = this.model_.bounds.min;
+ range = 1000;
+ } else {
+ min = this.model_.bounds.min;
+ range = this.model_.bounds.range;
+ }
- addBinding({
- keyCode: 'm'.charCodeAt(0),
- callback: function(e) {
- this.setCurrentSelectionAsInterestRange_();
- e.stopPropagation();
- }
- });
+ var boost = range * 0.15;
+ this.displayTransform_.set(this.viewport_.currentDisplayTransform);
+ this.displayTransform_.xSetWorldBounds(
+ min - boost, min + range + boost, w);
+ this.viewport_.setDisplayTransformImmediately(this.displayTransform_);
+ },
+
+ /**
+ * @param {Filter} filter The filter to use for finding matches.
+ * @param {Selection} selection The selection to add matches to.
+ * @return {Task} which performs the filtering.
+ */
+ addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) {
+ var modelTrack = this.modelTrack_;
+ var firstT = modelTrack.addAllEventsMatchingFilterToSelectionAsTask(
+ filter, selection);
+ var lastT = firstT.after(function() {
+ this.upperModelTrack_.addAllEventsMatchingFilterToSelection(
+ filter, selection);
+
+ }, this);
+ return firstT;
+ },
+
+ onMouseMove_: function(e) {
+ // Zooming requires the delta since the last mousemove so we need to avoid
+ // tracking it when the zoom interaction is active.
+ if (this.isZooming_)
+ return;
+
+ this.storeLastMousePos_(e);
+ },
+
+ onTouchStart_: function(e) {
+ this.storeLastTouchPositions_(e);
+ this.focusElements_();
+ },
+
+ onTouchMove_: function(e) {
+ e.preventDefault();
+ this.onUpdateTransformForTouch_(e);
+ },
+
+ onTouchEnd_: function(e) {
+ this.storeLastTouchPositions_(e);
+ this.focusElements_();
+ },
+
+ addHotKeys_: function() {
+ this.addKeyDownHotKeys_();
+ this.addKeyPressHotKeys_();
+ },
+
+ addKeyPressHotKeys_: function() {
+ var addBinding = function(dict) {
+ dict.eventType = 'keypress';
+ dict.useCapture = false;
+ dict.thisArg = this;
+ var binding = new tr.ui.b.HotKey(dict);
+ this.$.hotkey_controller.addHotKey(binding);
+ }.bind(this);
+
+ addBinding({
+ keyCodes: ['w'.charCodeAt(0), ','.charCodeAt(0)],
+ callback: function(e) {
+ this.zoomBy_(1.5, true);
+ e.stopPropagation();
+ }
+ });
- addBinding({
- keyCode: 'p'.charCodeAt(0),
- callback: function(e) {
- this.selectPowerSamplesInCurrentTimeRange_();
- e.stopPropagation();
- }
- });
+ addBinding({
+ keyCodes: ['s'.charCodeAt(0), 'o'.charCodeAt(0)],
+ callback: function(e) {
+ this.zoomBy_(1 / 1.5, true);
+ e.stopPropagation();
+ }
+ });
- addBinding({
- keyCode: 'h'.charCodeAt(0),
- callback: function(e) {
- this.toggleHighDetails_();
- e.stopPropagation();
- }
- });
- },
-
- get viewWidth_() {
- return this.modelTrackContainer_.canvas.clientWidth;
- },
-
- addKeyDownHotKeys_: function() {
- var addBinding = function(dict) {
- dict.eventType = 'keydown';
- dict.useCapture = false;
- dict.thisArg = this;
- var binding = new tr.ui.b.HotKey(dict);
- this.$.hotkey_controller.addHotKey(binding);
- }.bind(this);
-
- addBinding({
- keyCode: 37, // Left arrow.
- callback: function(e) {
- var curSel = this.brushingStateController_.selection;
- var sel = this.viewport.getShiftedSelection(curSel, -1);
-
- if (sel) {
- this.brushingStateController.changeSelectionFromTimeline(sel);
- this.panToSelection();
- } else {
- this.queueSmoothPan_(this.viewWidth_ * 0.3, 0);
- }
- e.preventDefault();
- e.stopPropagation();
- }
- });
+ addBinding({
+ keyCode: 'g'.charCodeAt(0),
+ callback: function(e) {
+ this.onGridToggle_(true);
+ e.stopPropagation();
+ }
+ });
- addBinding({
- keyCode: 39, // Right arrow.
- callback: function(e) {
- var curSel = this.brushingStateController_.selection;
- var sel = this.viewport.getShiftedSelection(curSel, 1);
- if (sel) {
- this.brushingStateController.changeSelectionFromTimeline(sel);
- this.panToSelection();
- } else {
- this.queueSmoothPan_(-this.viewWidth_ * 0.3, 0);
- }
- e.preventDefault();
- e.stopPropagation();
- }
- });
- },
+ addBinding({
+ keyCode: 'G'.charCodeAt(0),
+ callback: function(e) {
+ this.onGridToggle_(false);
+ e.stopPropagation();
+ }
+ });
- onDblClick_: function(e) {
- if (this.mouseModeSelector_.mode !==
- tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
- return;
+ addBinding({
+ keyCodes: ['W'.charCodeAt(0), '<'.charCodeAt(0)],
+ callback: function(e) {
+ this.zoomBy_(10, true);
+ e.stopPropagation();
+ }
+ });
- var curSelection = this.brushingStateController_.selection;
- if (!curSelection.length || !tr.b.getOnlyElement(curSelection).title)
- return;
+ addBinding({
+ keyCodes: ['S'.charCodeAt(0), 'O'.charCodeAt(0)],
+ callback: function(e) {
+ this.zoomBy_(1 / 10, true);
+ e.stopPropagation();
+ }
+ });
- var selection = new tr.model.EventSet();
- var filter = new tr.c.ExactTitleFilter(
- tr.b.getOnlyElement(curSelection).title);
- this.modelTrack_.addAllEventsMatchingFilterToSelection(filter,
- selection);
+ addBinding({
+ keyCode: 'a'.charCodeAt(0),
+ callback: function(e) {
+ this.queueSmoothPan_(this.viewWidth_ * 0.3, 0);
+ e.stopPropagation();
+ }
+ });
- this.brushingStateController.changeSelectionFromTimeline(selection);
- },
+ addBinding({
+ keyCodes: ['d'.charCodeAt(0), 'e'.charCodeAt(0)],
+ callback: function(e) {
+ this.queueSmoothPan_(this.viewWidth_ * -0.3, 0);
+ e.stopPropagation();
+ }
+ });
- onMouseWheel_: function(e) {
- if (!e.altKey)
- return;
+ addBinding({
+ keyCode: 'A'.charCodeAt(0),
+ callback: function(e) {
+ this.queueSmoothPan_(viewWidth * 0.5, 0);
+ e.stopPropagation();
+ }
+ });
- var delta = e.wheelDelta / 120;
- var zoomScale = Math.pow(1.5, delta);
- this.zoomBy_(zoomScale);
- e.preventDefault();
- },
+ addBinding({
+ keyCode: 'D'.charCodeAt(0),
+ callback: function(e) {
+ this.queueSmoothPan_(viewWidth * -0.5, 0);
+ e.stopPropagation();
+ }
+ });
- onMouseDown_: function(e) {
- if (this.mouseModeSelector_.mode !==
- tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
- return;
+ addBinding({
+ keyCode: '0'.charCodeAt(0),
+ callback: function(e) {
+ this.setInitialViewport_();
+ e.stopPropagation();
+ }
+ });
- // Mouse down must start on ruler track for crosshair guide lines to draw.
- if (e.target !== this.rulerTrack_)
- return;
+ addBinding({
+ keyCode: 'f'.charCodeAt(0),
+ callback: function(e) {
+ this.zoomToSelection();
+ e.stopPropagation();
+ }
+ });
- // Make sure we don't start a selection drag event here.
- this.dragBeginEvent_ = undefined;
+ addBinding({
+ keyCode: 'm'.charCodeAt(0),
+ callback: function(e) {
+ this.setCurrentSelectionAsInterestRange_();
+ e.stopPropagation();
+ }
+ });
- // Remove nav string marker if it exists, since we're clearing the
- // find control box.
- if (this.xNavStringMarker_) {
- this.model.removeAnnotation(this.xNavStringMarker_);
- this.xNavStringMarker_ = undefined;
+ addBinding({
+ keyCode: 'p'.charCodeAt(0),
+ callback: function(e) {
+ this.selectPowerSamplesInCurrentTimeRange_();
+ e.stopPropagation();
}
+ });
- var dt = this.viewport_.currentDisplayTransform;
- tr.ui.b.trackMouseMovesUntilMouseUp(function(e) { // Mouse move handler.
- // If mouse event is on ruler, don't do anything.
- if (e.target === this.rulerTrack_)
- return;
-
- var relativePosition = this.extractRelativeMousePosition_(e);
- var loc = tr.model.Location.fromViewCoordinates(
- this.viewport_, relativePosition.x, relativePosition.y);
- // Not all points on the timeline represents a valid location.
- // ex. process header tracks, letter dot tracks.
- if (!loc)
- return;
-
- if (this.guideLineAnnotation_ === undefined) {
- this.guideLineAnnotation_ =
- new tr.model.XMarkerAnnotation(loc.xWorld);
- this.model.addAnnotation(this.guideLineAnnotation_);
+ addBinding({
+ keyCode: 'h'.charCodeAt(0),
+ callback: function(e) {
+ this.toggleHighDetails_();
+ e.stopPropagation();
+ }
+ });
+ },
+
+ get viewWidth_() {
+ return this.modelTrackContainer_.canvas.clientWidth;
+ },
+
+ addKeyDownHotKeys_: function() {
+ var addBinding = function(dict) {
+ dict.eventType = 'keydown';
+ dict.useCapture = false;
+ dict.thisArg = this;
+ var binding = new tr.ui.b.HotKey(dict);
+ this.$.hotkey_controller.addHotKey(binding);
+ }.bind(this);
+
+ addBinding({
+ keyCode: 37, // Left arrow.
+ callback: function(e) {
+ var curSel = this.brushingStateController_.selection;
+ var sel = this.viewport.getShiftedSelection(curSel, -1);
+
+ if (sel) {
+ this.brushingStateController.changeSelectionFromTimeline(sel);
+ this.panToSelection();
} else {
- this.guideLineAnnotation_.timestamp = loc.xWorld;
- this.modelTrackContainer_.invalidate();
- }
-
- // Set the findcontrol's text to nav string of current state.
- var state = new tr.ui.b.UIState(loc,
- this.viewport_.currentDisplayTransform.scaleX);
- this.timelineView_.setFindCtlText(
- state.toUserFriendlyString(this.viewport_));
- }.bind(this),
- undefined, // Mouse up handler.
- function onKeyUpDuringDrag() {
- if (this.dragBeginEvent_) {
- this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_,
- this.dragBoxXEnd_, this.dragBoxYEnd_);
+ this.queueSmoothPan_(this.viewWidth_ * 0.3, 0);
}
- }.bind(this));
- },
-
- queueSmoothPan_: function(viewDeltaX, deltaY) {
- var deltaX = this.viewport_.currentDisplayTransform.xViewVectorToWorld(
- viewDeltaX);
- var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
- deltaX, deltaY);
- this.viewport_.queueDisplayTransformAnimation(animation);
- },
-
- /**
- * Zoom in or out on the timeline by the given scale factor.
- * @param {Number} scale The scale factor to apply. If <1, zooms out.
- * @param {boolean} Whether to change the zoom level smoothly.
- */
- zoomBy_: function(scale, smooth) {
- if (scale <= 0) {
- return;
- }
-
- smooth = !!smooth;
- var vp = this.viewport_;
- var pixelRatio = window.devicePixelRatio || 1;
-
- var goalFocalPointXView = this.lastMouseViewPos_.x * pixelRatio;
- var goalFocalPointXWorld = vp.currentDisplayTransform.xViewToWorld(
- goalFocalPointXView);
- if (smooth) {
- var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
- goalFocalPointXWorld, goalFocalPointXView,
- vp.currentDisplayTransform.panY,
- scale);
- vp.queueDisplayTransformAnimation(animation);
- } else {
- this.displayTransform_.set(vp.currentDisplayTransform);
- this.displayTransform_.scaleX *= scale;
- this.displayTransform_.xPanWorldPosToViewPos(
- goalFocalPointXWorld, goalFocalPointXView, this.viewWidth_);
- vp.setDisplayTransformImmediately(this.displayTransform_);
+ e.preventDefault();
+ e.stopPropagation();
}
- },
-
- /**
- * Zoom into the current selection.
- */
- zoomToSelection: function() {
- if (!this.brushingStateController.selectionOfInterest.length)
- return;
-
- var bounds = this.brushingStateController.selectionOfInterest.bounds;
- if (!bounds.range)
- return;
-
- var worldCenter = bounds.center;
- var viewCenter = this.modelTrackContainer_.canvas.width / 2;
- var adjustedWorldRange = bounds.range * 1.25;
- var newScale = this.modelTrackContainer_.canvas.width /
- adjustedWorldRange;
- var zoomInRatio = newScale /
- this.viewport_.currentDisplayTransform.scaleX;
-
- var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
- worldCenter, viewCenter,
- this.viewport_.currentDisplayTransform.panY,
- zoomInRatio);
- this.viewport_.queueDisplayTransformAnimation(animation);
- },
-
- /**
- * Pan the view so the current selection becomes visible.
- */
- panToSelection: function() {
- if (!this.brushingStateController.selectionOfInterest.length)
- return;
-
- var bounds = this.brushingStateController.selectionOfInterest.bounds;
- var worldCenter = bounds.center;
- var viewWidth = this.viewWidth_;
-
- var dt = this.viewport_.currentDisplayTransform;
- if (false && !bounds.range) {
- if (dt.xWorldToView(bounds.center) < 0 ||
- dt.xWorldToView(bounds.center) > viewWidth) {
- this.displayTransform_.set(dt);
- this.displayTransform_.xPanWorldPosToViewPos(
- worldCenter, 'center', viewWidth);
- var deltaX = this.displayTransform_.panX - dt.panX;
- var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
- deltaX, 0);
- this.viewport_.queueDisplayTransformAnimation(animation);
+ });
+
+ addBinding({
+ keyCode: 39, // Right arrow.
+ callback: function(e) {
+ var curSel = this.brushingStateController_.selection;
+ var sel = this.viewport.getShiftedSelection(curSel, 1);
+ if (sel) {
+ this.brushingStateController.changeSelectionFromTimeline(sel);
+ this.panToSelection();
+ } else {
+ this.queueSmoothPan_(-this.viewWidth_ * 0.3, 0);
}
- return;
+ e.preventDefault();
+ e.stopPropagation();
}
+ });
+ },
+
+ onDblClick_: function(e) {
+ if (this.mouseModeSelector_.mode !==
+ tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
+ return;
+
+ var curSelection = this.brushingStateController_.selection;
+ if (!curSelection.length || !tr.b.getOnlyElement(curSelection).title)
+ return;
+
+ var selection = new tr.model.EventSet();
+ var filter = new tr.c.ExactTitleFilter(
+ tr.b.getOnlyElement(curSelection).title);
+ this.modelTrack_.addAllEventsMatchingFilterToSelection(filter,
+ selection);
+
+ this.brushingStateController.changeSelectionFromTimeline(selection);
+ },
+
+ onMouseWheel_: function(e) {
+ if (!e.altKey)
+ return;
+
+ var delta = e.wheelDelta / 120;
+ var zoomScale = Math.pow(1.5, delta);
+ this.zoomBy_(zoomScale);
+ e.preventDefault();
+ },
+
+ onMouseDown_: function(e) {
+ if (this.mouseModeSelector_.mode !==
+ tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
+ return;
+
+ // Mouse down must start on ruler track for crosshair guide lines to draw.
+ if (e.target !== this.rulerTrack_)
+ return;
+
+ // Make sure we don't start a selection drag event here.
+ this.dragBeginEvent_ = undefined;
+
+ // Remove nav string marker if it exists, since we're clearing the
+ // find control box.
+ if (this.xNavStringMarker_) {
+ this.model.removeAnnotation(this.xNavStringMarker_);
+ this.xNavStringMarker_ = undefined;
+ }
- this.displayTransform_.set(dt);
- this.displayTransform_.xPanWorldBoundsIntoView(
- bounds.min,
- bounds.max,
- viewWidth);
- var deltaX = this.displayTransform_.panX - dt.panX;
- var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
- deltaX, 0);
- this.viewport_.queueDisplayTransformAnimation(animation);
- },
-
- navToPosition: function(uiState, showNavLine) {
- var location = uiState.location;
- var scaleX = uiState.scaleX;
- var track = location.getContainingTrack(this.viewport_);
-
- var worldCenter = location.xWorld;
- var viewCenter = this.modelTrackContainer_.canvas.width / 5;
- var zoomInRatio = scaleX /
- this.viewport_.currentDisplayTransform.scaleX;
-
- // Vertically scroll so track is in view.
- track.scrollIntoViewIfNeeded();
-
- // Perform zoom and panX animation.
- var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
- worldCenter, viewCenter,
- this.viewport_.currentDisplayTransform.panY,
- zoomInRatio);
- this.viewport_.queueDisplayTransformAnimation(animation);
-
- if (!showNavLine)
+ var dt = this.viewport_.currentDisplayTransform;
+ tr.ui.b.trackMouseMovesUntilMouseUp(function(e) { // Mouse move handler.
+ // If mouse event is on ruler, don't do anything.
+ if (e.target === this.rulerTrack_)
return;
- // Add an X Marker Annotation at the specified timestamp.
- if (this.xNavStringMarker_)
- this.model.removeAnnotation(this.xNavStringMarker_);
- this.xNavStringMarker_ =
- new tr.model.XMarkerAnnotation(worldCenter);
- this.model.addAnnotation(this.xNavStringMarker_);
- },
-
- selectPowerSamplesInCurrentTimeRange_: function() {
- var selectionBounds = this.brushingStateController_.selection.bounds;
- if (this.model.device.powerSeries && !selectionBounds.empty) {
- var events = this.model.device.powerSeries.getSamplesWithinRange(
- selectionBounds.min, selectionBounds.max);
- var selection = new tr.model.EventSet(events);
- this.brushingStateController_.changeSelectionFromTimeline(selection);
- }
- },
- setCurrentSelectionAsInterestRange_: function() {
- var selectionBounds = this.brushingStateController_.selection.bounds;
- if (selectionBounds.empty) {
- this.viewport_.interestRange.reset();
+ var relativePosition = this.extractRelativeMousePosition_(e);
+ var loc = tr.model.Location.fromViewCoordinates(
+ this.viewport_, relativePosition.x, relativePosition.y);
+ // Not all points on the timeline represents a valid location.
+ // ex. process header tracks, letter dot tracks.
+ if (!loc)
return;
- }
- if (this.viewport_.interestRange.min == selectionBounds.min &&
- this.viewport_.interestRange.max == selectionBounds.max)
- this.viewport_.interestRange.reset();
- else
- this.viewport_.interestRange.set(selectionBounds);
- },
-
- toggleHighDetails_: function() {
- this.viewport_.highDetails = !this.viewport_.highDetails;
- },
-
- hideDragBox_: function() {
- this.$.drag_box.style.left = '-1000px';
- this.$.drag_box.style.top = '-1000px';
- this.$.drag_box.style.width = 0;
- this.$.drag_box.style.height = 0;
- },
-
- setDragBoxPosition_: function(xStart, yStart, xEnd, yEnd) {
- var loY = Math.min(yStart, yEnd);
- var hiY = Math.max(yStart, yEnd);
- var loX = Math.min(xStart, xEnd);
- var hiX = Math.max(xStart, xEnd);
- var modelTrackRect = this.modelTrack_.getBoundingClientRect();
- var dragRect = {left: loX, top: loY, width: hiX - loX, height: hiY - loY};
-
- dragRect.right = dragRect.left + dragRect.width;
- dragRect.bottom = dragRect.top + dragRect.height;
-
- var modelTrackContainerRect =
- this.modelTrackContainer_.getBoundingClientRect();
- var clipRect = {
- left: modelTrackContainerRect.left,
- top: modelTrackContainerRect.top,
- right: modelTrackContainerRect.right,
- bottom: modelTrackContainerRect.bottom
- };
-
- var headingWidth = window.getComputedStyle(
- this.querySelector('tr-ui-heading')).width;
- var trackTitleWidth = parseInt(headingWidth);
- clipRect.left = clipRect.left + trackTitleWidth;
-
- var intersectRect_ = function(r1, r2) {
- if (r2.left > r1.right || r2.right < r1.left ||
- r2.top > r1.bottom || r2.bottom < r1.top)
- return false;
-
- var results = {};
- results.left = Math.max(r1.left, r2.left);
- results.top = Math.max(r1.top, r2.top);
- results.right = Math.min(r1.right, r2.right);
- results.bottom = Math.min(r1.bottom, r2.bottom);
- results.width = results.right - results.left;
- results.height = results.bottom - results.top;
- return results;
- };
-
- // TODO(dsinclair): intersectRect_ can return false (which should actually
- // be undefined) but we use finalDragBox without checking the return value
- // which could potentially blowup. Fix this .....
- var finalDragBox = intersectRect_(clipRect, dragRect);
-
- this.$.drag_box.style.left = finalDragBox.left + 'px';
- this.$.drag_box.style.width = finalDragBox.width + 'px';
- this.$.drag_box.style.top = finalDragBox.top + 'px';
- this.$.drag_box.style.height = finalDragBox.height + 'px';
- this.$.drag_box.style.whiteSpace = 'nowrap';
-
- var pixelRatio = window.devicePixelRatio || 1;
- var canv = this.modelTrackContainer_.canvas;
- var dt = this.viewport_.currentDisplayTransform;
- var loWX = dt.xViewToWorld(
- (loX - canv.offsetLeft) * pixelRatio);
- var hiWX = dt.xViewToWorld(
- (hiX - canv.offsetLeft) * pixelRatio);
-
- this.$.drag_box.textContent =
- tr.v.Unit.byName.timeDurationInMs.format(hiWX - loWX);
-
- var e = new tr.b.Event('selectionChanging');
- e.loWX = loWX;
- e.hiWX = hiWX;
- this.dispatchEvent(e);
- },
-
- onGridToggle_: function(left) {
- var selection = this.brushingStateController_.selection;
- var tb = left ? selection.bounds.min : selection.bounds.max;
-
- // Toggle the grid off if the grid is on, the marker position is the same
- // and the same element is selected (same timebase).
- if (this.viewport_.gridEnabled &&
- this.viewport_.gridSide === left &&
- this.viewport_.gridInitialTimebase === tb) {
- this.viewport_.gridside = undefined;
- this.viewport_.gridEnabled = false;
- this.viewport_.gridInitialTimebase = undefined;
- return;
+ if (this.guideLineAnnotation_ === undefined) {
+ this.guideLineAnnotation_ =
+ new tr.model.XMarkerAnnotation(loc.xWorld);
+ this.model.addAnnotation(this.guideLineAnnotation_);
+ } else {
+ this.guideLineAnnotation_.timestamp = loc.xWorld;
+ this.modelTrackContainer_.invalidate();
}
- // Shift the timebase left until its just left of model_.bounds.min.
- var numIntervalsSinceStart = Math.ceil((tb - this.model_.bounds.min) /
- this.viewport_.gridStep_);
-
- this.viewport_.gridEnabled = true;
- this.viewport_.gridSide = left;
- this.viewport_.gridInitialTimebase = tb;
- this.viewport_.gridTimebase = tb -
- (numIntervalsSinceStart + 1) * this.viewport_.gridStep_;
- },
-
- storeLastMousePos_: function(e) {
- this.lastMouseViewPos_ = this.extractRelativeMousePosition_(e);
- },
-
- storeLastTouchPositions_: function(e) {
- this.lastTouchViewPositions_ = this.extractRelativeTouchPositions_(e);
- },
-
- extractRelativeMousePosition_: function(e) {
- var canv = this.modelTrackContainer_.canvas;
- return {
- x: e.clientX - canv.offsetLeft,
- y: e.clientY - canv.offsetTop
- };
- },
-
- extractRelativeTouchPositions_: function(e) {
- var canv = this.modelTrackContainer_.canvas;
-
- var touches = [];
- for (var i = 0; i < e.touches.length; ++i) {
- touches.push({
- x: e.touches[i].clientX - canv.offsetLeft,
- y: e.touches[i].clientY - canv.offsetTop
- });
+ // Set the findcontrol's text to nav string of current state.
+ var state = new tr.ui.b.UIState(loc,
+ this.viewport_.currentDisplayTransform.scaleX);
+ this.timelineView_.setFindCtlText(
+ state.toUserFriendlyString(this.viewport_));
+ }.bind(this),
+ undefined, // Mouse up handler.
+ function onKeyUpDuringDrag() {
+ if (this.dragBeginEvent_) {
+ this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_,
+ this.dragBoxXEnd_, this.dragBoxYEnd_);
}
- return touches;
- },
-
- storeInitialMouseDownPos_: function(e) {
-
- var position = this.extractRelativeMousePosition_(e);
-
- this.mouseViewPosAtMouseDown_.x = position.x;
- this.mouseViewPosAtMouseDown_.y = position.y;
- },
-
- focusElements_: function() {
- this.$.hotkey_controller.childRequestsGeneralFocus(this);
- },
-
- storeInitialInteractionPositionsAndFocus_: function(e) {
+ }.bind(this));
+ },
+
+ queueSmoothPan_: function(viewDeltaX, deltaY) {
+ var deltaX = this.viewport_.currentDisplayTransform.xViewVectorToWorld(
+ viewDeltaX);
+ var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
+ deltaX, deltaY);
+ this.viewport_.queueDisplayTransformAnimation(animation);
+ },
+
+ /**
+ * Zoom in or out on the timeline by the given scale factor.
+ * @param {Number} scale The scale factor to apply. If <1, zooms out.
+ * @param {boolean} Whether to change the zoom level smoothly.
+ */
+ zoomBy_: function(scale, smooth) {
+ if (scale <= 0) {
+ return;
+ }
- this.storeInitialMouseDownPos_(e);
- this.storeLastMousePos_(e);
+ smooth = !!smooth;
+ var vp = this.viewport_;
+ var pixelRatio = window.devicePixelRatio || 1;
- this.focusElements_();
- },
+ var goalFocalPointXView = this.lastMouseViewPos_.x * pixelRatio;
+ var goalFocalPointXWorld = vp.currentDisplayTransform.xViewToWorld(
+ goalFocalPointXView);
+ if (smooth) {
+ var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
+ goalFocalPointXWorld, goalFocalPointXView,
+ vp.currentDisplayTransform.panY,
+ scale);
+ vp.queueDisplayTransformAnimation(animation);
+ } else {
+ this.displayTransform_.set(vp.currentDisplayTransform);
+ this.displayTransform_.scaleX *= scale;
+ this.displayTransform_.xPanWorldPosToViewPos(
+ goalFocalPointXWorld, goalFocalPointXView, this.viewWidth_);
+ vp.setDisplayTransformImmediately(this.displayTransform_);
+ }
+ },
+
+ /**
+ * Zoom into the current selection.
+ */
+ zoomToSelection: function() {
+ if (!this.brushingStateController.selectionOfInterest.length)
+ return;
+
+ var bounds = this.brushingStateController.selectionOfInterest.bounds;
+ if (!bounds.range)
+ return;
+
+ var worldCenter = bounds.center;
+ var viewCenter = this.modelTrackContainer_.canvas.width / 2;
+ var adjustedWorldRange = bounds.range * 1.25;
+ var newScale = this.modelTrackContainer_.canvas.width /
+ adjustedWorldRange;
+ var zoomInRatio = newScale /
+ this.viewport_.currentDisplayTransform.scaleX;
+
+ var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
+ worldCenter, viewCenter,
+ this.viewport_.currentDisplayTransform.panY,
+ zoomInRatio);
+ this.viewport_.queueDisplayTransformAnimation(animation);
+ },
+
+ /**
+ * Pan the view so the current selection becomes visible.
+ */
+ panToSelection: function() {
+ if (!this.brushingStateController.selectionOfInterest.length)
+ return;
+
+ var bounds = this.brushingStateController.selectionOfInterest.bounds;
+ var worldCenter = bounds.center;
+ var viewWidth = this.viewWidth_;
+
+ var dt = this.viewport_.currentDisplayTransform;
+ if (false && !bounds.range) {
+ if (dt.xWorldToView(bounds.center) < 0 ||
+ dt.xWorldToView(bounds.center) > viewWidth) {
+ this.displayTransform_.set(dt);
+ this.displayTransform_.xPanWorldPosToViewPos(
+ worldCenter, 'center', viewWidth);
+ var deltaX = this.displayTransform_.panX - dt.panX;
+ var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
+ deltaX, 0);
+ this.viewport_.queueDisplayTransformAnimation(animation);
+ }
+ return;
+ }
- onBeginPanScan_: function(e) {
- var vp = this.viewport_;
- this.viewportDisplayTransformAtMouseDown_ =
- vp.currentDisplayTransform.clone();
- this.isPanningAndScanning_ = true;
+ this.displayTransform_.set(dt);
+ this.displayTransform_.xPanWorldBoundsIntoView(
+ bounds.min,
+ bounds.max,
+ viewWidth);
+ var deltaX = this.displayTransform_.panX - dt.panX;
+ var animation = new tr.ui.TimelineDisplayTransformPanAnimation(
+ deltaX, 0);
+ this.viewport_.queueDisplayTransformAnimation(animation);
+ },
+
+ navToPosition: function(uiState, showNavLine) {
+ var location = uiState.location;
+ var scaleX = uiState.scaleX;
+ var track = location.getContainingTrack(this.viewport_);
+
+ var worldCenter = location.xWorld;
+ var viewCenter = this.modelTrackContainer_.canvas.width / 5;
+ var zoomInRatio = scaleX /
+ this.viewport_.currentDisplayTransform.scaleX;
+
+ // Vertically scroll so track is in view.
+ track.scrollIntoViewIfNeeded();
+
+ // Perform zoom and panX animation.
+ var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation(
+ worldCenter, viewCenter,
+ this.viewport_.currentDisplayTransform.panY,
+ zoomInRatio);
+ this.viewport_.queueDisplayTransformAnimation(animation);
+
+ if (!showNavLine)
+ return;
+ // Add an X Marker Annotation at the specified timestamp.
+ if (this.xNavStringMarker_)
+ this.model.removeAnnotation(this.xNavStringMarker_);
+ this.xNavStringMarker_ =
+ new tr.model.XMarkerAnnotation(worldCenter);
+ this.model.addAnnotation(this.xNavStringMarker_);
+ },
+
+ selectPowerSamplesInCurrentTimeRange_: function() {
+ var selectionBounds = this.brushingStateController_.selection.bounds;
+ if (this.model.device.powerSeries && !selectionBounds.empty) {
+ var events = this.model.device.powerSeries.getSamplesWithinRange(
+ selectionBounds.min, selectionBounds.max);
+ var selection = new tr.model.EventSet(events);
+ this.brushingStateController_.changeSelectionFromTimeline(selection);
+ }
+ },
- this.storeInitialInteractionPositionsAndFocus_(e);
- e.preventDefault();
- },
+ setCurrentSelectionAsInterestRange_: function() {
+ var selectionBounds = this.brushingStateController_.selection.bounds;
+ if (selectionBounds.empty) {
+ this.viewport_.interestRange.reset();
+ return;
+ }
- onUpdatePanScan_: function(e) {
- if (!this.isPanningAndScanning_)
- return;
+ if (this.viewport_.interestRange.min === selectionBounds.min &&
+ this.viewport_.interestRange.max === selectionBounds.max)
+ this.viewport_.interestRange.reset();
+ else
+ this.viewport_.interestRange.set(selectionBounds);
+ },
+
+ toggleHighDetails_: function() {
+ this.viewport_.highDetails = !this.viewport_.highDetails;
+ },
+
+ hideDragBox_: function() {
+ this.$.drag_box.style.left = '-1000px';
+ this.$.drag_box.style.top = '-1000px';
+ this.$.drag_box.style.width = 0;
+ this.$.drag_box.style.height = 0;
+ },
+
+ setDragBoxPosition_: function(xStart, yStart, xEnd, yEnd) {
+ var loY = Math.min(yStart, yEnd);
+ var hiY = Math.max(yStart, yEnd);
+ var loX = Math.min(xStart, xEnd);
+ var hiX = Math.max(xStart, xEnd);
+ var modelTrackRect = this.modelTrack_.getBoundingClientRect();
+ var dragRect = {left: loX, top: loY, width: hiX - loX, height: hiY - loY};
+
+ dragRect.right = dragRect.left + dragRect.width;
+ dragRect.bottom = dragRect.top + dragRect.height;
+
+ var modelTrackContainerRect =
+ this.modelTrackContainer_.getBoundingClientRect();
+ var clipRect = {
+ left: modelTrackContainerRect.left,
+ top: modelTrackContainerRect.top,
+ right: modelTrackContainerRect.right,
+ bottom: modelTrackContainerRect.bottom
+ };
+
+ var headingWidth = window.getComputedStyle(
+ Polymer.dom(this).querySelector('tr-ui-heading')).width;
+ var trackTitleWidth = parseInt(headingWidth);
+ clipRect.left = clipRect.left + trackTitleWidth;
+
+ var intersectRect_ = function(r1, r2) {
+ if (r2.left > r1.right || r2.right < r1.left ||
+ r2.top > r1.bottom || r2.bottom < r1.top)
+ return false;
+
+ var results = {};
+ results.left = Math.max(r1.left, r2.left);
+ results.top = Math.max(r1.top, r2.top);
+ results.right = Math.min(r1.right, r2.right);
+ results.bottom = Math.min(r1.bottom, r2.bottom);
+ results.width = results.right - results.left;
+ results.height = results.bottom - results.top;
+ return results;
+ };
+
+ // TODO(dsinclair): intersectRect_ can return false (which should actually
+ // be undefined) but we use finalDragBox without checking the return value
+ // which could potentially blowup. Fix this .....
+ var finalDragBox = intersectRect_(clipRect, dragRect);
+
+ this.$.drag_box.style.left = finalDragBox.left + 'px';
+ this.$.drag_box.style.width = finalDragBox.width + 'px';
+ this.$.drag_box.style.top = finalDragBox.top + 'px';
+ this.$.drag_box.style.height = finalDragBox.height + 'px';
+ this.$.drag_box.style.whiteSpace = 'nowrap';
+
+ var pixelRatio = window.devicePixelRatio || 1;
+ var canv = this.modelTrackContainer_.canvas;
+ var dt = this.viewport_.currentDisplayTransform;
+ var loWX = dt.xViewToWorld(
+ (loX - canv.offsetLeft) * pixelRatio);
+ var hiWX = dt.xViewToWorld(
+ (hiX - canv.offsetLeft) * pixelRatio);
+
+ Polymer.dom(this.$.drag_box).textContent =
+ tr.b.Unit.byName.timeDurationInMs.format(hiWX - loWX);
+
+ var e = new tr.b.Event('selectionChanging');
+ e.loWX = loWX;
+ e.hiWX = hiWX;
+ this.dispatchEvent(e);
+ },
+
+ onGridToggle_: function(left) {
+ var selection = this.brushingStateController_.selection;
+ var tb = left ? selection.bounds.min : selection.bounds.max;
+
+ // Toggle the grid off if the grid is on, the marker position is the same
+ // and the same element is selected (same timebase).
+ if (this.viewport_.gridEnabled &&
+ this.viewport_.gridSide === left &&
+ this.viewport_.gridInitialTimebase === tb) {
+ this.viewport_.gridside = undefined;
+ this.viewport_.gridEnabled = false;
+ this.viewport_.gridInitialTimebase = undefined;
+ return;
+ }
- var viewWidth = this.viewWidth_;
+ // Shift the timebase left until its just left of model_.bounds.min.
+ var numIntervalsSinceStart = Math.ceil((tb - this.model_.bounds.min) /
+ this.viewport_.gridStep_);
+
+ this.viewport_.gridEnabled = true;
+ this.viewport_.gridSide = left;
+ this.viewport_.gridInitialTimebase = tb;
+ this.viewport_.gridTimebase = tb -
+ (numIntervalsSinceStart + 1) * this.viewport_.gridStep_;
+ },
+
+ storeLastMousePos_: function(e) {
+ this.lastMouseViewPos_ = this.extractRelativeMousePosition_(e);
+ },
+
+ storeLastTouchPositions_: function(e) {
+ this.lastTouchViewPositions_ = this.extractRelativeTouchPositions_(e);
+ },
+
+ extractRelativeMousePosition_: function(e) {
+ var canv = this.modelTrackContainer_.canvas;
+ return {
+ x: e.clientX - canv.offsetLeft,
+ y: e.clientY - canv.offsetTop
+ };
+ },
+
+ extractRelativeTouchPositions_: function(e) {
+ var canv = this.modelTrackContainer_.canvas;
+
+ var touches = [];
+ for (var i = 0; i < e.touches.length; ++i) {
+ touches.push({
+ x: e.touches[i].clientX - canv.offsetLeft,
+ y: e.touches[i].clientY - canv.offsetTop
+ });
+ }
+ return touches;
+ },
- var pixelRatio = window.devicePixelRatio || 1;
- var xDeltaView = pixelRatio * (this.lastMouseViewPos_.x -
- this.mouseViewPosAtMouseDown_.x);
+ storeInitialMouseDownPos_: function(e) {
- var yDelta = this.lastMouseViewPos_.y -
- this.mouseViewPosAtMouseDown_.y;
+ var position = this.extractRelativeMousePosition_(e);
- this.displayTransform_.set(this.viewportDisplayTransformAtMouseDown_);
- this.displayTransform_.incrementPanXInViewUnits(xDeltaView);
- this.displayTransform_.panY -= yDelta;
- this.viewport_.setDisplayTransformImmediately(this.displayTransform_);
+ this.mouseViewPosAtMouseDown_.x = position.x;
+ this.mouseViewPosAtMouseDown_.y = position.y;
+ },
- e.preventDefault();
- e.stopPropagation();
+ focusElements_: function() {
+ this.$.hotkey_controller.childRequestsGeneralFocus(this);
+ },
- this.storeLastMousePos_(e);
- },
+ storeInitialInteractionPositionsAndFocus_: function(e) {
- onEndPanScan_: function(e) {
- this.isPanningAndScanning_ = false;
+ this.storeInitialMouseDownPos_(e);
+ this.storeLastMousePos_(e);
- this.storeLastMousePos_(e);
+ this.focusElements_();
+ },
- if (!e.isClick)
- e.preventDefault();
- },
-
- onBeginSelection_: function(e) {
- var canv = this.modelTrackContainer_.canvas;
- var rect = this.modelTrack_.getBoundingClientRect();
- var canvRect = canv.getBoundingClientRect();
-
- var inside = rect &&
- e.clientX >= rect.left &&
- e.clientX < rect.right &&
- e.clientY >= rect.top &&
- e.clientY < rect.bottom &&
- e.clientX >= canvRect.left &&
- e.clientX < canvRect.right;
-
- if (!inside)
- return;
+ onBeginPanScan_: function(e) {
+ var vp = this.viewport_;
+ this.viewportDisplayTransformAtMouseDown_ =
+ vp.currentDisplayTransform.clone();
+ this.isPanningAndScanning_ = true;
- this.dragBeginEvent_ = e;
+ this.storeInitialInteractionPositionsAndFocus_(e);
+ e.preventDefault();
+ },
- this.storeInitialInteractionPositionsAndFocus_(e);
- e.preventDefault();
- },
+ onUpdatePanScan_: function(e) {
+ if (!this.isPanningAndScanning_)
+ return;
- onUpdateSelection_: function(e) {
- if (!this.dragBeginEvent_)
- return;
+ var viewWidth = this.viewWidth_;
- // Update the drag box
- this.dragBoxXStart_ = this.dragBeginEvent_.clientX;
- this.dragBoxXEnd_ = e.clientX;
- this.dragBoxYStart_ = this.dragBeginEvent_.clientY;
- this.dragBoxYEnd_ = e.clientY;
- this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_,
- this.dragBoxXEnd_, this.dragBoxYEnd_);
+ var pixelRatio = window.devicePixelRatio || 1;
+ var xDeltaView = pixelRatio * (this.lastMouseViewPos_.x -
+ this.mouseViewPosAtMouseDown_.x);
- },
+ var yDelta = this.lastMouseViewPos_.y -
+ this.mouseViewPosAtMouseDown_.y;
- onEndSelection_: function(e) {
- e.preventDefault();
+ this.displayTransform_.set(this.viewportDisplayTransformAtMouseDown_);
+ this.displayTransform_.incrementPanXInViewUnits(xDeltaView);
+ this.displayTransform_.panY -= yDelta;
+ this.viewport_.setDisplayTransformImmediately(this.displayTransform_);
- if (!this.dragBeginEvent_)
- return;
+ e.preventDefault();
+ e.stopPropagation();
- // Stop the dragging.
- this.hideDragBox_();
- var eDown = this.dragBeginEvent_;
- this.dragBeginEvent_ = undefined;
-
- // Figure out extents of the drag.
- var loY = Math.min(eDown.clientY, e.clientY);
- var hiY = Math.max(eDown.clientY, e.clientY);
- var loX = Math.min(eDown.clientX, e.clientX);
- var hiX = Math.max(eDown.clientX, e.clientX);
-
- // Convert to worldspace.
- var canv = this.modelTrackContainer_.canvas;
- var worldOffset = canv.getBoundingClientRect().left;
- var loVX = loX - worldOffset;
- var hiVX = hiX - worldOffset;
-
- // Figure out what has been selected.
- var selection = new tr.model.EventSet();
- if (eDown.appendSelection) {
- var previousSelection = this.brushingStateController_.selection;
- if (previousSelection !== undefined)
- selection.addEventSet(previousSelection);
- }
- this.modelTrack_.addIntersectingEventsInRangeToSelection(
- loVX, hiVX, loY, hiY, selection);
+ this.storeLastMousePos_(e);
+ },
- // Activate the new selection.
- this.brushingStateController_.changeSelectionFromTimeline(selection);
- },
+ onEndPanScan_: function(e) {
+ this.isPanningAndScanning_ = false;
- onBeginZoom_: function(e) {
- this.isZooming_ = true;
+ this.storeLastMousePos_(e);
- this.storeInitialInteractionPositionsAndFocus_(e);
+ if (!e.isClick)
e.preventDefault();
- },
-
- onUpdateZoom_: function(e) {
- if (!this.isZooming_)
- return;
- var newPosition = this.extractRelativeMousePosition_(e);
-
- var zoomScaleValue = 1 + (this.lastMouseViewPos_.y -
- newPosition.y) * 0.01;
-
- this.zoomBy_(zoomScaleValue, false);
- this.storeLastMousePos_(e);
- },
-
- onEndZoom_: function(e) {
- this.isZooming_ = false;
-
- if (!e.isClick)
- e.preventDefault();
- },
-
- computeTouchCenter_: function(positions) {
- var xSum = 0;
- var ySum = 0;
- for (var i = 0; i < positions.length; ++i) {
- xSum += positions[i].x;
- ySum += positions[i].y;
- }
- return {
- x: xSum / positions.length,
- y: ySum / positions.length
- };
- },
-
- computeTouchSpan_: function(positions) {
- var xMin = Number.MAX_VALUE;
- var yMin = Number.MAX_VALUE;
- var xMax = Number.MIN_VALUE;
- var yMax = Number.MIN_VALUE;
- for (var i = 0; i < positions.length; ++i) {
- xMin = Math.min(xMin, positions[i].x);
- yMin = Math.min(yMin, positions[i].y);
- xMax = Math.max(xMax, positions[i].x);
- yMax = Math.max(yMax, positions[i].y);
- }
- return Math.sqrt((xMin - xMax) * (xMin - xMax) +
- (yMin - yMax) * (yMin - yMax));
- },
-
- onUpdateTransformForTouch_: function(e) {
- var newPositions = this.extractRelativeTouchPositions_(e);
- var currentPositions = this.lastTouchViewPositions_;
-
- var newCenter = this.computeTouchCenter_(newPositions);
- var currentCenter = this.computeTouchCenter_(currentPositions);
-
- var newSpan = this.computeTouchSpan_(newPositions);
- var currentSpan = this.computeTouchSpan_(currentPositions);
+ },
+
+ onBeginSelection_: function(e) {
+ var canv = this.modelTrackContainer_.canvas;
+ var rect = this.modelTrack_.getBoundingClientRect();
+ var canvRect = canv.getBoundingClientRect();
+
+ var inside = rect &&
+ e.clientX >= rect.left &&
+ e.clientX < rect.right &&
+ e.clientY >= rect.top &&
+ e.clientY < rect.bottom &&
+ e.clientX >= canvRect.left &&
+ e.clientX < canvRect.right;
+
+ if (!inside)
+ return;
+
+ this.dragBeginEvent_ = e;
+
+ this.storeInitialInteractionPositionsAndFocus_(e);
+ e.preventDefault();
+ },
+
+ onUpdateSelection_: function(e) {
+ if (!this.dragBeginEvent_)
+ return;
+
+ // Update the drag box
+ this.dragBoxXStart_ = this.dragBeginEvent_.clientX;
+ this.dragBoxXEnd_ = e.clientX;
+ this.dragBoxYStart_ = this.dragBeginEvent_.clientY;
+ this.dragBoxYEnd_ = e.clientY;
+ this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_,
+ this.dragBoxXEnd_, this.dragBoxYEnd_);
+
+ },
+
+ onEndSelection_: function(e) {
+ e.preventDefault();
+
+ if (!this.dragBeginEvent_)
+ return;
+
+ // Stop the dragging.
+ this.hideDragBox_();
+ var eDown = this.dragBeginEvent_;
+ this.dragBeginEvent_ = undefined;
+
+ // Figure out extents of the drag.
+ var loY = Math.min(eDown.clientY, e.clientY);
+ var hiY = Math.max(eDown.clientY, e.clientY);
+ var loX = Math.min(eDown.clientX, e.clientX);
+ var hiX = Math.max(eDown.clientX, e.clientX);
+
+ // Convert to worldspace.
+ var canv = this.modelTrackContainer_.canvas;
+ var worldOffset = canv.getBoundingClientRect().left;
+ var loVX = loX - worldOffset;
+ var hiVX = hiX - worldOffset;
+
+ // Figure out what has been selected.
+ var selection = new tr.model.EventSet();
+ if (eDown.appendSelection) {
+ var previousSelection = this.brushingStateController_.selection;
+ if (previousSelection !== undefined)
+ selection.addEventSet(previousSelection);
+ }
+ this.modelTrack_.addIntersectingEventsInRangeToSelection(
+ loVX, hiVX, loY, hiY, selection);
- var vp = this.viewport_;
- var viewWidth = this.viewWidth_;
- var pixelRatio = window.devicePixelRatio || 1;
+ // Activate the new selection.
+ this.brushingStateController_.changeSelectionFromTimeline(selection);
+ },
- var xDelta = pixelRatio * (newCenter.x - currentCenter.x);
- var yDelta = newCenter.y - currentCenter.y;
- var zoomScaleValue = currentSpan > 10 ? newSpan / currentSpan : 1;
+ onBeginZoom_: function(e) {
+ this.isZooming_ = true;
- var viewFocus = pixelRatio * newCenter.x;
- var worldFocus = vp.currentDisplayTransform.xViewToWorld(viewFocus);
+ this.storeInitialInteractionPositionsAndFocus_(e);
+ e.preventDefault();
+ },
- this.displayTransform_.set(vp.currentDisplayTransform);
- this.displayTransform_.scaleX *= zoomScaleValue;
- this.displayTransform_.xPanWorldPosToViewPos(
- worldFocus, viewFocus, viewWidth);
- this.displayTransform_.incrementPanXInViewUnits(xDelta);
- this.displayTransform_.panY -= yDelta;
- vp.setDisplayTransformImmediately(this.displayTransform_);
- this.storeLastTouchPositions_(e);
- },
+ onUpdateZoom_: function(e) {
+ if (!this.isZooming_)
+ return;
+ var newPosition = this.extractRelativeMousePosition_(e);
- initHintText_: function() {
- this.$.hint_text.style.display = 'none';
+ var zoomScaleValue = 1 + (this.lastMouseViewPos_.y -
+ newPosition.y) * 0.01;
- this.pendingHintTextClearTimeout_ = undefined;
- },
+ this.zoomBy_(zoomScaleValue, false);
+ this.storeLastMousePos_(e);
+ },
- showHintText_: function(text) {
- if (this.pendingHintTextClearTimeout_) {
- window.clearTimeout(this.pendingHintTextClearTimeout_);
- this.pendingHintTextClearTimeout_ = undefined;
- }
- this.pendingHintTextClearTimeout_ = setTimeout(
- this.hideHintText_.bind(this), 1000);
- this.$.hint_text.textContent = text;
- this.$.hint_text.style.display = '';
- },
+ onEndZoom_: function(e) {
+ this.isZooming_ = false;
- hideHintText_: function() {
+ if (!e.isClick)
+ e.preventDefault();
+ },
+
+ computeTouchCenter_: function(positions) {
+ var xSum = 0;
+ var ySum = 0;
+ for (var i = 0; i < positions.length; ++i) {
+ xSum += positions[i].x;
+ ySum += positions[i].y;
+ }
+ return {
+ x: xSum / positions.length,
+ y: ySum / positions.length
+ };
+ },
+
+ computeTouchSpan_: function(positions) {
+ var xMin = Number.MAX_VALUE;
+ var yMin = Number.MAX_VALUE;
+ var xMax = Number.MIN_VALUE;
+ var yMax = Number.MIN_VALUE;
+ for (var i = 0; i < positions.length; ++i) {
+ xMin = Math.min(xMin, positions[i].x);
+ yMin = Math.min(yMin, positions[i].y);
+ xMax = Math.max(xMax, positions[i].x);
+ yMax = Math.max(yMax, positions[i].y);
+ }
+ return Math.sqrt((xMin - xMax) * (xMin - xMax) +
+ (yMin - yMax) * (yMin - yMax));
+ },
+
+ onUpdateTransformForTouch_: function(e) {
+ var newPositions = this.extractRelativeTouchPositions_(e);
+ var currentPositions = this.lastTouchViewPositions_;
+
+ var newCenter = this.computeTouchCenter_(newPositions);
+ var currentCenter = this.computeTouchCenter_(currentPositions);
+
+ var newSpan = this.computeTouchSpan_(newPositions);
+ var currentSpan = this.computeTouchSpan_(currentPositions);
+
+ var vp = this.viewport_;
+ var viewWidth = this.viewWidth_;
+ var pixelRatio = window.devicePixelRatio || 1;
+
+ var xDelta = pixelRatio * (newCenter.x - currentCenter.x);
+ var yDelta = newCenter.y - currentCenter.y;
+ var zoomScaleValue = currentSpan > 10 ? newSpan / currentSpan : 1;
+
+ var viewFocus = pixelRatio * newCenter.x;
+ var worldFocus = vp.currentDisplayTransform.xViewToWorld(viewFocus);
+
+ this.displayTransform_.set(vp.currentDisplayTransform);
+ this.displayTransform_.scaleX *= zoomScaleValue;
+ this.displayTransform_.xPanWorldPosToViewPos(
+ worldFocus, viewFocus, viewWidth);
+ this.displayTransform_.incrementPanXInViewUnits(xDelta);
+ this.displayTransform_.panY -= yDelta;
+ vp.setDisplayTransformImmediately(this.displayTransform_);
+ this.storeLastTouchPositions_(e);
+ },
+
+ initHintText_: function() {
+ this.$.hint_text.style.display = 'none';
+
+ this.pendingHintTextClearTimeout_ = undefined;
+ },
+
+ showHintText_: function(text) {
+ if (this.pendingHintTextClearTimeout_) {
+ window.clearTimeout(this.pendingHintTextClearTimeout_);
this.pendingHintTextClearTimeout_ = undefined;
- this.$.hint_text.style.display = 'none';
}
- });
- </script>
-</polymer-element>
+ this.pendingHintTextClearTimeout_ = setTimeout(
+ this.hideHintText_.bind(this), 1000);
+ Polymer.dom(this.$.hint_text).textContent = text;
+ this.$.hint_text.style.display = '';
+ },
+
+ hideHintText_: function() {
+ this.pendingHintTextClearTimeout_ = undefined;
+ this.$.hint_text.style.display = 'none';
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html
index 70c00ec74d0..3c026b86718 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html
@@ -20,15 +20,15 @@ tr.b.unittest.testSuite(function() {
var Task = tr.b.Task;
test('instantiate', function() {
- var num_threads = 500;
+ var numThreads = 500;
var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
var p100 = model.getOrCreateProcess(100);
- for (var i = 0; i < num_threads; i++) {
+ for (var i = 0; i < numThreads; i++) {
var t = p100.getOrCreateThread(101 + i);
- if (i % 2 == 0) {
+ if (i % 2 === 0) {
t.sliceGroup.beginSlice('cat', 'a', 100);
t.sliceGroup.endSlice(110);
} else {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html
index e6dc34ab422..88a9419e731 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html
@@ -29,7 +29,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/timeline_view_metadata_overlay.html">
<link rel="import" href="/tracing/value/ui/preferred_display_unit.html">
-<polymer-element name='tr-ui-timeline-view'>
+<dom-module id='tr-ui-timeline-view'>
<template>
<style>
:host {
@@ -133,398 +133,409 @@ found in the LICENSE file.
<tr-v-ui-preferred-display-unit id="display_unit">
</tr-v-ui-preferred-display-unit>
</template>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-timeline-view',
+
+ attached: function() {
+ this.async(function() {
+ this.trackViewContainer_ = Polymer.dom(this).querySelector(
+ '#track_view_container');
+ if (!this.trackViewContainer_)
+ console.error('missing trackviewContainer');
+ });
+ },
+
+ ready: function() {
+ this.tabIndex = 0; // Let the timeline able to receive key events.
+
+ this.titleEl_ = this.$.title;
+ this.leftControlsEl_ = this.$.left_controls;
+ this.rightControlsEl_ = this.$.right_controls;
+ this.collapsingControlsEl_ = this.$.collapsing_controls;
+ this.sidePanelContainer_ = this.$.side_panel_container;
+
+ this.brushingStateController_ = new tr.c.BrushingStateController(this);
+
+ this.findCtl_ = this.$.view_find_control;
+ this.findCtl_.controller = new tr.ui.FindController(
+ this.brushingStateController_);
+
+ this.scriptingCtl_ = document.createElement('tr-ui-scripting-control');
+ this.scriptingCtl_.controller = new tr.c.ScriptingController(
+ this.brushingStateController_);
+
+ this.sidePanelContainer_.brushingStateController =
+ this.brushingStateController_;
+
+ if (window.tr.metrics && window.tr.metrics.sh &&
+ window.tr.metrics.sh.SystemHealthMetric) {
+ this.railScoreSpan_ = document.createElement(
+ 'tr-metrics-ui-sh-system-health-span');
+ Polymer.dom(this.rightControls).appendChild(this.railScoreSpan_);
+ } else {
+ this.railScoreSpan_ = undefined;
+ }
- <script>
- 'use strict';
+ this.optionsDropdown_ = this.$.view_options_dropdown;
+ Polymer.dom(this.optionsDropdown_.iconElement).textContent = 'View Options';
+
+ this.showFlowEvents_ = false;
+ Polymer.dom(this.optionsDropdown_).appendChild(tr.ui.b.createCheckBox(
+ this, 'showFlowEvents',
+ 'tr.ui.TimelineView.showFlowEvents', false,
+ 'Flow events'));
+ this.highlightVSync_ = false;
+ this.highlightVSyncCheckbox_ = tr.ui.b.createCheckBox(
+ this, 'highlightVSync',
+ 'tr.ui.TimelineView.highlightVSync', false,
+ 'Highlight VSync');
+ Polymer.dom(this.optionsDropdown_).appendChild(
+ this.highlightVSyncCheckbox_);
+
+ this.initMetadataButton_();
+ this.initConsoleButton_();
+ this.initHelpButton_();
+
+ Polymer.dom(this.collapsingControls).appendChild(this.scriptingCtl_);
+
+ this.dragEl_ = this.$.drag_handle;
+
+ this.analysisEl_ = this.$.analysis;
+ this.analysisEl_.brushingStateController = this.brushingStateController_;
+
+ this.addEventListener(
+ 'requestSelectionChange',
+ function(e) {
+ var sc = this.brushingStateController_;
+ sc.changeSelectionFromRequestSelectionChangeEvent(e.selection);
+ }.bind(this));
+
+ // Bookkeeping.
+ this.onViewportChanged_ = this.onViewportChanged_.bind(this);
+ this.bindKeyListeners_();
+
+ this.dragEl_.target = this.analysisEl_;
+ },
+
+ get globalMode() {
+ return this.hotkeyController.globalMode;
+ },
+
+ set globalMode(globalMode) {
+ globalMode = !!globalMode;
+ this.brushingStateController_.historyEnabled = globalMode;
+ this.hotkeyController.globalMode = globalMode;
+ },
+
+ get hotkeyController() {
+ return this.$.hkc;
+ },
+
+ updateDocumentFavicon: function() {
+ var hue;
+ if (!this.model)
+ hue = 'blue';
+ else
+ hue = this.model.faviconHue;
+
+ var faviconData = tr.ui.b.FaviconsByHue[hue];
+ if (faviconData === undefined)
+ faviconData = tr.ui.b.FaviconsByHue['blue'];
+
+ // Find link if its there
+ var link = Polymer.dom(document.head).querySelector(
+ 'link[rel="shortcut icon"]');
+ if (!link) {
+ link = document.createElement('link');
+ link.rel = 'shortcut icon';
+ Polymer.dom(document.head).appendChild(link);
+ }
+ link.href = faviconData;
+ },
+
+ get showFlowEvents() {
+ return this.showFlowEvents_;
+ },
+
+ set showFlowEvents(showFlowEvents) {
+ this.showFlowEvents_ = showFlowEvents;
+ if (!this.trackView_)
+ return;
+ this.trackView_.viewport.showFlowEvents = showFlowEvents;
+ },
+
+ get highlightVSync() {
+ return this.highlightVSync_;
+ },
+
+ set highlightVSync(highlightVSync) {
+ this.highlightVSync_ = highlightVSync;
+ if (!this.trackView_)
+ return;
+ this.trackView_.viewport.highlightVSync = highlightVSync;
+ },
+
+ initHelpButton_: function() {
+ var helpButtonEl = this.$.view_help_button;
+
+ var dlg = new tr.ui.b.Overlay();
+ dlg.title = 'Chrome Tracing Help';
+ dlg.visible = false;
+ dlg.appendChild(
+ document.createElement('tr-ui-timeline-view-help-overlay'));
+
+ function onClick(e) {
+ dlg.visible = !dlg.visible;
+ // Stop event so it doesn't trigger new click listener on document.
+ e.stopPropagation();
+ }
- Polymer({
- ready: function() {
- this.tabIndex = 0; // Let the timeline able to receive key events.
+ helpButtonEl.addEventListener('click', onClick.bind(this));
+ },
- this.titleEl_ = this.$.title;
- this.leftControlsEl_ = this.$.left_controls;
- this.rightControlsEl_ = this.$.right_controls;
- this.collapsingControlsEl_ = this.$.collapsing_controls;
- this.sidePanelContainer_ = this.$.side_panel_container;
+ initConsoleButton_: function() {
+ var toggleEl = this.$.view_console_button;
- this.brushingStateController_ = new tr.c.BrushingStateController(this);
+ function onClick(e) {
+ this.scriptingCtl_.toggleVisibility();
+ e.stopPropagation();
+ return false;
+ }
+ toggleEl.addEventListener('click', onClick.bind(this));
+ },
- this.findCtl_ = this.$.view_find_control;
- this.findCtl_.controller = new tr.ui.FindController(
- this.brushingStateController_);
+ initMetadataButton_: function() {
+ var showEl = this.$.view_metadata_button;
- this.scriptingCtl_ = document.createElement('tr-ui-scripting-control');
- this.scriptingCtl_.controller = new tr.c.ScriptingController(
- this.brushingStateController_);
+ function onClick(e) {
+ var dlg = new tr.ui.b.Overlay();
+ dlg.title = 'Metadata for trace';
- this.sidePanelContainer_.brushingStateController =
- this.brushingStateController_;
+ var metadataOverlay = document.createElement(
+ 'tr-ui-timeline-view-metadata-overlay');
+ metadataOverlay.metadata = this.model.metadata;
- if (window.tr.metrics && window.tr.metrics.sh &&
- window.tr.metrics.sh.systemHealthMetric) {
- this.railScoreSpan_ = document.createElement(
- 'tr-metrics-ui-sh-system-health-span');
- this.rightControls.appendChild(this.railScoreSpan_);
- } else {
- this.railScoreSpan_ = undefined;
- }
+ Polymer.dom(dlg).appendChild(metadataOverlay);
+ dlg.visible = true;
- this.optionsDropdown_ = this.$.view_options_dropdown;
- this.optionsDropdown_.iconElement.textContent = 'View Options';
-
- this.showFlowEvents_ = false;
- this.optionsDropdown_.appendChild(tr.ui.b.createCheckBox(
- this, 'showFlowEvents',
- 'tr.ui.TimelineView.showFlowEvents', false,
- 'Flow events'));
- this.highlightVSync_ = false;
- this.highlightVSyncCheckbox_ = tr.ui.b.createCheckBox(
- this, 'highlightVSync',
- 'tr.ui.TimelineView.highlightVSync', false,
- 'Highlight VSync');
- this.optionsDropdown_.appendChild(this.highlightVSyncCheckbox_);
-
- this.initMetadataButton_();
- this.initConsoleButton_();
- this.initHelpButton_();
-
- this.collapsingControls.appendChild(this.scriptingCtl_);
-
- this.dragEl_ = this.$.drag_handle;
-
- this.analysisEl_ = this.$.analysis;
- this.analysisEl_.brushingStateController = this.brushingStateController_;
-
- this.addEventListener(
- 'requestSelectionChange',
- function(e) {
- var sc = this.brushingStateController_;
- sc.changeSelectionFromRequestSelectionChangeEvent(e.selection);
- }.bind(this));
-
- // Bookkeeping.
- this.onViewportChanged_ = this.onViewportChanged_.bind(this);
- this.bindKeyListeners_();
-
- this.dragEl_.target = this.analysisEl_;
- },
-
- domReady: function() {
- this.trackViewContainer_ = this.querySelector('#track_view_container');
- },
-
- get globalMode() {
- return this.hotkeyController.globalMode;
- },
-
- set globalMode(globalMode) {
- globalMode = !!globalMode;
- this.brushingStateController_.historyEnabled = globalMode;
- this.hotkeyController.globalMode = globalMode;
- },
-
- get hotkeyController() {
- return this.$.hkc;
- },
-
- updateDocumentFavicon: function() {
- var hue;
- if (!this.model)
- hue = 'blue';
- else
- hue = this.model.faviconHue;
-
- var faviconData = tr.ui.b.FaviconsByHue[hue];
- if (faviconData === undefined)
- faviconData = tr.ui.b.FaviconsByHue['blue'];
-
- // Find link if its there
- var link = document.head.querySelector('link[rel="shortcut icon"]');
- if (!link) {
- link = document.createElement('link');
- link.rel = 'shortcut icon';
- document.head.appendChild(link);
- }
- link.href = faviconData;
- },
-
- get showFlowEvents() {
- return this.showFlowEvents_;
- },
-
- set showFlowEvents(showFlowEvents) {
- this.showFlowEvents_ = showFlowEvents;
- if (!this.trackView_)
- return;
- this.trackView_.viewport.showFlowEvents = showFlowEvents;
- },
-
- get highlightVSync() {
- return this.highlightVSync_;
- },
-
- set highlightVSync(highlightVSync) {
- this.highlightVSync_ = highlightVSync;
- if (!this.trackView_)
- return;
- this.trackView_.viewport.highlightVSync = highlightVSync;
- },
-
- initHelpButton_: function() {
- var helpButtonEl = this.$.view_help_button;
-
- function onClick(e) {
- var dlg = new tr.ui.b.Overlay();
- dlg.title = 'Chrome Tracing Help';
- dlg.appendChild(
- document.createElement('tr-ui-timeline-view-help-overlay'));
- dlg.visible = true;
-
- // Stop event so it doesn't trigger new click listener on document.
- e.stopPropagation();
+ e.stopPropagation();
+ return false;
+ }
+ showEl.addEventListener('click', onClick.bind(this));
+
+ this.updateMetadataButtonVisibility_();
+ },
+
+ updateMetadataButtonVisibility_: function() {
+ var showEl = this.$.view_metadata_button;
+ showEl.style.display =
+ (this.model && this.model.metadata.length) ? '' : 'none';
+ },
+
+ get leftControls() {
+ return this.leftControlsEl_;
+ },
+
+ get rightControls() {
+ return this.rightControlsEl_;
+ },
+
+ get collapsingControls() {
+ return this.collapsingControlsEl_;
+ },
+
+ get viewTitle() {
+ return Polymer.dom(this.titleEl_).textContent.substring(
+ Polymer.dom(this.titleEl_).textContent.length - 2);
+ },
+
+ set viewTitle(text) {
+ if (text === undefined) {
+ Polymer.dom(this.titleEl_).textContent = '';
+ this.titleEl_.hidden = true;
+ return;
+ }
+ this.titleEl_.hidden = false;
+ Polymer.dom(this.titleEl_).textContent = text;
+ },
+
+ get model() {
+ if (this.trackView_)
+ return this.trackView_.model;
+ return undefined;
+ },
+
+ set model(model) {
+ var modelInstanceChanged = model !== this.model;
+ var modelValid = model && !model.bounds.isEmpty;
+
+ var importWarningsEl = Polymer.dom(this.root).querySelector(
+ '#import-warnings');
+ Polymer.dom(importWarningsEl).textContent = '';
+
+ // Remove old trackView if the model has completely changed.
+ if (modelInstanceChanged) {
+ if (this.railScoreSpan_)
+ this.railScoreSpan_.model = undefined;
+ Polymer.dom(this.trackViewContainer_).textContent = '';
+ if (this.trackView_) {
+ this.trackView_.viewport.removeEventListener(
+ 'change', this.onViewportChanged_);
+ this.trackView_.brushingStateController = undefined;
+ this.trackView_.detach();
+ this.trackView_ = undefined;
}
- helpButtonEl.addEventListener('click', onClick.bind(this));
- },
-
- initConsoleButton_: function() {
- var toggleEl = this.$.view_console_button;
+ this.brushingStateController_.modelWillChange();
+ }
- function onClick(e) {
- this.scriptingCtl_.toggleVisibility();
- e.stopPropagation();
- return false;
- }
- toggleEl.addEventListener('click', onClick.bind(this));
- },
+ // Create new trackView if needed.
+ if (modelValid && !this.trackView_) {
+ this.trackView_ = document.createElement('tr-ui-timeline-track-view');
+ this.trackView_.timelineView = this;
- initMetadataButton_: function() {
- var showEl = this.$.view_metadata_button;
+ this.trackView.brushingStateController = this.brushingStateController_;
- function onClick(e) {
- var dlg = new tr.ui.b.Overlay();
- dlg.title = 'Metadata for trace';
+ Polymer.dom(this.trackViewContainer_).appendChild(this.trackView_);
+ this.trackView_.viewport.addEventListener(
+ 'change', this.onViewportChanged_);
+ }
- var metadataOverlay = document.createElement(
- 'tr-ui-timeline-view-metadata-overlay');
- metadataOverlay.metadata = this.model.metadata;
+ // Set the model.
+ if (modelValid) {
+ this.trackView_.model = model;
+ this.trackView_.viewport.showFlowEvents = this.showFlowEvents;
+ this.trackView_.viewport.highlightVSync = this.highlightVSync;
+ if (this.railScoreSpan_)
+ this.railScoreSpan_.model = model;
- dlg.appendChild(metadataOverlay);
- dlg.visible = true;
+ this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit;
+ }
- e.stopPropagation();
- return false;
- }
- showEl.addEventListener('click', onClick.bind(this));
+ if (model) {
+ model.importWarningsThatShouldBeShownToUser.forEach(
+ function(importWarning) {
+ importWarningsEl.addMessage(
+ 'Import Warning: ' + importWarning.type + ': ' +
+ importWarning.message);
+ }, this);
+ }
+ // Do things that are selection specific
+ if (modelInstanceChanged) {
this.updateMetadataButtonVisibility_();
- },
-
- updateMetadataButtonVisibility_: function() {
- var showEl = this.$.view_metadata_button;
- showEl.style.display =
- (this.model && this.model.metadata.length) ? '' : 'none';
- },
-
- get leftControls() {
- return this.leftControlsEl_;
- },
-
- get rightControls() {
- return this.rightControlsEl_;
- },
-
- get collapsingControls() {
- return this.collapsingControlsEl_;
- },
-
- get viewTitle() {
- return this.titleEl_.textContent.substring(
- this.titleEl_.textContent.length - 2);
- },
-
- set viewTitle(text) {
- if (text === undefined) {
- this.titleEl_.textContent = '';
- this.titleEl_.hidden = true;
- return;
- }
- this.titleEl_.hidden = false;
- this.titleEl_.textContent = text;
- },
-
- get model() {
- if (this.trackView_)
- return this.trackView_.model;
- return undefined;
- },
-
- set model(model) {
- var modelInstanceChanged = model != this.model;
- var modelValid = model && !model.bounds.isEmpty;
-
- var importWarningsEl = this.shadowRoot.querySelector('#import-warnings');
- importWarningsEl.textContent = '';
-
- // Remove old trackView if the model has completely changed.
- if (modelInstanceChanged) {
- if (this.railScoreSpan_)
- this.railScoreSpan_.model = undefined;
- this.trackViewContainer_.textContent = '';
- if (this.trackView_) {
- this.trackView_.viewport.removeEventListener(
- 'change', this.onViewportChanged_);
- this.trackView_.brushingStateController = undefined;
- this.trackView_.detach();
- this.trackView_ = undefined;
- }
- this.brushingStateController_.modelWillChange();
- }
-
- // Create new trackView if needed.
- if (modelValid && !this.trackView_) {
- this.trackView_ = document.createElement('tr-ui-timeline-track-view');
- this.trackView_.timelineView = this;
-
- this.trackView.brushingStateController = this.brushingStateController_;
-
- this.trackViewContainer_.appendChild(this.trackView_);
- this.trackView_.viewport.addEventListener(
- 'change', this.onViewportChanged_);
- }
-
- // Set the model.
- if (modelValid) {
- this.trackView_.model = model;
- this.trackView_.viewport.showFlowEvents = this.showFlowEvents;
- this.trackView_.viewport.highlightVSync = this.highlightVSync;
- if (this.railScoreSpan_)
- this.railScoreSpan_.model = model;
-
- this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit;
+ this.brushingStateController_.modelDidChange();
+ this.onViewportChanged_();
+ }
+ },
+
+ get brushingStateController() {
+ return this.brushingStateController_;
+ },
+
+ get trackView() {
+ return this.trackView_;
+ },
+
+ get settings() {
+ if (!this.settings_)
+ this.settings_ = new tr.b.Settings();
+ return this.settings_;
+ },
+
+ /**
+ * Deprecated. Kept around because third_party code occasionally calls
+ * this to set up embedding.
+ */
+ set focusElement(value) {
+ throw new Error('This is deprecated. Please set globalMode to true.');
+ },
+
+ bindKeyListeners_: function() {
+ var hkc = this.hotkeyController;
+
+ // Shortcuts that *can* steal focus from the console and the filter text
+ // box.
+ hkc.addHotKey(new tr.ui.b.HotKey({
+ eventType: 'keypress',
+ keyCode: '`'.charCodeAt(0),
+ useCapture: true,
+ thisArg: this,
+ callback: function(e) {
+ this.scriptingCtl_.toggleVisibility();
+ if (!this.scriptingCtl_.hasFocus)
+ this.focus();
+ e.stopPropagation();
}
-
- if (model) {
- model.importWarningsThatShouldBeShownToUser.forEach(
- function(importWarning) {
- importWarningsEl.addMessage(
- 'Import Warning: ' + importWarning.type + ': ' +
- importWarning.message);
- }, this);
+ }));
+
+ // Shortcuts that *can* steal focus from the filter text box.
+ hkc.addHotKey(new tr.ui.b.HotKey({
+ eventType: 'keypress',
+ keyCode: '/'.charCodeAt(0),
+ useCapture: true,
+ thisArg: this,
+ callback: function(e) {
+ if (this.scriptingCtl_.hasFocus)
+ return;
+ if (this.findCtl_.hasFocus)
+ this.focus();
+ else
+ this.findCtl_.focus();
+ e.preventDefault();
+ e.stopPropagation();
}
-
- // Do things that are selection specific
- if (modelInstanceChanged) {
- this.updateMetadataButtonVisibility_();
- this.brushingStateController_.modelDidChange();
- this.onViewportChanged_();
+ }));
+
+ // Shortcuts that *can't* steal focus.
+ hkc.addHotKey(new tr.ui.b.HotKey({
+ eventType: 'keypress',
+ keyCode: '?'.charCodeAt(0),
+ useCapture: false,
+ thisArg: this,
+ callback: function(e) {
+ this.$.view_help_button.click();
+ e.stopPropagation();
}
- },
-
- get brushingStateController() {
- return this.brushingStateController_;
- },
-
- get trackView() {
- return this.trackView_;
- },
-
- get settings() {
- if (!this.settings_)
- this.settings_ = new tr.b.Settings();
- return this.settings_;
- },
-
- /**
- * Deprecated. Kept around because third_party code occasionally calls
- * this to set up embedding.
- */
- set focusElement(value) {
- throw new Error('This is deprecated. Please set globalMode to true.');
- },
-
- bindKeyListeners_: function() {
- var hkc = this.hotkeyController;
-
- // Shortcuts that *can* steal focus from the console and the filter text
- // box.
- hkc.addHotKey(new tr.ui.b.HotKey({
- eventType: 'keypress',
- keyCode: '`'.charCodeAt(0),
- useCapture: true,
- thisArg: this,
- callback: function(e) {
- this.scriptingCtl_.toggleVisibility();
- if (!this.scriptingCtl_.hasFocus)
- this.focus();
- e.stopPropagation();
- }
- }));
-
- // Shortcuts that *can* steal focus from the filter text box.
- hkc.addHotKey(new tr.ui.b.HotKey({
- eventType: 'keypress',
- keyCode: '/'.charCodeAt(0),
- useCapture: true,
- thisArg: this,
- callback: function(e) {
- if (this.scriptingCtl_.hasFocus)
- return;
- if (this.findCtl_.hasFocus)
- this.focus();
- else
- this.findCtl_.focus();
- e.preventDefault();
- e.stopPropagation();
- }
- }));
-
- // Shortcuts that *can't* steal focus.
- hkc.addHotKey(new tr.ui.b.HotKey({
- eventType: 'keypress',
- keyCode: '?'.charCodeAt(0),
- useCapture: false,
- thisArg: this,
- callback: function(e) {
- this.$.view_help_button.click();
- e.stopPropagation();
- }
- }));
-
- hkc.addHotKey(new tr.ui.b.HotKey({
- eventType: 'keypress',
- keyCode: 'v'.charCodeAt(0),
- useCapture: false,
- thisArg: this,
- callback: function(e) {
- this.toggleHighlightVSync_();
- e.stopPropagation();
- }
- }));
- },
-
- onViewportChanged_: function(e) {
- var spc = this.sidePanelContainer_;
- if (!this.trackView_) {
- spc.rangeOfInterest.reset();
- return;
+ }));
+
+ hkc.addHotKey(new tr.ui.b.HotKey({
+ eventType: 'keypress',
+ keyCode: 'v'.charCodeAt(0),
+ useCapture: false,
+ thisArg: this,
+ callback: function(e) {
+ this.toggleHighlightVSync_();
+ e.stopPropagation();
}
+ }));
+ },
+
+ onViewportChanged_: function(e) {
+ var spc = this.sidePanelContainer_;
+ if (!this.trackView_) {
+ spc.rangeOfInterest.reset();
+ return;
+ }
- var vr = this.trackView_.viewport.interestRange.asRangeObject();
- if (!spc.rangeOfInterest.equals(vr))
- spc.rangeOfInterest = vr;
+ var vr = this.trackView_.viewport.interestRange.asRangeObject();
+ if (!spc.rangeOfInterest.equals(vr))
+ spc.rangeOfInterest = vr;
- if (this.railScoreSpan_ && this.model)
- this.railScoreSpan_.model = this.model;
- },
+ if (this.railScoreSpan_ && this.model)
+ this.railScoreSpan_.model = this.model;
+ },
- toggleHighlightVSync_: function() {
- this.highlightVSyncCheckbox_.checked =
- !this.highlightVSyncCheckbox_.checked;
- },
+ toggleHighlightVSync_: function() {
+ this.highlightVSyncCheckbox_.checked =
+ !this.highlightVSyncCheckbox_.checked;
+ },
- setFindCtlText: function(string) {
- this.findCtl_.setText(string);
- }
- });
- </script>
-</polymer-element>
+ setFindCtlText: function(string) {
+ this.findCtl_.setText(string);
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html
index 1cde57bd69c..8e35cf3ccca 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/mouse_mode_icon.html">
<link rel="import" href="/tracing/ui/base/overlay.html">
-<polymer-element name="tr-ui-timeline-view-help-overlay">
+<dom-module id='tr-ui-timeline-view-help-overlay'>
<template>
<style>
:host {
@@ -102,7 +102,7 @@ found in the LICENSE file.
</div>
<h3>
- <tr-ui-b-mouse-mode-icon modeName="SELECTION"></tr-ui-b-mouse-mode-icon>
+ <tr-ui-b-mouse-mode-icon mode-name="SELECTION"></tr-ui-b-mouse-mode-icon>
Select mode
</h3>
<div class='pair'>
@@ -121,7 +121,7 @@ found in the LICENSE file.
</div>
<h3>
- <tr-ui-b-mouse-mode-icon modeName="PANSCAN"></tr-ui-b-mouse-mode-icon>
+ <tr-ui-b-mouse-mode-icon mode-name="PANSCAN"></tr-ui-b-mouse-mode-icon>
Pan mode
</h3>
<div class='pair'>
@@ -130,7 +130,7 @@ found in the LICENSE file.
</div>
<h3>
- <tr-ui-b-mouse-mode-icon modeName="ZOOM"></tr-ui-b-mouse-mode-icon>
+ <tr-ui-b-mouse-mode-icon mode-name="ZOOM"></tr-ui-b-mouse-mode-icon>
Zoom mode
</h3>
<div class='pair'>
@@ -139,7 +139,7 @@ found in the LICENSE file.
</div>
<h3>
- <tr-ui-b-mouse-mode-icon modeName="TIMING"></tr-ui-b-mouse-mode-icon>
+ <tr-ui-b-mouse-mode-icon mode-name="TIMING"></tr-ui-b-mouse-mode-icon>
Timing mode
</h3>
<div class='pair'>
@@ -226,18 +226,19 @@ found in the LICENSE file.
</div>
</div>
</template>
-
- <script>
- 'use strict';
-
- Polymer('tr-ui-timeline-view-help-overlay', {
- ready: function() {
- var mod = tr.isMac ? 'cmd ' : 'ctrl';
- var spans = this.shadowRoot.querySelectorAll('span.mod');
- for (var i = 0; i < spans.length; i++) {
- spans[i].textContent = mod;
- }
- }
- });
- </script>
-</polymer-element>
+</dom-module>
+<script>
+'use strict';
+
+Polymer({
+ is: 'tr-ui-timeline-view-help-overlay',
+
+ ready: function() {
+ var mod = tr.isMac ? 'cmd ' : 'ctrl';
+ var spans = Polymer.dom(this.root).querySelectorAll(
+ 'span.mod');
+ for (var i = 0; i < spans.length; i++)
+ Polymer.dom(spans[i]).textContent = mod;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html
index 0727958cfbe..2ea3ea2453f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html
@@ -9,7 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/overlay.html">
<link rel="import" href="/tracing/value/ui/generic_table_view.html">
-<polymer-element name="tr-ui-timeline-view-metadata-overlay">
+<dom-module id='tr-ui-timeline-view-metadata-overlay'>
<template>
<style>
:host {
@@ -20,23 +20,24 @@ found in the LICENSE file.
</style>
<tr-v-ui-generic-table-view id="gtv"></tr-v-ui-generic-table-view>
</template>
+</dom-module>
+<script>
+'use strict';
- <script>
- 'use strict';
+Polymer({
+ is: 'tr-ui-timeline-view-metadata-overlay',
- Polymer('tr-ui-timeline-view-metadata-overlay', {
- created: function() {
- this.metadata_ = undefined;
- },
+ created: function() {
+ this.metadata_ = undefined;
+ },
- get metadata() {
- return this.metadata_;
- },
+ get metadata() {
+ return this.metadata_;
+ },
- set metadata(metadata) {
- this.metadata_ = metadata;
- this.$.gtv.items = this.metadata_;
- }
- });
- </script>
-</polymer-element>
+ set metadata(metadata) {
+ this.metadata_ = metadata;
+ this.$.gtv.items = this.metadata_;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html
index e3e2e060985..c87b325f17f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html
@@ -22,7 +22,7 @@ tr.b.unittest.testSuite(function() {
container.id = 'track_view_container';
var view = document.createElement('tr-ui-timeline-view');
- view.appendChild(container);
+ Polymer.dom(view).appendChild(container);
view.trackViewContainer_ = container;
return view;
}
@@ -32,7 +32,7 @@ tr.b.unittest.testSuite(function() {
var withMetadata = opt_withMetadata !== undefined ?
opt_withMetadata : true;
- var num_tests = 50;
+ var numTests = 50;
var testIndex = 0;
var startTime = 0;
@@ -41,19 +41,19 @@ tr.b.unittest.testSuite(function() {
io.showImportWarnings = false;
model.importOptions = io;
- for (testIndex = 0; testIndex < num_tests; ++testIndex) {
+ for (testIndex = 0; testIndex < numTests; ++testIndex) {
var process = model.getOrCreateProcess(10000 + testIndex);
- if (testIndex % 2 == 0) {
+ if (testIndex % 2 === 0) {
var thread = process.getOrCreateThread('Thread Name Here');
- thread.sliceGroup.pushSlice(new tr.model.Slice(
+ thread.sliceGroup.pushSlice(new tr.model.ThreadSlice(
'foo', 'a', 0, startTime, {}, 1));
- thread.sliceGroup.pushSlice(new tr.model.Slice(
+ thread.sliceGroup.pushSlice(new tr.model.ThreadSlice(
'bar', 'b', 0, startTime + 23, {}, 10));
} else {
var thread = process.getOrCreateThread('Name');
- thread.sliceGroup.pushSlice(new tr.model.Slice(
+ thread.sliceGroup.pushSlice(new tr.model.ThreadSlice(
'foo', 'a', 0, startTime + 4, {}, 11));
- thread.sliceGroup.pushSlice(new tr.model.Slice(
+ thread.sliceGroup.pushSlice(new tr.model.ThreadSlice(
'bar', 'b', 0, startTime + 22, {}, 14));
}
}
@@ -111,12 +111,12 @@ tr.b.unittest.testSuite(function() {
view.model = model11;
var simpleButton1 = document.createElement('tr-ui-b-toolbar-button');
- simpleButton1.textContent = 'M';
- view.leftControls.appendChild(simpleButton1);
+ Polymer.dom(simpleButton1).textContent = 'M';
+ Polymer.dom(view.leftControls).appendChild(simpleButton1);
var simpleButton2 = document.createElement('tr-ui-b-toolbar-button');
- simpleButton2.textContent = 'am button';
- view.leftControls.appendChild(simpleButton2);
+ Polymer.dom(simpleButton2).textContent = 'am button';
+ Polymer.dom(view.leftControls).appendChild(simpleButton2);
this.addHTMLOutput(view);
});
@@ -158,4 +158,3 @@ tr.b.unittest.testSuite(function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html
index 92f4679ae01..59301b9a62e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html
@@ -113,17 +113,10 @@ tr.exportTo('tr.ui', function() {
* and then runs the pendingSetFunction_, if present.
*/
checkForAttach_: function() {
- if (!this.isAttachedToDocumentOrInTestMode || this.clientWidth == 0)
+ if (!this.isAttachedToDocumentOrInTestMode || this.clientWidth === 0)
return;
- if (!this.iframe_) {
- this.iframe_ = document.createElement('iframe');
- this.iframe_.style.cssText =
- 'position:absolute;width:100%;height:0;border:0;visibility:hidden;';
- this.parentEl_.appendChild(this.iframe_);
-
- this.iframe_.contentWindow.addEventListener('resize', this.onResize_);
- }
+ window.addEventListener('resize', this.dispatchChangeEvent.bind(this));
var curSize = this.parentEl_.clientWidth + 'x' +
this.parentEl_.clientHeight;
@@ -155,10 +148,7 @@ tr.exportTo('tr.ui', function() {
window.clearInterval(this.checkForAttachInterval_);
this.checkForAttachInterval_ = undefined;
}
- if (this.iframe_) {
- this.iframe_.removeEventListener('resize', this.onResize_);
- this.parentEl_.removeChild(this.iframe_);
- }
+ window.removeEventListener('resize', this.dispatchChangeEvent.bind(this));
},
initAnimationController_: function() {
@@ -297,7 +287,7 @@ tr.exportTo('tr.ui', function() {
},
set gridEnabled(enabled) {
- if (this.gridEnabled_ == enabled)
+ if (this.gridEnabled_ === enabled)
return;
this.gridEnabled_ = enabled && true;
@@ -309,7 +299,7 @@ tr.exportTo('tr.ui', function() {
},
set gridTimebase(timebase) {
- if (this.gridTimebase_ == timebase)
+ if (this.gridTimebase_ === timebase)
return;
this.gridTimebase_ = timebase;
this.dispatchChangeEvent();
@@ -398,7 +388,7 @@ tr.exportTo('tr.ui', function() {
event, offset, newSelection);
}
- if (newSelection.length == 0)
+ if (newSelection.length === 0)
return undefined;
return newSelection;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html
index 75a4939427e..7492a56d7c1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html
@@ -64,87 +64,6 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(shifted.equals(
new tr.model.EventSet(t1.sliceGroup.slices[1])));
});
-
- test('locationObj', function() {
- var process;
- var thread;
- var model = tr.c.TestUtils.newModelWithEvents([], {
- shiftWorldToZero: false,
- pruneContainers: false,
- customizeModelCallback: function(model) {
- process = model.getOrCreateProcess(123);
- thread = process.getOrCreateThread(456);
-
- thread.asyncSliceGroup.push(
- tr.c.TestUtils.newAsyncSliceNamed('a', 80, 20, thread, thread));
- thread.asyncSliceGroup.push(
- tr.c.TestUtils.newAsyncSliceNamed('a', 85, 10, thread, thread));
- }
- });
-
- var timeline = document.createElement('tr-ui-timeline-track-view');
- var vp = new tr.ui.TimelineViewport(timeline);
- timeline.model = model;
- timeline.style.maxHeight = '600px';
- this.addHTMLOutput(timeline);
-
- // Our stableId to track map is not automatically built. We need to
- // search for the tracks and manually build the stableId map here.
- var processTracks = document.getElementsByClassName('process-track-base');
- vp.modelTrackContainer = {
- addContainersToTrackMap: function(containerToTrackMap) {
- // Invoking the process track's addContainersToTrackMap is enough to
- // build the map for all children (i.e. Threads, AsyncSliceGroups)
- // as well.
- for (var i = 0; i < processTracks.length; i++)
- processTracks[i].addContainersToTrackMap(containerToTrackMap);
- },
- addEventListener: function() {},
- canvas: {
- offsetLeft: tr.ui.b.constants.HEADING_WIDTH,
- offsetTop: 0
- }
- };
- vp.rebuildContainerToTrackMap();
-
- var asyncTrack =
- vp.containerToTrackMap.getTrackByStableId('123.456.AsyncSliceGroup');
- assert.isDefined(asyncTrack);
- assert.isFalse(asyncTrack.expanded); // Make sure this starts unexpanded.
-
- // Hack to allow Location to find the element we're looking for.
- // This ensures the correct behaviour of document.elementFrompoint(x,y) of
- // an originally off-screen element.
- asyncTrack.scrollIntoView();
-
- var boundRect = asyncTrack.getBoundingClientRect();
- var viewX = boundRect.left;
- var viewY = boundRect.top + boundRect.height / 2;
- var location = Location.fromViewCoordinates(vp, viewX, viewY);
- assert.equal(asyncTrack, location.getContainingTrack(vp));
- assert.deepEqual(location.toViewCoordinates(vp),
- { viewX: viewX, viewY: viewY });
-
- // Try expanding the multi-row track so that the dimensions of the thread
- // track changes.
- asyncTrack.expanded = true;
- // Expanding the track causes the height to double. We can calculate the new
- // viewY with respect to the track's old boundRect. ViewX remains unchanged.
- var expandedViewY = boundRect.top + boundRect.height;
- assert.deepEqual(location.toViewCoordinates(vp),
- { viewX: viewX, viewY: expandedViewY });
-
- // Test the functionality of fromStableIdAndTimestamp.
- var locationFromCoord =
- Location.fromViewCoordinates(vp, viewX, boundRect.top);
- var locationFromStableId =
- Location.fromStableIdAndTimestamp(vp, '123.456.AsyncSliceGroup',
- location.xWorld);
- assert.deepEqual(locationFromCoord, locationFromStableId);
-
- // Undo scroll.
- document.getElementById('results-container').scrollTop = 0;
- });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html
index 48d488e3e48..723ca4522d9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html
@@ -43,10 +43,10 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = AlertTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html
index 56971486083..229402eba6b 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html
@@ -28,14 +28,14 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport);
- this.classList.add('async-slice-group-track');
+ Polymer.dom(this).classList.add('async-slice-group-track');
this.group_ = undefined;
},
addSubTrack_: function(slices) {
var track = new tr.ui.tracks.SliceTrack(this.viewport);
track.slices = slices;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
track.asyncStyle = true;
return track;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
index cb924f42113..824b7d0cf2e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/ui/timeline_track_view.html">
<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/ui/timeline_track_view.html">
<script>
'use strict';
@@ -216,8 +216,8 @@ tr.b.unittest.testSuite(function() {
processTrack.process = process;
threadTrack.thread = thread;
groupTrack.group = group;
- processTrack.appendChild(threadTrack);
- threadTrack.appendChild(groupTrack);
+ Polymer.dom(processTrack).appendChild(threadTrack);
+ Polymer.dom(threadTrack).appendChild(groupTrack);
assert.equal(processTrack.eventContainer, process);
assert.equal(threadTrack.eventContainer, thread);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html
index bf84ef56c6a..c8a974c8ba9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html
@@ -49,7 +49,7 @@ tr.b.unittest.testSuite(function() {
function drawSeriesWithDetails(test, series, highDetails) {
var div = document.createElement('div');
var canvas = document.createElement('canvas');
- div.appendChild(canvas);
+ Polymer.dom(div).appendChild(canvas);
var pixelRatio = window.devicePixelRatio || 1;
@@ -166,31 +166,29 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
series.addIntersectingEventsInRangeToSelectionInWorldSpace(
-30.5, -29.5, 40, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 0);
+ assert.equal(tr.b.getOnlyElement(sel).index, 0);
// Select second point.
var sel = new EventSet();
series.addIntersectingEventsInRangeToSelectionInWorldSpace(
-28.8, -28.2, 40, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 1);
+ assert.equal(tr.b.getOnlyElement(sel).index, 1);
// Select points in the middle.
var sel = new EventSet();
series.addIntersectingEventsInRangeToSelectionInWorldSpace(
-0.99, 1.01, 40, sel);
assert.lengthOf(sel, 3);
- assert.equal(sel[0].index, 29);
- assert.equal(sel[1].index, 30);
- assert.equal(sel[2].index, 31);
+ var iterator = sel[Symbol.iterator]();
+ assert.equal(iterator.next().value.index, 29);
+ assert.equal(iterator.next().value.index, 30);
+ assert.equal(iterator.next().value.index, 31);
// Select the last point.
var sel = new EventSet();
series.addIntersectingEventsInRangeToSelectionInWorldSpace(
668.99, 668.99, 40, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 59);
+ assert.equal(tr.b.getOnlyElement(sel).index, 59);
// Too far right.
var sel = new EventSet();
@@ -223,8 +221,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
assert.isTrue(series.addEventNearToProvidedEventToSelection(
series.points[0].modelItem, 1, sel));
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 1);
+ assert.equal(tr.b.getOnlyElement(sel).index, 1);
var sel = new EventSet();
assert.isFalse(series.addEventNearToProvidedEventToSelection(
@@ -235,14 +232,12 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
assert.isTrue(series.addEventNearToProvidedEventToSelection(
series.points[30].modelItem, 1, sel));
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 31);
+ assert.equal(tr.b.getOnlyElement(sel).index, 31);
var sel = new EventSet();
assert.isTrue(series.addEventNearToProvidedEventToSelection(
series.points[30].modelItem, -1, sel));
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 29);
+ assert.equal(tr.b.getOnlyElement(sel).index, 29);
// Last point.
var sel = new EventSet();
@@ -253,8 +248,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
assert.isTrue(series.addEventNearToProvidedEventToSelection(
series.points[59].modelItem, -1, sel));
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 58);
+ assert.equal(tr.b.getOnlyElement(sel).index, 58);
});
test('checkAddClosestEventToSelection', function() {
@@ -267,8 +261,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
series.addClosestEventToSelection(-40, 11, -0.5, 0.5, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 0);
+ assert.equal(tr.b.getOnlyElement(sel).index, 0);
// Between two points.
var sel = new EventSet();
@@ -277,8 +270,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
series.addClosestEventToSelection(0.4, 0.4, -0.5, 0.5, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 30);
+ assert.equal(tr.b.getOnlyElement(sel).index, 30);
// Right of last point.
var sel = new EventSet();
@@ -287,8 +279,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
series.addClosestEventToSelection(40, 12, -0.5, 0.5, sel);
- assert.lengthOf(sel, 1);
- assert.equal(sel[0].index, 59);
+ assert.equal(tr.b.getOnlyElement(sel).index, 59);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html
index 86e80ae1cde..f736a5bfd13 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/tracks/chart_transform.html">
-<link rel="import" href="/tracing/ui/tracks/track.html">
<link rel="import" href="/tracing/ui/base/heading.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/chart_transform.html">
+<link rel="import" href="/tracing/ui/tracks/track.html">
<style>
.chart-track {
@@ -36,7 +36,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('chart-track');
+ Polymer.dom(this).classList.add('chart-track');
this.series_ = undefined;
// GUID -> {axis: ChartAxis, series: [ChartSeries]}.
@@ -47,7 +47,7 @@ tr.exportTo('tr.ui.tracks', function() {
this.bottomPadding_ = undefined;
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
set heading(heading) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html
index 7595a2e2cd7..e7dfbb02131 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html
@@ -101,10 +101,10 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = buildTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
@@ -122,10 +122,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
viewport.highDetails = true;
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = buildTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
track.series[0].points[1].modelItem.selectionState =
SelectionState.SELECTED;
@@ -167,9 +167,10 @@ tr.b.unittest.testSuite(function() {
track.addIntersectingEventsInRangeToSelectionInWorldSpace(
-1.1, -0.7, 0.01, sel);
assert.lengthOf(sel, 3);
- assert.equal(sel[0], track.series[0].points[1].modelItem);
- assert.equal(sel[1], track.series[1].points[1].modelItem);
- assert.equal(sel[2], track.series[2].points[3].modelItem);
+ var iterator = sel[Symbol.iterator]();
+ assert.equal(iterator.next().value, track.series[0].points[1].modelItem);
+ assert.equal(iterator.next().value, track.series[1].points[1].modelItem);
+ assert.equal(iterator.next().value, track.series[2].points[3].modelItem);
});
test('checkaddEventNearToProvidedEventToSelection', function() {
@@ -185,8 +186,7 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
assert.isTrue(track.addEventNearToProvidedEventToSelection(
track.series[1].points[1].modelItem, 1, sel));
- assert.lengthOf(sel, 1);
- assert.equal(sel[0], track.series[1].points[2].modelItem);
+ assert.equal(tr.b.getOnlyElement(sel), track.series[1].points[2].modelItem);
});
test('checkAddClosestEventToSelection', function() {
@@ -195,8 +195,9 @@ tr.b.unittest.testSuite(function() {
var sel = new EventSet();
track.addClosestEventToSelection(-0.8, 0.4, 0.5, 1.5, sel);
assert.lengthOf(sel, 2);
- assert.equal(sel[0], track.series[0].points[2].modelItem);
- assert.equal(sel[1], track.series[2].points[4].modelItem);
+ var iterator = sel[Symbol.iterator]();
+ assert.equal(iterator.next().value, track.series[0].points[2].modelItem);
+ assert.equal(iterator.next().value, track.series[2].points[4].modelItem);
});
test('checkAutoSetAllAxes', function() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html
index ff98f4057e0..026c432b161 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html
@@ -26,7 +26,7 @@ tr.exportTo('tr.ui.tracks', function() {
* outerTopViewY -> +--------------------/-\-------+ <- Top padding
* innerTopViewY -> + - - - - - - - - - -| |- - - -+ <- Axis max
* | .. ==\-/== |
- * | == Series == |
+ * | === Series === |
* | ==/-\== .. |
* innerBottomViewY -> + - - -Point- - - - - - - - - -+ <- Axis min
* outerBottomViewY -> +-------\-/--------------------+ <- Bottom padding
@@ -60,7 +60,7 @@ tr.exportTo('tr.ui.tracks', function() {
this.axis_ = axis;
this.innerHeight_ = this.innerBottomViewY - this.innerTopViewY;
- };
+ }
ChartTransform.prototype = {
worldXToViewX: function(worldX) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html
index cdad43bef5c..566004740c9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html
@@ -6,9 +6,9 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/task.html">
-<link rel="import" href="/tracing/ui/tracks/track.html">
<link rel="import" href="/tracing/core/filter.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/track.html">
<script>
'use strict';
@@ -29,7 +29,7 @@ tr.exportTo('tr.ui.tracks', function() {
},
detach: function() {
- this.textContent = '';
+ Polymer.dom(this).textContent = '';
},
get tracks_() {
@@ -120,7 +120,7 @@ tr.exportTo('tr.ui.tracks', function() {
clearTracks_: function() {
this.tracks_.forEach(function(track) {
- this.removeChild(track);
+ Polymer.dom(this).removeChild(track);
}, this);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html
index 759b2433596..638c8bbce41 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html
@@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/tracks/chart_axis.html">
<link rel="import" href="/tracing/ui/tracks/chart_point.html">
<link rel="import" href="/tracing/ui/tracks/chart_series.html">
<link rel="import" href="/tracing/ui/tracks/chart_track.html">
-<link rel="import" href="/tracing/ui/base/ui.html">
<script>
'use strict';
@@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.ChartTrack.prototype.decorate.call(this, viewport);
- this.classList.add('counter-track');
+ Polymer.dom(this).classList.add('counter-track');
},
get counter() {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
index afa3ad3f967..1224676b0d7 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
@@ -56,11 +56,11 @@ tr.b.unittest.testSuite(function() {
viewport.modelTrackContainer = drawingContainer;
var modelTrack = new tr.ui.tracks.ModelTrack(viewport);
- drawingContainer.appendChild(modelTrack);
+ Polymer.dom(drawingContainer).appendChild(modelTrack);
modelTrack.model = model;
- viewportDiv.appendChild(drawingContainer);
+ Polymer.dom(viewportDiv).appendChild(drawingContainer);
this.addHTMLOutput(viewportDiv);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html
index 8cf6dcdfa00..4a1b8b0badc 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html
@@ -41,10 +41,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(testEl);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- testEl.appendChild(drawingContainer);
+ Polymer.dom(testEl).appendChild(drawingContainer);
var track = new CounterTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(testEl);
// Force the container to update sizes so the test can use coordinates that
@@ -88,10 +88,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new CounterTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html
index 84b7afe6582..dd4dfe0c97a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html
@@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
- this.classList.add('cpu-track');
+ Polymer.dom(this).classList.add('cpu-track');
this.detailedMode_ = true;
},
@@ -81,7 +81,7 @@ tr.exportTo('tr.ui.tracks', function() {
var track = new tr.ui.tracks.SliceTrack(this.viewport);
track.slices = slices;
track.heading = this.cpu_.userFriendlyName + ':';
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
if (this.detailedMode_) {
@@ -93,7 +93,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.heading = this.cpu_.userFriendlyName + ' ' +
counter.name + ':';
track.counter = counter;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
}
},
@@ -127,7 +127,7 @@ tr.exportTo('tr.ui.tracks', function() {
}
return selection;
};
- this.appendChild(samplesTrack);
+ Polymer.dom(this).appendChild(samplesTrack);
}, this);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
index 61108d514fc..bd268b50940 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/ui/timeline_track_view.html">
<link rel="import" href="/tracing/model/model.html">
+<link rel="import" href="/tracing/ui/timeline_track_view.html">
<script>
'use strict';
@@ -15,7 +15,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Cpu = tr.model.Cpu;
var CpuTrack = tr.ui.tracks.CpuTrack;
- var Slice = tr.model.Slice;
+ var ThreadSlice = tr.model.ThreadSlice;
var StackFrame = tr.model.StackFrame;
var Sample = tr.model.Sample;
var Thread = tr.model.Thread;
@@ -24,8 +24,8 @@ tr.b.unittest.testSuite(function() {
test('basicCpu', function() {
var cpu = new Cpu({}, 7);
cpu.slices = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 2.1, {}, 4.8)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 2.1, {}, 4.8)
];
cpu.updateBounds();
@@ -35,7 +35,7 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
var track = new CpuTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
track.heading = 'CPU ' + cpu.cpuNumber;
track.cpu = cpu;
@@ -86,7 +86,7 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
var track = new CpuTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
track.heading = 'CPU ' + cpu.cpuNumber;
track.cpu = cpu;
@@ -96,4 +96,3 @@ tr.b.unittest.testSuite(function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html
index dfc6c364eea..c29086490f9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html
@@ -32,7 +32,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
ContainerTrack.prototype.decorate.call(this, viewport);
- this.classList.add('device-track');
+ Polymer.dom(this).classList.add('device-track');
this.device_ = undefined;
this.powerSeriesTrack_ = undefined;
},
@@ -72,8 +72,9 @@ tr.exportTo('tr.ui.tracks', function() {
this.powerSeriesTrack_.powerSeries = this.device.powerSeries;
if (this.powerSeriesTrack_.hasVisibleContent) {
- this.appendChild(this.powerSeriesTrack_);
- this.appendChild(new tr.ui.tracks.SpacingTrack(this.viewport));
+ Polymer.dom(this).appendChild(this.powerSeriesTrack_);
+ Polymer.dom(this).appendChild(
+ new tr.ui.tracks.SpacingTrack(this.viewport));
}
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html
index ce849355882..ed670eb5baa 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html
@@ -28,7 +28,7 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new tr.ui.TimelineViewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
if (series) {
series.updateBounds();
@@ -62,7 +62,7 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = createDrawingContainer(device.powerSeries);
var track = new DeviceTrack(drawingContainer.viewport);
track.device = device;
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(drawingContainer);
});
@@ -73,7 +73,7 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = createDrawingContainer(device.powerSeries);
var track = new DeviceTrack(drawingContainer.viewport);
track.device = device;
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
// Adding output should throw due to no visible content.
assert.throw(function() { this.addHTMLOutput(drawingContainer); });
@@ -94,7 +94,7 @@ tr.b.unittest.testSuite(function() {
var track = new DeviceTrack(drawingContainer.viewport);
track.device = device;
track.device = device;
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(drawingContainer);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html
index 69a8ca43026..56014ac31a0 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html
@@ -8,9 +8,9 @@ found in the LICENSE file.
<link rel="stylesheet" href="/tracing/ui/tracks/drawing_container.css">
<link rel="import" href="/tracing/base/raf.html">
-<link rel="import" href="/tracing/ui/tracks/track.html">
<link rel="import" href="/tracing/ui/base/constants.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/track.html">
<script>
'use strict';
@@ -35,12 +35,12 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('drawing-container');
+ Polymer.dom(this).classList.add('drawing-container');
this.canvas_ = document.createElement('canvas');
this.canvas_.className = 'drawing-container-canvas';
this.canvas_.style.left = tr.ui.b.constants.HEADING_WIDTH + 'px';
- this.appendChild(this.canvas_);
+ Polymer.dom(this).appendChild(this.canvas_);
this.ctx_ = this.canvas_.getContext('2d');
@@ -112,6 +112,10 @@ tr.exportTo('tr.ui.tracks', function() {
var visibleChildTracks =
tr.b.asArray(this.children).filter(this.visibleFilter_);
+ if (visibleChildTracks.length === 0) {
+ return;
+ }
+
var thisBounds = this.getBoundingClientRect();
var firstChildTrackBounds = visibleChildTracks[0].getBoundingClientRect();
@@ -124,12 +128,12 @@ tr.exportTo('tr.ui.tracks', function() {
var innerHeight = lastChildTrackBounds.bottom - firstChildTrackBounds.top;
var pixelRatio = window.devicePixelRatio || 1;
- if (this.canvas_.width != innerWidth * pixelRatio) {
+ if (this.canvas_.width !== innerWidth * pixelRatio) {
this.canvas_.width = innerWidth * pixelRatio;
this.canvas_.style.width = innerWidth + 'px';
}
- if (this.canvas_.height != innerHeight * pixelRatio) {
+ if (this.canvas_.height !== innerHeight * pixelRatio) {
this.canvas_.height = innerHeight * pixelRatio;
this.canvas_.style.height = innerHeight + 'px';
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
index 9cb3d727c66..3645c4b8394 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
@@ -42,11 +42,11 @@ tr.b.unittest.testSuite(function() {
this.viewport.modelTrackContainer = this.drawingContainer;
var modelTrack = new tr.ui.tracks.ModelTrack(this.viewport);
- this.drawingContainer.appendChild(modelTrack);
+ Polymer.dom(this.drawingContainer).appendChild(modelTrack);
modelTrack.model = model;
- this.viewportDiv.appendChild(this.drawingContainer);
+ Polymer.dom(this.viewportDiv).appendChild(this.drawingContainer);
this.addHTMLOutput(this.viewportDiv);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html
index 943e245b37c..9918fec0935 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html
@@ -48,10 +48,10 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = FrameTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html
index 0e2e4d54c24..143957a8640 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html
@@ -63,7 +63,7 @@ tr.exportTo('tr.ui.tracks', function() {
var track = new tr.ui.tracks.LetterDotTrack(this.viewport);
track.heading = 'Memory Dumps';
track.items = items;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
},
appendUsedMemoryTrack_: function() {
@@ -77,7 +77,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.height = USED_MEMORY_TRACK_HEIGHT + 'px';
track.series = series;
track.autoSetAllAxes({expandMax: true});
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
},
appendAllocatedMemoryTrack_: function() {
@@ -91,7 +91,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.height = ALLOCATED_MEMORY_TRACK_HEIGHT + 'px';
track.series = series;
track.autoSetAllAxes({expandMax: true});
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html
index 268da37bcf7..0add321fca7 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html
@@ -26,10 +26,10 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new GlobalMemoryDumpTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
drawingContainer.invalidate();
track.memoryDumps = dumps;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html
index 8e8f181ff90..7c9c049d956 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html
@@ -56,7 +56,7 @@ tr.exportTo('tr.ui.tracks', function() {
addSubTrack_: function(slices) {
var track = new tr.ui.tracks.SliceTrack(this.viewport);
track.slices = slices;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
return track;
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
index 1b2c1346a16..b98c2417c7e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
@@ -22,7 +22,7 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new tr.ui.TimelineViewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new tr.ui.tracks.InteractionTrack(viewport);
track.model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(1);
@@ -44,7 +44,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(2, track.subRows_.length);
assert.equal(2, track.subRows_[0].length);
assert.equal(3, track.subRows_[1].length);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html
index 20ffea84d05..f69f61ef0e9 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html
@@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/tracks/process_track_base.html">
<link rel="import" href="/tracing/ui/tracks/cpu_track.html">
+<link rel="import" href="/tracing/ui/tracks/process_track_base.html">
<link rel="import" href="/tracing/ui/tracks/spacing_track.html">
<script>
@@ -66,11 +66,11 @@ tr.exportTo('tr.ui.tracks', function() {
track.cpu = cpu;
if (!track.hasVisibleContent)
continue;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
didAppendAtLeastOneTrack = true;
}
if (didAppendAtLeastOneTrack)
- this.appendChild(new SpacingTrack(this.viewport));
+ Polymer.dom(this).appendChild(new SpacingTrack(this.viewport));
}
};
@@ -80,4 +80,3 @@ tr.exportTo('tr.ui.tracks', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html
index 64f26e4fb4f..75ff6c86927 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html
@@ -39,11 +39,11 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('letter-dot-track');
+ Polymer.dom(this).classList.add('letter-dot-track');
this.items_ = undefined;
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
set heading(heading) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html
index 93c2bcfbb9a..6f55ed14b62 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html
@@ -38,10 +38,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = LetterDotTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
index 2d13a901ba8..517eec0f2db 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
@@ -29,6 +29,7 @@ tr.exportTo('tr.ui.tracks', function() {
var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump;
var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump;
var addOwnershipLink = tr.model.MemoryDumpTestUtils.addOwnershipLink;
+ var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
@@ -54,7 +55,8 @@ tr.exportTo('tr.ui.tracks', function() {
var allocatorDumps = tr.b.mapItems(dumpData, function(allocatorName, data) {
var size = data.size;
assert.typeOf(size, 'number'); // Sanity check.
- return newAllocatorDump(memoryDump, allocatorName, { size: size });
+ return newAllocatorDump(memoryDump, allocatorName,
+ {numerics: {size: size}});
});
// Add ownership links between them.
@@ -76,7 +78,7 @@ tr.exportTo('tr.ui.tracks', function() {
function addProcessMemoryDumpWithFields(globalMemoryDump, process, start,
opt_pssValues, opt_dumpData) {
- var pmd = addProcessMemoryDump(globalMemoryDump, process, start);
+ var pmd = addProcessMemoryDump(globalMemoryDump, process, {ts: start});
if (opt_pssValues !== undefined)
pmd.vmRegions = createVMRegions(opt_pssValues);
if (opt_dumpData !== undefined)
@@ -96,12 +98,12 @@ tr.exportTo('tr.ui.tracks', function() {
var pb = model.getOrCreateProcess(6);
var pc = model.getOrCreateProcess(9);
- var gmd1 = addGlobalMemoryDump(model, 0, LIGHT);
+ var gmd1 = addGlobalMemoryDump(model, {ts: 0, levelOfDetail: LIGHT});
addProcessMemoryDumpWithFields(gmd1, pa, 0, maybePssValues([111]));
addProcessMemoryDumpWithFields(gmd1, pb, 0.2, undefined,
maybeDumpData({oilpan: {size: 1024}}));
- var gmd2 = addGlobalMemoryDump(model, 5, DETAILED);
+ var gmd2 = addGlobalMemoryDump(model, {ts: 5, levelOfDetail: DETAILED});
addProcessMemoryDumpWithFields(gmd2, pa, 0);
addProcessMemoryDumpWithFields(gmd2, pb, 4.99, maybePssValues([100, 50]),
maybeDumpData({v8: {size: 512}}));
@@ -109,13 +111,20 @@ tr.exportTo('tr.ui.tracks', function() {
maybeDumpData({oilpan: {size: 128, owns: 'v8'},
v8: {size: 384, owns: 'tracing'}, tracing: {size: 65920}}));
- var gmd3 = addGlobalMemoryDump(model, 15, DETAILED);
+ var gmd3 = addGlobalMemoryDump(model, {ts: 15, levelOfDetail: DETAILED});
addProcessMemoryDumpWithFields(gmd3, pa, 15.5, maybePssValues([]),
maybeDumpData({v8: {size: 768}}));
addProcessMemoryDumpWithFields(gmd3, pc, 14.5,
maybePssValues([70, 70, 70]), maybeDumpData({oilpan: {size: 512}}));
- var gmd4 = addGlobalMemoryDump(model, 18, LIGHT);
+ var gmd4 = addGlobalMemoryDump(model, {ts: 18, levelOfDetail: LIGHT});
+
+ var gmd5 = addGlobalMemoryDump(model,
+ {ts: 20, levelOfDetail: BACKGROUND});
+ addProcessMemoryDumpWithFields(gmd5, pa, 0, maybePssValues([105]));
+ addProcessMemoryDumpWithFields(gmd5, pb, 0.2, undefined,
+ maybeDumpData({oilpan: {size: 100}}));
+
});
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html
index 821186182b4..a7fd6d19380 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
<link rel="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/ui/tracks/chart_axis.html">
@@ -22,35 +23,26 @@ tr.exportTo('tr.ui.tracks', function() {
var DISPLAYED_SIZE_NUMERIC_NAME =
tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;
+ var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND;
var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
- /**
- * Add numeric values from a source dictionary to the numeric values in
- * a destination dictionary. Undefined values are treated as zeros. Note that
- * this method modifies the destination dictionary in place.
- *
- * Example: addDictionary({a: 1, b: 2}, {b: 3, c: 4}) will update the
- * destination dictionary (first argument) to {a: 1, b: 5, c: 4}.
- */
- function addDictionary(dstDict, srcDict) {
- tr.b.iterItems(srcDict, function(key, value) {
- var existingValue = dstDict[key];
- if (existingValue === undefined)
- existingValue = 0;
- dstDict[key] = existingValue + value;
+ /** Extract PSS values of processes in a global memory dump. */
+ function extractGlobalMemoryDumpUsedSizes(globalMemoryDump, addSize) {
+ tr.b.iterItems(globalMemoryDump.processMemoryDumps, function(pid, pmd) {
+ var mostRecentVmRegions = pmd.mostRecentVmRegions;
+ if (mostRecentVmRegions === undefined)
+ return;
+ addSize(pid, mostRecentVmRegions.byteStats.proportionalResident || 0,
+ pmd.process.userFriendlyName);
});
}
- /**
- * Get a dictionary mapping root allocator names (e.g. 'v8') to the
- * corresponding sizes (e.g. 1024) in a process memory dump.
- */
- function getProcessMemoryDumpAllocatorSizes(processMemoryDump) {
+ /** Extract sizes of root allocators in a process memory dump. */
+ function extractProcessMemoryDumpAllocatorSizes(processMemoryDump, addSize) {
var allocatorDumps = processMemoryDump.memoryAllocatorDumps;
if (allocatorDumps === undefined)
- return {};
- var allocatorSizes = {};
+ return;
allocatorDumps.forEach(function(allocatorDump) {
// Don't show tracing overhead in the charts.
// TODO(petrcermak): Find a less hacky way to do this.
@@ -62,72 +54,91 @@ tr.exportTo('tr.ui.tracks', function() {
var allocatorSizeValue = allocatorSize.value;
if (allocatorSizeValue === undefined)
return;
- allocatorSizes[allocatorDump.fullName] = allocatorSizeValue;
+ addSize(allocatorDump.fullName, allocatorSizeValue);
});
- return allocatorSizes;
- };
+ }
- /**
- * Get a dictionary mapping root allocator names (e.g. 'v8') to the
- * corresponding sizes (e.g. 1024) in a global memory dump (i.e. summed over
- * all simultaneous process memory dumps).
- */
- function getGlobalMemoryDumpAllocatorSizes(globalMemoryDump) {
- var globalAllocatorSizes = {};
- tr.b.iterItems(globalMemoryDump.processMemoryDumps,
- function(pid, processMemoryDump) {
- addDictionary(globalAllocatorSizes,
- getProcessMemoryDumpAllocatorSizes(processMemoryDump));
- });
- return globalAllocatorSizes;
+ /** Extract sizes of root allocators in a global memory dump. */
+ function extractGlobalMemoryDumpAllocatorSizes(globalMemoryDump, addSize) {
+ tr.b.iterItems(
+ globalMemoryDump.processMemoryDumps,
+ (pid, pmd) => extractProcessMemoryDumpAllocatorSizes(pmd, addSize));
}
/**
- * A generic function which converts a list of memory dumps to a list of chart
- * series (one per root allocator). Each series represents the evolution of
- * the size of a the corresponding root allocator (e.g. 'v8') over time.
+ * A generic function which converts a list of memory dumps to a list of
+ * chart series.
+ *
+ * @param {!Array<!tr.model.ContainerMemoryDump>} memoryDumps List of
+ * container memory dumps.
+ * @param {!function(
+ * !tr.model.ContainerMemoryDump,
+ * !function(string, number, string=))} dumpSizeExtractor Callback for
+ * extracting sizes from a container memory dump.
+ * @return {(!Array<!tr.ui.tracks.ChartSeries>|undefined)} List of chart
+ * series (or undefined if no size is extracted from any container memory
+ * dump).
*/
- function buildAllocatedMemoryChartSeries(memoryDumps,
- memoryDumpToAllocatorSizesFn) {
- var allocatorNameToPoints = {};
- var dumpsData = memoryDumps.map(function(memoryDump) {
- var allocatorSizes = memoryDumpToAllocatorSizesFn(memoryDump);
- tr.b.iterItems(allocatorSizes, function(allocatorName) {
- allocatorNameToPoints[allocatorName] = [];
+ function buildMemoryChartSeries(memoryDumps, dumpSizeExtractor) {
+ var dumpCount = memoryDumps.length;
+ var idToTimestampToPoint = {};
+ var idToName = {};
+
+ // Extract the sizes of all components from each memory dump.
+ memoryDumps.forEach(function(dump, index) {
+ dumpSizeExtractor(dump, function addSize(id, size, opt_name) {
+ var timestampToPoint = idToTimestampToPoint[id];
+ if (timestampToPoint === undefined) {
+ idToTimestampToPoint[id] = timestampToPoint = new Array(dumpCount);
+ for (var i = 0; i < dumpCount; i++) {
+ var modelItem = memoryDumps[i];
+ timestampToPoint[i] = new tr.ui.tracks.ChartPoint(
+ modelItem, modelItem.start, 0);
+ }
+ }
+ timestampToPoint[index].y += size;
+ if (opt_name !== undefined)
+ idToName[id] = opt_name;
});
- return {dump: memoryDump, sizes: allocatorSizes};
});
- // Do not generate any chart series if no process memory dump contains any
- // allocator dumps.
- if (Object.keys(allocatorNameToPoints).length === 0)
+ // Do not generate any chart series if no sizes were extracted.
+ var ids = Object.keys(idToTimestampToPoint);
+ if (ids.length === 0)
return undefined;
- dumpsData.forEach(function(dumpData) {
- var memoryDump = dumpData.dump;
- var allocatorSizes = dumpData.sizes;
- tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) {
- var allocatorSize = allocatorSizes[allocatorName] || 0;
- points.push(new tr.ui.tracks.ChartPoint(
- memoryDump, memoryDump.start, allocatorSize));
- });
- });
+ ids.sort();
+ for (var i = 0; i < dumpCount; i++) {
+ var baseSize = 0;
+ // Traverse |ids| in reverse (alphabetical) order so that the first id is
+ // at the top of the chart.
+ for (var j = ids.length - 1; j >= 0; j--) {
+ var point = idToTimestampToPoint[ids[j]][i];
+ point.yBase = baseSize;
+ point.y += baseSize;
+ baseSize = point.y;
+ }
+ }
- // Create one common axis for all allocated memory chart series.
+ // Create one common axis for all memory chart series.
var axis = new tr.ui.tracks.ChartAxis(0);
- // Build a chart series for each allocator.
- var series = [];
- tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) {
+ // Build a chart series for each id.
+ var series = ids.map(function(id) {
var colorId = ColorScheme.getColorIdForGeneralPurposeString(
- allocatorName);
+ idToName[id] || id);
var renderingConfig = {
- chartType: tr.ui.tracks.ChartSeriesType.LINE,
- colorId: colorId
+ chartType: tr.ui.tracks.ChartSeriesType.AREA,
+ colorId: colorId,
+ backgroundOpacity: 0.8
};
- series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig));
+ return new tr.ui.tracks.ChartSeries(idToTimestampToPoint[id],
+ axis, renderingConfig);
});
+ // Ensure that the series at the top of the chart are drawn last.
+ series.reverse();
+
return series;
}
@@ -136,6 +147,8 @@ tr.exportTo('tr.ui.tracks', function() {
* inside).
*/
function buildMemoryLetterDots(memoryDumps) {
+ var backgroundMemoryColorId =
+ ColorScheme.getColorIdForReservedName('background_memory_dump');
var lightMemoryColorId =
ColorScheme.getColorIdForReservedName('light_memory_dump');
var detailedMemoryColorId =
@@ -143,6 +156,9 @@ tr.exportTo('tr.ui.tracks', function() {
return memoryDumps.map(function(memoryDump) {
var memoryColorId;
switch (memoryDump.levelOfDetail) {
+ case BACKGROUND:
+ memoryColorId = backgroundMemoryColorId;
+ break;
case DETAILED:
memoryColorId = detailedMemoryColorId;
break;
@@ -161,71 +177,8 @@ tr.exportTo('tr.ui.tracks', function() {
* process over time.
*/
function buildGlobalUsedMemoryChartSeries(globalMemoryDumps) {
- // Do not generate the chart if no process memory dump contains VM regions.
- var containsVmRegions = globalMemoryDumps.some(function(globalDump) {
- for (var pid in globalDump.processMemoryDumps)
- if (globalDump.processMemoryDumps[pid].mostRecentVmRegions)
- return true;
- return false;
- });
- if (!containsVmRegions)
- return undefined;
-
- // Find all processes that dump memory at least once.
- var pidToProcess = {};
- globalMemoryDumps.forEach(function(globalDump) {
- tr.b.iterItems(globalDump.processMemoryDumps, function(pid, processDump) {
- pidToProcess[pid] = processDump.process;
- });
- });
-
- // Build one list of points for each instrumented process.
- var pidToPoints = {};
- tr.b.iterItems(pidToProcess, function(pid, process) {
- pidToPoints[pid] = [];
- });
-
- // For every timestamp, calculate the total PSS (proportional set size) of
- // each process and append it to the corresponding list of points.
- globalMemoryDumps.forEach(function(globalDump) {
- var pssBase = 0;
- tr.b.iterItems(pidToPoints, function(pid, points) {
- var processMemoryDump = globalDump.processMemoryDumps[pid];
- var cumulativePss = pssBase;
- // If no dump was found (probably dead) or it does not provide the
- // necessary information (namely most recent VM regions), assume zero.
- if (processMemoryDump !== undefined) {
- var vmRegions = processMemoryDump.mostRecentVmRegions;
- if (vmRegions !== undefined)
- cumulativePss += vmRegions.byteStats.proportionalResident || 0;
- }
- points.push(new tr.ui.tracks.ChartPoint(
- globalDump, globalDump.start, cumulativePss, pssBase));
- pssBase = cumulativePss;
- });
- });
-
- // Create one common axis for all used memory chart series.
- var axis = new tr.ui.tracks.ChartAxis(0);
-
- // Build a chart series for each instrumented process.
- var series = [];
- tr.b.iterItems(pidToPoints, function(pid, points) {
- var process = pidToProcess[pid];
- var colorId = ColorScheme.getColorIdForGeneralPurposeString(
- process.userFriendlyName);
- var renderingConfig = {
- chartType: tr.ui.tracks.ChartSeriesType.AREA,
- colorId: colorId,
- backgroundOpacity: 0.8
- };
- series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig));
- });
-
- // Show the first series (with the smallest cumulative value) at the top.
- series.reverse();
-
- return series;
+ return buildMemoryChartSeries(globalMemoryDumps,
+ extractGlobalMemoryDumpUsedSizes);
}
/**
@@ -234,8 +187,8 @@ tr.exportTo('tr.ui.tracks', function() {
* corresponding root allocator (e.g. 'v8') over time.
*/
function buildProcessAllocatedMemoryChartSeries(processMemoryDumps) {
- return buildAllocatedMemoryChartSeries(processMemoryDumps,
- getProcessMemoryDumpAllocatorSizes);
+ return buildMemoryChartSeries(processMemoryDumps,
+ extractProcessMemoryDumpAllocatorSizes);
}
/**
@@ -244,8 +197,8 @@ tr.exportTo('tr.ui.tracks', function() {
* corresponding root allocator (e.g. 'v8') over time.
*/
function buildGlobalAllocatedMemoryChartSeries(globalMemoryDumps) {
- return buildAllocatedMemoryChartSeries(globalMemoryDumps,
- getGlobalMemoryDumpAllocatorSizes);
+ return buildMemoryChartSeries(globalMemoryDumps,
+ extractGlobalMemoryDumpAllocatorSizes);
}
return {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html
index 58e46078245..f19757c1553 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html
@@ -22,11 +22,12 @@ tr.b.unittest.testSuite(function() {
var dumps = createTestGlobalMemoryDumps(false, false);
var items = tr.ui.tracks.buildMemoryLetterDots(dumps);
- assert.lengthOf(items, 4);
+ assert.lengthOf(items, 5);
assert.equal(items[0].start, 0);
assert.equal(items[1].start, 5);
assert.equal(items[2].start, 15);
assert.equal(items[3].start, 18);
+ assert.equal(items[4].start, 20);
// Check model mapping.
assert.equal(items[1].selectionState, SelectionState.HIGHLIGHTED);
@@ -38,11 +39,12 @@ tr.b.unittest.testSuite(function() {
var dumps = createTestGlobalMemoryDumps(false, false);
var items = tr.ui.tracks.buildMemoryLetterDots(dumps);
- assert.lengthOf(items, 4);
+ assert.lengthOf(items, 5);
assert.equal(items[0].start, 0);
assert.equal(items[1].start, 5);
assert.equal(items[2].start, 15);
assert.equal(items[3].start, 18);
+ assert.equal(items[4].start, 20);
// Check model mapping.
assert.equal(items[1].selectionState, SelectionState.HIGHLIGHTED);
@@ -67,9 +69,9 @@ tr.b.unittest.testSuite(function() {
var sb = series[1];
var sc = series[0];
- assert.lengthOf(sa.points, 4);
- assert.lengthOf(sb.points, 4);
- assert.lengthOf(sc.points, 4);
+ assert.lengthOf(sa.points, 5);
+ assert.lengthOf(sb.points, 5);
+ assert.lengthOf(sc.points, 5);
// Process A: VM regions defined -> sum their PSS values (111).
// Process B: VM regions undefined and no previous value -> assume zero.
@@ -78,36 +80,36 @@ tr.b.unittest.testSuite(function() {
assert.equal(sb.points[0].x, 0);
assert.equal(sc.points[0].x, 0);
assert.equal(sa.points[0].y, 111);
- assert.equal(sb.points[0].y, 111);
- assert.equal(sc.points[0].y, 111);
+ assert.equal(sb.points[0].y, 0);
+ assert.equal(sc.points[0].y, 0);
assert.equal(sa.points[0].yBase, 0);
- assert.equal(sb.points[0].yBase, 111);
- assert.equal(sc.points[0].yBase, 111);
+ assert.equal(sb.points[0].yBase, 0);
+ assert.equal(sc.points[0].yBase, 0);
// Process A: VM regions undefined -> assume previous value (111).
- // Process B: VM regions defined -> sum their PSS values (555).
+ // Process B: VM regions defined -> sum their PSS values (100 + 50).
// Process C: VM regions undefined -> assume previous value (0).
assert.equal(sa.points[1].x, 5);
assert.equal(sb.points[1].x, 5);
assert.equal(sc.points[1].x, 5);
- assert.equal(sa.points[1].y, 111);
- assert.equal(sb.points[1].y, 261);
- assert.equal(sc.points[1].y, 261);
- assert.equal(sa.points[1].yBase, 0);
- assert.equal(sb.points[1].yBase, 111);
- assert.equal(sc.points[1].yBase, 261);
+ assert.equal(sa.points[1].y, 150 + 111);
+ assert.equal(sb.points[1].y, 150);
+ assert.equal(sc.points[1].y, 0);
+ assert.equal(sa.points[1].yBase, 150);
+ assert.equal(sb.points[1].yBase, 0);
+ assert.equal(sc.points[1].yBase, 0);
// Process A: VM regions defined -> sum their PSS values (0).
// Process B: Memory dump not present -> assume process not alive (0).
- // Process C: VM regions defined -> sum their PSS values (999).
+ // Process C: VM regions defined -> sum their PSS values (70 + 70 + 70).
assert.equal(sa.points[2].x, 15);
assert.equal(sb.points[2].x, 15);
assert.equal(sc.points[2].x, 15);
- assert.equal(sa.points[2].y, 0);
- assert.equal(sb.points[2].y, 0);
+ assert.equal(sa.points[2].y, 210);
+ assert.equal(sb.points[2].y, 210);
assert.equal(sc.points[2].y, 210);
- assert.equal(sa.points[2].yBase, 0);
- assert.equal(sb.points[2].yBase, 0);
+ assert.equal(sa.points[2].yBase, 210);
+ assert.equal(sb.points[2].yBase, 210);
assert.equal(sc.points[2].yBase, 0);
// All processes: Memory dump not present -> assume process not alive (0).
@@ -117,10 +119,23 @@ tr.b.unittest.testSuite(function() {
assert.equal(sa.points[3].y, 0);
assert.equal(sb.points[3].y, 0);
assert.equal(sc.points[3].y, 0);
- assert.equal(sc.points[3].yBase, 0);
- assert.equal(sc.points[3].yBase, 0);
+ assert.equal(sa.points[3].yBase, 0);
+ assert.equal(sb.points[3].yBase, 0);
assert.equal(sc.points[3].yBase, 0);
+ // Process A: VM regions defined -> sum their PSS values (105).
+ // Process B: VM regions undefined and no previous value -> assume zero.
+ // Process C: Memory dump not present -> assume process not alive (0).
+ assert.equal(sa.points[4].x, 20);
+ assert.equal(sb.points[4].x, 20);
+ assert.equal(sc.points[4].x, 20);
+ assert.equal(sa.points[4].y, 105);
+ assert.equal(sb.points[4].y, 0);
+ assert.equal(sc.points[4].y, 0);
+ assert.equal(sa.points[4].yBase, 0);
+ assert.equal(sb.points[4].yBase, 0);
+ assert.equal(sc.points[4].yBase, 0);
+
// Check model mapping.
assert.equal(sa.points[1].selectionState, SelectionState.HIGHLIGHTED);
assert.isTrue(sb.points[2].selected);
@@ -142,11 +157,11 @@ tr.b.unittest.testSuite(function() {
assert.lengthOf(series, 2);
- var so = series[0];
- var sv = series[1];
+ var so = series[1];
+ var sv = series[0];
- assert.lengthOf(so.points, 4);
- assert.lengthOf(sv.points, 4);
+ assert.lengthOf(so.points, 5);
+ assert.lengthOf(sv.points, 5);
// Oilpan: Only process B dumps allocated objects size (1024).
// V8: No process dumps allocated objects size (0).
@@ -154,27 +169,42 @@ tr.b.unittest.testSuite(function() {
assert.equal(sv.points[0].x, 0);
assert.equal(so.points[0].y, 1024);
assert.equal(sv.points[0].y, 0);
+ assert.equal(so.points[0].yBase, 0);
+ assert.equal(sv.points[0].yBase, 0);
// Oilpan: Process B did not provide a value and process C dumps (128).
// V8: Processes B and C dump (512 + 256).
assert.equal(so.points[1].x, 5);
assert.equal(sv.points[1].x, 5);
- assert.equal(so.points[1].y, 128);
+ assert.equal(so.points[1].y, 768 + 128);
assert.equal(sv.points[1].y, 768);
+ assert.equal(so.points[1].yBase, 768);
+ assert.equal(sv.points[1].yBase, 0);
// Oilpan: Process B assumed not alive and process C dumps (512)
// V8: Process A dumps now, process B assumed not alive, process C did not
// provide a value (768).
assert.equal(so.points[2].x, 15);
assert.equal(sv.points[2].x, 15);
- assert.equal(so.points[2].y, 512);
+ assert.equal(so.points[2].y, 768 + 512);
assert.equal(sv.points[2].y, 768);
+ assert.equal(so.points[2].yBase, 768);
+ assert.equal(sv.points[2].yBase, 0);
// All processes: Memory dump not present -> assume process not alive (0).
assert.equal(so.points[3].x, 18);
assert.equal(sv.points[3].x, 18);
assert.equal(so.points[3].y, 0);
assert.equal(sv.points[3].y, 0);
+ assert.equal(so.points[3].yBase, 0);
+ assert.equal(sv.points[3].yBase, 0);
+
+ // Oilpan: Only process B dumps allocated objects size (100).
+ // V8: No process dumps allocated objects size (0).
+ assert.equal(so.points[4].x, 20);
+ assert.equal(sv.points[4].x, 20);
+ assert.equal(so.points[4].y, 100);
+ assert.equal(sv.points[4].y, 0);
// Check model mapping.
assert.equal(so.points[1].selectionState, SelectionState.HIGHLIGHTED);
@@ -199,8 +229,8 @@ tr.b.unittest.testSuite(function() {
// charts).
assert.lengthOf(series, 2);
- var so = series[0];
- var sv = series[1];
+ var so = series[1];
+ var sv = series[0];
assert.lengthOf(so.points, 2);
assert.lengthOf(sv.points, 2);
@@ -209,8 +239,10 @@ tr.b.unittest.testSuite(function() {
// V8: Process dumps (256).
assert.equal(so.points[0].x, 5.12);
assert.equal(sv.points[0].x, 5.12);
- assert.equal(so.points[0].y, 128);
+ assert.equal(so.points[0].y, 256 + 128);
assert.equal(sv.points[0].y, 256);
+ assert.equal(so.points[0].yBase, 256);
+ assert.equal(sv.points[0].yBase, 0);
// Oilpan: Process dumps (512).
// V8: Process did not provide a value (0).
@@ -218,6 +250,8 @@ tr.b.unittest.testSuite(function() {
assert.equal(sv.points[1].x, 14.5);
assert.equal(so.points[1].y, 512);
assert.equal(sv.points[1].y, 0);
+ assert.equal(so.points[1].yBase, 0);
+ assert.equal(sv.points[1].yBase, 0);
// Check model mapping.
assert.equal(so.points[1].selectionState, SelectionState.HIGHLIGHTED);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html
index 29e8b94c85e..051135d49e1 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html
@@ -43,7 +43,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
- this.classList.add('model-track');
+ Polymer.dom(this).classList.add('model-track');
var typeInfos = tr.ui.tracks.Highlighter.getAllRegisteredTypeInfos();
this.highlighters_ = typeInfos.map(
@@ -86,7 +86,7 @@ tr.exportTo('tr.ui.tracks', function() {
},
updateContents_: function() {
- this.textContent = '';
+ Polymer.dom(this).textContent = '';
if (!this.model_)
return;
@@ -103,19 +103,19 @@ tr.exportTo('tr.ui.tracks', function() {
if (this.model_.userModel.expectations.length) {
var mrt = new tr.ui.tracks.InteractionTrack(this.viewport_);
mrt.model = this.model_;
- this.appendChild(mrt);
+ Polymer.dom(this).appendChild(mrt);
}
if (this.model_.alerts.length) {
var at = new tr.ui.tracks.AlertTrack(this.viewport_);
at.alerts = this.model_.alerts;
- this.appendChild(at);
+ Polymer.dom(this).appendChild(at);
}
if (this.model_.globalMemoryDumps.length) {
var gmdt = new tr.ui.tracks.GlobalMemoryDumpTrack(this.viewport_);
gmdt.memoryDumps = this.model_.globalMemoryDumps;
- this.appendChild(gmdt);
+ Polymer.dom(this).appendChild(gmdt);
}
this.appendDeviceTrack_();
@@ -134,7 +134,7 @@ tr.exportTo('tr.ui.tracks', function() {
if (!track.hasVisibleContent)
continue;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
this.viewport_.rebuildEventToTrackMap();
this.viewport_.rebuildContainerToTrackMap();
@@ -179,7 +179,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.device = this.model.device;
if (!track.hasVisibleContent)
return;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
},
appendKernelTrack_: function() {
@@ -188,6 +188,14 @@ tr.exportTo('tr.ui.tracks', function() {
track.kernel = this.model.kernel;
if (!track.hasVisibleContent)
return;
+ Polymer.dom(this).appendChild(track);
+ },
+
+ appendCpuUsageTrack_: function() {
+ var track = new tr.ui.tracks.CpuUsageTrack(this.viewport);
+ track.initialize(this.model);
+ if (!track.hasVisibleContent)
+ return;
this.appendChild(track);
},
@@ -318,17 +326,17 @@ tr.exportTo('tr.ui.tracks', function() {
var startBounds = startTrack.getBoundingClientRect();
var endBounds = endTrack.getBoundingClientRect();
- if (flowEvent.selectionState == SelectionState.SELECTED) {
+ if (flowEvent.selectionState === SelectionState.SELECTED) {
ctx.shadowBlur = 1;
ctx.shadowColor = 'red';
ctx.shadowOffsety = 2;
ctx.strokeStyle = 'red';
- } else if (flowEvent.selectionState == SelectionState.HIGHLIGHTED) {
+ } else if (flowEvent.selectionState === SelectionState.HIGHLIGHTED) {
ctx.shadowBlur = 1;
ctx.shadowColor = 'red';
ctx.shadowOffsety = 2;
ctx.strokeStyle = 'red';
- } else if (flowEvent.selectionState == SelectionState.DIMMED) {
+ } else if (flowEvent.selectionState === SelectionState.DIMMED) {
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
@@ -394,7 +402,8 @@ tr.exportTo('tr.ui.tracks', function() {
var bounds = track.getBoundingClientRect();
var size = bounds.left + bounds.top + bounds.bottom + bounds.right;
if (size === 0)
- return this.calculateTrackY_(track.parentNode, canvasBounds);
+ return this.calculateTrackY_(
+ Polymer.dom(track).parentNode, canvasBounds);
return bounds.top - canvasBounds.top + (bounds.height / 2);
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html
index 04637ef2d2a..787dc1a17ac 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html
@@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/tracks/container_track.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/model/model_settings.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/container_track.html">
<script>
'use strict';
@@ -84,7 +84,7 @@ tr.exportTo('tr.ui.tracks', function() {
},
set expanded(expanded) {
- if (this.expanded_ == expanded)
+ if (this.expanded_ === expanded)
return;
this.expanded_ = expanded;
this.expandedStateChanged_();
@@ -178,10 +178,10 @@ tr.exportTo('tr.ui.tracks', function() {
},
updateHeadingAndTooltip_: function() {
- if (!this.firstChild)
+ if (!Polymer.dom(this).firstChild)
return;
- this.firstChild.heading = this.heading_;
- this.firstChild.tooltip = this.tooltip_;
+ Polymer.dom(this).firstChild.heading = this.heading_;
+ Polymer.dom(this).firstChild.tooltip = this.tooltip_;
},
/**
@@ -201,10 +201,10 @@ tr.exportTo('tr.ui.tracks', function() {
return false;
if (!a.length || !b.length)
return false;
- if (a.length != b.length)
+ if (a.length !== b.length)
return false;
for (var i = 0; i < a.length; ++i) {
- if (a[i] != b[i])
+ if (a[i] !== b[i])
return false;
}
return true;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html
index 6bb39093015..7910ed1857a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html
@@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html">
+<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/ui/analysis/object_instance_view.html">
+<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html">
+<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/ui/tracks/multi_row_track.html">
<link rel="import" href="/tracing/ui/tracks/object_instance_track.html">
-<link rel="import" href="/tracing/base/sorted_array_utils.html">
-<link rel="import" href="/tracing/ui/base/ui.html">
<script>
'use strict';
@@ -30,7 +30,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport);
- this.classList.add('object-instance-group-track');
+ Polymer.dom(this).classList.add('object-instance-group-track');
this.objectInstances_ = undefined;
},
@@ -46,7 +46,7 @@ tr.exportTo('tr.ui.tracks', function() {
var hasMultipleRows = this.subRows.length > 1;
var track = new tr.ui.tracks.ObjectInstanceTrack(this.viewport);
track.objectInstances = objectInstances;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
return track;
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html
index 4b6d3cacf11..f6a4fdda61c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html
@@ -36,12 +36,12 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('object-instance-track');
+ Polymer.dom(this).classList.add('object-instance-track');
this.objectInstances_ = [];
this.objectSnapshots_ = [];
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
set heading(heading) {
@@ -61,7 +61,7 @@ tr.exportTo('tr.ui.tracks', function() {
},
set objectInstances(objectInstances) {
- if (!objectInstances || objectInstances.length == 0) {
+ if (!objectInstances || objectInstances.length === 0) {
this.heading = '';
this.objectInstances_ = [];
this.objectSnapshots_ = [];
@@ -133,7 +133,7 @@ tr.exportTo('tr.ui.tracks', function() {
if (x > viewRWorld)
break;
- var right = instance.deletionTs == Number.MAX_VALUE ?
+ var right = instance.deletionTs === Number.MAX_VALUE ?
viewRWorld : instance.deletionTs;
ctx.fillStyle = EventPresenter.getObjectInstanceColor(instance);
ctx.fillRect(x, pixelRatio, right - x, height - 2 * pixelRatio);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html
index 1ba79b9db6c..aa0ab3f9a82 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html
@@ -49,10 +49,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = ObjectInstanceTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html
index 5905882acff..c650bdaf80d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html
@@ -39,7 +39,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
ChartTrack.prototype.decorate.call(this, viewport);
- this.classList.add('power-series-track');
+ Polymer.dom(this).classList.add('power-series-track');
this.heading = 'Power';
this.powerSeries_ = undefined;
},
@@ -65,7 +65,7 @@ tr.exportTo('tr.ui.tracks', function() {
var axis = new tr.ui.tracks.ChartAxis(0, undefined);
var pts = this.powerSeries_.samples.map(function(smpl) {
- return new tr.ui.tracks.ChartPoint(smpl, smpl.start, smpl.power);
+ return new tr.ui.tracks.ChartPoint(smpl, smpl.start, smpl.powerInW);
});
var renderingConfig = {
chartType: tr.ui.tracks.ChartSeriesType.AREA,
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html
index 29997361918..9c0913afb54 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html
@@ -28,7 +28,7 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new tr.ui.TimelineViewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
if (series) {
series.updateBounds();
@@ -61,7 +61,7 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = createDrawingContainer(series);
var track = new PowerSeriesTrack(drawingContainer.viewport);
track.powerSeries = series;
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(drawingContainer);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html
index c197bd9d010..c0051a7bd19 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html
@@ -62,7 +62,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.height = ALLOCATED_MEMORY_TRACK_HEIGHT + 'px';
track.series = series;
track.autoSetAllAxes({expandMax: true});
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html
index a4515d50403..06c2df6894e 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html
@@ -8,8 +8,8 @@ found in the LICENSE file.
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/ui/timeline_viewport.html">
<link rel="import" href="/tracing/ui/tracks/drawing_container.html">
-<link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html">
<link rel="import" href="/tracing/ui/tracks/memory_dump_track_test_utils.html">
+<link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html">
<script>
'use strict';
@@ -26,10 +26,10 @@ tr.b.unittest.testSuite(function() {
var div = document.createElement('div');
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new ProcessMemoryDumpTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
drawingContainer.invalidate();
track.memoryDumps = dumps;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html
index 4390766292d..9069ca86abe 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html
@@ -76,7 +76,7 @@ tr.exportTo('tr.ui.tracks', function() {
if (currentSlice) {
// simply find end of current important slice
- if (!op.isStart && op.slice == currentSlice) {
+ if (!op.isStart && op.slice === currentSlice) {
// important slice has ended
pushRect(lastStart, op.time, currentSlice);
lastStart = depth >= 1 ? op.time : undefined;
@@ -84,19 +84,19 @@ tr.exportTo('tr.ui.tracks', function() {
}
} else {
if (op.isStart) {
- if (depth == 1) {
+ if (depth === 1) {
lastStart = op.time;
currentSlice = op.slice;
} else if (op.slice) {
// switch to slice
- if (op.time != lastStart) {
+ if (op.time !== lastStart) {
pushRect(lastStart, op.time, undefined);
lastStart = op.time;
}
currentSlice = op.slice;
}
} else {
- if (depth == 0) {
+ if (depth === 0) {
pushRect(lastStart, op.time, undefined);
lastStart = undefined;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html
index 42451c042d9..84263855eef 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/ui/base/draw_helpers.html">
<link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html">
<link rel="import" href="/tracing/ui/tracks/process_track_base.html">
-<link rel="import" href="/tracing/ui/base/draw_helpers.html">
<script>
'use strict';
@@ -117,7 +117,7 @@ tr.exportTo('tr.ui.tracks', function() {
if (processMemoryDumps.length) {
var pmdt = new tr.ui.tracks.ProcessMemoryDumpTrack(this.viewport_);
pmdt.memoryDumps = processMemoryDumps;
- this.appendChild(pmdt);
+ Polymer.dom(this).appendChild(pmdt);
}
},
@@ -152,4 +152,3 @@ tr.exportTo('tr.ui.tracks', function() {
};
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html
index d96f1ce02cb..b56b2cf3002 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html
@@ -44,17 +44,17 @@ tr.exportTo('tr.ui.tracks', function() {
this.processBase_ = undefined;
- this.classList.add('process-track-base');
- this.classList.add('expanded');
+ Polymer.dom(this).classList.add('process-track-base');
+ Polymer.dom(this).classList.add('expanded');
this.processNameEl_ = tr.ui.b.createSpan();
- this.processNameEl_.classList.add('process-track-name');
+ Polymer.dom(this.processNameEl_).classList.add('process-track-name');
this.headerEl_ = tr.ui.b.createDiv({className: 'process-track-header'});
- this.headerEl_.appendChild(this.processNameEl_);
+ Polymer.dom(this.headerEl_).appendChild(this.processNameEl_);
this.headerEl_.addEventListener('click', this.onHeaderClick_.bind(this));
- this.appendChild(this.headerEl_);
+ Polymer.dom(this).appendChild(this.headerEl_);
},
get processBase() {
@@ -75,7 +75,7 @@ tr.exportTo('tr.ui.tracks', function() {
},
get expanded() {
- return this.classList.contains('expanded');
+ return Polymer.dom(this).classList.contains('expanded');
},
set expanded(expanded) {
@@ -84,7 +84,7 @@ tr.exportTo('tr.ui.tracks', function() {
if (this.expanded === expanded)
return;
- this.classList.toggle('expanded');
+ Polymer.dom(this).classList.toggle('expanded');
// Expanding and collapsing tracks is, essentially, growing and shrinking
// the viewport. We dispatch a change event to trigger any processing
@@ -119,7 +119,8 @@ tr.exportTo('tr.ui.tracks', function() {
if (!this.processBase_)
return;
- this.processNameEl_.textContent = this.processBase_.userFriendlyName;
+ Polymer.dom(this.processNameEl_).textContent =
+ this.processBase_.userFriendlyName;
this.headerEl_.title = this.processBase_.userFriendlyDetails;
// Create the object instance tracks for this process.
@@ -156,7 +157,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.process = this.process;
if (!track.hasVisibleContent)
return;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
// no spacing track, since this track only shown in collapsed state
},
@@ -167,7 +168,7 @@ tr.exportTo('tr.ui.tracks', function() {
var track = new tr.ui.tracks.FrameTrack(this.viewport);
track.frames = frames;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
},
appendObjectInstanceTracks_: function() {
@@ -228,11 +229,11 @@ tr.exportTo('tr.ui.tracks', function() {
}
var track = new trackConstructor(this.viewport);
track.objectInstances = visibleInstances;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
didAppendAtLeastOneTrack = true;
}, this);
if (didAppendAtLeastOneTrack)
- this.appendChild(new SpacingTrack(this.viewport));
+ Polymer.dom(this).appendChild(new SpacingTrack(this.viewport));
},
appendCounterTracks_: function() {
@@ -244,8 +245,8 @@ tr.exportTo('tr.ui.tracks', function() {
counters.forEach(function(counter) {
var track = new tr.ui.tracks.CounterTrack(this.viewport);
track.counter = counter;
- this.appendChild(track);
- this.appendChild(new SpacingTrack(this.viewport));
+ Polymer.dom(this).appendChild(track);
+ Polymer.dom(this).appendChild(new SpacingTrack(this.viewport));
}.bind(this));
},
@@ -260,8 +261,8 @@ tr.exportTo('tr.ui.tracks', function() {
track.thread = thread;
if (!track.hasVisibleContent)
return;
- this.appendChild(track);
- this.appendChild(new SpacingTrack(this.viewport));
+ Polymer.dom(this).appendChild(track);
+ Polymer.dom(this).appendChild(new SpacingTrack(this.viewport));
}.bind(this));
}
};
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html
index 70da91be408..770dc97318d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html
@@ -34,12 +34,12 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('rect-track');
+ Polymer.dom(this).classList.add('rect-track');
this.asyncStyle_ = false;
this.rects_ = null;
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
set heading(heading) {
@@ -163,7 +163,7 @@ tr.exportTo('tr.ui.tracks', function() {
var instantEventWidth = 2 * viewPixWidthWorld;
tr.b.iterateOverIntersectingIntervals(this.rects_,
function(x) { return x.start; },
- function(x) { return x.duration == 0 ?
+ function(x) { return x.duration === 0 ?
x.duration + instantEventWidth :
x.duration; },
loWX, hiWX,
@@ -237,7 +237,7 @@ tr.exportTo('tr.ui.tracks', function() {
this.start = start;
this.duration = duration;
this.end = start + duration;
- };
+ }
Rect.prototype = {
__proto__: tr.model.ProxySelectableItem.prototype
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html
index 6dcb905a304..f6d33831a9d 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html
@@ -19,7 +19,7 @@ tr.b.unittest.testSuite(function() {
var EventSet = tr.model.EventSet;
var RectTrack = tr.ui.tracks.RectTrack;
var Rect = tr.ui.tracks.Rect;
- var Slice = tr.model.Slice;
+ var ThreadSlice = tr.model.ThreadSlice;
var Viewport = tr.ui.TimelineViewport;
test('instantiate_withRects', function() {
@@ -27,10 +27,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
@@ -53,20 +53,20 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
track.heading = 'testBasicSlices';
track.rects = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 2.1, {}, 4.8),
- new Slice('', 'b', 1, 7, {}, 0.5),
- new Slice('', 'c', 2, 7.6, {}, 0.4)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 2.1, {}, 4.8),
+ new ThreadSlice('', 'b', 1, 7, {}, 0.5),
+ new ThreadSlice('', 'c', 2, 7.6, {}, 0.4)
];
var dt = new tr.ui.TimelineDisplayTransform();
@@ -79,10 +79,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
@@ -114,14 +114,14 @@ tr.b.unittest.testSuite(function() {
var dict = optDicts[dictIndex];
var div = document.createElement('div');
- div.appendChild(document.createTextNode(dict.trackName));
+ Polymer.dom(div).appendChild(document.createTextNode(dict.trackName));
var viewport = new Viewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = new RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
@@ -144,10 +144,10 @@ tr.b.unittest.testSuite(function() {
test('findAllObjectsMatchingInRectTrack', function() {
var track = new RectTrack(new tr.ui.TimelineViewport());
track.rects = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 2.1, {}, 4.8),
- new Slice('', 'b', 1, 7, {}, 0.5),
- new Slice('', 'c', 2, 7.6, {}, 0.4)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 2.1, {}, 4.8),
+ new ThreadSlice('', 'b', 1, 7, {}, 0.5),
+ new ThreadSlice('', 'c', 2, 7.6, {}, 0.4)
];
var selection = new EventSet();
track.addAllEventsMatchingFilterToSelection(
@@ -160,23 +160,24 @@ tr.b.unittest.testSuite(function() {
test('selectionHitTesting', function() {
var testEl = document.createElement('div');
- testEl.appendChild(tr.ui.b.createScopedStyle('heading { width: 100px; }'));
+ Polymer.dom(testEl).appendChild(
+ tr.ui.b.createScopedStyle('heading { width: 100px; }'));
testEl.style.width = '600px';
var viewport = new Viewport(testEl);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- testEl.appendChild(drawingContainer);
+ Polymer.dom(testEl).appendChild(drawingContainer);
var track = new RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(testEl);
drawingContainer.updateCanvasSizeIfNeeded_();
track.heading = 'testSelectionHitTesting';
track.rects = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 5, {}, 4.8)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 5, {}, 4.8)
];
var y = track.getBoundingClientRect().top + 5;
var pixelRatio = window.devicePixelRatio || 1;
@@ -217,10 +218,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new Viewport(testEl);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- testEl.appendChild(drawingContainer);
+ Polymer.dom(testEl).appendChild(drawingContainer);
var track = new RectTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(testEl);
drawingContainer.updateCanvasSizeIfNeeded_();
@@ -231,8 +232,8 @@ tr.b.unittest.testSuite(function() {
track.heading = 'testElide';
track.rects = [
// title, colorId, start, args, opt_duration
- new Slice('', bigtitle, 0, 1, {}, 1),
- new Slice('', smalltitle, 1, 2, {}, 1)
+ new ThreadSlice('', bigtitle, 0, 1, {}, 1),
+ new ThreadSlice('', smalltitle, 1, 2, {}, 1)
];
var dt = new tr.ui.TimelineDisplayTransform();
dt.xSetWorldBounds(0, 3.3, track.clientWidth);
@@ -296,10 +297,10 @@ tr.b.unittest.testSuite(function() {
test('rectTrackAddItemNearToProvidedEvent', function() {
var track = new RectTrack(new tr.ui.TimelineViewport());
track.rects = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 2.1, {}, 4.8),
- new Slice('', 'b', 1, 7, {}, 0.5),
- new Slice('', 'c', 2, 7.6, {}, 0.4)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 2.1, {}, 4.8),
+ new ThreadSlice('', 'b', 1, 7, {}, 0.5),
+ new ThreadSlice('', 'c', 2, 7.6, {}, 0.4)
];
var sel = new EventSet();
track.addAllEventsMatchingFilterToSelection(
@@ -308,27 +309,30 @@ tr.b.unittest.testSuite(function() {
// Select to the right of B.
var selRight = new EventSet();
- ret = track.addEventNearToProvidedEventToSelection(sel[0], 1, selRight);
+ ret = track.addEventNearToProvidedEventToSelection(
+ tr.b.getFirstElement(sel), 1, selRight);
assert.isTrue(ret);
- assert.equal(track.rects[2].modelItem, selRight[0]);
+ assert.equal(track.rects[2].modelItem, tr.b.getFirstElement(selRight));
// Select to the right of the 2nd b.
var selRight2 = new EventSet();
- ret = track.addEventNearToProvidedEventToSelection(sel[0], 2, selRight2);
+ ret = track.addEventNearToProvidedEventToSelection(
+ tr.b.getFirstElement(sel), 2, selRight2);
assert.isTrue(ret);
- assert.equal(track.rects[3].modelItem, selRight2[0]);
+ assert.equal(track.rects[3].modelItem, tr.b.getFirstElement(selRight2));
// Select to 2 to the right of the 2nd b.
var selRightOfRight = new EventSet();
ret = track.addEventNearToProvidedEventToSelection(
- selRight[0], 1, selRightOfRight);
+ tr.b.getFirstElement(selRight), 1, selRightOfRight);
assert.isTrue(ret);
- assert.equal(track.rects[3].modelItem, selRightOfRight[0]);
+ assert.equal(track.rects[3].modelItem,
+ tr.b.getFirstElement(selRightOfRight));
// Select to the right of the rightmost slice.
var selNone = new EventSet();
ret = track.addEventNearToProvidedEventToSelection(
- selRightOfRight[0], 1, selNone);
+ tr.b.getFirstElement(selRightOfRight), 1, selNone);
assert.isFalse(ret);
assert.equal(0, selNone.length);
@@ -339,7 +343,8 @@ tr.b.unittest.testSuite(function() {
var ret;
selNone = new EventSet();
- ret = track.addEventNearToProvidedEventToSelection(sel[0], -1, selNone);
+ ret = track.addEventNearToProvidedEventToSelection(
+ tr.b.getFirstElement(sel), -1, selNone);
assert.isFalse(ret);
assert.equal(0, selNone.length);
});
@@ -347,10 +352,10 @@ tr.b.unittest.testSuite(function() {
test('rectTrackAddClosestEventToSelection', function() {
var track = new RectTrack(new tr.ui.TimelineViewport());
track.rects = [
- new Slice('', 'a', 0, 1, {}, 1),
- new Slice('', 'b', 1, 2.1, {}, 4.8),
- new Slice('', 'b', 1, 7, {}, 0.5),
- new Slice('', 'c', 2, 7.6, {}, 0.4)
+ new ThreadSlice('', 'a', 0, 1, {}, 1),
+ new ThreadSlice('', 'b', 1, 2.1, {}, 4.8),
+ new ThreadSlice('', 'b', 1, 7, {}, 0.5),
+ new ThreadSlice('', 'c', 2, 7.6, {}, 0.4)
];
// Before with not range.
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html
index 30ce44be39d..63d409c45da 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html
@@ -33,7 +33,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('ruler-track');
+ Polymer.dom(this).classList.add('ruler-track');
this.strings_secs_ = [];
this.strings_msecs_ = [];
this.strings_usecs_ = [];
@@ -44,7 +44,7 @@ tr.exportTo('tr.ui.tracks', function() {
var heading = document.createElement('tr-ui-heading');
heading.arrowVisible = false;
- this.appendChild(heading);
+ Polymer.dom(this).appendChild(heading);
},
detach: function() {
@@ -55,9 +55,9 @@ tr.exportTo('tr.ui.tracks', function() {
viewportChange_: function() {
if (this.viewport.interestRange.isEmpty)
- this.classList.remove('tall-mode');
+ Polymer.dom(this).classList.remove('tall-mode');
else
- this.classList.add('tall-mode');
+ Polymer.dom(this).classList.add('tall-mode');
},
draw: function(type, viewLWorld, viewRWorld) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html
index 3ca0d72fdf4..bde5c5c916f 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html
@@ -19,10 +19,10 @@ tr.b.unittest.testSuite(function() {
var viewport = new tr.ui.TimelineViewport(div);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- div.appendChild(drawingContainer);
+ Polymer.dom(div).appendChild(drawingContainer);
var track = tr.ui.tracks.RulerTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
this.addHTMLOutput(div);
drawingContainer.invalidate();
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html
index 78ffd07cf00..70c7bc5c26c 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html
@@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/tracks/multi_row_track.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/ui/base/ui.html">
+<link rel="import" href="/tracing/ui/tracks/multi_row_track.html">
<script>
'use strict';
@@ -27,7 +27,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport);
- this.classList.add('slice-group-track');
+ Polymer.dom(this).classList.add('slice-group-track');
this.group_ = undefined;
// Set the collapse threshold so we don't collapse by default, but the
// user can explicitly collapse if they want it.
@@ -37,7 +37,7 @@ tr.exportTo('tr.ui.tracks', function() {
addSubTrack_: function(slices) {
var track = new tr.ui.tracks.SliceTrack(this.viewport);
track.slices = slices;
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
return track;
},
@@ -111,7 +111,7 @@ tr.exportTo('tr.ui.tracks', function() {
ops.sort(function(ix, iy) {
var x = slices[ix];
var y = slices[iy];
- if (x.start != y.start)
+ if (x.start !== y.start)
return x.start - y.start;
// Elements get inserted into the slices array in order of when the
@@ -131,7 +131,7 @@ tr.exportTo('tr.ui.tracks', function() {
// Try to fit the slice into the existing subrows.
var inserted = false;
for (var j = subRows.length - 1; j >= 0; j--) {
- if (subRows[j].length == 0)
+ if (subRows[j].length === 0)
continue;
var insertedSlice = subRows[j][subRows[j].length - 1];
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
index 6e3ff9813c4..fa5f75fad57 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
@@ -6,8 +6,8 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/ui/timeline_track_view.html">
<link rel="import" href="/tracing/model/slice_group.html">
+<link rel="import" href="/tracing/ui/timeline_track_view.html">
<script>
'use strict';
@@ -163,7 +163,7 @@ tr.b.unittest.testSuite(function() {
// Pattern being tested:
// [ a ]
- // [ b1 ] []<- b2 where b2.duration = 0 and b2.end == a.end.
+ // [ b1 ] []<- b2 where b2.duration = 0 and b2.end === a.end.
var sA = group.pushSlice(newSliceEx({title: 'a', start: 1, duration: 3}));
var sB1 = group.pushSlice(newSliceEx({title: 'b1', start: 1, duration: 2}));
var sB2 = group.pushSlice(newSliceEx({title: 'b2', start: 4, duration: 0}));
@@ -256,8 +256,8 @@ test('sliceGroupContainerMap', function() {
processTrack.process = process;
threadTrack.thread = thread;
groupTrack.group = group;
- processTrack.appendChild(threadTrack);
- threadTrack.appendChild(groupTrack);
+ Polymer.dom(processTrack).appendChild(threadTrack);
+ Polymer.dom(threadTrack).appendChild(groupTrack);
assert.equal(processTrack.eventContainer, process);
assert.equal(threadTrack.eventContainer, thread);
@@ -290,4 +290,3 @@ test('sliceGroupContainerMap', function() {
});
});
</script>
-
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html
index 2c22784a848..f0af57af087 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html
@@ -15,11 +15,11 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var SliceTrack = tr.ui.tracks.SliceTrack;
- var Slice = tr.model.Slice;
+ var ThreadSlice = tr.model.ThreadSlice;
test('modelMapping', function() {
var track = new SliceTrack(new tr.ui.TimelineViewport());
- var slice = new Slice('', 'a', 0, 1, {}, 1);
+ var slice = new ThreadSlice('', 'a', 0, 1, {}, 1);
track.slices = [slice];
var me0 = track.rects[0].modelItem;
assert.equal(slice, me0);
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html
index 5eea1c903e0..7b2fa252627 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html
@@ -27,10 +27,10 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('spacing-track');
+ Polymer.dom(this).classList.add('spacing-track');
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
addAllEventsMatchingFilterToSelection: function(filter, selection) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html
index e3e9ea89d40..0f47419bf9a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html
@@ -27,11 +27,11 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
- this.classList.add('stacked-bars-track');
+ Polymer.dom(this).classList.add('stacked-bars-track');
this.objectInstance_ = null;
this.heading_ = document.createElement('tr-ui-heading');
- this.appendChild(this.heading_);
+ Polymer.dom(this).appendChild(this.heading_);
},
set heading(heading) {
@@ -69,8 +69,8 @@ tr.exportTo('tr.ui.tracks', function() {
snapshots,
function(x) { return x.ts; },
function(x, i) {
- if (i == snapshots.length - 1) {
- if (snapshots.length == 1)
+ if (i === snapshots.length - 1) {
+ if (snapshots.length === 1)
return maxBounds;
return snapshots[i].ts - snapshots[i - 1].ts;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html
index aca956546b3..ece278cee1a 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html
@@ -32,7 +32,7 @@ tr.exportTo('tr.ui.tracks', function() {
decorate: function(viewport) {
tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
- this.classList.add('thread-track');
+ Polymer.dom(this).classList.add('thread-track');
},
get thread() {
@@ -78,7 +78,7 @@ tr.exportTo('tr.ui.tracks', function() {
timeSlicesTrack.height = tr.ui.b.THIN_SLICE_HEIGHT + 'px';
timeSlicesTrack.slices = this.thread_.timeSlices;
if (timeSlicesTrack.hasVisibleContent)
- this.appendChild(timeSlicesTrack);
+ Polymer.dom(this).appendChild(timeSlicesTrack);
}
if (this.thread_.sliceGroup.length) {
@@ -87,7 +87,7 @@ tr.exportTo('tr.ui.tracks', function() {
track.tooltip = this.thread_.userFriendlyDetails;
track.group = this.thread_.sliceGroup;
if (track.hasVisibleContent)
- this.appendChild(track);
+ Polymer.dom(this).appendChild(track);
}
},
@@ -99,7 +99,7 @@ tr.exportTo('tr.ui.tracks', function() {
asyncTrack.group = subGroup;
asyncTrack.heading = title;
if (asyncTrack.hasVisibleContent)
- this.appendChild(asyncTrack);
+ Polymer.dom(this).appendChild(asyncTrack);
}, this);
},
@@ -132,7 +132,7 @@ tr.exportTo('tr.ui.tracks', function() {
}
return selection;
};
- this.appendChild(samplesTrack);
+ Polymer.dom(this).appendChild(samplesTrack);
}, this);
},
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html
index 068c4f01e02..ed658480fd4 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html
@@ -37,15 +37,16 @@ tr.b.unittest.testSuite(function() {
t1.sliceGroup.pushSlice(new ThreadSlice('', 'b', 0, 5.1, {}, 4));
var testEl = document.createElement('div');
- testEl.appendChild(tr.ui.b.createScopedStyle('heading { width: 100px; }'));
+ Polymer.dom(testEl).appendChild(
+ tr.ui.b.createScopedStyle('heading { width: 100px; }'));
testEl.style.width = '600px';
var viewport = new Viewport(testEl);
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
- testEl.appendChild(drawingContainer);
+ Polymer.dom(testEl).appendChild(drawingContainer);
var track = new ThreadTrack(viewport);
- drawingContainer.appendChild(track);
+ Polymer.dom(drawingContainer).appendChild(track);
drawingContainer.updateCanvasSizeIfNeeded_();
track.thread = t1;
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html
index 09a54c27223..4b151ebf8f5 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html
@@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() {
throw new Error('viewport is required when creating a Track.');
this.viewport_ = viewport;
- this.classList.add('track');
+ Polymer.dom(this).classList.add('track');
},
get viewport() {
@@ -57,11 +57,11 @@ tr.exportTo('tr.ui.tracks', function() {
context: function() {
// This is a little weird here, but we have to be able to walk up the
// parent tree to get the context.
- if (!this.parentNode)
+ if (!Polymer.dom(this).parentNode)
return undefined;
- if (!this.parentNode.context)
+ if (!Polymer.dom(this).parentNode.context)
throw new Error('Parent container does not support context() method.');
- return this.parentNode.context();
+ return Polymer.dom(this).parentNode.context();
},
decorateChild_: function(childTrack) {
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html
index 0300e36d672..b4704f25a47 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html
@@ -29,61 +29,64 @@ with a brushingStateController field to persist the state (see the
tr.c.BrushingStateController and tr.ui.b.BrushingState classes for more
details).
-->
-<polymer-element name="tr-ui-b-view-specific-brushing-state">
- <script>
- 'use strict';
+<dom-module id='tr-ui-b-view-specific-brushing-state'>
+ <template></template>
+</dom-module>
+<script>
+'use strict';
- Polymer({
- /** Compulsory unique identifier of the associated view. */
- get viewId() {
- return this.getAttribute('view-id');
- },
+Polymer({
+ is: 'tr-ui-b-view-specific-brushing-state',
- set viewId(viewId) {
- this.setAttribute('view-id', viewId);
- },
+ /** Compulsory unique identifier of the associated view. */
+ get viewId() {
+ return this.getAttribute('view-id');
+ },
- /**
- * Retrieve the persisted state of the associated view. The returned object
- * (or any of its fields) must not be modified by the caller (unless the
- * object/field is treated as a reference).
- *
- * If no state has been persisted yet or there is no ancestor element with
- * a brushingStateController field, this method returns undefined.
- */
- get: function() {
- var viewId = this.viewId;
- if (!viewId)
- throw new Error('Element must have a view-id attribute!');
+ set viewId(viewId) {
+ Polymer.dom(this).setAttribute('view-id', viewId);
+ },
- var brushingStateController =
- tr.c.BrushingStateController.getControllerForElement(this);
- if (!brushingStateController)
- return undefined;
+ /**
+ * Retrieve the persisted state of the associated view. The returned object
+ * (or any of its fields) must not be modified by the caller (unless the
+ * object/field is treated as a reference).
+ *
+ * If no state has been persisted yet or there is no ancestor element with
+ * a brushingStateController field, this method returns undefined.
+ */
+ get: function() {
+ var viewId = this.viewId;
+ if (!viewId)
+ throw new Error('Element must have a view-id attribute!');
- return brushingStateController.getViewSpecificBrushingState(viewId);
- },
+ var brushingStateController =
+ tr.c.BrushingStateController.getControllerForElement(this);
+ if (!brushingStateController)
+ return undefined;
- /**
- * Persist the provided state of the associated view. The provided object
- * (or any of its fields) must not be modified afterwards (unless the
- * object/field is treated as a reference).
- *
- * If there is no ancestor element with a brushingStateController field,
- * this method does nothing.
- */
- set: function(state) {
- var viewId = this.viewId;
- if (!viewId)
- throw new Error('Element must have a view-id attribute!');
+ return brushingStateController.getViewSpecificBrushingState(viewId);
+ },
- var brushingStateController =
- tr.c.BrushingStateController.getControllerForElement(this);
- if (!brushingStateController)
- return;
+ /**
+ * Persist the provided state of the associated view. The provided object
+ * (or any of its fields) must not be modified afterwards (unless the
+ * object/field is treated as a reference).
+ *
+ * If there is no ancestor element with a brushingStateController field,
+ * this method does nothing.
+ */
+ set: function(state) {
+ var viewId = this.viewId;
+ if (!viewId)
+ throw new Error('Element must have a view-id attribute!');
- brushingStateController.changeViewSpecificBrushingState(viewId, state);
- }
- });
- </script>
-</polymer-element>
+ var brushingStateController =
+ tr.c.BrushingStateController.getControllerForElement(this);
+ if (!brushingStateController)
+ return;
+
+ brushingStateController.changeViewSpecificBrushingState(viewId, state);
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html
index e4e8ece0441..aff2cc5a473 100644
--- a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html
@@ -18,13 +18,13 @@ tr.b.unittest.testSuite(function() {
var stateElement = document.createElement(
'tr-ui-b-view-specific-brushing-state');
stateElement.viewId = viewId;
- containerEl.appendChild(stateElement);
+ Polymer.dom(containerEl).appendChild(stateElement);
return stateElement;
}
function addChildDiv(element) {
var child = element.ownerDocument.createElement('div');
- element.appendChild(child);
+ Polymer.dom(element).appendChild(child);
return child;
}
diff --git a/chromium/third_party/catapult/tracing/tracing/value/__init__.py b/chromium/third_party/catapult/tracing/tracing/value/__init__.py
deleted file mode 100644
index c134637dac2..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/value/__init__.py
+++ /dev/null
@@ -1,192 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Simplified version of telemetry Value system, just enough for us to get
-# us up and running.
-
-
-class Value(object):
-
- def __init__(self, canonical_url, name, units, description=None,
- important=False, ir_stable_id=None):
- self.canonical_url = canonical_url
- self.name = name
- self.units = units
- self.description = description
- self.important = important
- self.ir_stable_id = ir_stable_id
-
- def AsDict(self):
- d = {
- 'canonical_url': self.canonical_url,
- 'name': self.name,
- 'important': self.important
- }
- # Only dump values if they're non-None, because Python json-ification turns
- # these to null, instead of leaving them out.
- if self.units is not None:
- d['units'] = self.units
-
- if self.description is not None:
- d['description'] = self.description
-
- if self.ir_stable_id is not None:
- d['ir_stable_id'] = self.ir_stable_id
-
- self._AsDictInto(d)
- assert 'type' in d
-
- return d
-
- def _AsDictInto(self, d):
- raise NotImplementedError()
-
- @classmethod
- def FromDict(cls, d):
- if d['type'] == 'dict':
- return DictValue.FromDict(d)
- elif d['type'] == 'scalar':
- return ScalarValue.FromDict(d)
- elif d['type'] == 'failure':
- return FailureValue.FromDict(d)
- elif d['type'] == 'skip':
- return SkipValue.FromDict(d)
- else:
- raise NotImplementedError()
-
-
-# TODO(eakuefner): Change to NumericValue after porting Unit
-# (https://github.com/catapult-project/catapult/issues/2049)
-class ScalarValue(Value):
-
- def __init__(self, canonical_url, name, value, description=None,
- important=False, ir_stable_id=None):
- assert isinstance(value, dict)
- super(ScalarValue, self).__init__(canonical_url, name, units=None,
- description=description,
- important=important,
- ir_stable_id=ir_stable_id)
- self._value = value
-
- def __repr__(self):
- return '%s("%s", "%s")' % (self.__class__.__name__,
- self.name, self.value)
-
- def _AsDictInto(self, d):
- d['type'] = 'scalar'
- d['value'] = self._value
-
- @classmethod
- def FromDict(cls, d):
- assert d.get('units', None) == None
- return cls(d['canonical_url'], name=d['name'],
- description=d.get('description', None),
- value=d['value'],
- important=d['important'],
- ir_stable_id=d.get('ir_stable_id', None))
-
- @property
- def value(self):
- return self._value
-
- def __getitem__(self, key):
- return self._value[key]
-
-
-class DictValue(Value):
-
- def __init__(self, canonical_url, name, value, description=None,
- important=False, ir_stable_id=None):
- assert isinstance(value, dict)
- super(DictValue, self).__init__(canonical_url, name, units=None,
- description=description,
- important=important,
- ir_stable_id=ir_stable_id)
- self._value = value
-
- def __repr__(self):
- return '%s("%s", "%s")' % (self.__class__.__name__,
- self.name, self.value)
-
- def _AsDictInto(self, d):
- d['type'] = 'dict'
- d['value'] = self._value
-
- @classmethod
- def FromDict(cls, d):
- assert d.get('units', None) == None
- return cls(d['canonical_url'], name=d['name'],
- description=d.get('description', None),
- value=d['value'],
- important=d['important'],
- ir_stable_id=d.get('ir_stable_id', None))
-
- @property
- def value(self):
- return self._value
-
- def __getitem__(self, key):
- return self._value[key]
-
-class FailureValue(Value):
-
- def __init__(self, canonical_url, failure_type_name, description, stack,
- important=False, ir_stable_id=None):
- super(FailureValue, self).__init__(canonical_url,
- name=failure_type_name,
- units=None,
- description=description,
- important=important,
- ir_stable_id=ir_stable_id)
- assert isinstance(stack, basestring)
- self.stack = stack
-
- def __repr__(self):
- return '%s("%s", "%s")' % (self.__class__.__name__,
- self.name, self.description)
-
- def _AsDictInto(self, d):
- d['type'] = 'failure'
- d['stack_str'] = self.stack
-
- @classmethod
- def FromDict(cls, d):
- assert d.get('units', None) == None
- return cls(d['canonical_url'],
- failure_type_name=d['name'],
- description=d.get('description', None),
- stack=d['stack_str'],
- important=d.get('important', False),
- ir_stable_id=d.get('ir_stable_id', None))
-
- def GetGTestPrintString(self):
- return self.stack
-
-
-class SkipValue(Value):
-
- def __init__(self, canonical_url, skipped_result_name,
- description=None, important=False, ir_stable_id=None):
- super(SkipValue, self).__init__(canonical_url,
- name=skipped_result_name,
- units=None,
- description=description,
- important=important,
- ir_stable_id=ir_stable_id)
-
- def __repr__(self):
- return '%s("%s", "%s")' % (self.__class__.__name__,
- self.name, self.description)
-
- def _AsDictInto(self, d):
- d['type'] = 'skip'
-
- @classmethod
- def FromDict(cls, d):
- assert d.get('units', None) == None
- return cls(d['canonical_url'],
- skipped_result_name=d['name'],
- description=d.get('description', None),
- important=d.get('important', False),
- ir_stable_id=d.get('ir_stable_id', None))
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/breakdown.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/breakdown.html
new file mode 100644
index 00000000000..ed3a7f4e8b3
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/breakdown.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/related_value_map.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v.d', function() {
+ class Breakdown extends tr.v.d.Diagnostic {
+ constructor() {
+ super();
+ this.values_ = new Map();
+ this.colorScheme = undefined;
+ }
+
+ /**
+ * Add a Value by an explicit name to this map.
+ *
+ * @param {string} name
+ * @param {number} value
+ */
+ set(name, value) {
+ if (typeof name !== 'string' ||
+ typeof value !== 'number') {
+ throw new Error('Breakdown maps from strings to numbers');
+ }
+ this.values_.set(name, value);
+ }
+
+ /**
+ * @param {string} name
+ * @return {number}
+ */
+ get(name) {
+ return this.values_.get(name) || 0;
+ }
+
+ *[Symbol.iterator]() {
+ for (var pair of this.values_)
+ yield pair;
+ }
+
+ asDictInto_(d) {
+ d.values = {};
+ for (var [name, value] of this) {
+ if (isNaN(value)) {
+ value = 'NaN';
+ } else if (value === Infinity) {
+ value = 'Infinity';
+ } else if (value === -Infinity) {
+ value = '-Infinity';
+ }
+ d.values[name] = value;
+ }
+ if (this.colorScheme) {
+ d.colorScheme = this.colorScheme;
+ }
+ }
+
+ static fromDict(d) {
+ var breakdown = new Breakdown();
+ tr.b.iterItems(d.values, (name, value) => {
+ if (typeof(value) === 'string') {
+ if (value === '-Infinity') {
+ value = -Infinity;
+ } else if (value === 'Infinity') {
+ value = Infinity;
+ } else if (value === 'NaN') {
+ value = NaN;
+ }
+ } else if (value === null) {
+ value = NaN;
+ }
+ breakdown.set(name, value);
+ });
+ if (d.colorScheme) {
+ breakdown.colorScheme = d.colorScheme;
+ }
+ return breakdown;
+ }
+ }
+
+ tr.v.d.Diagnostic.register(Breakdown, {
+ elementName: 'tr-v-ui-breakdown-span'
+ });
+
+ return {
+ Breakdown: Breakdown
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/composition.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/composition.html
deleted file mode 100644
index c58f29d0b02..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/composition.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2016 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/value/diagnostics/related_value_set.html">
-
-<script>
-'use strict';
-
-tr.exportTo('tr.v.d', function() {
- /** @constructor */
- function Composition(opt_values) {
- tr.v.d.RelatedValueSet.call(this, opt_values);
- }
-
- Composition.prototype = {
- __proto__: tr.v.d.RelatedValueSet.prototype
- };
-
- Composition.fromDict = function(d) {
- return new Composition(d.guids.map(guid => new tr.v.d.ValueRef(guid)));
- };
-
- tr.v.d.Diagnostic.register(Composition);
-
- return {
- Composition: Composition
- };
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic.html
index 2b65454620b..b111453fed4 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic.html
@@ -11,21 +11,25 @@ found in the LICENSE file.
'use strict';
tr.exportTo('tr.v.d', function() {
- /** @constructor */
- function Diagnostic() {
- }
-
- Diagnostic.prototype = {
- asDict: function() {
+ class Diagnostic {
+ asDict() {
var result = {type: this.constructor.name};
this.asDictInto_(result);
return result;
- },
+ }
- asDictInto_: function(d) {
+ asDictInto_(d) {
throw new Error('Abstract virtual method');
}
- };
+
+ static fromDict(d) {
+ var typeInfo = Diagnostic.findTypeInfoWithName(d.type);
+ if (!typeInfo)
+ throw new Error('Unrecognized diagnostic type: ' + d.type);
+
+ return typeInfo.constructor.fromDict(d);
+ }
+ }
var options = new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);
options.defaultMetadata = {};
@@ -35,24 +39,12 @@ tr.exportTo('tr.v.d', function() {
Diagnostic.addEventListener('will-register', function(e) {
var constructor = e.typeInfo.constructor;
if (!(constructor.fromDict instanceof Function) ||
+ (constructor.fromDict === Diagnostic.fromDict) ||
(constructor.fromDict.length !== 1)) {
throw new Error('Diagnostics must define fromDict(d)');
}
-
- // When subclasses set their prototype to an entirely new object and omit
- // their constructor, then it becomes impossible for asDict() to find their
- // constructor name. Add it back here so that asDict() can find it.
- constructor.prototype.constructor = constructor;
});
- Diagnostic.fromDict = function(d) {
- var typeInfo = Diagnostic.findTypeInfoWithName(d.type);
- if (!typeInfo)
- throw new Error('Unrecognized diagnostic type: ' + d.type);
-
- return typeInfo.constructor.fromDict(d);
- };
-
return {
Diagnostic: Diagnostic
};
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map.html
index 4af13e22d54..e0afe91d668 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map.html
@@ -11,85 +11,69 @@ found in the LICENSE file.
Diagnostic registry.
-->
-<link rel="import" href="/tracing/value/diagnostics/composition.html">
+<link rel="import" href="/tracing/value/diagnostics/breakdown.html">
<link rel="import" href="/tracing/value/diagnostics/generic.html">
<link rel="import" href="/tracing/value/diagnostics/iteration_info.html">
<link rel="import" href="/tracing/value/diagnostics/related_event_set.html">
+<link rel="import" href="/tracing/value/diagnostics/related_histogram_breakdown.html">
<link rel="import" href="/tracing/value/diagnostics/related_value_map.html">
<link rel="import" href="/tracing/value/diagnostics/related_value_set.html">
+<link rel="import" href="/tracing/value/diagnostics/scalar.html">
<script>
'use strict';
tr.exportTo('tr.v.d', function() {
- /** @constructor */
- function DiagnosticMap() {
- this.diagnosticsByName_ = {};
- }
-
- DiagnosticMap.prototype = {
+ class DiagnosticMap extends Map {
/**
* Add a new Diagnostic to this map.
*
* @param {string} name
* @param {!tr.v.d.Diagnostic} diagnostic
*/
- add: function(name, diagnostic) {
- if (!(diagnostic instanceof tr.v.d.Diagnostic))
- throw new Error('Must be instanceof Diagnostic: ' + diagnostic);
-
+ set(name, diagnostic) {
if (typeof(name) !== 'string')
throw new Error('name must be string, not ' + name);
- if (this.diagnosticsByName_[name])
- throw new Error('Attempt to add duplicate diagnostic ' + name);
+ if (!(diagnostic instanceof tr.v.d.Diagnostic))
+ throw new Error('Must be instanceof Diagnostic: ' + diagnostic);
- this.diagnosticsByName_[name] = diagnostic;
- },
+ Map.prototype.set.call(this, name, diagnostic);
+ }
/**
* Add Diagnostics from a dictionary of dictionaries.
*
* @param {Object} dict
*/
- addDicts: function(dict) {
+ addDicts(dict) {
tr.b.iterItems(dict, function(name, diagnosticDict) {
- this.add(name, tr.v.d.Diagnostic.fromDict(diagnosticDict));
+ this.set(name, tr.v.d.Diagnostic.fromDict(diagnosticDict));
}, this);
- },
-
- /**
- * @param {string} name
- * @return {tr.v.d.Diagnostic}
- */
- get: function(name) {
- return this.diagnosticsByName_[name];
- },
-
- /**
- * Iterate over this map's key-value-pairs.
- *
- * @param {function(string, tr.v.d.Diagnostic)} callback
- * @param {Object=} opt_this
- */
- forEach: function(callback, opt_this) {
- tr.b.iterItems(this.diagnosticsByName_, callback, opt_this || this);
- },
+ }
- asDict: function() {
+ asDict() {
var dict = {};
- this.forEach(function(name, diagnostic) {
+ for (var [name, diagnostic] of this) {
dict[name] = diagnostic.asDict();
- });
+ }
return dict;
}
- };
- DiagnosticMap.fromDict = function(d) {
- var diagnostics = new DiagnosticMap();
- diagnostics.addDicts(d);
- return diagnostics;
- };
+ static fromDict(d) {
+ var diagnostics = new DiagnosticMap();
+ diagnostics.addDicts(d);
+ return diagnostics;
+ }
+
+ static fromObject(obj) {
+ var diagnostics = new DiagnosticMap();
+ tr.b.iterItems(obj, function(name, diagnostic) {
+ diagnostics.set(name, diagnostic);
+ });
+ return diagnostics;
+ }
+ }
return {
DiagnosticMap: DiagnosticMap
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map_test.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map_test.html
new file mode 100644
index 00000000000..8b7210e966f
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/diagnostic_map_test.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('clone', function() {
+ var diagnostics = new tr.v.d.DiagnosticMap();
+ diagnostics.set('generic', new tr.v.d.Generic({a: ['b', 3]}));
+ diagnostics.set('breakdown', new tr.v.d.Breakdown());
+ diagnostics.set('events', new tr.v.d.RelatedEventSet());
+ diagnostics.set('value set', new tr.v.d.RelatedValueSet());
+ diagnostics.set('value map', new tr.v.d.RelatedValueMap());
+ diagnostics.set('histogram breakdown',
+ new tr.v.d.RelatedHistogramBreakdown());
+
+ var clone = tr.v.d.DiagnosticMap.fromDict(diagnostics.asDict());
+ assert.instanceOf(clone.get('generic'), tr.v.d.Generic);
+ assert.deepEqual(clone.get('generic').value,
+ diagnostics.get('generic').value);
+ assert.instanceOf(clone.get('breakdown'), tr.v.d.Breakdown);
+ assert.instanceOf(clone.get('events'), tr.v.d.RelatedEventSet);
+ assert.instanceOf(clone.get('value set'), tr.v.d.RelatedValueSet);
+ assert.instanceOf(clone.get('value map'), tr.v.d.RelatedValueMap);
+ assert.instanceOf(clone.get('histogram breakdown'),
+ tr.v.d.RelatedHistogramBreakdown);
+ });
+
+ test('requireFromDict', function() {
+ class MissingFromDict extends tr.v.d.Diagnostic { }
+ assert.throws(() => tr.v.d.Diagnostic.register(MissingFromDict));
+
+ class InvalidFromDict extends tr.v.d.Diagnostic {
+ static fromDict() {
+ }
+ }
+ assert.throws(() => tr.v.d.Diagnostic.register(InvalidFromDict));
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/event_ref.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/event_ref.html
new file mode 100644
index 00000000000..3df5f311cfb
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/event_ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/guid.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v.d', function() {
+ /**
+ * Similar to ValueRef, this is a placeholder in case the referenced Event
+ * isn't available in memory to point to directly.
+ */
+ class EventRef {
+ /**
+ * @param {!Object} event
+ * @param {string} event.stableId
+ * @param {string} event.title
+ * @param {number} event.start
+ * @param {number} event.duration
+ */
+ constructor(event) {
+ this.stableId = event.stableId;
+ this.title = event.title;
+ this.start = event.start;
+ this.duration = event.duration;
+ this.end = this.start + this.duration;
+
+ // tr.v.d.RelatedEventSet identifies events using stableId, but
+ // tr.model.EventSet uses guid.
+ this.guid = tr.b.GUID.allocateSimple();
+ }
+ }
+
+ return {
+ EventRef: EventRef
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/generic.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/generic.html
index 7ac19796e34..fae4fdd3119 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/generic.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/generic.html
@@ -15,25 +15,24 @@ tr.exportTo('tr.v.d', function() {
* A Generic diagnostic can contain any Plain-Ol'-Data objects that can be
* serialized using JSON.stringify(): null, boolean, number, string, array,
* dict. Generic diagnostics cannot contain tr.v.Value objects!
- *
- * @constructor
- * @param {*} value
*/
- function Generic(value) {
- this.value = value;
- }
-
- Generic.prototype = {
- __proto__: tr.v.d.Diagnostic.prototype,
+ class Generic extends tr.v.d.Diagnostic {
+ /**
+ * @param {*} value
+ */
+ constructor(value) {
+ super();
+ this.value = value;
+ }
- asDictInto_: function(d) {
+ asDictInto_(d) {
d.value = this.value;
}
- };
- Generic.fromDict = function(d) {
- return new Generic(d.value);
- };
+ static fromDict(d) {
+ return new Generic(d.value);
+ }
+ }
tr.v.d.Diagnostic.register(Generic, {
elementName: 'tr-v-ui-generic-diagnostic-span'
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/iteration_info.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/iteration_info.html
index d2047935916..5ce2faf8f9d 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/iteration_info.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/iteration_info.html
@@ -5,91 +5,198 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/utils.html">
<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
<script>
'use strict';
tr.exportTo('tr.v.d', function() {
- /**
- * @constructor
- * @param {!Object} info
- * @param {string} info.benchmarkName
- * @param {undefined|string} info.label
- * @param {undefined|!Object} info.storyGroupingKeys
- * @param {undefined|string} info.storyDisplayName
- * @param {string} info.storyUrl
- * @param {number} info.storyRepeatCounter
- * @param {number} info.storysetRepeatCounter
- * @param {number} info.benchmarkStartMs Milliseconds since Unix epoch.
- */
- function IterationInfo(info) {
- this.benchmarkName_ = info.benchmarkName;
- this.benchmarkStart_ = new Date(info.benchmarkStartMs);
- this.label_ = info.label;
- this.storyDisplayName_ = info.storyDisplayName;
- this.storyGroupingKeys_ = info.storyGroupingKeys;
- this.storyRepeatCounter_ = info.storyRepeatCounter;
- this.storyUrl_ = info.storyUrl;
- this.storysetRepeatCounter_ = info.storysetRepeatCounter;
- }
+ class IterationInfo extends tr.v.d.Diagnostic {
+ constructor(opt_info) {
+ super();
+
+ this.benchmarkName_ = '';
+ this.benchmarkStart_ = undefined;
+ this.label_ = '';
+ this.osVersion_ = '';
+ this.productVersion_ = '';
+ this.storyDisplayName_ = '';
+ this.storyGroupingKeys_ = {};
+ this.storyRepeatCounter_ = undefined;
+ this.storyUrl_ = '';
+ this.storysetRepeatCounter_ = undefined;
+
+ if (opt_info)
+ this.addInfo(opt_info);
+ }
- IterationInfo.prototype = {
- __proto__: tr.v.d.Diagnostic.prototype,
+ /**
+ * @param {!Object} info
+ * @param {string} info.benchmarkName
+ * @param {undefined|string} info.label
+ * @param {undefined|!Object} info.storyGroupingKeys
+ * @param {undefined|string} info.storyDisplayName
+ * @param {undefined|string} info.storyUrl
+ * @param {undefined|number} info.storyRepeatCounter
+ * @param {number} info.storysetRepeatCounter
+ * @param {number} info.benchmarkStartMs Milliseconds since Unix epoch.
+ */
+ addInfo(info) {
+ // IterationInfo from Telemetry
+ if (info.benchmarkName)
+ this.benchmarkName_ = info.benchmarkName;
+ if (info.benchmarkStartMs)
+ this.benchmarkStart_ = new Date(info.benchmarkStartMs);
+ if (info.label)
+ this.label_ = info.label;
+ if (info.storyDisplayName)
+ this.storyDisplayName_ = info.storyDisplayName;
+ if (info.storyGroupingKeys)
+ this.storyGroupingKeys_ = info.storyGroupingKeys;
+ if (info.storyRepeatCounter !== undefined)
+ this.storyRepeatCounter_ = info.storyRepeatCounter;
+ if (info.storyUrl)
+ this.storyUrl_ = info.storyUrl;
+ if (info.storysetRepeatCounter !== undefined)
+ this.storysetRepeatCounter_ = info.storysetRepeatCounter;
+
+ // From platform tracing metadata
+ if (info['os-version'])
+ this.osVersion_ = info['os-version'];
+ if (info['product-version'])
+ this.productVersion_ = info['product-version'];
+ }
+
+ addToValue(value) {
+ value.diagnostics.set(IterationInfo.NAME, this);
+ }
- asDictInto_: function(d) {
+ /**
+ * @param {!tr.v.Value} value
+ * @return {(undefined|!tr.v.d.IterationInfo)}
+ */
+ static getFromValue(value) {
+ return value.diagnostics.get(IterationInfo.NAME);
+ }
+
+ asDictInto_(d) {
d.benchmarkName = this.benchmarkName;
- d.benchmarkStartMs = this.benchmarkStart.getTime();
+ if (this.benchmarkStart)
+ d.benchmarkStartMs = this.benchmarkStart.getTime();
d.label = this.label;
d.storyDisplayName = this.storyDisplayName;
d.storyGroupingKeys = this.storyGroupingKeys;
d.storyRepeatCounter = this.storyRepeatCounter;
d.storyUrl = this.storyUrl;
d.storysetRepeatCounter = this.storysetRepeatCounter;
- },
+ d['os-version'] = this.osVersion;
+ d['product-version'] = this.productVersion;
+ }
+
+ static fromDict(d) {
+ var info = new IterationInfo();
+ info.addInfo(d);
+ return info;
+ }
get displayLabel() {
if (this.label)
return this.label;
- return this.benchmarkName + ' ' + this.benchmarkStart;
- },
+ return this.benchmarkName + ' ' + this.benchmarkStartString;
+ }
+
+ get osVersion() {
+ return this.osVersion_;
+ }
+
+ get productVersion() {
+ return this.productVersion_;
+ }
get benchmarkName() {
return this.benchmarkName_;
- },
+ }
get label() {
return this.label_;
- },
+ }
get storyGroupingKeys() {
return this.storyGroupingKeys_;
- },
+ }
get storyDisplayName() {
return this.storyDisplayName_;
- },
+ }
get storyUrl() {
return this.storyUrl_;
- },
+ }
get storyRepeatCounter() {
return this.storyRepeatCounter_;
- },
+ }
+
+ get storyRepeatCounterLabel() {
+ return 'story repeat ' + this.storyRepeatCounter;
+ }
get storysetRepeatCounter() {
return this.storysetRepeatCounter_;
- },
+ }
+
+ get storysetRepeatCounterLabel() {
+ return 'storyset repeat ' + this.storysetRepeatCounter;
+ }
get benchmarkStart() {
return this.benchmarkStart_;
}
- };
- IterationInfo.fromDict = function(d) {
- return new IterationInfo(d);
- };
+ get benchmarkStartString() {
+ if (this.benchmarkStart_ === undefined)
+ return '';
+ return tr.b.formatDate(this.benchmarkStart);
+ }
+
+ /**
+ * @param {!tr.v.Value} value
+ * @param {string} fieldName
+ * @param {*} defaultValue
+ * @return {*}
+ */
+ static getField(value, fieldName, defaultValue) {
+ var iteration = tr.v.d.IterationInfo.getFromValue(value);
+ if (!(iteration instanceof tr.v.d.IterationInfo) ||
+ !iteration[fieldName]) {
+ return defaultValue;
+ }
+ return iteration[fieldName];
+ }
+
+ /**
+ * @param {!tr.v.Value} value
+ * @param {string} storyGroupingKey
+ * @return {string}
+ */
+ static getStoryGroupingKeyLabel(value, storyGroupingKey) {
+ var iteration = tr.v.d.IterationInfo.getFromValue(value);
+ if (!(iteration instanceof tr.v.d.IterationInfo))
+ return storyGroupingKey + ': undefined';
+ return storyGroupingKey + ': ' +
+ iteration.storyGroupingKeys[storyGroupingKey];
+ }
+ }
+
+ // Diagnostics generally do not need a constant name or getFromValue().
+ // IterationInfo is a special kind of Diagnostic that is produced by
+ // telemetry, which shepherds whole flocks of traces at once, and needs a
+ // system to identify and find traces by these attributes.
+
+ // Values produced by telemetry all have a single IterationInfo at this key in
+ // their DiagnosticMap.
+ IterationInfo.NAME = 'iteration';
tr.v.d.Diagnostic.register(IterationInfo, {
elementName: 'tr-v-ui-iteration-info-span'
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set.html
index fa611de3695..c01ef300a5c 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set.html
@@ -7,70 +7,60 @@ found in the LICENSE file.
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
+<link rel="import" href="/tracing/value/diagnostics/event_ref.html">
<script>
'use strict';
tr.exportTo('tr.v.d', function() {
/**
- * Similar to ValueRef, this is a placeholder in case the referenced Event
- * isn't available in memory to point to directly.
- *
- * @constructor
- * @param {!Object} event
- * @param {string} event.stableId
- * @param {string} event.title
- * @param {number} event.start
- * @param {number} event.duration
+ * @typedef {!(tr.v.d.EventRef|tr.model.Event)} EventLike
*/
- function EventRef(event) {
- this.stableId = event.stableId;
- this.title = event.title;
- this.start = event.start;
- this.duration = event.duration;
- this.end = this.start + this.duration;
-
- // tr.v.d.RelatedEventSet identifies events using stableId, but
- // tr.model.EventSet uses guid.
- this.guid = tr.b.GUID.allocateSimple();
- }
/**
* A RelatedEventSet diagnostic contains references to Events
- *
- * @constructor
- * @param {(!tr.model.EventSet|Array.<!(EventRef|tr.model.Event)>|!EventRef|!tr.model.Event)=} opt_events
*/
- function RelatedEventSet(opt_events) {
- this.eventsByStableId_ = {};
-
- if (opt_events) {
- if (opt_events instanceof tr.model.EventSet ||
- opt_events instanceof Array)
- opt_events.forEach(this.push.bind(this));
- else
- this.push(opt_events);
+ class RelatedEventSet extends tr.v.d.Diagnostic {
+ /**
+ * @param {!(tr.model.EventSet|Array.<EventLike>|EventLike)=} opt_events
+ */
+ constructor(opt_events) {
+ super();
+ this.eventsByStableId_ = new Map();
+ if (opt_events) {
+ if (opt_events instanceof tr.model.EventSet ||
+ opt_events instanceof Array) {
+ for (var event of opt_events)
+ this.add(event);
+ } else {
+ this.add(opt_events);
+ }
+ }
}
- }
-
- RelatedEventSet.prototype = {
- __proto__: tr.v.d.Diagnostic.prototype,
/**
- * Add an event to this set.
- *
- * @param {!(EventRef|tr.model.Event)} event
+ * @param {!(tr.v.d.EventRef|tr.model.Event)} event
*/
- push: function(event) {
- this.eventsByStableId_[event.stableId] = event;
- },
+ add(event) {
+ this.eventsByStableId_.set(event.stableId, event);
+ }
/**
- * @return {!Array.<!(EventRef|tr.model.Event)>}
+ * @param {!(tr.v.d.EventRef|tr.model.Event)} event
+ * @return {boolean}
*/
- get events() {
- return tr.b.dictionaryValues(this.eventsByStableId_);
- },
+ has(event) {
+ return this.eventsByStableId_.has(event.stableId);
+ }
+
+ get length() {
+ return this.eventsByStableId_.size;
+ }
+
+ *[Symbol.iterator]() {
+ for (var [stableId, event] of this.eventsByStableId_)
+ yield event;
+ }
/**
* Resolve all EventRefs into Events by finding their stableIds in |model|.
@@ -82,34 +72,36 @@ tr.exportTo('tr.v.d', function() {
* @param {!tr.model.Model} model
* @param {boolean=} opt_required
*/
- resolve: function(model, opt_required) {
- tr.b.iterItems(this.eventsByStableId_, function(stableId, event) {
- if (!(event instanceof EventRef))
- return;
+ resolve(model, opt_required) {
+ for (var [stableId, event] of this.eventsByStableId_) {
+ if (!(event instanceof tr.v.d.EventRef))
+ continue;
event = model.getEventByStableId(stableId);
if (event instanceof tr.model.Event)
- this.eventsByStableId_[stableId] = event;
+ this.eventsByStableId_.set(stableId, event);
else if (opt_required)
- throw new Error('Unable to find Event ' + ref.stableId);
- }, this);
- },
+ throw new Error('Unable to find Event ' + stableId);
+ }
+ }
- asDictInto_: function(d) {
- d.events = this.events.map(function eventAsDict(event) {
- return {
+ asDictInto_(d) {
+ d.events = [];
+ for (var event of this) {
+ d.events.push({
stableId: event.stableId,
title: event.title,
start: event.start,
duration: event.duration
- };
- });
+ });
+ }
}
- };
- RelatedEventSet.fromDict = function(d) {
- return new RelatedEventSet(d.events.map(event => new EventRef(event)));
- };
+ static fromDict(d) {
+ return new RelatedEventSet(d.events.map(
+ event => new tr.v.d.EventRef(event)));
+ }
+ }
tr.v.d.Diagnostic.register(RelatedEventSet, {
elementName: 'tr-v-ui-related-event-set-span'
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set_test.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set_test.html
index de901b53e2d..cc22d27ec1a 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_event_set_test.html
@@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/value/diagnostics/related_event_set.html">
@@ -26,27 +27,22 @@ tr.b.unittest.testSuite(function() {
});
var d = new tr.v.d.RelatedEventSet(slice);
- assert.lengthOf(d.events, 1);
- assert.strictEqual(d.events[0], slice);
+ assert.strictEqual(tr.b.getOnlyElement([...d]), slice);
d = new tr.v.d.RelatedEventSet([slice]);
- assert.lengthOf(d.events, 1);
- assert.strictEqual(d.events[0], slice);
+ assert.strictEqual(tr.b.getOnlyElement([...d]), slice);
d = new tr.v.d.RelatedEventSet(new tr.model.EventSet([slice]));
- assert.lengthOf(d.events, 1);
- assert.strictEqual(d.events[0], slice);
+ assert.strictEqual(tr.b.getOnlyElement([...d]), slice);
var d2 = tr.v.d.Diagnostic.fromDict(d.asDict());
assert.instanceOf(d2, tr.v.d.RelatedEventSet);
- assert.lengthOf(d2.events, 1);
- // Can't use assert.instanceOf() because EventRef is private.
- assert.isFalse(d2.events[0] instanceof tr.model.Event);
+ assert.instanceOf(tr.b.getOnlyElement([...d2]), tr.v.d.EventRef);
d2.resolve(model, true);
- assert.strictEqual(d2.events[0], slice);
+ assert.strictEqual(tr.b.getOnlyElement([...d2]), slice);
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown.html
new file mode 100644
index 00000000000..fedfb1275a1
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/related_value_map.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v.d', function() {
+ var COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER =
+ 'ChromeUserFriendlyCategory';
+
+ /**
+ * RelatedHistogramBreakdown encapsulates an additive relationship between
+ * Histograms: the Histogram that contains this RelatedHistogramBreakdown
+ * diagnostic is composed of the Histograms referenced by this
+ * RelatedHistogramBreakdown diagnostic. RelatedHistogramBreakdown is a
+ * "breakdown" of its containing Histogram into its contained Histograms. This
+ * additive relationship can apply to groups of other things besides Events,
+ * such as memory allocations. RelatedHistogramBreakdowns over groups of
+ * Events is expected to be the most common way of building
+ * RelatedHistogramBreakdowns, though it is not the only way. See
+ * buildFromEvents() for an example of how to build a
+ * RelatedHistogramBreakdown from an EventSet and a grouping function.
+ */
+ class RelatedHistogramBreakdown extends tr.v.d.RelatedValueMap {
+ constructor() {
+ super();
+ this.colorScheme = undefined;
+ }
+
+ /**
+ * Add a Histogram by an explicit name to this map.
+ *
+ * @param {string} name
+ * @param {!(tr.v.d.ValueRef|tr.v.Histogram)} value
+ */
+ set(name, value) {
+ if (!(value instanceof tr.v.d.ValueRef)) {
+ if (!(value instanceof tr.v.Histogram)) {
+ throw new Error(
+ 'RelatedHistogramBreakdown can only contain Histograms');
+ }
+
+ if (value.name.indexOf(name) !== (value.name.length - name.length)) {
+ throw new Error(
+ 'RelatedHistogramBreakdown name must be a suffix of value.name');
+ }
+
+ if ((this.length > 0) &&
+ (value.unit !==
+ tr.b.getFirstElement(this)[1].unit)) {
+ throw new Error('Units mismatch', tr.b.getFirstElement(this)[1].unit,
+ value.unit);
+ }
+ }
+
+ tr.v.d.RelatedValueMap.prototype.set.call(this, name, value);
+ }
+
+ asDictInto_(d) {
+ tr.v.d.RelatedValueMap.prototype.asDictInto_.call(this, d);
+ if (this.colorScheme)
+ d.colorScheme = this.colorScheme;
+ }
+
+ static fromDict(d) {
+ var diagnostic = new RelatedHistogramBreakdown();
+ tr.b.iterItems(d.values, function(name, guid) {
+ diagnostic.set(name, new tr.v.d.ValueRef(guid));
+ });
+ if (d.colorScheme)
+ diagnostic.colorScheme = d.colorScheme;
+ return diagnostic;
+ }
+
+ /**
+ * Build a RelatedHistogramBreakdown and its Histograms from |events|. Group
+ * events using |categoryForEvent|. Add the Histograms to |values|.
+ * Histograms' names are prefixed with |namePrefix|. Histograms are built
+ * with |opt_binBoundaries|. The numeric sample for each Event is derived
+ * from |opt_sampleForEvent|, which defaults to event.cpuSelfTime. The caller
+ * must add the result RelatedHistogramBreakdown to their Histogram's
+ * diagnostics.
+ *
+ * @param {!tr.v.ValueSet} values
+ * @param {string} namePrefix
+ * @param {!tr.model.EventSet} events
+ * @param {!function(!tr.model.Event):string} categoryForEvent
+ * @param {!tr.b.Unit} unit
+ * @param {!function(!tr.model.Event):number=} opt_sampleForEvent
+ * @param {!tr.v.HistogramBinBoundaries=} opt_binBoundaries
+ * @param {*=} opt_this
+ * @return {!RelatedHistogramBreakdown}
+ */
+ static buildFromEvents(values, namePrefix, events, categoryForEvent, unit,
+ opt_sampleForEvent, opt_binBoundaries, opt_this) {
+ var sampleForEvent = opt_sampleForEvent || ((event) => event.cpuSelfTime);
+
+ var diagnostic = new RelatedHistogramBreakdown();
+ for (var event of events) {
+ var sample = sampleForEvent.call(opt_this, event);
+ if (sample === undefined)
+ continue;
+
+ var eventCategory = categoryForEvent.call(opt_this, event);
+ var value = diagnostic.get(eventCategory);
+ if (value === undefined) {
+ value = new tr.v.Histogram(
+ namePrefix + eventCategory, unit, opt_binBoundaries);
+ values.addHistogram(value);
+ diagnostic.set(eventCategory, value);
+ }
+
+ value.addSample(sample,
+ {relatedEvents: new tr.v.d.RelatedEventSet([event])});
+ }
+ return diagnostic;
+ }
+ }
+
+ tr.v.d.Diagnostic.register(RelatedHistogramBreakdown, {
+ elementName: 'tr-v-ui-breakdown-span'
+ });
+
+ return {
+ COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER:
+ COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER,
+ RelatedHistogramBreakdown: RelatedHistogramBreakdown
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown_test.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown_test.html
new file mode 100644
index 00000000000..af6c4c3e318
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_histogram_breakdown_test.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_driver.html">
+<link rel="import" href="/tracing/model/event_set.html">
+<link rel="import" href="/tracing/value/diagnostics/related_histogram_breakdown.html">
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var TEST_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 10, 10);
+
+ test('build', function() {
+ var values = new tr.v.ValueSet();
+ var events = new tr.model.EventSet([
+ {
+ guid: 9,
+ title: 'V8.Execute',
+ cpuSelfTime: 1,
+ stableId: '11.11'
+ },
+ {
+ guid: 10,
+ title: 'V8.Execute',
+ cpuSelfTime: 2,
+ stableId: '22.22'
+ },
+ {
+ guid: 11,
+ title: 'UpdateLayoutTree',
+ cpuSelfTime: 3,
+ stableId: '33.33'
+ },
+ {
+ guid: 12,
+ title: 'UpdateLayoutTree',
+ cpuSelfTime: undefined,
+ stableId: '44.44'
+ }
+ ]);
+
+ var sampleForEvent = undefined;
+ var diagnostic = tr.v.d.RelatedHistogramBreakdown.buildFromEvents(
+ values, 'foo-', events,
+ tr.e.chrome.ChromeUserFriendlyCategoryDriver.fromEvent,
+ tr.b.Unit.byName.timeDurationInMs, sampleForEvent, TEST_BOUNDARIES);
+
+ assert.lengthOf(diagnostic, 2);
+ var scriptValue = values.getValuesNamed('foo-script_execute')[0];
+ assert.instanceOf(scriptValue, tr.v.Histogram);
+ assert.lengthOf(scriptValue.centralBins[1].diagnosticMaps, 1);
+ assert.strictEqual(scriptValue, diagnostic.get('script_execute'));
+ events = [...events];
+ var relatedEvents = scriptValue.centralBins[1].diagnosticMaps[0]
+ .get('relatedEvents');
+ assert.lengthOf(relatedEvents, 1);
+ assert.strictEqual(events[0], [...relatedEvents][0]);
+ assert.lengthOf(scriptValue.centralBins[2].diagnosticMaps, 1);
+ assert.lengthOf(
+ scriptValue.centralBins[2].diagnosticMaps[0]
+ .get('relatedEvents'), 1);
+ assert.strictEqual(events[1],
+ [...scriptValue.centralBins[2].diagnosticMaps[0]
+ .get('relatedEvents')][0]);
+
+ var styleValue = values.getValuesNamed('foo-style')[0];
+ assert.instanceOf(styleValue, tr.v.Histogram);
+ assert.lengthOf(styleValue.centralBins[3].diagnosticMaps, 1);
+ relatedEvents = styleValue.centralBins[3].diagnosticMaps[0]
+ .get('relatedEvents');
+ assert.strictEqual(styleValue, diagnostic.get('style'));
+ assert.lengthOf(relatedEvents, 1);
+ assert.strictEqual(events[2], [...relatedEvents][0]);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_map.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_map.html
index b3ee5011017..54f0aff9ea3 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_map.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_map.html
@@ -6,60 +6,60 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/value/diagnostics/related_value_set.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
+<link rel="import" href="/tracing/value/diagnostics/value_ref.html">
<script>
'use strict';
tr.exportTo('tr.v.d', function() {
- /** @constructor */
- function RelatedValueMap() {
- this.valuesByName_ = {};
- }
-
- RelatedValueMap.prototype = {
- __proto__: tr.v.d.Diagnostic.prototype,
+ class RelatedValueMap extends tr.v.d.Diagnostic {
+ constructor() {
+ super();
+ this.valuesByName_ = new Map();
+ }
/**
- * Add a named Value to this map.
+ * Lookup a Histogram by name. Returns undefined if |name| is not found.
*
* @param {string} name
- * @param {!(tr.v.d.ValueRef|tr.v.Value)} value
+ * @return {!tr.v.d.ValueRef|!tr.v.Histogram|undefined}
*/
- set: function(name, value) {
- if (!(value instanceof tr.v.Value) &&
- !(value instanceof tr.v.d.ValueRef))
- throw new Error('Must be instanceof Value or ValueRef: ' + value);
-
- this.valuesByName_[name] = value;
- },
+ get(name) {
+ return this.valuesByName_.get(name);
+ }
/**
- * Iterate over the named Values.
+ * Add a Histogram by an explicit name to this map.
*
- * @param {!function(string, !(tr.v.d.ValueRef|tr.v.Value))} callback
- * @param {*=} opt_this
+ * @param {string} name
+ * @param {!(tr.v.d.ValueRef|tr.v.Histogram)} value
*/
- iterItems: function(callback, opt_this) {
- tr.b.iterItems(this.valuesByName_, callback, opt_this || this);
- },
+ set(name, value) {
+ if (!(value instanceof tr.v.Histogram) &&
+ !(value instanceof tr.v.d.ValueRef))
+ throw new Error('Must be instanceof Histogram or ValueRef: ' + value);
- /**
- * @return {!Array.<!(tr.v.d.ValueRef|tr.v.Value)>}
- */
- get values() {
- return tr.b.dictionaryValues(this.valuesByName_);
- },
+ this.valuesByName_.set(name, value);
+ }
/**
- * Lookup a Value by name. Returns undefined if |name| is not found.
+ * Add a Histogram implicitly by its own name to this map.
*
- * @param {string} name
- * @return {!tr.v.d.ValueRef|!tr.v.Value|undefined}
+ * @param {!(tr.v.d.ValueRef|tr.v.Histogram)} value
*/
- get: function(name) {
- return this.valuesByName_[name];
- },
+ add(value) {
+ this.set(value.name, value);
+ }
+
+ get length() {
+ return this.valuesByName_.size;
+ }
+
+ *[Symbol.iterator]() {
+ for (var pair of this.valuesByName_)
+ yield pair;
+ }
/**
* Resolve all ValueRefs into Values by looking up their guids in
@@ -72,37 +72,39 @@ tr.exportTo('tr.v.d', function() {
* @param {!tr.v.ValueSet} valueSet
* @param {boolean=} opt_required
*/
- resolve: function(valueSet, opt_required) {
- this.iterItems(function(name, value) {
+ resolve(valueSet, opt_required) {
+ for (var [name, value] of this) {
if (!(value instanceof tr.v.d.ValueRef))
- return;
+ continue;
- value = valueSet.lookup(value.guid);
- if (value instanceof tr.v.Value)
- this.valuesByName_[name] = value;
+ var guid = value.guid;
+ value = valueSet.lookup(guid);
+ if (value instanceof tr.v.Histogram)
+ this.valuesByName_.set(name, value);
else if (opt_required)
- throw new Error('Unable to find Value ' + guid);
- }, this);
- },
+ throw new Error('Unable to find Histogram ' + guid);
+ }
+ }
- asDictInto_: function(d) {
- d.values = tr.b.mapItems(this.valuesByName_, (name, value) => value.guid);
+ asDictInto_(d) {
+ d.values = {};
+ for (var [name, value] of this)
+ d.values[name] = value.guid;
}
- };
- RelatedValueMap.fromDict = function(d) {
- var map = new RelatedValueMap();
- tr.b.iterItems(d.values, function(name, guid) {
- map.set(name, new tr.v.d.ValueRef(guid));
- });
- return map;
- };
+ static fromDict(d) {
+ var map = new RelatedValueMap();
+ tr.b.iterItems(d.values, function(name, guid) {
+ map.set(name, new tr.v.d.ValueRef(guid));
+ });
+ return map;
+ }
+ }
tr.v.d.Diagnostic.register(RelatedValueMap, {
elementName: 'tr-v-ui-related-value-map-span'
});
-
return {
RelatedValueMap: RelatedValueMap
};
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_set.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_set.html
index 412c4dff0f2..27dfa04f99f 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_set.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/related_value_set.html
@@ -7,49 +7,48 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
+<link rel="import" href="/tracing/value/diagnostics/value_ref.html">
<script>
'use strict';
tr.exportTo('tr.v.d', function() {
- /** @constructor */
- function ValueRef(guid) {
- this.guid = guid;
- }
-
- /** @constructor */
- function RelatedValueSet(opt_values) {
- this.valuesByGuid_ = {};
-
- if (opt_values)
- opt_values.forEach(this.add, this);
- }
-
- RelatedValueSet.prototype = {
- __proto__: tr.v.d.Diagnostic.prototype,
+ class RelatedValueSet extends tr.v.d.Diagnostic {
+ constructor(opt_values) {
+ super();
+ this.valuesByGuid_ = new Map();
+
+ if (opt_values)
+ for (var value of opt_values)
+ this.add(value);
+ }
/**
- * Add a Value to this set.
- *
- * @param {!(ValueRef|tr.v.Value)} v
+ * @param {!(tr.v.d.ValueRef|tr.v.Histogram)} v
*/
- add: function(value) {
- if (!(value instanceof tr.v.Value) &&
- !(value instanceof ValueRef))
- throw new Error('Must be instanceof Value or ValueRef: ' + value);
+ add(value) {
+ if (!(value instanceof tr.v.Histogram) &&
+ !(value instanceof tr.v.d.ValueRef))
+ throw new Error('Must be instanceof Histogram or ValueRef: ' + value);
- if (this.valuesByGuid_[value.guid])
+ if (this.valuesByGuid_.get(value.guid))
throw new Error('Tried to add same value twice');
- this.valuesByGuid_[value.guid] = value;
- },
+ this.valuesByGuid_.set(value.guid, value);
+ }
- /**
- * @return {Array.<(ValueRef|tr.v.Value)>}
- */
- get values() {
- return tr.b.dictionaryValues(this.valuesByGuid_);
- },
+ has(value) {
+ return this.valuesByGuid_.has(value.guid);
+ }
+
+ get length() {
+ return this.valuesByGuid_.size;
+ }
+
+ *[Symbol.iterator]() {
+ for (var [guid, value] of this.valuesByGuid_)
+ yield value;
+ }
/**
* Resolve all ValueRefs into Values by looking up their guids in
@@ -62,27 +61,30 @@ tr.exportTo('tr.v.d', function() {
* @param {!tr.v.ValueSet} valueSet
* @param {boolean=} opt_required
*/
- resolve: function(valueSet, opt_required) {
- tr.b.iterItems(this.valuesByGuid_, function(guid, value) {
- if (!(value instanceof ValueRef))
- return;
+ resolve(valueSet, opt_required) {
+ for (var [guid, value] of this.valuesByGuid_) {
+ if (!(value instanceof tr.v.d.ValueRef))
+ continue;
value = valueSet.lookup(guid);
- if (value instanceof tr.v.Value)
- this.valuesByGuid_[guid] = value;
+ if (value instanceof tr.v.Histogram)
+ this.valuesByGuid_.set(guid, value);
else if (opt_required)
- throw new Error('Unable to find Value ' + guid);
- }, this);
- },
+ throw new Error('Unable to find Histogram ' + guid);
+ }
+ }
- asDictInto_: function(d) {
- d.guids = tr.b.dictionaryKeys(this.valuesByGuid_);
+ asDictInto_(d) {
+ d.guids = [];
+ for (var value of this)
+ d.guids.push(value.guid);
}
- };
- RelatedValueSet.fromDict = function(d) {
- return new RelatedValueSet(d.guids.map(guid => new ValueRef(guid)));
- };
+ static fromDict(d) {
+ return new RelatedValueSet(d.guids.map(
+ guid => new tr.v.d.ValueRef(guid)));
+ }
+ }
tr.v.d.Diagnostic.register(RelatedValueSet, {
elementName: 'tr-v-ui-related-value-set-span'
@@ -90,7 +92,6 @@ tr.exportTo('tr.v.d', function() {
return {
RelatedValueSet: RelatedValueSet,
- ValueRef: ValueRef
};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/scalar.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/scalar.html
new file mode 100644
index 00000000000..e03688220a8
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/scalar.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
+<link rel="import" href="/tracing/value/numeric.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v.d', function() {
+ class Scalar extends tr.v.d.Diagnostic {
+ /**
+ * @param {!tr.v.ScalarNumeric} value
+ */
+ constructor(value) {
+ super();
+ if (!(value instanceof tr.v.ScalarNumeric))
+ throw new Error("expected ScalarNumeric");
+ this.value = value;
+ }
+
+ asDictInto_(d) {
+ d.value = this.value.asDict();
+ }
+
+ static fromDict(d) {
+ return new Scalar(tr.v.ScalarNumeric.fromDict(d.value));
+ }
+ }
+
+ tr.v.d.Diagnostic.register(Scalar, {
+ elementName: 'tr-v-ui-scalar-diagnostic-span'
+ });
+
+ return {
+ Scalar: Scalar
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/diagnostics/value_ref.html b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/value_ref.html
new file mode 100644
index 00000000000..c2712d041a3
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/diagnostics/value_ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/base.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v.d', function() {
+ /** @constructor */
+ function ValueRef(guid) {
+ this.guid = guid;
+ }
+
+ return {
+ ValueRef: ValueRef
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/histogram.html b/chromium/third_party/catapult/tracing/tracing/value/histogram.html
new file mode 100644
index 00000000000..439658f6f2a
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/histogram.html
@@ -0,0 +1,1002 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/running_statistics.html">
+<link rel="import" href="/tracing/base/sorted_array_utils.html">
+<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+<link rel="import" href="/tracing/value/numeric.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.v', function() {
+ var MAX_DIAGNOSTIC_MAPS = 16;
+
+ var DEFAULT_BOUNDARIES_FOR_UNIT = new Map();
+
+ class HistogramBin {
+ /**
+ * @param {!tr.b.Range} range
+ */
+ constructor(range) {
+ this.range = range;
+ this.count = 0;
+ this.diagnosticMaps = [];
+ }
+
+ /**
+ * @param {*} value
+ */
+ addSample(value) {
+ this.count += 1;
+ }
+
+ /**
+ * @param {!tr.v.d.DiagnosticMap} diagnostics
+ */
+ addDiagnosticMap(diagnostics) {
+ tr.b.Statistics.uniformlySampleStream(
+ this.diagnosticMaps, this.count, diagnostics, MAX_DIAGNOSTIC_MAPS);
+ }
+
+ addBin(other) {
+ if (!this.range.equals(other.range))
+ throw new Error('Merging incompatible Histogram bins.');
+ tr.b.Statistics.mergeSampledStreams(this.diagnosticMaps, this.count,
+ other.diagnosticMaps, other.count, MAX_DIAGNOSTIC_MAPS);
+ this.count += other.count;
+ }
+
+ fromDict(dict) {
+ this.count = dict[0];
+ if (dict.length > 1) {
+ for (var map of dict[1]) {
+ this.diagnosticMaps.push(tr.v.d.DiagnosticMap.fromDict(map));
+ }
+ }
+ }
+
+ asDict() {
+ if (!this.diagnosticMaps.length) {
+ return [this.count];
+ }
+ // It's more efficient to serialize these 2 fields in an array. If you
+ // add any other fields, you should re-evaluate whether it would be more
+ // efficient to serialize as a dict.
+ return [this.count, this.diagnosticMaps.map(d => d.asDict())];
+ }
+ }
+
+ var DEFAULT_SUMMARY_OPTIONS = new Map([
+ ['avg', true],
+ ['geometricMean', false],
+ ['std', true],
+ ['count', true],
+ ['sum', true],
+ ['min', true],
+ ['max', true],
+ ['nans', false],
+ // Don't include 'percentile' here. Its default value is [], which is
+ // modifiable. Callers may push to it, so there must be a different Array
+ // instance for each Histogram instance.
+ ]);
+
+ /**
+ * This is basically a histogram, but so much more.
+ * Histogram is serializable using asDict/fromDict.
+ * Histogram computes several statistics of its contents.
+ * Histograms can be merged.
+ * getDifferenceSignificance() test whether one Histogram is statistically
+ * significantly different from another Histogram.
+ * Histogram stores a random sample of the exact number values added to it.
+ * Histogram stores a random sample of optional per-sample DiagnosticMaps.
+ * Histogram is visualized by <tr-v-ui-histogram-span>, which supports
+ * selecting bins, and visualizing the DiagnosticMaps of selected bins.
+ *
+ * @param {!tr.b.Unit} unit
+ * @param {!tr.v.HistogramBinBoundaries=} opt_binBoundaries
+ */
+ class Histogram {
+ constructor(name, unit, opt_binBoundaries) {
+ var binBoundaries = opt_binBoundaries;
+ if (!binBoundaries) {
+ var baseUnit = unit.baseUnit ? unit.baseUnit : unit;
+ binBoundaries = DEFAULT_BOUNDARIES_FOR_UNIT.get(baseUnit.unitName);
+ }
+
+ // If this Histogram is being deserialized, then its guid will be set by
+ // fromDict().
+ // If this Histogram is being computed by a metric, then its guid will be
+ // allocated the first time the guid is gotten by asDict().
+ this.guid_ = undefined;
+
+ // Serialize binBoundaries here instead of holding a reference to it in
+ // case it is modified.
+ this.binBoundariesDict_ = binBoundaries.asDict();
+
+ this.centralBins = [];
+ this.description = '';
+ this.diagnostics = new tr.v.d.DiagnosticMap();
+ this.maxCount_ = 0;
+ this.name_ = name;
+ this.nanDiagnosticMaps = [];
+ this.numNans = 0;
+ this.running = new tr.b.RunningStatistics();
+ this.sampleValues_ = [];
+ this.shortName = undefined;
+ this.summaryOptions = new Map(DEFAULT_SUMMARY_OPTIONS);
+ this.summaryOptions.set('percentile', []);
+ this.unit = unit;
+
+ this.underflowBin = new HistogramBin(tr.b.Range.fromExplicitRange(
+ -Number.MAX_VALUE, binBoundaries.range.min));
+ this.overflowBin = new HistogramBin(tr.b.Range.fromExplicitRange(
+ binBoundaries.range.max, Number.MAX_VALUE));
+
+ for (var range of binBoundaries.binRanges()) {
+ this.centralBins.push(new HistogramBin(range));
+ }
+
+ this.allBins = [this.underflowBin];
+ for (var bin of this.centralBins)
+ this.allBins.push(bin);
+ this.allBins.push(this.overflowBin);
+
+ this.maxNumSampleValues_ = this.defaultMaxNumSampleValues_;
+ }
+
+ get maxNumSampleValues() {
+ return this.maxNumSampleValues_;
+ }
+
+ set maxNumSampleValues(n) {
+ this.maxNumSampleValues_ = n;
+ tr.b.Statistics.uniformlySampleArray(
+ this.sampleValues_, this.maxNumSampleValues_);
+ }
+
+ get name() {
+ return this.name_;
+ }
+
+ get guid() {
+ if (this.guid_ === undefined)
+ this.guid_ = tr.b.GUID.allocateUUID4();
+
+ return this.guid_;
+ }
+
+ set guid(guid) {
+ if (this.guid_ !== undefined)
+ throw new Error('Cannot reset guid');
+
+ this.guid_ = guid;
+ }
+
+ static fromDict(dict) {
+ var hist = new Histogram(dict.name,
+ tr.b.Unit.fromJSON(dict.unit),
+ HistogramBinBoundaries.fromDict(
+ dict.binBoundaries));
+ hist.guid = dict.guid;
+ if (dict.shortName) {
+ hist.shortName = dict.shortName;
+ }
+ if (dict.description) {
+ hist.description = dict.description;
+ }
+ if (dict.diagnostics) {
+ hist.diagnostics.addDicts(dict.diagnostics);
+ }
+ if (dict.underflowBin) {
+ hist.underflowBin.fromDict(dict.underflowBin);
+ }
+ if (dict.overflowBin) {
+ hist.overflowBin.fromDict(dict.overflowBin);
+ }
+ if (dict.centralBins) {
+ if (dict.centralBins.length !== undefined) {
+ for (var i = 0; i < dict.centralBins.length; ++i) {
+ hist.centralBins[i].fromDict(dict.centralBins[i]);
+ }
+ } else {
+ tr.b.iterItems(dict.centralBins, (i, binDict) => {
+ hist.centralBins[i].fromDict(binDict);
+ });
+ }
+ }
+ for (var bin of hist.allBins) {
+ hist.maxCount_ = Math.max(hist.maxCount_, bin.count);
+ }
+ if (dict.running) {
+ hist.running = tr.b.RunningStatistics.fromDict(dict.running);
+ }
+ if (dict.summaryOptions) {
+ hist.customizeSummaryOptions(dict.summaryOptions);
+ }
+ if (dict.maxNumSampleValues !== undefined) {
+ hist.maxNumSampleValues = dict.maxNumSampleValues;
+ }
+ if (dict.sampleValues) {
+ hist.sampleValues_ = dict.sampleValues;
+ }
+ if (dict.numNans) {
+ hist.numNans = dict.numNans;
+ }
+ if (dict.nanDiagnostics) {
+ for (var map of dict.nanDiagnostics) {
+ hist.nanDiagnosticMaps.push(tr.v.d.DiagnosticMap.fromDict(map));
+ }
+ }
+ return hist;
+ }
+
+ /**
+ * Build a Histogram from a set of samples in order to effectively merge a
+ * set of ScalarNumerics.
+ * The range of the resulting histogram is determined by the smallest and
+ * largest sample value, which is unpredictable.
+ * https://github.com/catapult-project/catapult/issues/2685
+ *
+ * @param {!tr.b.Unit} unit
+ * @param {!Array.<number>} samples
+ * @return {!Histogram}
+ */
+ static buildFromSamples(unit, samples) {
+ var boundaries = HistogramBinBoundaries.createFromSamples(samples);
+ var result = new Histogram(unit, boundaries);
+ result.maxNumSampleValues = 1000;
+
+ // TODO(eakuefner): Propagate diagnosticMaps?
+ for (var sample of samples)
+ result.addSample(sample);
+
+ return result;
+ }
+
+ get numValues() {
+ return tr.b.Statistics.sum(this.allBins, function(e) {
+ return e.count;
+ });
+ }
+
+ get average() {
+ return this.running.mean;
+ }
+
+ get standardDeviation() {
+ return this.running.stddev;
+ }
+
+ get geometricMean() {
+ return this.running.geometricMean;
+ }
+
+ get sum() {
+ return this.running.sum;
+ }
+
+ get maxCount() {
+ return this.maxCount_;
+ }
+
+ /**
+ * Requires that units agree.
+ * Returns DONT_CARE if that is the units' improvementDirection.
+ * Returns SIGNIFICANT if the Mann-Whitney U test returns a
+ * p-value less than opt_alpha or DEFAULT_ALPHA. Returns INSIGNIFICANT if
+ * the p-value is greater than alpha.
+ *
+ * @param {!tr.v.Histogram} other
+ * @param {number=} opt_alpha
+ * @return {!tr.b.Statistics.Significance}
+ */
+ getDifferenceSignificance(other, opt_alpha) {
+ if (this.unit !== other.unit)
+ throw new Error('Cannot compare Numerics with different units');
+
+ if (this.unit.improvementDirection ===
+ tr.b.ImprovementDirection.DONT_CARE) {
+ return tr.b.Statistics.Significance.DONT_CARE;
+ }
+
+ if (!(other instanceof Histogram))
+ throw new Error('Unable to compute a p-value');
+
+ var testResult = tr.b.Statistics.mwu(
+ this.sampleValues, other.sampleValues, opt_alpha);
+ return testResult.significance;
+ }
+
+ /*
+ * Compute an approximation of percentile based on the counts in the bins.
+ * If the real percentile lies within |this.range| then the result of
+ * the function will deviate from the real percentile by at most
+ * the maximum width of the bin(s) within which the point(s)
+ * from which the real percentile would be calculated lie.
+ * If the real percentile is outside |this.range| then the function
+ * returns the closest range limit: |this.range.min| or |this.range.max|.
+ *
+ * @param {number} percent The percent must be between 0.0 and 1.0.
+ */
+ getApproximatePercentile(percent) {
+ if (!(percent >= 0 && percent <= 1))
+ throw new Error('percent must be [0,1]');
+ if (this.numValues === 0)
+ return 0;
+ var valuesToSkip = Math.floor((this.numValues - 1) * percent);
+ for (var i = 0; i < this.allBins.length; i++) {
+ var bin = this.allBins[i];
+ valuesToSkip -= bin.count;
+ if (valuesToSkip < 0) {
+ if (bin === this.underflowBin)
+ return bin.range.max;
+ else if (bin === this.overflowBin)
+ return bin.range.min;
+ else
+ return bin.range.center;
+ }
+ }
+ throw new Error('Unreachable');
+ }
+
+ getBinForValue(value) {
+ // Don't use subtraction to avoid arithmetic overflow.
+ var binIndex = tr.b.findHighIndexInSortedArray(
+ this.allBins, b => value < b.range.max ? -1 : 1);
+ return this.allBins[binIndex] || this.overflowBin;
+ }
+
+ /**
+ * @param {number|*} value
+ * @param {(!Object|!tr.v.d.DiagnosticMap)=} opt_diagnostics
+ */
+ addSample(value, opt_diagnostics) {
+ if (opt_diagnostics &&
+ !(opt_diagnostics instanceof tr.v.d.DiagnosticMap))
+ opt_diagnostics = tr.v.d.DiagnosticMap.fromObject(opt_diagnostics);
+
+ if (typeof(value) !== 'number' || isNaN(value)) {
+ this.numNans++;
+ if (opt_diagnostics) {
+ tr.b.Statistics.uniformlySampleStream(this.nanDiagnosticMaps,
+ this.numNans, opt_diagnostics, MAX_DIAGNOSTIC_MAPS);
+ }
+ } else {
+ this.running.add(value);
+
+ var bin = this.getBinForValue(value);
+ bin.addSample(value);
+ if (opt_diagnostics)
+ bin.addDiagnosticMap(opt_diagnostics);
+ if (bin.count > this.maxCount_)
+ this.maxCount_ = bin.count;
+ }
+
+ tr.b.Statistics.uniformlySampleStream(this.sampleValues_,
+ this.numValues + this.numNans, value, this.maxNumSampleValues);
+ }
+
+ sampleValuesInto(samples) {
+ for (var sampleValue of this.sampleValues)
+ samples.push(sampleValue);
+ }
+
+ /**
+ * Return true if this Histogram can be added to |other|.
+ *
+ * @param {!tr.v.Histogram} other
+ * @return {boolean}
+ */
+ canAddHistogram(other) {
+ if (this.unit !== other.unit)
+ return false;
+ if (this.allBins.length !== other.allBins.length)
+ return false;
+
+ for (var i = 0; i < this.allBins.length; ++i)
+ if (!this.allBins[i].range.equals(other.allBins[i].range))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Add |other| to this Histogram in-place if they can be added.
+ *
+ * @param {!tr.v.Histogram} other
+ */
+ addHistogram(other) {
+ if (!this.canAddHistogram(other)) {
+ throw new Error('Merging incompatible Histograms');
+ }
+
+ tr.b.Statistics.mergeSampledStreams(this.nanDiagnosticMaps, this.numNans,
+ other.nanDiagnosticMaps, other.numNans, MAX_DIAGNOSTIC_MAPS);
+ tr.b.Statistics.mergeSampledStreams(
+ this.sampleValues, this.numValues,
+ other.sampleValues, other.numValues, tr.b.Statistics.mean(
+ [this.maxNumSampleValues, other.maxNumSampleValues]));
+ this.numNans += other.numNans;
+ this.running = this.running.merge(other.running);
+ for (var i = 0; i < this.allBins.length; ++i) {
+ this.allBins[i].addBin(other.allBins[i]);
+ }
+ }
+
+ /**
+ * Controls which statistics are exported to dashboard for this numeric.
+ * The |summaryOptions| parameter is a dictionary with optional boolean
+ * fields |count|, |sum|, |avg|, |std|, |min|, |max| and an optional
+ * array field |percentile|.
+ * Each percentile should be a number between 0.0 and 1.0.
+ * The options not included in the |summaryOptions| will not change.
+ */
+ customizeSummaryOptions(summaryOptions) {
+ tr.b.iterItems(summaryOptions, (key, value) =>
+ this.summaryOptions.set(key, value));
+ }
+
+ /**
+ * Returns a Map {statisticName: ScalarNumeric}.
+ *
+ * Each enabled summary option produces the corresponding value:
+ * min, max, count, sum, avg, or std.
+ * Each percentile 0.x produces pct_0x0.
+ * Each percentile 0.xx produces pct_0xx.
+ * Each percentile 0.xxy produces pct_0xx_y.
+ * Percentile 1.0 produces pct_100.
+ *
+ * @return {!Map.<string, ScalarNumeric>}
+ */
+ get statisticsScalars() {
+ function statNameToKey(stat) {
+ switch (stat) {
+ case 'std':
+ return 'stddev';
+ case 'avg':
+ return 'mean';
+ }
+ return stat;
+ }
+ /**
+ * Converts the given percent to a string in the format specified above.
+ * @param {number} percent The percent must be between 0.0 and 1.0.
+ */
+ function percentToString(percent) {
+ if (percent < 0 || percent > 1)
+ throw new Error('Percent must be between 0.0 and 1.0');
+ switch (percent) {
+ case 0:
+ return '000';
+ case 1:
+ return '100';
+ }
+ var str = percent.toString();
+ if (str[1] !== '.')
+ throw new Error('Unexpected percent');
+ // Pad short strings with zeros.
+ str = str + '0'.repeat(Math.max(4 - str.length, 0));
+ if (str.length > 4)
+ str = str.slice(0, 4) + '_' + str.slice(4);
+ return '0' + str.slice(2);
+ }
+
+ var results = new Map();
+ for (var [stat, option] of this.summaryOptions) {
+ if (!option) {
+ continue;
+ }
+
+ if (stat === 'percentile') {
+ for (var percent of option) {
+ var percentile = this.getApproximatePercentile(percent);
+ results.set('pct_' + percentToString(percent),
+ new tr.v.ScalarNumeric(this.unit, percentile));
+ }
+ } else if (stat === 'nans') {
+ results.set('nans', new tr.v.ScalarNumeric(
+ tr.b.Unit.byName.count_smallerIsBetter, this.numNans));
+ } else {
+ var statUnit = stat === 'count' ?
+ tr.b.Unit.byName.count_smallerIsBetter : this.unit;
+ var key = statNameToKey(stat);
+ var statValue = this.running[key];
+
+ if (typeof(statValue) === 'number') {
+ results.set(stat, new tr.v.ScalarNumeric(statUnit, statValue));
+ }
+ }
+ }
+ return results;
+ }
+
+ get sampleValues() {
+ return this.sampleValues_;
+ }
+
+ /**
+ * Create a new Histogram object that is exactly the same as this one, with
+ * this Histogram's name, unit, and binBoundaries, guid, bin counts, and
+ * diagnostics.
+ * @return {!tr.v.Histogram}
+ */
+ clone() {
+ return Histogram.fromDict(this.asDict());
+ }
+
+ /**
+ * Create a new Histogram with this Histogram's name, unit, and
+ * binBoundaries, but not its guid, bin counts, or diagnostics.
+ * @return {!tr.v.Histogram}
+ */
+ cloneEmpty() {
+ var binBoundaries = HistogramBinBoundaries.fromDict(
+ this.binBoundariesDict_);
+ return new Histogram(this.name, this.unit, binBoundaries);
+ }
+
+ asDict() {
+ var dict = {};
+ dict.binBoundaries = this.binBoundariesDict_;
+ dict.name = this.name;
+ dict.unit = this.unit.asJSON();
+ dict.guid = this.guid;
+ if (this.shortName) {
+ dict.shortName = this.shortName;
+ }
+ if (this.description) {
+ dict.description = this.description;
+ }
+ if (this.diagnostics.size) {
+ dict.diagnostics = this.diagnostics.asDict();
+ }
+ if (this.maxNumSampleValues !== this.defaultMaxNumSampleValues_) {
+ dict.maxNumSampleValues = this.maxNumSampleValues;
+ }
+ if (this.numNans) {
+ dict.numNans = this.numNans;
+ }
+ if (this.nanDiagnosticMaps.length) {
+ dict.nanDiagnostics = this.nanDiagnosticMaps.map(
+ dm => dm.asDict());
+ }
+ if (this.underflowBin.count) {
+ dict.underflowBin = this.underflowBin.asDict();
+ }
+ if (this.overflowBin.count) {
+ dict.overflowBin = this.overflowBin.asDict();
+ }
+
+ if (this.numValues) {
+ dict.sampleValues = this.sampleValues.slice();
+ dict.running = this.running.asDict();
+ dict.centralBins = this.centralBinsAsDict_();
+ }
+
+ var summaryOptions = {};
+ var anyOverriddenSummaryOptions = false;
+ for (var [name, option] of this.summaryOptions) {
+ if (name === 'percentile') {
+ if (option.length === 0) {
+ continue;
+ }
+ option = option.slice();
+ } else if (option === DEFAULT_SUMMARY_OPTIONS.get(name)) {
+ continue;
+ }
+ summaryOptions[name] = option;
+ anyOverriddenSummaryOptions = true;
+ }
+ if (anyOverriddenSummaryOptions) {
+ dict.summaryOptions = summaryOptions;
+ }
+
+ return dict;
+ }
+
+ centralBinsAsDict_() {
+ // dict.centralBins may be either an array or a dict, whichever is more
+ // efficient.
+ // The overhead of the array form is significant when the histogram is
+ // sparse, and the overhead of the dict form is significant when the
+ // histogram is dense.
+ // The dict form is more efficient when more than half of centralBins are
+ // empty. The array form is more efficient when fewer than half of
+ // centralBins are empty.
+
+ var numCentralBins = this.centralBins.length;
+
+ // If all centralBins are empty, then don't serialize anything for them.
+ var emptyBins = 0;
+
+ for (var i = 0; i < numCentralBins; ++i) {
+ if (this.centralBins[i].count === 0) {
+ ++emptyBins;
+ }
+ }
+
+ if (emptyBins === numCentralBins) {
+ return undefined;
+ }
+
+ if (emptyBins > (numCentralBins / 2)) {
+ var centralBinsDict = {};
+ for (var i = 0; i < numCentralBins; ++i) {
+ var bin = this.centralBins[i];
+ if (bin.count > 0) {
+ centralBinsDict[i] = bin.asDict();
+ }
+ }
+ return centralBinsDict;
+ }
+
+ var centralBinsArray = [];
+ for (var i = 0; i < numCentralBins; ++i) {
+ centralBinsArray.push(this.centralBins[i].asDict());
+ }
+ return centralBinsArray;
+ }
+
+ get defaultMaxNumSampleValues_() {
+ return this.allBins.length * 10;
+ }
+ }
+
+ var HISTOGRAM_BIN_BOUNDARIES_CACHE = new Map();
+
+ /**
+ * Reusable builder for tr.v.Histogram objects.
+ *
+ * The bins of the numeric are specified by adding the desired boundaries
+ * between bins. Initially, the builder has only a single boundary:
+ *
+ * range.min=range.max
+ * |
+ * |
+ * -MAX_INT <--------|------------------------------------------> +MAX_INT
+ * : resulting : resulting :
+ * : underflow : overflow :
+ * : bin : bin :
+ *
+ * More boundaries can be added (in increasing order) using addBinBoundary,
+ * addLinearBins and addExponentialBins:
+ *
+ * range.min range.max
+ * | | | | |
+ * | | | | |
+ * -MAX_INT <--------|---------|---------|-----|---------|------> +MAX_INT
+ * : resulting : result. : result. : : result. : resulting :
+ * : underflow : central : central : ... : central : overflow :
+ * : bin : bin 0 : bin 1 : : bin N-1 : bin :
+ *
+ * An important feature of the builder is that it's reusable, i.e. it can be
+ * used to build multiple numerics with the same unit and bin structure.
+ *
+ */
+ class HistogramBinBoundaries {
+ /**
+ * Create a linearly scaled tr.v.HistogramBinBoundaries with |numBins| bins
+ * ranging from |min| to |max|.
+ *
+ * @param {number} min
+ * @param {number} max
+ * @param {number} numBins
+ * @return {tr.v.HistogramBinBoundaries}
+ */
+ static createLinear(min, max, numBins) {
+ return new HistogramBinBoundaries(min).addLinearBins(max, numBins);
+ }
+
+ /**
+ * Create an exponentially scaled tr.v.HistogramBinBoundaries with |numBins|
+ * bins ranging from |min| to |max|.
+ *
+ * @param {number} min
+ * @param {number} max
+ * @param {number} numBins
+ * @return {tr.v.HistogramBinBoundaries}
+ */
+ static createExponential(min, max, numBins) {
+ return new HistogramBinBoundaries(min).addExponentialBins(max, numBins);
+ }
+
+ /**
+ * @param {Array.<number>} binBoundaries
+ */
+ static createWithBoundaries(binBoundaries) {
+ var builder = new HistogramBinBoundaries(binBoundaries[0]);
+ for (var boundary of binBoundaries.slice(1))
+ builder.addBinBoundary(boundary);
+ return builder;
+ }
+
+ static createFromSamples(samples) {
+ var range = new tr.b.Range();
+ // Prevent non-numeric samples from introducing NaNs into the range.
+ for (var sample of samples)
+ if (!isNaN(Math.max(sample)))
+ range.addValue(sample);
+
+ // HistogramBinBoundaries.addLinearBins() requires this.
+ if (range.isEmpty)
+ range.addValue(1);
+ if (range.min === range.max)
+ range.addValue(range.min - 1);
+
+ // This optimizes the resolution when samples are uniformly distributed
+ // (which is almost never the case).
+ var numBins = Math.ceil(Math.sqrt(samples.length));
+ var builder = new HistogramBinBoundaries(range.min);
+ builder.addLinearBins(range.max, numBins);
+ return builder;
+ }
+
+ /**
+ * @param {number} minBinBoundary The minimum boundary between bins, namely
+ * the underflow bin and the first central bin (or the overflow bin if
+ * no other boundaries are added later).
+ */
+ constructor(minBinBoundary) {
+ this.boundaries_ = undefined;
+ this.builder_ = [minBinBoundary];
+ this.range_ = new tr.b.Range();
+ this.range_.addValue(minBinBoundary);
+ }
+
+ get range() {
+ return this.range_;
+ }
+
+ asDict() {
+ // Copy builder_ in case ours is modified later.
+ return this.builder_.slice();
+ }
+
+ static fromDict(dict) {
+ // When loading a results2.html with many Histograms with the same bin
+ // boundaries, caching the HistogramBinBoundaries not only speeds up
+ // loading, but also prevents a bug where build_ is occasionally
+ // non-deterministic, which causes similar Histograms to be unmergeable.
+ var cacheKey = JSON.stringify(dict);
+ if (HISTOGRAM_BIN_BOUNDARIES_CACHE.has(cacheKey)) {
+ return HISTOGRAM_BIN_BOUNDARIES_CACHE.get(cacheKey);
+ }
+
+ var binBoundaries = new HistogramBinBoundaries(dict[0]);
+ for (var slice of dict.slice(1)) {
+ if (!(slice instanceof Array)) {
+ binBoundaries.addBinBoundary(slice);
+ continue;
+ }
+ switch (slice[0]) {
+ case HistogramBinBoundaries.SLICE_TYPE.LINEAR:
+ binBoundaries.addLinearBins(slice[1], slice[2]);
+ break;
+
+ case HistogramBinBoundaries.SLICE_TYPE.EXPONENTIAL:
+ binBoundaries.addExponentialBins(slice[1], slice[2]);
+ break;
+
+ default:
+ throw new Error('Unrecognized HistogramBinBoundaries slice type');
+ }
+ }
+ HISTOGRAM_BIN_BOUNDARIES_CACHE.set(cacheKey, binBoundaries);
+ return binBoundaries;
+ }
+
+ /**
+ * Yield Ranges of adjacent boundaries.
+ */
+ *binRanges() {
+ if (this.boundaries_ === undefined) {
+ this.build_();
+ }
+ for (var i = 0; i < this.boundaries_.length - 1; ++i) {
+ yield tr.b.Range.fromExplicitRange(
+ this.boundaries_[i], this.boundaries_[i + 1]);
+ }
+ }
+
+ build_() {
+ if (typeof this.builder_[0] !== 'number') {
+ throw new Error('Invalid start of builder_');
+ }
+ this.boundaries_ = [this.builder_[0]];
+
+ for (var slice of this.builder_.slice(1)) {
+ if (!(slice instanceof Array)) {
+ this.boundaries_.push(slice);
+ continue;
+ }
+ var nextMaxBinBoundary = slice[1];
+ var binCount = slice[2];
+ var curMaxBinBoundary = this.boundaries_[
+ this.boundaries_.length - 1];
+
+ switch (slice[0]) {
+ case HistogramBinBoundaries.SLICE_TYPE.LINEAR:
+ var binWidth = (nextMaxBinBoundary - curMaxBinBoundary) / binCount;
+ for (var i = 1; i < binCount; i++) {
+ var boundary = curMaxBinBoundary + i * binWidth;
+ this.boundaries_.push(boundary);
+ }
+ break;
+
+ case HistogramBinBoundaries.SLICE_TYPE.EXPONENTIAL:
+ var binExponentWidth =
+ Math.log(nextMaxBinBoundary / curMaxBinBoundary) / binCount;
+ for (var i = 1; i < binCount; i++) {
+ var boundary = curMaxBinBoundary * Math.exp(i * binExponentWidth)
+ this.boundaries_.push(boundary);
+ }
+ break;
+
+ default:
+ throw new Error('Unrecognized HistogramBinBoundaries slice type');
+ }
+ this.boundaries_.push(nextMaxBinBoundary);
+ }
+ }
+
+ /**
+ * Add a bin boundary |nextMaxBinBoundary| to the builder.
+ *
+ * This operation effectively corresponds to appending a new central bin
+ * with the range [this.range.max, nextMaxBinBoundary].
+ *
+ * @param {number} nextMaxBinBoundary The added bin boundary (must be
+ * greater than |this.maxMinBoundary|).
+ */
+ addBinBoundary(nextMaxBinBoundary) {
+ if (nextMaxBinBoundary <= this.range.max) {
+ throw new Error('The added max bin boundary must be larger than ' +
+ 'the current max boundary');
+ }
+
+ // If boundaries_ had been built, then clear them.
+ this.boundaries_ = undefined;
+
+ this.builder_.push(nextMaxBinBoundary);
+ this.range.addValue(nextMaxBinBoundary);
+ return this;
+ }
+
+ /**
+ * Add |binCount| linearly scaled bin boundaries up to |nextMaxBinBoundary|
+ * to the builder.
+ *
+ * This operation corresponds to appending |binCount| central bins of
+ * constant range width
+ * W = ((|nextMaxBinBoundary| - |this.range.max|) / |binCount|)
+ * with the following ranges:
+ *
+ * [|this.maxMinBoundary|, |this.maxMinBoundary| + W]
+ * [|this.maxMinBoundary| + W, |this.maxMinBoundary| + 2W]
+ * [|this.maxMinBoundary| + 2W, |this.maxMinBoundary| + 3W]
+ * ...
+ * [|this.maxMinBoundary| + (|binCount| - 2) * W,
+ * |this.maxMinBoundary| + (|binCount| - 2) * W]
+ * [|this.maxMinBoundary| + (|binCount| - 1) * W,
+ * |nextMaxBinBoundary|]
+ *
+ * @param {number} nextBinBoundary The last added bin boundary (must be
+ * greater than |this.maxMinBoundary|).
+ * @param {number} binCount Number of bins to be added (must be positive).
+ */
+ addLinearBins(nextMaxBinBoundary, binCount) {
+ if (binCount <= 0)
+ throw new Error('Bin count must be positive');
+
+ if (nextMaxBinBoundary <= this.range.max) {
+ throw new Error('The new max bin boundary must be greater than ' +
+ 'the previous max bin boundary');
+ }
+
+ // If boundaries_ had been built, then clear them.
+ this.boundaries_ = undefined;
+
+ this.builder_.push([HistogramBinBoundaries.SLICE_TYPE.LINEAR,
+ nextMaxBinBoundary, binCount]);
+ this.range.addValue(nextMaxBinBoundary);
+ return this;
+ }
+
+ /**
+ * Add |binCount| exponentially scaled bin boundaries up to
+ * |nextMaxBinBoundary| to the builder.
+ *
+ * This operation corresponds to appending |binCount| central bins with
+ * a constant difference between the logarithms of their range min and max
+ * D = ((ln(|nextMaxBinBoundary|) - ln(|this.range.max|)) / |binCount|)
+ * with the following ranges:
+ *
+ * [|this.maxMinBoundary|, |this.maxMinBoundary| * exp(D)]
+ * [|this.maxMinBoundary| * exp(D), |this.maxMinBoundary| * exp(2D)]
+ * [|this.maxMinBoundary| * exp(2D), |this.maxMinBoundary| * exp(3D)]
+ * ...
+ * [|this.maxMinBoundary| * exp((|binCount| - 2) * D),
+ * |this.maxMinBoundary| * exp((|binCount| - 2) * D)]
+ * [|this.maxMinBoundary| * exp((|binCount| - 1) * D),
+ * |nextMaxBinBoundary|]
+ *
+ * This method requires that the current max bin boundary is positive.
+ *
+ * @param {number} nextBinBoundary The last added bin boundary (must be
+ * greater than |this.maxMinBoundary|).
+ * @param {number} binCount Number of bins to be added (must be positive).
+ */
+ addExponentialBins(nextMaxBinBoundary, binCount) {
+ if (binCount <= 0) {
+ throw new Error('Bin count must be positive');
+ }
+ if (this.range.max <= 0) {
+ throw new Error('Current max bin boundary must be positive');
+ }
+ if (this.range.max >= nextMaxBinBoundary) {
+ throw new Error('The last added max boundary must be greater than ' +
+ 'the current max boundary boundary');
+ }
+
+ // If boundaries_ had been built, then clear them.
+ this.boundaries_ = undefined;
+
+ this.builder_.push([HistogramBinBoundaries.SLICE_TYPE.EXPONENTIAL,
+ nextMaxBinBoundary, binCount]);
+ this.range.addValue(nextMaxBinBoundary);
+ return this;
+ }
+ }
+
+ HistogramBinBoundaries.SLICE_TYPE = {
+ LINEAR: 0,
+ EXPONENTIAL: 1,
+ };
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.timeDurationInMs.unitName,
+ HistogramBinBoundaries.createExponential(1e-3, 1e6, 1e2));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.timeStampInMs.unitName,
+ HistogramBinBoundaries.createLinear(0, 1e10, 1e3));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.normalizedPercentage.unitName,
+ HistogramBinBoundaries.createLinear(0, 1.0, 20));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.sizeInBytes.unitName,
+ HistogramBinBoundaries.createExponential(1, 1e12, 1e2));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.energyInJoules.unitName,
+ HistogramBinBoundaries.createExponential(1e-3, 1e3, 50));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.powerInWatts.unitName,
+ HistogramBinBoundaries.createExponential(1e-3, 1, 50));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.unitlessNumber.unitName,
+ HistogramBinBoundaries.createExponential(1e-3, 1e3, 50));
+
+ DEFAULT_BOUNDARIES_FOR_UNIT.set(
+ tr.b.Unit.byName.count.unitName,
+ HistogramBinBoundaries.createExponential(1, 1e3, 20));
+
+ return {
+ Histogram: Histogram,
+ HistogramBinBoundaries: HistogramBinBoundaries,
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/histogram_test.html b/chromium/third_party/catapult/tracing/tracing/value/histogram_test.html
new file mode 100644
index 00000000000..744828a6e61
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/histogram_test.html
@@ -0,0 +1,508 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/generic.html">
+<link rel="import" href="/tracing/value/histogram.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var unitlessNumber = tr.b.Unit.byName.unitlessNumber;
+ var unitlessNumber_smallerIsBetter =
+ tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
+
+ var TEST_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 1000, 10);
+
+ function checkBoundaries(boundaries, expectedMinBoundary, expectedMaxBoundary,
+ expectedUnit, expectedBinRanges) {
+ assert.strictEqual(boundaries.range.min, expectedMinBoundary);
+ assert.strictEqual(boundaries.range.max, expectedMaxBoundary);
+
+ // Check that the boundaries can be used multiple times.
+ for (var i = 0; i < 3; i++) {
+ var numeric = new tr.v.Histogram('', expectedUnit, boundaries);
+ assert.instanceOf(numeric, tr.v.Histogram);
+ assert.strictEqual(numeric.unit, expectedUnit);
+ assert.strictEqual(numeric.numValues, 0);
+
+ assert.lengthOf(numeric.allBins, expectedBinRanges.length);
+ for (var j = 0; j < expectedBinRanges.length; j++) {
+ var bin = numeric.allBins[j];
+ assert.strictEqual(bin.count, 0);
+ assert.isTrue(bin.range.equals(expectedBinRanges[j]));
+ }
+ }
+ }
+
+ test('serialization', function() {
+ // Ensure that serialized Histograms don't take up too much more space than
+ // necessary.
+ var hist = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+
+ // You can change these numbers, but when you do, please explain in your CL
+ // description why they changed.
+ var dict = hist.asDict();
+ assert.strictEqual(107, JSON.stringify(dict).length);
+ assert.isUndefined(dict.centralBins);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+
+ hist.addSample(100);
+ dict = hist.asDict();
+ assert.strictEqual(202, JSON.stringify(dict).length);
+ assert.isUndefined(dict.centralBins.length);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+
+ hist.addSample(100);
+ dict = hist.asDict();
+ // SAMPLE_VALUES grew by "100,"
+ assert.strictEqual(206, JSON.stringify(dict).length);
+ assert.isUndefined(dict.centralBins.length);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+
+ hist.addSample(271, {foo: new tr.v.d.Generic('bar')});
+ dict = hist.asDict();
+ assert.strictEqual(266, JSON.stringify(dict).length);
+ assert.isUndefined(dict.centralBins.length);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+
+ // Add samples to most bins so that centralBinsArray is more efficient than
+ // centralBinsDict.
+ for (var i = 10; i < 100; ++i) {
+ hist.addSample(10 * i);
+ }
+ dict = hist.asDict();
+ assert.strictEqual(687, JSON.stringify(hist.asDict()).length);
+ assert.lengthOf(dict.centralBins, 10);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+
+ // Lowering maxNumSampleValues takes a random sub-sample of the existing
+ // sampleValues. We have deliberately set all samples to 3-digit numbers so
+ // that the serialized size is constant regardless of which samples are
+ // retained.
+ hist.maxNumSampleValues = 10;
+ dict = hist.asDict();
+ assert.strictEqual(379, JSON.stringify(dict).length);
+ assert.lengthOf(dict.centralBins, 10);
+ assert.deepEqual(dict, tr.v.Histogram.fromDict(dict).asDict());
+ });
+
+ test('significance', function() {
+ var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 10);
+ var numericA = new tr.v.Histogram(
+ '', unitlessNumber_smallerIsBetter, boundaries);
+ var numericB = new tr.v.Histogram(
+ '', unitlessNumber_smallerIsBetter, boundaries);
+
+ var dontCare = new tr.v.Histogram('', unitlessNumber, boundaries);
+ assert.strictEqual(dontCare.getDifferenceSignificance(dontCare),
+ tr.b.Statistics.Significance.DONT_CARE);
+
+ for (var i = 0; i < 100; ++i) {
+ numericA.addSample(i);
+ numericB.addSample(i * 0.85);
+ }
+
+ assert.strictEqual(numericA.getDifferenceSignificance(numericB),
+ tr.b.Statistics.Significance.INSIGNIFICANT);
+ assert.strictEqual(numericB.getDifferenceSignificance(numericA),
+ tr.b.Statistics.Significance.INSIGNIFICANT);
+ assert.strictEqual(numericA.getDifferenceSignificance(numericB, 0.1),
+ tr.b.Statistics.Significance.SIGNIFICANT);
+ assert.strictEqual(numericB.getDifferenceSignificance(numericA, 0.1),
+ tr.b.Statistics.Significance.SIGNIFICANT);
+ });
+
+ test('numericBasic', function() {
+ var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ assert.equal(n.getBinForValue(250).range.min, 200);
+ assert.equal(n.getBinForValue(250).range.max, 300);
+
+ n.addSample(-1, {foo: new tr.v.d.Generic('a')});
+ n.addSample(0, {foo: new tr.v.d.Generic('b')});
+ n.addSample(0, {foo: new tr.v.d.Generic('c')});
+ n.addSample(500, {foo: new tr.v.d.Generic('c')});
+ n.addSample(999, {foo: new tr.v.d.Generic('d')});
+ n.addSample(1000, {foo: new tr.v.d.Generic('d')});
+ assert.equal(n.underflowBin.count, 1);
+
+ assert.equal(n.getBinForValue(0).count, 2);
+ assert.deepEqual(
+ n.getBinForValue(0).diagnosticMaps.map(dm => dm.get('foo').value),
+ ['b', 'c']);
+
+ assert.equal(n.getBinForValue(500).count, 1);
+ assert.equal(n.getBinForValue(999).count, 1);
+
+ assert.equal(n.overflowBin.count, 1);
+ assert.equal(n.numValues, 6);
+ assert.closeTo(n.average, 416.3, 0.1);
+ });
+
+ test('numericNans', function() {
+ var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+
+ n.addSample(undefined, {foo: new tr.v.d.Generic('b')});
+ n.addSample(NaN, {'foo': new tr.v.d.Generic('c')});
+ n.addSample(undefined);
+ n.addSample(NaN);
+
+ assert.equal(n.numNans, 4);
+ assert.deepEqual(n.nanDiagnosticMaps.map(dm => dm.get('foo').value),
+ ['b', 'c']);
+
+ var n2 = n.clone();
+ assert.instanceOf(n2.nanDiagnosticMaps[0], tr.v.d.DiagnosticMap);
+ assert.instanceOf(n2.nanDiagnosticMaps[0].get('foo'), tr.v.d.Generic);
+ });
+
+ test('addHistogramsValid', function() {
+ var n0 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ var n1 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+
+ n0.addSample(-1, {foo: new tr.v.d.Generic('a0')});
+ n0.addSample(0, {foo: new tr.v.d.Generic('b0')});
+ n0.addSample(0, {foo: new tr.v.d.Generic('c0')});
+ n0.addSample(500, {foo: new tr.v.d.Generic('c0')});
+ n0.addSample(1000, {foo: new tr.v.d.Generic('d0')});
+ n0.addSample(NaN, {foo: new tr.v.d.Generic('e0')});
+
+ n1.addSample(-1, {foo: new tr.v.d.Generic('a1')});
+ n1.addSample(0, {foo: new tr.v.d.Generic('b1')});
+ n1.addSample(0, {foo: new tr.v.d.Generic('c1')});
+ n1.addSample(999, {foo: new tr.v.d.Generic('d1')});
+ n1.addSample(1000, {foo: new tr.v.d.Generic('d1')});
+ n1.addSample(NaN, {foo: new tr.v.d.Generic('e1')});
+
+ n0.addHistogram(n1);
+
+ assert.equal(n0.numNans, 2);
+ assert.deepEqual(n0.nanDiagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['e0', 'e1']);
+
+ assert.equal(n0.underflowBin.count, 2);
+ assert.deepEqual(
+ n0.underflowBin.diagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['a0', 'a1']);
+
+ assert.equal(n0.getBinForValue(0).count, 4);
+ assert.deepEqual(
+ n0.getBinForValue(0).diagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['b0', 'c0', 'b1', 'c1']);
+
+ assert.equal(n0.getBinForValue(500).count, 1);
+ assert.deepEqual(
+ n0.getBinForValue(500).diagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['c0']);
+
+ assert.equal(n0.getBinForValue(999).count, 1);
+ assert.deepEqual(
+ n0.getBinForValue(999).diagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['d1']);
+
+ assert.equal(n0.overflowBin.count, 2);
+ assert.deepEqual(
+ n0.overflowBin.diagnosticMaps.map(dmd => dmd.get('foo').value),
+ ['d0', 'd1']);
+
+ assert.equal(n0.numValues, 10);
+ assert.closeTo(n0.average, 349.7, 0.1);
+
+ assert.equal(2, n0.maxCount);
+ assert.equal(2, n1.maxCount);
+
+ var n02 = n0.clone();
+ assert.instanceOf(n02.underflowBin.diagnosticMaps[0], tr.v.d.DiagnosticMap);
+ assert.instanceOf(n02.underflowBin.diagnosticMaps[0].get('foo'),
+ tr.v.d.Generic);
+ });
+
+ test('addHistogramsInvalid', function() {
+ var n0 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
+ tr.v.HistogramBinBoundaries.createLinear(0, 1000, 10));
+ var n1 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
+ tr.v.HistogramBinBoundaries.createLinear(0, 1001, 10));
+ var n2 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
+ tr.v.HistogramBinBoundaries.createLinear(0, 1000, 11));
+
+ assert.isFalse(n0.canAddHistogram(n1));
+ assert.isFalse(n0.canAddHistogram(n2));
+ assert.isFalse(n1.canAddHistogram(n0));
+ assert.isFalse(n1.canAddHistogram(n2));
+ assert.isFalse(n2.canAddHistogram(n0));
+ assert.isFalse(n2.canAddHistogram(n1));
+
+ assert.throws(n0.addHistogram.bind(n0, n1), Error);
+ assert.throws(n0.addHistogram.bind(n0, n2), Error);
+ });
+
+ test('addHistogramWithNonDiagnosticMapThrows', function() {
+ var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ assert.throws(n.addSample.bind(42, 'foo'), Error);
+ });
+
+ test('numericPercentile', function() {
+ function check(array, min, max, bins, precision) {
+ var boundaries = tr.v.HistogramBinBoundaries.createLinear(min, max, bins);
+ var n = new tr.v.Histogram(
+ '', tr.b.Unit.byName.timeDurationInMs, boundaries);
+ array.forEach((x) => n.addSample(x, {foo: new tr.v.d.Generic('x')}));
+ [0.25, 0.5, 0.75, 0.8, 0.95, 0.99].forEach(function(percent) {
+ var expected = tr.b.Statistics.percentile(array, percent);
+ var actual = n.getApproximatePercentile(percent);
+ assert.closeTo(expected, actual, precision);
+ });
+ }
+ check([1, 2, 5, 7], 0.5, 10.5, 10, 1e-3);
+ check([3, 3, 4, 4], 0.5, 10.5, 10, 1e-3);
+ check([1, 10], 0.5, 10.5, 10, 1e-3);
+ check([1, 2, 3, 4, 5], 0.5, 10.5, 10, 1e-3);
+ check([3, 3, 3, 3, 3], 0.5, 10.5, 10, 1e-3);
+ check([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3);
+ check([1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3);
+ check([0, 11], 0.5, 10.5, 10, 1);
+ check([0, 6, 11], 0.5, 10.5, 10, 1);
+ var array = [];
+ for (var i = 0; i < 1000; i++)
+ array.push((i * i) % 10 + 1);
+ check(array, 0.5, 10.5, 10, 1e-3);
+ // If the real percentile is outside the bin range then the approximation
+ // error can be high.
+ check([-10000], 0, 10, 10, 10000);
+ check([10000], 0, 10, 10, 10000 - 10);
+ // The result is no more than the bin width away from the real percentile.
+ check([1, 1], 0, 10, 1, 10);
+ });
+
+ test('histogramBinBoundaries_addBinBoundary', function() {
+ var b = new tr.v.HistogramBinBoundaries(-100);
+ b.addBinBoundary(50);
+
+ checkBoundaries(b, -100, 50, tr.b.Unit.byName.timeDurationInMs, [
+ tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
+ tr.b.Range.fromExplicitRange(-100, 50),
+ tr.b.Range.fromExplicitRange(50, Number.MAX_VALUE)
+ ]);
+
+ b.addBinBoundary(60);
+ b.addBinBoundary(75);
+
+ checkBoundaries(b, -100, 75, tr.b.Unit.byName.timeDurationInMs, [
+ tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
+ tr.b.Range.fromExplicitRange(-100, 50),
+ tr.b.Range.fromExplicitRange(50, 60),
+ tr.b.Range.fromExplicitRange(60, 75),
+ tr.b.Range.fromExplicitRange(75, Number.MAX_VALUE)
+ ]);
+ });
+
+ test('histogramBinBoundaries_addLinearBins', function() {
+ var b = new tr.v.HistogramBinBoundaries(1000);
+ b.addLinearBins(1200, 5);
+
+ checkBoundaries(b, 1000, 1200, tr.b.Unit.byName.powerInWatts, [
+ tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 1000),
+ tr.b.Range.fromExplicitRange(1000, 1040),
+ tr.b.Range.fromExplicitRange(1040, 1080),
+ tr.b.Range.fromExplicitRange(1080, 1120),
+ tr.b.Range.fromExplicitRange(1120, 1160),
+ tr.b.Range.fromExplicitRange(1160, 1200),
+ tr.b.Range.fromExplicitRange(1200, Number.MAX_VALUE)
+ ]);
+ });
+
+ test('histogramBinBoundaries_addExponentialBins', function() {
+ var b = new tr.v.HistogramBinBoundaries(0.5);
+ b.addExponentialBins(8, 4);
+
+ checkBoundaries(b, 0.5, 8, tr.b.Unit.byName.energyInJoules, [
+ tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 0.5),
+ tr.b.Range.fromExplicitRange(0.5, 1),
+ tr.b.Range.fromExplicitRange(1, 2),
+ tr.b.Range.fromExplicitRange(2, 4),
+ tr.b.Range.fromExplicitRange(4, 8),
+ tr.b.Range.fromExplicitRange(8, Number.MAX_VALUE)
+ ]);
+ });
+
+ test('histogramBinBoundaries_combined', function() {
+ var b = new tr.v.HistogramBinBoundaries(-273.15);
+ b.addBinBoundary(-50);
+ b.addLinearBins(4, 3);
+ b.addExponentialBins(16, 2);
+ b.addLinearBins(17, 4);
+ b.addBinBoundary(100);
+
+ checkBoundaries(b, -273.15, 100, tr.b.Unit.byName.unitlessNumber, [
+ tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -273.15),
+ tr.b.Range.fromExplicitRange(-273.15, -50),
+ tr.b.Range.fromExplicitRange(-50, -32),
+ tr.b.Range.fromExplicitRange(-32, -14),
+ tr.b.Range.fromExplicitRange(-14, 4),
+ tr.b.Range.fromExplicitRange(4, 8),
+ tr.b.Range.fromExplicitRange(8, 16),
+ tr.b.Range.fromExplicitRange(16, 16.25),
+ tr.b.Range.fromExplicitRange(16.25, 16.5),
+ tr.b.Range.fromExplicitRange(16.5, 16.75),
+ tr.b.Range.fromExplicitRange(16.75, 17),
+ tr.b.Range.fromExplicitRange(17, 100),
+ tr.b.Range.fromExplicitRange(100, Number.MAX_VALUE)
+ ]);
+ });
+
+ test('histogramBinBoundaries_throws', function() {
+ var b0 = new tr.v.HistogramBinBoundaries(-7);
+ assert.throws(function() { b0.addBinBoundary(-10 /* must be > -7 */); });
+ assert.throws(function() { b0.addBinBoundary(-7 /* must be > -7 */); });
+ assert.throws(function() { b0.addLinearBins(-10 /* must be > -7 */, 10); });
+ assert.throws(function() { b0.addLinearBins(-7 /* must be > -7 */, 100); });
+ assert.throws(function() { b0.addLinearBins(10, 0 /* must be > 0 */); });
+ assert.throws(function() {
+ // Current max bin boundary (-7) must be positive.
+ b0.addExponentialBins(16, 4);
+ });
+
+ var b1 = new tr.v.HistogramBinBoundaries(8);
+ assert.throws(() => b1.addExponentialBins(20, 0 /* must be > 0 */));
+ assert.throws(() => b1.addExponentialBins(5 /* must be > 8 */, 3));
+ assert.throws(() => b1.addExponentialBins(8 /* must be > 8 */, 3));
+ });
+
+ test('statisticsScalars', function() {
+ var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
+ var n = new tr.v.Histogram('', unitlessNumber, boundaries);
+
+ n.addSample(50);
+ n.addSample(60);
+ n.addSample(70);
+ n.addSample('i am not a number');
+
+ n.customizeSummaryOptions({
+ count: true,
+ min: true,
+ max: true,
+ sum: true,
+ avg: true,
+ std: true,
+ nans: true,
+ geometricMean: true,
+ percentile: [0.5, 1]
+ });
+
+ // Test round-tripping summaryOptions.
+ n = n.clone();
+
+ var stats = n.statisticsScalars;
+ assert.strictEqual(stats.get('nans').unit,
+ tr.b.Unit.byName.count_smallerIsBetter);
+ assert.strictEqual(stats.get('nans').value, 1);
+ assert.strictEqual(stats.get('count').unit,
+ tr.b.Unit.byName.count_smallerIsBetter);
+ assert.strictEqual(stats.get('count').value, 3);
+ assert.strictEqual(stats.get('min').unit, n.unit);
+ assert.strictEqual(stats.get('min').value, 50);
+ assert.strictEqual(stats.get('max').unit, n.unit);
+ assert.strictEqual(stats.get('max').value, 70);
+ assert.strictEqual(stats.get('sum').unit, n.unit);
+ assert.strictEqual(stats.get('sum').value, 180);
+ assert.strictEqual(stats.get('avg').unit, n.unit);
+ assert.strictEqual(stats.get('avg').value, 60);
+ assert.strictEqual(stats.get('std').value, 10);
+ assert.strictEqual(stats.get('pct_050').unit, n.unit);
+ assert.closeTo(stats.get('pct_050').value, 60, 1);
+ assert.strictEqual(stats.get('pct_100').unit, n.unit);
+ assert.closeTo(stats.get('pct_100').value, 70, 1);
+ assert.strictEqual(stats.get('geometricMean').unit, n.unit);
+ assert.closeTo(stats.get('geometricMean').value, 59.439, 1e-3);
+ });
+
+ test('statisticsScalarsNoSummaryOptions', function() {
+ var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
+ var n = new tr.v.Histogram('', unitlessNumber, boundaries);
+
+ n.addSample(50);
+ n.addSample(60);
+ n.addSample(70);
+
+ n.customizeSummaryOptions({
+ count: false,
+ min: false,
+ max: false,
+ sum: false,
+ avg: false,
+ std: false,
+ percentile: []
+ });
+
+ assert.strictEqual(n.statisticsScalars.size, 0);
+ });
+
+ test('statisticsScalarsEmptyNumericValue', function() {
+ var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
+ var n = new tr.v.Histogram('', unitlessNumber, boundaries);
+ n.customizeSummaryOptions({
+ count: true,
+ min: true,
+ max: true,
+ sum: true,
+ avg: true,
+ std: true,
+ percentile: [0, 0.01, 0.1, 0.5, 0.995, 1]
+ });
+
+ var stats = n.statisticsScalars;
+ assert.strictEqual(stats.get('count').value, 0);
+ assert.strictEqual(stats.get('min').value, Infinity);
+ assert.strictEqual(stats.get('max').value, -Infinity);
+ assert.strictEqual(stats.get('sum').value, 0);
+ assert.strictEqual(stats.get('avg'), undefined);
+ assert.strictEqual(stats.get('std'), undefined);
+ assert.strictEqual(stats.get('pct_000').value, 0);
+ assert.strictEqual(stats.get('pct_001').value, 0);
+ assert.strictEqual(stats.get('pct_010').value, 0);
+ assert.strictEqual(stats.get('pct_050').value, 0);
+ assert.strictEqual(stats.get('pct_099_5').value, 0);
+ assert.strictEqual(stats.get('pct_100').value, 0);
+ });
+
+ test('sampleValues', function() {
+ var n0 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ var n1 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ // maxNumSampleValues defaults to numBins * 10, which, including the
+ // underflowBin and overflowBin plus this builder's 10 central bins,
+ // is 12 * 10.
+ assert.strictEqual(n0.maxNumSampleValues, 120);
+ assert.strictEqual(n1.maxNumSampleValues, 120);
+ var values0 = [];
+ var values1 = [];
+ for (var i = 0; i < 10; ++i) {
+ values0.push(i);
+ n0.addSample(i);
+ }
+ for (var i = 10; i < 20; ++i) {
+ values1.push(i);
+ n1.addSample(i);
+ }
+ assert.deepEqual(n0.sampleValues, values0);
+ assert.deepEqual(n1.sampleValues, values1);
+ n0.addHistogram(n1);
+ assert.deepEqual(n0.sampleValues, values0.concat(values1));
+ var n2 = n0.clone();
+ assert.deepEqual(n2.sampleValues, values0.concat(values1));
+
+ for (var i = 0; i < 200; ++i)
+ n0.addSample(i);
+ assert.strictEqual(n0.sampleValues.length, n0.maxNumSampleValues);
+
+ var n3 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
+ n3.maxNumSampleValues = 10;
+ for (var i = 0; i < 100; ++i)
+ n3.addSample(i);
+ assert.strictEqual(n3.sampleValues.length, 10);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/numeric.html b/chromium/third_party/catapult/tracing/tracing/value/numeric.html
index f8fc53f890a..1b9df822bc9 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/numeric.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/numeric.html
@@ -6,29 +6,21 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/base/range.html">
-<link rel="import" href="/tracing/base/running_statistics.html">
-<link rel="import" href="/tracing/base/sorted_array_utils.html">
-<link rel="import" href="/tracing/base/statistics.html">
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/base/unit.html">
<script>
'use strict';
tr.exportTo('tr.v', function() {
- var Range = tr.b.Range;
+ class NumericBase {
+ constructor(unit) {
+ if (!(unit instanceof tr.b.Unit))
+ throw new Error('Expected provided unit to be instance of Unit');
- var MAX_SOURCE_INFOS = 16;
-
- function NumericBase(unit) {
- if (!(unit instanceof tr.v.Unit))
- throw new Error('Expected provided unit to be instance of Unit');
-
- this.unit = unit;
- }
+ this.unit = unit;
+ }
- NumericBase.prototype = {
- asDict: function() {
+ asDict() {
var d = {
unit: this.unit.asJSON()
};
@@ -36,591 +28,28 @@ tr.exportTo('tr.v', function() {
this.asDictInto_(d);
return d;
}
- };
-
- NumericBase.fromDict = function(d) {
- if (d.type === 'scalar')
- return ScalarNumeric.fromDict(d);
- if (d.type === 'numeric')
- return Numeric.fromDict(d);
-
- throw new Error('Not implemented');
- };
+ static fromDict(d) {
+ if (d.type === 'scalar')
+ return ScalarNumeric.fromDict(d);
- function NumericBin(parentNumeric, opt_range) {
- this.parentNumeric = parentNumeric;
- this.range = opt_range || (new tr.b.Range());
- this.count = 0;
- this.sourceInfos = [];
- }
-
- NumericBin.fromDict = function(parentNumeric, d) {
- var n = new NumericBin(parentNumeric);
- n.range.min = d.min;
- n.range.max = d.max;
- n.count = d.count;
- n.sourceInfos = d.sourceInfos;
- return n;
- };
-
- NumericBin.prototype = {
- add: function(value, sourceInfo) {
- this.count += 1;
- tr.b.Statistics.uniformlySampleStream(this.sourceInfos, this.count,
- sourceInfo, MAX_SOURCE_INFOS);
- },
-
- addBin: function(other) {
- if (!this.range.equals(other.range))
- throw new Error('Merging incompatible Numeric bins.');
- tr.b.Statistics.mergeSampledStreams(this.sourceInfos, this.count,
- other.sourceInfos, other.count, MAX_SOURCE_INFOS);
- this.count += other.count;
- },
-
- asDict: function() {
- return {
- min: this.range.min,
- max: this.range.max,
- count: this.count,
- sourceInfos: this.sourceInfos.slice(0)
- };
- },
-
- asJSON: function() {
- return this.asDict();
+ throw new Error('Not implemented');
}
- };
-
- function Numeric(unit, range, binInfo) {
- NumericBase.call(this, unit);
-
- this.range = range;
-
- this.numNans = 0;
- this.nanSourceInfos = [];
-
- this.running = new tr.b.RunningStatistics();
- this.maxCount_ = 0;
-
- this.underflowBin = binInfo.underflowBin;
- this.centralBins = binInfo.centralBins;
- this.overflowBin = binInfo.overflowBin;
-
- this.allBins = [];
- this.allBins.push(this.underflowBin);
- this.allBins.push.apply(this.allBins, this.centralBins);
- this.allBins.push(this.overflowBin);
-
- this.allBins.forEach(function(bin) {
- if (bin.count > this.maxCount_)
- this.maxCount_ = bin.count;
- }, this);
-
- this.summaryOptions = this.defaultSummaryOptions();
}
- Numeric.fromDict = function(d) {
- var range = Range.fromExplicitRange(d.min, d.max);
- var binInfo = {};
- binInfo.underflowBin = NumericBin.fromDict(undefined, d.underflowBin);
- binInfo.centralBins = d.centralBins.map(function(binAsDict) {
- return NumericBin.fromDict(undefined, binAsDict);
- });
- binInfo.overflowBin = NumericBin.fromDict(undefined, d.overflowBin);
- var n = new Numeric(tr.v.Unit.fromJSON(d.unit), range, binInfo);
- n.allBins.forEach(function(bin) {
- bin.parentNumeric = n;
- });
- if (d.running)
- n.running = tr.b.RunningStatistics.fromDict(d.running);
- if (d.summaryOptions)
- n.customizeSummaryOptions(d.summaryOptions);
- n.numNans = d.numNans;
- n.nanSourceInfos = d.nanSourceInfos;
- return n;
- };
-
- Numeric.prototype = {
- __proto__: NumericBase.prototype,
-
- get numValues() {
- return tr.b.Statistics.sum(this.allBins, function(e) {
- return e.count;
- });
- },
-
- get average() {
- return this.running.mean;
- },
+ class ScalarNumeric extends NumericBase {
+ constructor(unit, value) {
+ if (!(unit instanceof tr.b.Unit))
+ throw new Error('Expected Unit');
- get sum() {
- return this.running.sum;
- },
-
- get maxCount() {
- return this.maxCount_;
- },
-
- /*
- * Compute an approximation of percentile based on the counts in the bins.
- * If the real percentile lies within |this.range| then the result of
- * the function will deviate from the real percentile by at most
- * the maximum width of the bin(s) within which the point(s)
- * from which the real percentile would be calculated lie.
- * If the real percentile is outside |this.range| then the function
- * returns the closest range limit: |this.range.min| or |this.range.max|.
- *
- * @param {number} percent The percent must be between 0.0 and 1.0.
- */
- getApproximatePercentile: function(percent) {
- if (!(percent >= 0 && percent <= 1))
- throw new Error('percent must be [0,1]');
- if (this.numValues == 0)
- return 0;
- var valuesToSkip = Math.floor((this.numValues - 1) * percent);
- for (var i = 0; i < this.allBins.length; i++) {
- var bin = this.allBins[i];
- valuesToSkip -= bin.count;
- if (valuesToSkip < 0) {
- if (bin === this.underflowBin)
- return bin.range.max;
- else if (bin === this.overflowBin)
- return bin.range.min;
- else
- return bin.range.center;
- }
- }
- throw new Error('Unreachable');
- },
-
- getInterpolatedCountAt: function(value) {
- var bin = this.getBinForValue(value);
- var idx = this.centralBins.indexOf(bin);
- if (idx < 0) {
- // |value| is in either the underflowBin or the overflowBin.
- // We can't interpolate between infinities.
- return bin.count;
- }
-
- // |value| must fall between the centers of two bins.
- // The bin whose center is less than |value| will be this:
- var lesserBin = bin;
-
- // The bin whose center is greater than |value| will be this:
- var greaterBin = bin;
-
- // One of those bins could be an under/overflow bin.
- // Avoid dealing with Infinities by arbitrarily saying that center of the
- // underflow bin is its range.max, and the center of the overflow bin is
- // its range.min.
- // The centers of bins in |this.centralBins| will default to their
- // |range.center|.
-
- var lesserBinCenter = undefined;
- var greaterBinCenter = undefined;
-
- if (value < greaterBin.range.center) {
- if (idx > 0) {
- lesserBin = this.centralBins[idx - 1];
- } else {
- lesserBin = this.underflowBin;
- lesserBinCenter = lesserBin.range.max;
- }
- } else {
- if (idx < (this.centralBins.length - 1)) {
- greaterBin = this.centralBins[idx + 1];
- } else {
- greaterBin = this.overflowBin;
- greaterBinCenter = greaterBin.range.min;
- }
- }
-
- if (greaterBinCenter === undefined)
- greaterBinCenter = greaterBin.range.center;
-
- if (lesserBinCenter === undefined)
- lesserBinCenter = lesserBin.range.center;
-
- value = tr.b.normalize(value, lesserBinCenter, greaterBinCenter);
-
- return tr.b.lerp(value, lesserBin.count, greaterBin.count);
- },
-
- getBinForValue: function(value) {
- // Don't use subtraction to avoid arithmetic overflow.
- var binIndex = tr.b.findHighIndexInSortedArray(
- this.allBins, b => value < b.range.max ? -1 : 1);
- return this.allBins[binIndex] || this.overflowBin;
- },
-
- add: function(value, sourceInfo) {
- if (typeof(value) !== 'number' || isNaN(value)) {
- this.numNans++;
- tr.b.Statistics.uniformlySampleStream(this.nanSourceInfos, this.numNans,
- sourceInfo, MAX_SOURCE_INFOS);
- return;
- }
-
- var bin = this.getBinForValue(value);
- bin.add(value, sourceInfo);
- this.running.add(value);
- if (bin.count > this.maxCount_)
- this.maxCount_ = bin.count;
- },
-
- addNumeric: function(other) {
- if (!this.range.equals(other.range) ||
- !this.unit === other.unit ||
- this.allBins.length !== other.allBins.length) {
- throw new Error('Merging incompatible Numerics.');
- }
- tr.b.Statistics.mergeSampledStreams(this.nanSourceInfos, this.numNans,
- other.nanSourceInfos, other.numNans, MAX_SOURCE_INFOS);
- this.numNans += other.numNans;
- this.running = this.running.merge(other.running);
- for (var i = 0; i < this.allBins.length; ++i) {
- this.allBins[i].addBin(other.allBins[i]);
- }
- },
-
- /**
- * Controls which statistics are exported to dashboard for this numeric.
- * The |summaryOptions| parameter is a dictionary with optional boolean
- * fields |count|, |sum|, |avg|, |std|, |min|, |max| and an optional
- * array field |percentile|.
- * Each percentile should be a number between 0.0 and 1.0.
- * The options not included in the |summaryOptions| will not change.
- */
- customizeSummaryOptions: function(summaryOptions) {
- tr.b.iterItems(summaryOptions, function(key, value) {
- this.summaryOptions[key] = value;
- }, this);
- },
-
- defaultSummaryOptions: function() {
- return {
- count: true,
- sum: true,
- avg: true,
- std: true,
- min: true,
- max: true,
- percentile: []
- };
- },
+ if (!(typeof(value) === 'number'))
+ throw new Error('Expected value to be number');
- /**
- * Returns an array of {name: string, scalar: ScalarNumeric} values.
- * Each enabled summary option produces the corresponding value:
- * min, max, count, sum, avg, or std.
- * Each percentile 0.x produces pct_0x0.
- * Each percentile 0.xx produces pct_0xx.
- * Each percentile 0.xxy produces pct_0xx_y.
- * Percentile 1.0 produces pct_100.
- */
- getSummarizedScalarNumericsWithNames: function() {
- function statNameToKey(stat) {
- switch (stat) {
- case 'std':
- return 'stddev';
- case 'avg':
- return 'mean';
- }
- return stat;
- }
- /**
- * Converts the given percent to a string in the format specified above.
- * @param {number} percent The percent must be between 0.0 and 1.0.
- */
- function percentToString(percent) {
- if (percent < 0 || percent > 1)
- throw new Error('Percent must be between 0.0 and 1.0');
- switch (percent) {
- case 0:
- return '000';
- case 1:
- return '100';
- }
- var str = percent.toString();
- if (str[1] !== '.')
- throw new Error('Unexpected percent');
- // Pad short strings with zeros.
- str = str + '0'.repeat(Math.max(4 - str.length, 0));
- if (str.length > 4)
- str = str.slice(0, 4) + '_' + str.slice(4);
- return '0' + str.slice(2);
- }
-
- var results = [];
- tr.b.iterItems(this.summaryOptions, function(stat, option) {
- if (!option)
- return;
- if (stat === 'percentile') {
- option.forEach(function(percent) {
- var percentile = this.getApproximatePercentile(percent);
- results.push({
- name: 'pct_' + percentToString(percent),
- scalar: new tr.v.ScalarNumeric(this.unit, percentile)
- });
- }, this);
- } else {
- var statUnit = stat === 'count' ?
- tr.v.Unit.byName.unitlessNumber_smallerIsBetter : this.unit;
- var key = statNameToKey(stat);
- var statValue = this.running[key];
- if (typeof(statValue) === 'number') {
- results.push({
- name: stat,
- scalar: new tr.v.ScalarNumeric(statUnit, statValue)
- });
- }
- }
- }, this);
- return results;
- },
-
- clone: function() {
- return Numeric.fromDict(this.asDict());
- },
-
- asDict: function() {
- var d = {
- unit: this.unit.asJSON(),
- type: 'numeric',
-
- min: this.range.min,
- max: this.range.max,
-
- numNans: this.numNans,
- nanSourceInfos: this.nanSourceInfos,
-
- running: this.running.asDict(),
- summaryOptions: this.summaryOptions,
-
- underflowBin: this.underflowBin.asDict(),
- centralBins: this.centralBins.map(function(bin) {
- return bin.asDict();
- }),
- overflowBin: this.overflowBin.asDict()
- };
- return d;
- },
-
- asJSON: function() {
- return this.asDict();
- }
- };
-
- /**
- * Reusable builder for tr.v.Numeric objects.
- *
- * The bins of the numeric are specified by adding the desired boundaries
- * between bins. Initially, the builder has only a single boundary:
- *
- * minBinBoundary=maxBinBoundary
- * |
- * |
- * -MAX_INT <--------|------------------------------------------> +MAX_INT
- * : resulting : resulting :
- * : underflow : overflow :
- * : bin : bin :
- *
- * More boundaries can be added (in increasing order) using addBinBoundary,
- * addLinearBins and addExponentialBins:
- *
- * minBinBoundary maxBinBoundary
- * | | | | |
- * | | | | |
- * -MAX_INT <--------|---------|---------|-----|---------|------> +MAX_INT
- * : resulting : result. : result. : : result. : resulting :
- * : underflow : central : central : ... : central : overflow :
- * : bin : bin 0 : bin 1 : : bin N-1 : bin :
- *
- * An important feature of the builder is that it's reusable, i.e. it can be
- * used to build multiple numerics with the same unit and bin structure.
- *
- * @constructor
- * @param {!tr.v.Unit} unit Unit of the resulting Numeric(s).
- * @param {number} minBinBoundary The minimum boundary between bins, namely
- * the underflow bin and the first central bin (or the overflow bin if
- * no other boundaries are added later).
- */
- function NumericBuilder(unit, minBinBoundary) {
- this.unit_ = unit;
- this.boundaries_ = [minBinBoundary];
- }
-
- NumericBuilder.prototype = {
- get minBinBoundary() {
- return this.boundaries_[0];
- },
-
- get maxBinBoundary() {
- return this.boundaries_[this.boundaries_.length - 1];
- },
-
- /**
- * Add a bin boundary |nextMaxBinBoundary| to the builder.
- *
- * This operation effectively corresponds to appending a new central bin
- * with the range [this.maxBinBoundary*, nextMaxBinBoundary].
- *
- * @param {number} nextMaxBinBoundary The added bin boundary (must be
- * greater than |this.maxMinBoundary|).
- */
- addBinBoundary: function(nextMaxBinBoundary) {
- if (nextMaxBinBoundary <= this.maxBinBoundary) {
- throw new Error('The added max bin boundary must be larger than ' +
- 'the current max boundary');
- }
- this.boundaries_.push(nextMaxBinBoundary);
-
- return this;
- },
-
- /**
- * Add |binCount| linearly scaled bin boundaries up to |nextMaxBinBoundary|
- * to the builder.
- *
- * This operation corresponds to appending |binCount| central bins of
- * constant range width
- * W = ((|nextMaxBinBoundary| - |this.maxBinBoundary|) / |binCount|)
- * with the following ranges:
- *
- * [|this.maxMinBoundary|, |this.maxMinBoundary| + W]
- * [|this.maxMinBoundary| + W, |this.maxMinBoundary| + 2W]
- * [|this.maxMinBoundary| + 2W, |this.maxMinBoundary| + 3W]
- * ...
- * [|this.maxMinBoundary| + (|binCount| - 2) * W,
- * |this.maxMinBoundary| + (|binCount| - 2) * W]
- * [|this.maxMinBoundary| + (|binCount| - 1) * W,
- * |nextMaxBinBoundary|]
- *
- * @param {number} nextBinBoundary The last added bin boundary (must be
- * greater than |this.maxMinBoundary|).
- * @param {number} binCount Number of bins to be added (must be positive).
- */
- addLinearBins: function(nextMaxBinBoundary, binCount) {
- if (binCount <= 0)
- throw new Error('Bin count must be positive');
-
- var curMaxBinBoundary = this.maxBinBoundary;
- if (curMaxBinBoundary >= nextMaxBinBoundary) {
- throw new Error('The last added max boundary must be greater than ' +
- 'the current max boundary boundary');
- }
-
- var binWidth = (nextMaxBinBoundary - curMaxBinBoundary) / binCount;
- for (var i = 1; i < binCount; i++)
- this.addBinBoundary(curMaxBinBoundary + i * binWidth);
- this.addBinBoundary(nextMaxBinBoundary);
-
- return this;
- },
-
- /**
- * Add |binCount| exponentially scaled bin boundaries up to
- * |nextMaxBinBoundary| to the builder.
- *
- * This operation corresponds to appending |binCount| central bins with
- * a constant difference between the logarithms of their range min and max
- * D = ((ln(|nextMaxBinBoundary|) - ln(|this.maxBinBoundary|)) / |binCount|)
- * with the following ranges:
- *
- * [|this.maxMinBoundary|, |this.maxMinBoundary| * exp(D)]
- * [|this.maxMinBoundary| * exp(D), |this.maxMinBoundary| * exp(2D)]
- * [|this.maxMinBoundary| * exp(2D), |this.maxMinBoundary| * exp(3D)]
- * ...
- * [|this.maxMinBoundary| * exp((|binCount| - 2) * D),
- * |this.maxMinBoundary| * exp((|binCount| - 2) * D)]
- * [|this.maxMinBoundary| * exp((|binCount| - 1) * D),
- * |nextMaxBinBoundary|]
- *
- * This method requires that the current max bin boundary is positive.
- *
- * @param {number} nextBinBoundary The last added bin boundary (must be
- * greater than |this.maxMinBoundary|).
- * @param {number} binCount Number of bins to be added (must be positive).
- */
- addExponentialBins: function(nextMaxBinBoundary, binCount) {
- if (binCount <= 0)
- throw new Error('Bin count must be positive');
-
- var curMaxBinBoundary = this.maxBinBoundary;
- if (curMaxBinBoundary <= 0)
- throw new Error('Current max bin boundary must be positive');
- if (curMaxBinBoundary >= nextMaxBinBoundary) {
- throw new Error('The last added max boundary must be greater than ' +
- 'the current max boundary boundary');
- }
-
- var binExponentWidth =
- Math.log(nextMaxBinBoundary / curMaxBinBoundary) / binCount;
- for (var i = 1; i < binCount; i++) {
- this.addBinBoundary(
- curMaxBinBoundary * Math.exp(i * binExponentWidth));
- }
- this.addBinBoundary(nextMaxBinBoundary);
-
- return this;
- },
-
- /**
- * Build a tr.v.Numeric from the list of bin boundaries.
- *
- * As explained earlier, this method can be called arbitrarily many times
- * to produce arbitrarily many distinct numerics.
- */
- build: function() {
- var binInfo = {
- underflowBin: new NumericBin(undefined,
- Range.fromExplicitRange(-Number.MAX_VALUE, this.minBinBoundary)),
- overflowBin: new NumericBin(undefined,
- Range.fromExplicitRange(this.maxBinBoundary, Number.MAX_VALUE)),
- centralBins: new Array(this.boundaries_.length - 1)
- };
- for (var i = 0; i < this.boundaries_.length - 1; i++) {
- binInfo.centralBins[i] = new NumericBin(undefined,
- Range.fromExplicitRange(
- this.boundaries_[i], this.boundaries_[i + 1]));
- }
-
- var numeric = new Numeric(
- this.unit_,
- Range.fromExplicitRange(this.minBinBoundary, this.maxBinBoundary),
- binInfo);
- numeric.allBins.forEach(function(bin) {
- bin.parentNumeric = numeric;
- });
- return numeric;
+ super(unit);
+ this.value = value;
}
- };
-
- /**
- * Create a linearly scaled tr.v.NumericBuilder with |numBins| bins ranging
- * from |range.min| to |range.max|.
- */
- NumericBuilder.createLinear = function(unit, range, numBins) {
- if (range.isEmpty)
- throw new Error('Range must be non-empty');
- return new NumericBuilder(unit, range.min).addLinearBins(
- range.max, numBins);
- };
-
- function ScalarNumeric(unit, value) {
- if (!(typeof(value) == 'number'))
- throw new Error('Expected value to be number');
-
- NumericBase.call(this, unit);
- this.value = value;
- }
- ScalarNumeric.prototype = {
- __proto__: NumericBase.prototype,
-
- asDictInto_: function(d) {
+ asDictInto_(d) {
d.type = 'scalar';
// Infinity and NaN are left out of JSON for security reasons that do not
@@ -633,34 +62,31 @@ tr.exportTo('tr.v', function() {
d.value = 'NaN';
else
d.value = this.value;
- },
+ }
- toString: function() {
+ toString() {
return this.unit.format(this.value);
}
- };
- ScalarNumeric.fromDict = function(d) {
- // Infinity and NaN are left out of JSON for security reasons that do not
- // apply to our use cases.
- if (typeof(d.value) === 'string') {
- if (d.value === '-Infinity') {
- d.value = -Infinity;
- } else if (d.value === 'Infinity') {
- d.value = Infinity;
- } else if (d.value === 'NaN') {
- d.value = NaN;
+ static fromDict(d) {
+ // Infinity and NaN are left out of JSON for security reasons that do not
+ // apply to our use cases.
+ if (typeof(d.value) === 'string') {
+ if (d.value === '-Infinity') {
+ d.value = -Infinity;
+ } else if (d.value === 'Infinity') {
+ d.value = Infinity;
+ } else if (d.value === 'NaN') {
+ d.value = NaN;
+ }
}
- }
- return new ScalarNumeric(tr.v.Unit.fromJSON(d.unit), d.value);
- };
+ return new ScalarNumeric(tr.b.Unit.fromJSON(d.unit), d.value);
+ }
+ }
return {
NumericBase: NumericBase,
- NumericBin: NumericBin,
- Numeric: Numeric,
- NumericBuilder: NumericBuilder,
ScalarNumeric: ScalarNumeric
};
});
diff --git a/chromium/third_party/catapult/tracing/tracing/value/numeric_test.html b/chromium/third_party/catapult/tracing/tracing/value/numeric_test.html
index ed586ededfb..281950a2666 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/numeric_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/numeric_test.html
@@ -7,172 +7,26 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+<link rel="import" href="/tracing/value/diagnostics/generic.html">
<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
-
- var TEST_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 1000),
- 10);
-
- function checkBuilder(builder, expectedMinBoundary, expectedMaxBoundary,
- expectedUnit, expectedBinRanges) {
- assert.strictEqual(builder.minBinBoundary, expectedMinBoundary);
- assert.strictEqual(builder.maxBinBoundary, expectedMaxBoundary);
-
- // Check that the builder can be used multiple times.
- for (var i = 0; i < 3; i++) {
- var numeric = builder.build();
- assert.instanceOf(numeric, tr.v.Numeric);
- assert.strictEqual(numeric.unit, expectedUnit);
- assert.strictEqual(numeric.numValues, 0);
-
- assert.lengthOf(numeric.allBins, expectedBinRanges.length);
- for (var j = 0; j < expectedBinRanges.length; j++) {
- var bin = numeric.allBins[j];
- assert.instanceOf(bin, tr.v.NumericBin);
- assert.strictEqual(bin.parentNumeric, numeric);
- assert.strictEqual(bin.count, 0);
- assert.isTrue(bin.range.equals(expectedBinRanges[j]));
- }
- }
- }
-
test('nonUnitThrows', function() {
assert.throws(function() { new tr.v.NumericBase('foo', -273.15); });
});
test('nonNumberScalarThrows', function() {
- var unit = tr.v.Unit.byName.sizeInBytes;
+ var unit = tr.b.Unit.byName.sizeInBytes;
assert.throws(function() { new tr.v.ScalarNumeric(unit, 'foo'); });
});
- test('numericBasic', function() {
- var n = TEST_NUMERIC_BUILDER.build();
- assert.equal(n.getBinForValue(250).range.min, 200);
- assert.equal(n.getBinForValue(250).range.max, 300);
- n.add(-1, 'a');
- n.add(0, 'b');
- n.add(0, 'c');
- n.add(500, 'c');
- n.add(999, 'd');
- n.add(1000, 'd');
- assert.equal(n.underflowBin.count, 1);
-
- assert.equal(n.getBinForValue(0).count, 2);
- assert.deepEqual(n.getBinForValue(0).sourceInfos,
- ['b', 'c']);
-
- assert.equal(n.getBinForValue(500).count, 1);
- assert.equal(n.getBinForValue(999).count, 1);
-
- assert.equal(n.overflowBin.count, 1);
- assert.equal(n.numValues, 6);
- assert.closeTo(n.average, 416.3, 0.1);
- });
-
- test('numericNans', function() {
- var n = TEST_NUMERIC_BUILDER.build();
- n.add(undefined, 'b');
- n.add(NaN, 'c');
-
- assert.equal(n.numNans, 2);
- assert.deepEqual(n.nanSourceInfos, ['b', 'c']);
- });
-
- test('addNumericsValid', function() {
- var n0 = TEST_NUMERIC_BUILDER.build();
- var n1 = TEST_NUMERIC_BUILDER.build();
- n0.add(-1, 'a0');
- n0.add(0, 'b0');
- n0.add(0, 'c0');
- n0.add(500, 'c0');
- n0.add(1000, 'd0');
- n0.add(NaN, 'e0');
-
- n1.add(-1, 'a1');
- n1.add(0, 'b1');
- n1.add(0, 'c1');
- n1.add(999, 'd1');
- n1.add(1000, 'd1');
- n1.add(NaN, 'e1');
-
- n0.addNumeric(n1);
-
- assert.equal(n0.numNans, 2);
- assert.deepEqual(n0.nanSourceInfos, ['e0', 'e1']);
-
- assert.equal(n0.underflowBin.count, 2);
- assert.deepEqual(n0.underflowBin.sourceInfos, ['a0', 'a1']);
-
- assert.equal(n0.getBinForValue(0).count, 4);
- assert.deepEqual(n0.getBinForValue(0).sourceInfos,
- ['b0', 'c0', 'b1', 'c1']);
-
- assert.equal(n0.getBinForValue(500).count, 1);
- assert.deepEqual(n0.getBinForValue(500).sourceInfos, ['c0']);
-
- assert.equal(n0.getBinForValue(999).count, 1);
- assert.deepEqual(n0.getBinForValue(999).sourceInfos, ['d1']);
-
- assert.equal(n0.overflowBin.count, 2);
- assert.deepEqual(n0.overflowBin.sourceInfos, ['d0', 'd1']);
-
- assert.equal(n0.numValues, 10);
- assert.closeTo(n0.average, 349.7, 0.1);
-
- assert.equal(2, n0.maxCount);
- assert.equal(2, n1.maxCount);
- });
-
- test('addNumericsInvalid', function() {
- var n0 = tr.v.NumericBuilder.createLinear(tr.v.Unit.byName.timeDurationInMs,
- tr.b.Range.fromExplicitRange(0, 1000), 10).build();
- var n1 = tr.v.NumericBuilder.createLinear(tr.v.Unit.byName.timeDurationInMs,
- tr.b.Range.fromExplicitRange(0, 1001), 10).build();
- var n2 = tr.v.NumericBuilder.createLinear(tr.v.Unit.byName.timeDurationInMs,
- tr.b.Range.fromExplicitRange(0, 1000), 11).build();
-
- assert.throws(n0.addNumeric.bind(n0, n1), Error);
- assert.throws(n0.addNumeric.bind(n0, n1), Error);
- });
-
- test('getInterpolateCountAt', function() {
- var n = tr.v.Numeric.fromDict({
- unit: 'unitless',
- min: 0,
- max: 100,
- centralBinWidth: 10,
- underflowBin: {min: -Number.MAX_VALUE, max: 0, count: 11},
- centralBins: [
- {min: 0, max: 10, count: 10},
- {min: 10, max: 20, count: 9},
- {min: 20, max: 30, count: 8},
- {min: 30, max: 40, count: 7},
- {min: 40, max: 50, count: 6},
- {min: 50, max: 60, count: 5},
- {min: 60, max: 70, count: 4},
- {min: 70, max: 80, count: 3},
- {min: 80, max: 90, count: 2},
- {min: 90, max: 100, count: 1}
- ],
- overflowBin: {min: 100, max: Number.MAX_VALUE, count: 0}
- });
-
- assert.equal(11, n.maxCount);
- assert.equal(11, n.getInterpolatedCountAt(-1));
- assert.equal(0, n.getInterpolatedCountAt(101));
- assert.closeTo(10.8, n.getInterpolatedCountAt(1), 1e-3);
- assert.closeTo(9.5, n.getInterpolatedCountAt(10), 1e-3);
- assert.closeTo(0.2, n.getInterpolatedCountAt(99), 1e-3);
- });
-
test('scalarBasic', function() {
- var unit = tr.v.Unit.byName.sizeInBytes;
+ var unit = tr.b.Unit.byName.sizeInBytes;
var d = {
type: 'scalar',
@@ -182,239 +36,5 @@ tr.b.unittest.testSuite(function() {
assert.deepEqual(d, tr.v.NumericBase.fromDict(d).asDict());
});
-
- test('numericPercentile', function() {
- function check(array, min, max, bins, precision) {
- var n = new tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs,
- tr.b.Range.fromExplicitRange(min, max),
- bins).build();
- array.forEach((x) => n.add(x, 'x'));
- [0.25, 0.5, 0.75, 0.8, 0.95, 0.99].forEach(function(percent) {
- var expected = tr.b.Statistics.percentile(array, percent);
- var actual = n.getApproximatePercentile(percent);
- assert.closeTo(expected, actual, precision);
- });
- }
- check([1, 2, 5, 7], 0.5, 10.5, 10, 1e-3);
- check([3, 3, 4, 4], 0.5, 10.5, 10, 1e-3);
- check([1, 10], 0.5, 10.5, 10, 1e-3);
- check([1, 2, 3, 4, 5], 0.5, 10.5, 10, 1e-3);
- check([3, 3, 3, 3, 3], 0.5, 10.5, 10, 1e-3);
- check([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3);
- check([1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3);
- check([0, 11], 0.5, 10.5, 10, 1);
- check([0, 6, 11], 0.5, 10.5, 10, 1);
- var array = [];
- for (var i = 0; i < 1000; i++)
- array.push((i * i) % 10 + 1);
- check(array, 0.5, 10.5, 10, 1e-3);
- // If the real percentile is outside the bin range then the approximation
- // error can be high.
- check([-10000], 0, 10, 10, 10000);
- check([10000], 0, 10, 10, 10000 - 10);
- // The result is no more than the bin width away from the real percentile.
- check([1, 1], 0, 10, 1, 10);
- });
-
- test('numericBuilder_empty', function() {
- var b = new tr.v.NumericBuilder(tr.v.Unit.byName.sizeInBytes, 0);
-
- checkBuilder(b, 0, 0, tr.v.Unit.byName.sizeInBytes, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 0),
- tr.b.Range.fromExplicitRange(0, Number.MAX_VALUE)
- ]);
- });
-
- test('numericBuilder_addBinBoundary', function() {
- var b = new tr.v.NumericBuilder(tr.v.Unit.byName.timeDurationInMs, -100);
- b.addBinBoundary(50);
-
- checkBuilder(b, -100, 50, tr.v.Unit.byName.timeDurationInMs, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
- tr.b.Range.fromExplicitRange(-100, 50),
- tr.b.Range.fromExplicitRange(50, Number.MAX_VALUE)
- ]);
-
- b.addBinBoundary(60);
- b.addBinBoundary(75);
-
- checkBuilder(b, -100, 75, tr.v.Unit.byName.timeDurationInMs, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
- tr.b.Range.fromExplicitRange(-100, 50),
- tr.b.Range.fromExplicitRange(50, 60),
- tr.b.Range.fromExplicitRange(60, 75),
- tr.b.Range.fromExplicitRange(75, Number.MAX_VALUE)
- ]);
- });
-
- test('numericBuilder_addLinearBins', function() {
- var b = new tr.v.NumericBuilder(tr.v.Unit.byName.powerInWatts, 1000);
- b.addLinearBins(1200, 5);
-
- checkBuilder(b, 1000, 1200, tr.v.Unit.byName.powerInWatts, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 1000),
- tr.b.Range.fromExplicitRange(1000, 1040),
- tr.b.Range.fromExplicitRange(1040, 1080),
- tr.b.Range.fromExplicitRange(1080, 1120),
- tr.b.Range.fromExplicitRange(1120, 1160),
- tr.b.Range.fromExplicitRange(1160, 1200),
- tr.b.Range.fromExplicitRange(1200, Number.MAX_VALUE)
- ]);
- });
-
- test('numericBuilder_addExponentialBins', function() {
- var b = new tr.v.NumericBuilder(tr.v.Unit.byName.energyInJoules, 0.5);
- b.addExponentialBins(8, 4);
-
- checkBuilder(b, 0.5, 8, tr.v.Unit.byName.energyInJoules, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 0.5),
- tr.b.Range.fromExplicitRange(0.5, 1),
- tr.b.Range.fromExplicitRange(1, 2),
- tr.b.Range.fromExplicitRange(2, 4),
- tr.b.Range.fromExplicitRange(4, 8),
- tr.b.Range.fromExplicitRange(8, Number.MAX_VALUE)
- ]);
- });
-
- test('numericBuilder_combined', function() {
- var b = new tr.v.NumericBuilder(tr.v.Unit.byName.unitlessNumber, -273.15);
- b.addBinBoundary(-50);
- b.addLinearBins(4, 3);
- b.addExponentialBins(16, 2);
- b.addLinearBins(17, 4);
- b.addBinBoundary(100);
-
- checkBuilder(b, -273.15, 100, tr.v.Unit.byName.unitlessNumber, [
- tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -273.15),
- tr.b.Range.fromExplicitRange(-273.15, -50),
- tr.b.Range.fromExplicitRange(-50, -32),
- tr.b.Range.fromExplicitRange(-32, -14),
- tr.b.Range.fromExplicitRange(-14, 4),
- tr.b.Range.fromExplicitRange(4, 8),
- tr.b.Range.fromExplicitRange(8, 16),
- tr.b.Range.fromExplicitRange(16, 16.25),
- tr.b.Range.fromExplicitRange(16.25, 16.5),
- tr.b.Range.fromExplicitRange(16.5, 16.75),
- tr.b.Range.fromExplicitRange(16.75, 17),
- tr.b.Range.fromExplicitRange(17, 100),
- tr.b.Range.fromExplicitRange(100, Number.MAX_VALUE)
- ]);
- });
-
- test('numericBuilder_throws', function() {
- var b0 = new tr.v.NumericBuilder(tr.v.Unit.byName.timeStampInMs, -7);
- assert.throws(function() { b0.addBinBoundary(-10 /* must be > -7 */); });
- assert.throws(function() { b0.addBinBoundary(-7 /* must be > -7 */); });
- assert.throws(function() { b0.addLinearBins(-10 /* must be > -7 */, 10); });
- assert.throws(function() { b0.addLinearBins(-7 /* must be > -7 */, 100); });
- assert.throws(function() { b0.addLinearBins(10, 0 /* must be > 0 */); });
- assert.throws(function() {
- // Current max bin boundary (-7) must be positive.
- b0.addExponentialBins(16, 4);
- });
-
- var b1 = new tr.v.NumericBuilder(tr.v.Unit.byName.sizeInBytes, 8);
- assert.throws(
- function() { b1.addExponentialBins(20, 0 /* must be > 0 */); });
- assert.throws(
- function() { b1.addExponentialBins(5 /* must be > 8 */, 3); });
- assert.throws(
- function() { b1.addExponentialBins(8 /* must be > 8 */, 3); });
- });
-
- test('getSummarizedScalarNumericsWithNames', function() {
- var n = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 100),
- 100).build();
-
- n.add(50);
- n.add(60);
- n.add(70);
-
- n.customizeSummaryOptions({
- count: true,
- min: true,
- max: true,
- sum: true,
- avg: true,
- std: true,
- percentile: [0.5, 1]
- });
-
- var results = n.getSummarizedScalarNumericsWithNames();
- var values = {};
- results.forEach(function(x) {
- values[x.name] = x.scalar;
- });
-
- assert.strictEqual(values.count.value, 3);
- assert.strictEqual(values.min.value, 50);
- assert.strictEqual(values.max.value, 70);
- assert.strictEqual(values.sum.value, 180);
- assert.strictEqual(values.avg.value, 60);
- assert.strictEqual(values.std.value, 10);
- assert.closeTo(values.pct_050.value, 60, 1);
- assert.closeTo(values.pct_100.value, 70, 1);
- });
-
- test('getSummarizedScalarNumericsWithNamesNoSummaryOptions', function() {
- var n = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 100),
- 100).build();
-
- n.add(50);
- n.add(60);
- n.add(70);
-
- n.customizeSummaryOptions({
- count: false,
- min: false,
- max: false,
- sum: false,
- avg: false,
- std: false,
- percentile: []
- });
-
- var results = n.getSummarizedScalarNumericsWithNames('abc');
- assert.strictEqual(results.length, 0);
- });
-
- test('getSummarizedScalarNumericsWithNamesEmptyNumericValue', function() {
- var n = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 100),
- 100).build();
-
- n.customizeSummaryOptions({
- count: true,
- min: true,
- max: true,
- sum: true,
- avg: true,
- std: true,
- percentile: [0, 0.01, 0.1, 0.5, 0.995, 1]
- });
-
- var results = n.getSummarizedScalarNumericsWithNames();
- var values = {};
- results.forEach(function(x) {
- values[x.name] = x.scalar;
- });
-
- assert.strictEqual(values.count.value, 0);
- assert.strictEqual(values.min.value, Infinity);
- assert.strictEqual(values.max.value, -Infinity);
- assert.strictEqual(values.sum.value, 0);
- assert.strictEqual(values.avg, undefined);
- assert.strictEqual(values.std, undefined);
- assert.strictEqual(values.pct_000.value, 0);
- assert.strictEqual(values.pct_001.value, 0);
- assert.strictEqual(values.pct_010.value, 0);
- assert.strictEqual(values.pct_050.value, 0);
- assert.strictEqual(values.pct_099_5.value, 0);
- assert.strictEqual(values.pct_100.value, 0);
- });
});
-
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span.html
index 9f90e35bdb7..05cc5410058 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span.html
@@ -17,59 +17,61 @@ tr.exportTo('tr.v.ui', function() {
};
});
</script>
-<polymer-element name="tr-v-ui-array-of-numbers-span">
+<dom-module id='tr-v-ui-array-of-numbers-span'>
<template>
</template>
- <script>
- 'use strict';
+</dom-module>
+<script>
+'use strict';
- Polymer({
- created: function() {
- this.numbers_ = undefined;
- this.summaryMode_ = tr.v.ui.ArrayOfNumbersSummaryModes.AVERAGE_MODE;
- },
+Polymer({
+ is: 'tr-v-ui-array-of-numbers-span',
- get summaryMode() {
- return this.summaryMode_;
- },
+ created: function() {
+ this.numbers_ = undefined;
+ this.summaryMode_ = tr.v.ui.ArrayOfNumbersSummaryModes.AVERAGE_MODE;
+ },
- set summaryMode(summaryMode) {
- this.summaryMode_ = summaryMode;
- this.updateContents_();
- },
+ get summaryMode() {
+ return this.summaryMode_;
+ },
+
+ set summaryMode(summaryMode) {
+ this.summaryMode_ = summaryMode;
+ this.updateContents_();
+ },
- get numbers() {
- return this.numbers_;
- },
+ get numbers() {
+ return this.numbers_;
+ },
- set numbers(numbers) {
- if (numbers === undefined) {
- this.numbers_ = undefined;
- this.updateContents_();
- return;
- }
- if (!(numbers instanceof Array))
- throw new Error('Must provide an array');
- this.numbers_ = numbers;
+ set numbers(numbers) {
+ if (numbers === undefined) {
+ this.numbers_ = undefined;
this.updateContents_();
- },
+ return;
+ }
+ if (!(numbers instanceof Array))
+ throw new Error('Must provide an array');
+ this.numbers_ = numbers;
+ this.updateContents_();
+ },
- updateContents_: function() {
- if (this.numbers_ === undefined) {
- this.shadowRoot.textContent = '-';
- return;
- }
+ updateContents_: function() {
+ if (this.numbers_ === undefined) {
+ Polymer.dom(this.root).textContent = '-';
+ return;
+ }
- var ArrayOfNumbersSummaryModes = tr.v.ui.ArrayOfNumbersSummaryModes;
- var value;
- if (this.summaryMode_ === ArrayOfNumbersSummaryModes.AVERAGE_MODE)
- value = tr.b.Statistics.mean(this.numbers_);
- else
- value = tr.b.Statistics.sum(this.numbers_);
+ var ArrayOfNumbersSummaryModes = tr.v.ui.ArrayOfNumbersSummaryModes;
+ var value;
+ if (this.summaryMode_ === ArrayOfNumbersSummaryModes.AVERAGE_MODE)
+ value = tr.b.Statistics.mean(this.numbers_);
+ else
+ value = tr.b.Statistics.sum(this.numbers_);
- var valueRounded = Math.round(value * 1000.0) / 1000.0;
- this.shadowRoot.textContent = valueRounded;
- }
- });
- </script>
-</polymer-element>
+ var valueRounded = Math.round(value * 1000.0) / 1000.0;
+ Polymer.dom(this.root).textContent = valueRounded;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span_test.html
index 9847276b8d7..28f61065f0f 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/array_of_numbers_span_test.html
@@ -22,7 +22,7 @@ tr.b.unittest.testSuite(function() {
span.numbers = [1, 2, 3];
span.summaryMode = tr.v.ui.ArrayOfNumbersSummaryModes.TOTALS_MODE;
this.addHTMLOutput(span);
- assert.equal(span.shadowRoot.textContent, '6');
+ assert.equal(Polymer.dom(span.root).textContent, '6');
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span.html
new file mode 100644
index 00000000000..a66a4b17122
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/extras/chrome/chrome_user_friendly_category_driver.html">
+<link rel="import" href="/tracing/ui/base/column_chart.html">
+<link rel="import" href="/tracing/ui/base/drag_handle.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+
+<dom-module id="tr-v-ui-breakdown-span">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: row;
+ }
+ #nans_message {
+ color: red;
+ }
+ </style>
+
+ <div id="outer">
+ <div id="container"></div>
+ <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle>
+ </div>
+ <div id="nans">
+ <div id="nans_message">Invalid categories:</div>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </div>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+Polymer({
+ is: 'tr-v-ui-breakdown-span',
+
+ created: function() {
+ this.diagnostic_ = undefined;
+ this.chart_ = new tr.ui.b.ColumnChart();
+ this.chart_.width = 190;
+ this.chart_.height = 200;
+ this.chart_.isStacked = true;
+ this.chart_.hideXAxis = true;
+ this.chart_.margin.top = 10;
+ this.chart_.margin.bottom = 10;
+ this.chart_.margin.right = 120;
+ this.minHeightPx_ = 40;
+ },
+
+ ready: function() {
+ Polymer.dom(this.$.container).appendChild(this.chart_);
+ this.$.drag_handle.target = this.$.container;
+ this.$.drag_handle.addEventListener(
+ 'drag-handle-resize', this.onResize_.bind(this));
+
+ this.$.table.showHeader = false;
+ this.$.table.tableColumns = [
+ {
+ value: row => row[0]
+ },
+ {
+ value: row => row[1]
+ }
+ ];
+ },
+
+ onResize_: function(event) {
+ event.stopPropagation();
+ var heightPx = parseInt(this.$.container.style.height);
+ if (heightPx < this.minHeightPx_) {
+ heightPx = this.minHeightPx_;
+ this.$.container.style.height = this.minHeightPx_ + 'px';
+ }
+ this.chart_.height = heightPx;
+ },
+
+ get diagnostic() {
+ return this.diagnostic_;
+ },
+
+ set diagnostic(d) {
+ this.diagnostic_ = d;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ if (!this.diagnostic_) {
+ this.chart_.data = [];
+ return;
+ }
+
+ var data = {x: 0};
+ this.minHeightPx_ = 20;
+ var tableRows = [];
+
+ for (var [name, value] of this.diagnostic) {
+ if ((typeof value === 'number') &&
+ (isNaN(value) || (value === Infinity) || (value <= 0))) {
+ tableRows.push([name, value]);
+ continue;
+ }
+
+ this.minHeightPx_ += 20;
+
+ var dataSeries = this.chart_.getDataSeries(name);
+ dataSeries.optional = true;
+
+ if (this.diagnostic.colorScheme ===
+ tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER) {
+ var cat = name.split(' ');
+ cat = cat[cat.length - 1];
+ var color = tr.e.chrome.ChromeUserFriendlyCategoryDriver.getColor(cat);
+ var hsl = color.toHSL();
+ hsl.l *= 0.85;
+ var highlightedColor = tr.b.Color.fromHSL(hsl);
+ dataSeries.highlightedColor = highlightedColor;
+ dataSeries.color = color;
+ }
+
+ if (value instanceof tr.v.Histogram) {
+ dataSeries.target = value;
+ data[name] = value.sum;
+ } else if (typeof value === 'number') {
+ data[name] = value;
+ } else {
+ throw new Error('unsupported value ' + value);
+ }
+ }
+
+ this.chart_.data = [data];
+ this.$.nans.style.display = tableRows.length ? 'block' : 'none';
+ this.$.table.tableRows = tableRows;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span_test.html
new file mode 100644
index 00000000000..d7a665ad2b0
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/breakdown_span_test.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/breakdown.html">
+<link rel="import" href="/tracing/value/diagnostics/related_histogram_breakdown.html">
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/ui/breakdown_span.html">
+<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('instantiate_RelatedHistogramBreakdown', function() {
+ var foo = new tr.v.Histogram('foo', tr.b.Unit.byName.timeDurationInMs);
+ var bar = new tr.v.Histogram('bar', tr.b.Unit.byName.timeDurationInMs);
+ for (var i = 0; i < 1e2; ++i) {
+ foo.addSample(Math.random());
+ bar.addSample(Math.random());
+ }
+ var breakdown = new tr.v.d.RelatedHistogramBreakdown();
+ breakdown.add(foo);
+ breakdown.add(bar);
+ var span = tr.v.ui.createDiagnosticSpan(breakdown);
+ assert.strictEqual('TR-V-UI-BREAKDOWN-SPAN', span.tagName);
+ this.addHTMLOutput(span);
+ });
+
+ test('instantiate_Breakdown', function() {
+ var breakdown = new tr.v.d.Breakdown();
+ breakdown.colorScheme =
+ tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER;
+ breakdown.set('script', 42);
+ breakdown.set('style', 57);
+
+ // Test weird numbers.
+ breakdown.set('ba---a', NaN);
+ breakdown.set('inf', Infinity);
+ breakdown.set('-inf', -Infinity);
+ breakdown.set('goose egg', 0);
+ breakdown.set('<0', -1);
+
+ // Test round-tripping.
+ breakdown = tr.v.d.Diagnostic.fromDict(breakdown.asDict());
+
+ var span = tr.v.ui.createDiagnosticSpan(breakdown);
+ assert.strictEqual('TR-V-UI-BREAKDOWN-SPAN', span.tagName);
+ this.addHTMLOutput(span);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table.html b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table.html
index 107849c0b01..1d9bcc5dd45 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table.html
@@ -8,16 +8,19 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
-<polymer-element name="tr-v-ui-diagnostic-map-table">
+<dom-module id="tr-v-ui-diagnostic-map-table">
<template>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
+
<script>
'use strict';
Polymer({
- ready: function() {
- this.titledDiagnosticMaps_ = undefined;
+ is: 'tr-v-ui-diagnostic-map-table',
+
+ created: function() {
+ this.diagnosticMaps_ = undefined;
},
/**
@@ -28,63 +31,44 @@ found in the LICENSE file.
* @param {!string} maps[].title
* @param {!tr.v.d.DiagnosticMap} maps[].diagnosticMap
*/
- set titledDiagnosticMaps(maps) {
- this.titledDiagnosticMaps_ = maps;
- this.updateContent_();
+ set diagnosticMaps(maps) {
+ this.diagnosticMaps_ = maps;
+ this.updateContents_();
},
- updateContent_: function() {
- if (this.titledDiagnosticMaps_ === undefined ||
- this.titledDiagnosticMaps_.length === 0) {
+ updateContents_: function() {
+ if (this.diagnosticMaps_ === undefined ||
+ this.diagnosticMaps_.length === 0) {
this.$.table.tableRows = [];
this.$.table.tableColumns = [];
return;
}
- var columns = [{
- title: 'Name',
-
- value: function(row) {
- return row.name;
- },
-
- cmp: function(a, b) {
- return a.name.localeCompare(b.name);
- }
- }];
-
- var rowNames = {};
- var rows = [];
+ var columnTitles = new Set();
+ for (var map of this.diagnosticMaps_)
+ for (var [name, diagnostic] of map)
+ columnTitles.add(name);
- this.titledDiagnosticMaps_.forEach(function(titledMap) {
- var title = titledMap.title;
- var diagnosticMap = titledMap.diagnosticMap;
-
- columns.push({
+ var columns = [];
+ function makeColumn(title) {
+ return {
title: title,
-
- value: function(row) {
- var diagnostic = diagnosticMap.get(row.name);
- if (diagnostic === undefined)
+ value: function(map) {
+ var diagnostic = map.get(title);
+ if (!diagnostic)
return '';
return tr.v.ui.createDiagnosticSpan(diagnostic);
}
- });
-
- diagnosticMap.forEach(function(name, diagnostic) {
- if (rowNames[name] !== true) {
- rowNames[name] = true;
- rows.push({name: name});
- }
- });
- }, this);
+ };
+ }
+ for (var title of columnTitles)
+ columns.push(makeColumn(title));
- rows.sort(columns[0].cmp);
this.$.table.tableColumns = columns;
- this.$.table.tableRows = rows;
+ this.$.table.tableRows = this.diagnosticMaps_;
this.$.table.rebuild();
}
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table_test.html
index 31eafe23413..ac051aaeda5 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_map_table_test.html
@@ -14,16 +14,13 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var map0 = new tr.v.d.DiagnosticMap();
- map0.add('genericA', new tr.v.d.Generic({a: 0}));
- map0.add('genericB', new tr.v.d.Generic({b: 0}));
+ map0.set('genericA', new tr.v.d.Generic({a: 0}));
+ map0.set('genericB', new tr.v.d.Generic({b: 0}));
var map1 = new tr.v.d.DiagnosticMap();
- map1.add('genericA', new tr.v.d.Generic({a: 1}));
- map1.add('genericB', new tr.v.d.Generic({b: 1}));
+ map1.set('genericA', new tr.v.d.Generic({a: 1}));
+ map1.set('genericB', new tr.v.d.Generic({b: 1}));
var table = document.createElement('tr-v-ui-diagnostic-map-table');
- table.titledDiagnosticMaps = [
- {title: 'map0', diagnosticMap: map0},
- {title: 'map1', diagnosticMap: map1},
- ];
+ table.diagnosticMaps = [map0, map1];
this.addHTMLOutput(table);
});
});
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_span.html
index 23940f0c0dd..b22c76a3955 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/diagnostic_span.html
@@ -6,13 +6,14 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/base/deep_utils.html">
-<link rel="import" href="/tracing/ui/base/polymer_utils.html">
<link rel="import" href="/tracing/value/diagnostics/diagnostic.html">
+<link rel="import" href="/tracing/value/ui/breakdown_span.html">
<link rel="import" href="/tracing/value/ui/generic_diagnostic_span.html">
<link rel="import" href="/tracing/value/ui/iteration_info_span.html">
<link rel="import" href="/tracing/value/ui/related_event_set_span.html">
<link rel="import" href="/tracing/value/ui/related_value_map_span.html">
<link rel="import" href="/tracing/value/ui/related_value_set_span.html">
+<link rel="import" href="/tracing/value/ui/scalar_diagnostic_span.html">
<script>
'use strict';
@@ -43,7 +44,7 @@ tr.exportTo('tr.v.ui', function() {
var tagName = typeInfo.metadata.elementName;
- if (!tr.ui.b.getPolymerElementNamed(tagName))
+ if (tr.ui.b.isUnknownElementName(tagName))
throw new Error('Element not registered: ' + tagName);
return tagName;
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/generic_diagnostic_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/generic_diagnostic_span.html
index 502cf020362..9ca063312e6 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/generic_diagnostic_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/generic_diagnostic_span.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
-<polymer-element name="tr-v-ui-generic-diagnostic-span">
+<dom-module id="tr-v-ui-generic-diagnostic-span">
<template>
<tr-ui-a-generic-object-view id="generic"></tr-ui-a-generic-object-view>
</template>
@@ -15,6 +15,8 @@ found in the LICENSE file.
<script>
'use strict';
Polymer({
+ is: 'tr-v-ui-generic-diagnostic-span',
+
ready: function() {
this.diagnostic_ = undefined;
},
@@ -38,4 +40,4 @@ found in the LICENSE file.
}
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/generic_table_view.html b/chromium/third_party/catapult/tracing/tracing/value/ui/generic_table_view.html
index f9becaee0e4..f88debafc1b 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/generic_table_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/generic_table_view.html
@@ -11,7 +11,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/value/generic_table.html">
<link rel="import" href="/tracing/value/ui/array_of_numbers_span.html">
-<polymer-element name="tr-v-ui-generic-table-view">
+<dom-module id='tr-v-ui-generic-table-view'>
<template>
<style>
:host {
@@ -24,7 +24,7 @@ found in the LICENSE file.
</style>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
@@ -145,7 +145,9 @@ tr.exportTo('tr.v.ui', function() {
}
};
- Polymer('tr-v-ui-generic-table-view', {
+ Polymer({
+ is: 'tr-v-ui-generic-table-view',
+
created: function() {
this.items_ = undefined;
this.importantColumNames_ = [];
@@ -212,7 +214,7 @@ tr.exportTo('tr.v.ui', function() {
// Set sizes. This is convoluted by the fact that the first
// table column must have fixed size.
var colWidthPercentage;
- if (columns.length == 1)
+ if (columns.length === 1)
colWidthPercentage = '100%';
else
colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%';
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span.html
index 2bc489865c7..31109ff72cf 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span.html
@@ -7,186 +7,293 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/statistics.html">
<link rel="import" href="/tracing/ui/base/bar_chart.html">
-<link rel="import" href="/tracing/value/ui/scalar_span.html">
+<link rel="import" href="/tracing/value/ui/diagnostic_map_table.html">
+<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
+<link rel="import" href="/tracing/value/ui/scalar_map_table.html">
-<polymer-element name="tr-v-ui-histogram-span">
+<dom-module id='tr-v-ui-histogram-span'>
<template>
<style>
- :host {
- display: flex;
- flex-direction: column;
- }
-
- #stats {
- display: flex;
- flex-direction: row;
- flex: 0 0 auto;
- font-weight: bold;
- }
-
- #nnans {
- color: red;
- }
- #table {
- flex: 1 1 auto;
- }
+ #container {
+ display: flex;
+ flex-direction: row;
+ }
+ #chart {
+ flex-grow: 1;
+ }
+ #chart svg {
+ display: block;
+ }
</style>
- <div id="stats">
- <span id="nsamples"></span>&nbsp;samples,&nbsp;
- <span id="hadnans"><span id="nnans"></span> non-numeric samples,&nbsp;
- </span>
- average=<tr-v-ui-scalar-span id="average"></tr-v-ui-scalar-span>
+
+ <div id="container">
+ <div id="chart"></div>
+ <div id="stats_container">
+ <tr-v-ui-scalar-map-table id="stats"></tr-v-ui-scalar-map-table>
+ </div>
</div>
- <div id="container"></div>
+
+ <tr-v-ui-diagnostic-map-table id="histogram_diagnostics"></tr-v-ui-diagnostic-map-table>
+ <tr-v-ui-diagnostic-map-table id="sample_diagnostics"></tr-v-ui-diagnostic-map-table>
</template>
- <script>
- 'use strict';
-
- Polymer({
- created: function() {
- this.histogram_ = undefined;
- this.chart_ = new tr.ui.b.BarChart();
- this.chart_.width = 400;
- this.chart_.height = 200;
- this.mouseDownBin_ = undefined;
- this.brushedBins_ = [];
- this.chart_.addEventListener('item-mousedown',
- this.onMouseDown_.bind(this));
- this.chart_.addEventListener('item-mousemove',
- this.onMouseMove_.bind(this));
- this.chart_.addEventListener('item-mouseup',
- this.onMouseUp_.bind(this));
- },
-
- ready: function() {
- this.$.container.appendChild(this.chart_);
- },
-
- get brushedBins() {
- return this.brushedBins_;
- },
-
- updateBrushedRange_: function(currentX) {
- this.brushedBins_ = [this.histogram_.getBinForValue(currentX)];
- var r = new tr.b.Range();
- r.addValue(this.mouseDownX_);
- r.addValue(currentX);
-
- // Collect bins:
- var centralMin = Number.MAX_VALUE;
- var centralMax = -Number.MAX_VALUE;
- this.histogram_.centralBins.forEach(function(bin) {
- centralMin = Math.min(centralMin, bin.range.min);
- centralMax = Math.max(centralMax, bin.range.max);
- if ((bin.range.max > r.min) &&
- (bin.range.min < r.max) &&
- (this.brushedBins_.indexOf(bin) < 0))
- this.brushedBins_.push(bin);
- }, this);
- if ((this.histogram_.underflowBin.max > r.min) &&
- (this.brushedBins_.indexOf(this.histogram_.underflowBin) < 0)) {
- this.brushedBins_.push(this.histogram_.underflowBin);
- }
- if ((this.histogram_.overflowBin.min < r.max) &&
- (this.brushedBins_.indexOf(this.histogram_.overflowBin) < 0)) {
- this.brushedBins_.push(this.histogram_.overflowBin);
- }
- this.brushedBins_.sort(function(a, b) {
- return a.range.min - b.range.min;
- });
-
- // Prevent Infinity:
- var minBin = this.histogram_.getBinForValue(r.min);
- var maxBin = this.histogram_.getBinForValue(r.max);
- var binWidth = this.histogram_.centralBins[0].range.range;
- r.min = minBin ? Math.max(centralMin - binWidth, minBin.range.min) :
- centralMin - binWidth;
- r.max = maxBin ? Math.min(centralMax + binWidth, maxBin.range.max) :
- centralMax + binWidth;
-
- this.chart_.brushedRange = r;
-
- this.dispatchEvent(new tr.b.Event('brushed-bins-changed'));
- },
-
- onMouseDown_: function(chartEvent) {
- chartEvent.stopPropagation();
- if (!this.histogram_)
- return;
- this.mouseDownX_ = chartEvent.x;
- this.updateBrushedRange_(chartEvent.x);
- },
-
- onMouseMove_: function(chartEvent) {
- chartEvent.stopPropagation();
- if (!this.histogram_)
- return;
- this.updateBrushedRange_(chartEvent.x);
- },
-
- onMouseUp_: function(chartEvent) {
- chartEvent.stopPropagation();
- if (!this.histogram_)
- return;
- this.updateBrushedRange_(chartEvent.x);
- this.mouseDownX_ = undefined;
- },
-
- get histogram() {
- return this.histogram_;
- },
-
- set histogram(histogram) {
- this.histogram_ = histogram;
+</dom-module>
+
+<script>
+'use strict';
+
+var DELTA = String.fromCharCode(916);
+
+var ABS_DELTA_AVG_NAME = 'abs' + DELTA + 'avg';
+
+Polymer({
+ is: 'tr-v-ui-histogram-span',
+
+ created: function() {
+ this.histogram_ = undefined;
+ this.referenceHistogram_ = undefined;
+ this.chart_ = new tr.ui.b.BarChart();
+ this.chart_.width = 300;
+ this.chart_.height = 200;
+ this.chart_.margin.top = 20;
+ this.chart_.margin.bottom = 28;
+ this.chart_.margin.left = 30;
+ this.chart_.margin.right = 30;
+ this.mouseDownBin_ = undefined;
+ this.brushedBins_ = [];
+ this.chart_.addEventListener('item-mousedown',
+ this.onMouseDown_.bind(this));
+ this.chart_.addEventListener('item-mousemove',
+ this.onMouseMove_.bind(this));
+ this.chart_.addEventListener('item-mouseup',
+ this.onMouseUp_.bind(this));
+ this.chart_.hideLegend = true;
+ },
+
+ ready: function() {
+ Polymer.dom(this.$.chart).appendChild(this.chart_);
+ },
+
+ get chartWidth() {
+ return this.chart_.width;
+ },
+
+ set chartWidth(width) {
+ this.chart_.width = width;
+ },
+
+ get chartHeight() {
+ return this.chart_.height;
+ },
+
+ set chartHeight(height) {
+ this.chart_.height = height;
+ },
+
+ get brushedBins() {
+ return this.brushedBins_;
+ },
+
+ updateBrushedRange_: function(currentX) {
+ this.brushedBins_ = [this.histogram_.getBinForValue(currentX)];
+ var r = new tr.b.Range();
+ r.addValue(this.mouseDownX_);
+ r.addValue(currentX);
+
+ // Collect bins:
+ var centralMin = Number.MAX_VALUE;
+ var centralMax = -Number.MAX_VALUE;
+ this.histogram_.centralBins.forEach(function(bin) {
+ centralMin = Math.min(centralMin, bin.range.min);
+ centralMax = Math.max(centralMax, bin.range.max);
+ if ((bin.range.max > r.min) &&
+ (bin.range.min < r.max) &&
+ (this.brushedBins_.indexOf(bin) < 0))
+ this.brushedBins_.push(bin);
+ }, this);
+ if ((this.histogram_.underflowBin.range.max > r.min) &&
+ (this.brushedBins_.indexOf(this.histogram_.underflowBin) < 0)) {
+ this.brushedBins_.push(this.histogram_.underflowBin);
+ }
+ if ((this.histogram_.overflowBin.range.min < r.max) &&
+ (this.brushedBins_.indexOf(this.histogram_.overflowBin) < 0)) {
+ this.brushedBins_.push(this.histogram_.overflowBin);
+ }
+ this.brushedBins_.sort(function(a, b) {
+ return a.range.min - b.range.min;
+ });
+
+ // Prevent Infinity:
+ var minBin = this.histogram_.getBinForValue(r.min);
+ var maxBin = this.histogram_.getBinForValue(r.max);
+ var binWidth = this.histogram_.centralBins[0].range.range;
+ r.min = minBin ? Math.max(centralMin - binWidth, minBin.range.min) :
+ centralMin - binWidth;
+ r.max = maxBin ? Math.min(centralMax + binWidth, maxBin.range.max) :
+ centralMax + binWidth;
+
+ this.chart_.brushedRange = r;
+ },
+
+ onMouseDown_: function(chartEvent) {
+ chartEvent.stopPropagation();
+ if (!this.histogram_)
+ return;
+ this.mouseDownX_ = chartEvent.x;
+ this.updateBrushedRange_(chartEvent.x);
+ },
+
+ onMouseMove_: function(chartEvent) {
+ chartEvent.stopPropagation();
+ if (!this.histogram_)
+ return;
+ this.updateBrushedRange_(chartEvent.x);
+ },
+
+ onMouseUp_: function(chartEvent) {
+ chartEvent.stopPropagation();
+ if (!this.histogram_)
+ return;
+ this.updateBrushedRange_(chartEvent.x);
+ this.updateDiagnostics_(this.brushedBins);
+ this.mouseDownX_ = undefined;
+ },
+
+ updateDiagnostics_: function(bins) {
+ var maps = [];
+ for (var bin of bins)
+ for (var map of bin.diagnosticMaps)
+ maps.push(map);
+
+ if (maps.length === 0) {
+ this.$.sample_diagnostics.style.display = 'none';
+ return;
+ }
+
+ this.$.sample_diagnostics.diagnosticMaps = maps;
+ this.$.sample_diagnostics.style.display = 'block';
+ },
+
+ get histogram() {
+ return this.histogram_;
+ },
+
+ set histogram(histogram) {
+ if (histogram === this.histogram_) {
+ return;
+ }
+ this.histogram_ = histogram;
+ this.updateContents_();
+ },
+
+ get referenceHistogram() {
+ return this.referenceHistogram_;
+ },
+
+ set referenceHistogram(histogram) {
+ if (histogram === this.referenceHistogram_) {
+ return;
+ }
+ this.referenceHistogram_ = histogram;
+ if (this.histogram) {
this.updateContents_();
- },
-
- set isYLogScale(logScale) {
- this.chart_.isYLogScale = logScale;
- },
-
- updateContents_: function() {
- this.$.container.style.display = this.histogram_ ? '' : 'none';
- if (!this.histogram_) {
- this.$.nsamples.textContent = 0;
- this.$.average.setValueAndUnit(undefined, undefined);
- return;
- }
+ }
+ },
+
+ getDeltaScalars_: function(scalarMap) {
+ if (!(this.referenceHistogram instanceof tr.v.Histogram) ||
+ (this.histogram.unit !== this.referenceHistogram.unit) ||
+ (this.histogram.numValues === 0) &&
+ (this.referenceHistogram.numValues === 0)) {
+ return;
+ }
+
+ var absDeltaAvg = this.histogram.average -
+ this.referenceHistogram.average;
+ scalarMap.set(ABS_DELTA_AVG_NAME, new tr.v.ScalarNumeric(
+ this.histogram.unit.correspondingDeltaUnit,
+ absDeltaAvg));
+
+ var suffix = tr.b.Unit.nameSuffixForImprovementDirection(
+ this.histogram.unit.improvementDirection);
+
+ scalarMap.set('%' + DELTA + 'avg', new tr.v.ScalarNumeric(
+ tr.b.Unit.byName['normalizedPercentageDelta' + suffix],
+ absDeltaAvg / this.referenceHistogram.average));
+
+ scalarMap.set('z-score', new tr.v.ScalarNumeric(
+ tr.b.Unit.byName['sigmaDelta' + suffix],
+ absDeltaAvg / this.referenceHistogram.standardDeviation));
+
+ var mwu = tr.b.Statistics.mwu(
+ this.histogram.sampleValues, this.referenceHistogram.sampleValues);
+ scalarMap.set('p-value', new tr.v.ScalarNumeric(
+ tr.b.Unit.byName.unitlessNumber,
+ mwu.p));
+
+ scalarMap.set('U', new tr.v.ScalarNumeric(
+ tr.b.Unit.byName.unitlessNumber,
+ mwu.U));
+
+ if (this.histogram.unit.improvementDirection !==
+ tr.b.ImprovementDirection.DONT_CARE) {
+ this.$.stats.setSignificanceForKey(ABS_DELTA_AVG_NAME, mwu.significance);
+ }
+ },
+
+ set isYLogScale(logScale) {
+ this.chart_.isYLogScale = logScale;
+ },
+
+ updateContents_: function() {
+ this.$.chart.style.display = this.histogram_ ? '' : 'none';
+ this.$.sample_diagnostics.style.display = 'none';
+ this.brushedBins_ = [];
+ if (!this.histogram_)
+ return;
+
+ this.$.container.style.display = '';
+
+ var scalarMap = new Map();
+ this.getDeltaScalars_(scalarMap);
+ for (var [name, scalar] of this.histogram_.statisticsScalars) {
+ scalarMap.set(name, scalar);
+ }
+ this.$.stats.scalarMap = scalarMap;
+
+ this.chart_.xAxisLabel = '#';
+ this.chart_.yAxisLabel = this.histogram.unit.unitString;
+
+ // https://github.com/catapult-project/catapult/issues/2859
+ // TODO(benjhayden) Compute chart_.height more intelligently:
+ // consider number of bins; |set chartHeight| should override this logic
+ // even when called before |set histogram|.
+ this.chart_.height = Math.max(200,
+ this.$.stats.getBoundingClientRect().height);
- this.$.nsamples.textContent = this.histogram_.numValues;
- this.$.average.setValueAndUnit(this.histogram_.average,
- this.histogram_.unit);
- if (this.histogram_.numNans > 0) {
- this.$.hadnans.style.display = '';
- this.$.nnans.textContent = this.histogram_.numNans;
- } else {
- this.$.hadnans.style.display = 'none';
+ var maximumBinValue = tr.b.Statistics.max(
+ this.histogram_.allBins, bin => bin.count);
+ var chartData = [];
+ var binWidth = this.histogram_.centralBins[0].range.range;
+ this.histogram_.allBins.forEach(function(bin) {
+ var x = bin.range.min;
+ if (x === -Number.MAX_VALUE) {
+ if (!bin.count)
+ return;
+ x = bin.range.max - binWidth;
}
+ chartData.push({x: x, y: bin.count});
+ });
+ chartData.sort((x, y) => x.x - y.x);
+ this.chart_.data = chartData;
+ this.chart_.brushedRange = new tr.b.Range();
- var maximumBinValue = tr.b.Statistics.max(this.histogram_.allBins,
- function(bin) {
- return bin.count;
- });
- var chartData = [];
- var binWidth = this.histogram_.centralBins[0].range.range;
- this.histogram_.allBins.forEach(function(bin) {
- var x = bin.range.min;
- if (x === -Number.MAX_VALUE) {
- if (!bin.count)
- return;
- x = bin.range.max - binWidth;
- }
- chartData.push({x: x,
- y: bin.count});
- });
- chartData.sort(function(x, y) {
- return x.x - y.x;
- });
- this.$.container.style.display = chartData.length ? '' : 'none';
- this.chart_.data = chartData;
- this.brushedBins_ = [];
- this.chart_.brushedRange = new tr.b.Range();
+ if (this.histogram_.diagnostics.size > 0) {
+ this.$.histogram_diagnostics.diagnosticMaps = [
+ this.histogram_.diagnostics];
+ this.$.histogram_diagnostics.style.display = 'block';
+ } else {
+ this.$.histogram_diagnostics.style.display = 'none';
}
- });
- </script>
-</polymer-element>
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span_test.html
index ad550b714f9..38942e87614 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_span_test.html
@@ -5,31 +5,29 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+<link rel="import" href="/tracing/value/diagnostics/generic.html">
<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/ui/histogram_span.html">
-<link rel="import" href="/tracing/value/unit.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var DURATION_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 1000),
- 10);
-
test('basic', function() {
- var h = DURATION_NUMERIC_BUILDER.build();
- h.add(-1, 'a');
- h.add(0, 'b');
- h.add(0, 'b');
- h.add(0, 'b');
- h.add(0, 'b');
- h.add(0, 'b');
- h.add(0, 'b');
- h.add(0, 'c');
- h.add(500, 'c');
- h.add(999, 'd');
- h.add(1000, 'd');
+ var h = new tr.v.Histogram('', tr.b.Unit.byName.unitlessNumber);
+ h.addSample(-1, {foo: new tr.v.d.Generic('a')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('b')});
+ h.addSample(0, {foo: new tr.v.d.Generic('c')});
+ h.addSample(500, {foo: new tr.v.d.Generic('c')});
+ h.addSample(999, {foo: new tr.v.d.Generic('d')});
+ h.addSample(1000, {foo: new tr.v.d.Generic('d')});
var span = document.createElement('tr-v-ui-histogram-span');
span.histogram = h;
@@ -43,7 +41,7 @@ tr.b.unittest.testSuite(function() {
});
test('emptyHistogram', function() {
- var h = DURATION_NUMERIC_BUILDER.build();
+ var h = new tr.v.Histogram('', tr.b.Unit.byName.unitlessNumber);
var span = document.createElement('tr-v-ui-histogram-span');
span.histogram = h;
@@ -51,9 +49,10 @@ tr.b.unittest.testSuite(function() {
});
test('nans', function() {
- var h = DURATION_NUMERIC_BUILDER.build();
- h.add(undefined, 'b');
- h.add(NaN, 'c');
+ var h = new tr.v.Histogram('', tr.b.Unit.byName.unitlessNumber);
+ h.addSample(undefined, {foo: new tr.v.d.Generic('b')});
+ h.addSample(NaN, {foo: new tr.v.d.Generic('c')});
+ h.customizeSummaryOptions({nans: true});
var span = document.createElement('tr-v-ui-histogram-span');
span.histogram = h;
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/iteration_info_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/iteration_info_span.html
index c8799005dc2..6b7d52be4b1 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/iteration_info_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/iteration_info_span.html
@@ -7,67 +7,84 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
-<polymer-element name="tr-v-ui-iteration-info-span">
+<dom-module id="tr-v-ui-iteration-info-span">
<template>
<tr-ui-b-table id="table"></tr-ui-b-table>
</template>
+</dom-module>
+<script>
+'use strict';
+Polymer({
+ is: 'tr-v-ui-iteration-info-span',
- <script>
- 'use strict';
- Polymer({
- ready: function() {
- this.diagnostic_ = undefined;
- this.$.table.showHeader = false;
- this.$.table.tableColumns = [
- {
- value: function(row) {
- return row[0];
- },
+ ready: function() {
+ this.diagnostic_ = undefined;
+ this.$.table.showHeader = false;
+ this.$.table.tableColumns = [
+ {
+ value: function(row) {
+ return row[0];
},
- {
- value: function(row) {
- return row[1];
- }
+ },
+ {
+ value: function(row) {
+ return row[1];
}
- ];
- },
-
- get diagnostic() {
- return this.diagnostic_;
- },
-
- set diagnostic(d) {
- this.diagnostic_ = d;
- this.updateContents_();
- },
-
- updateContents_: function() {
- if (this.diagnostic === undefined) {
- this.$.table.tableRows = [];
- return;
}
+ ];
+ },
- var rows = [
- ['benchmark name', this.diagnostic.benchmarkName],
- ['benchmark start', this.diagnostic.benchmarkStart],
- ['url', this.diagnostic.storyUrl],
- ['story', this.diagnostic.storyDisplayName],
- ['storyset repeat', this.diagnostic.storysetRepeatCounter],
- ['story repeat', this.diagnostic.storyRepeatCounter],
- ];
+ get diagnostic() {
+ return this.diagnostic_;
+ },
- if (this.diagnostic.label)
- rows.push(['label', this.diagnostic.label]);
+ set diagnostic(d) {
+ this.diagnostic_ = d;
+ this.updateContents_();
+ },
- if (Object.keys(this.diagnostic.storyGroupingKeys).length > 0) {
- var gov = document.createElement('tr-ui-a-generic-object-view');
- gov.object = this.diagnostic.storyGroupingKeys;
- rows.push(['grouping keys', gov]);
- }
+ updateContents_: function() {
+ if (this.diagnostic === undefined) {
+ this.$.table.tableRows = [];
+ return;
+ }
+
+ var rows = [];
- rows.sort((x, y) => x[0].localeCompare(y[0]));
- this.$.table.tableRows = rows;
+ if (this.diagnostic.osVersion) {
+ rows.push(['OS version', this.diagnostic.osVersion]);
+ }
+ if (this.diagnostic.productVersion) {
+ rows.push(['product version', this.diagnostic.productVersion]);
+ }
+ if (this.diagnostic.benchmarkName) {
+ rows.push(['benchmark name', this.diagnostic.benchmarkName]);
+ }
+ if (this.diagnostic.benchmarkStart) {
+ rows.push(['benchmark start', this.diagnostic.benchmarkStartString]);
+ }
+ if (this.diagnostic.storyUrl) {
+ rows.push(['url', this.diagnostic.storyUrl]);
+ }
+ if (this.diagnostic.storyDisplayName) {
+ rows.push(['story', this.diagnostic.storyDisplayName]);
+ }
+ if (this.diagnostic.storysetRepeatCounter !== undefined) {
+ rows.push(['storyset repeat', this.diagnostic.storysetRepeatCounter]);
+ }
+ if (this.diagnostic.storyRepeatCounter !== undefined) {
+ rows.push(['story repeat', this.diagnostic.storyRepeatCounter]);
+ }
+ if (this.diagnostic.label) {
+ rows.push(['label', this.diagnostic.label]);
+ }
+ if (this.diagnostic.storyGroupingKeys &&
+ (tr.b.dictionaryLength(this.diagnostic.storyGroupingKeys) > 0)) {
+ var gov = document.createElement('tr-ui-a-generic-object-view');
+ gov.object = this.diagnostic.storyGroupingKeys;
+ rows.push(['grouping keys', gov]);
}
- });
- </script>
-</polymer-element>
+ this.$.table.tableRows = rows;
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit.html b/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit.html
index 7e5a94efad1..988845d5f3e 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit.html
@@ -5,22 +5,23 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/base/unit.html">
-<polymer-element name="tr-v-ui-preferred-display-unit">
- <script>
+<script>
'use strict';
Polymer({
+ is: 'tr-v-ui-preferred-display-unit',
+
ready: function() {
this.preferredTimeDisplayMode_ = undefined;
},
attached: function() {
- tr.v.Unit.didPreferredTimeDisplayUnitChange();
+ tr.b.Unit.didPreferredTimeDisplayUnitChange();
},
detached: function() {
- tr.v.Unit.didPreferredTimeDisplayUnitChange();
+ tr.b.Unit.didPreferredTimeDisplayUnitChange();
},
// null means no-preference
@@ -32,9 +33,8 @@ found in the LICENSE file.
if (this.preferredTimeDisplayMode_ === v)
return;
this.preferredTimeDisplayMode_ = v;
- tr.v.Unit.didPreferredTimeDisplayUnitChange();
+ tr.b.Unit.didPreferredTimeDisplayUnitChange();
}
});
- </script>
-</polymer-element>
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit_test.html
index 742783fc17a..8eef8b5fada 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/preferred_display_unit_test.html
@@ -5,7 +5,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/time_display_mode.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
<link rel="import" href="/tracing/value/ui/preferred_display_unit.html">
<script>
@@ -14,7 +14,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var unit = document.createElement('tr-v-ui-preferred-display-unit');
- var ms = tr.v.TimeDisplayModes.ms;
+ var ms = tr.b.TimeDisplayModes.ms;
unit.preferredDisplayUnit = ms;
assert.equal(unit.preferredDisplayUnit, ms);
});
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span.html
index 349547f3b85..dd04ccb7481 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span.html
@@ -5,12 +5,15 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
-<polymer-element name="tr-v-ui-related-event-set-span">
+<dom-module id="tr-v-ui-related-event-set-span">
<script>
'use strict';
Polymer({
+ is: 'tr-v-ui-related-event-set-span',
+
ready: function() {
this.diagnostic_ = undefined;
},
@@ -25,13 +28,19 @@ found in the LICENSE file.
},
updateContents_: function() {
- this.textContent = '';
- var events = this.diagnostic.events;
+ Polymer.dom(this).textContent = '';
+ var events = new tr.model.EventSet([...this.diagnostic]);
var link = document.createElement('tr-ui-a-analysis-link');
- var label = (events.length === 1) ? 'event' : 'events';
- link.setSelectionAndContent(events, events.length + ' ' + label);
- this.appendChild(link);
+ var label = events.length + ' events';
+ if (events.length === 1) {
+ var event = tr.b.getOnlyElement(events);
+ label = event.title + ' ';
+ label += tr.b.Unit.byName.timeDurationInMs.format(
+ event.duration);
+ }
+ link.setSelectionAndContent(events, label);
+ Polymer.dom(this).appendChild(link);
}
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span_test.html
index 97adc4d708c..bbf729f78d7 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_event_set_span_test.html
@@ -26,14 +26,15 @@ tr.b.unittest.testSuite(function() {
tr.c.TestUtils.newModel(function(model) {
var proc = model.getOrCreateProcess(1);
var thread = proc.getOrCreateThread(2);
- var event = tr.c.TestUtils.newSliceEx({start: 0, duration: 1});
+ var event = tr.c.TestUtils.newSliceEx(
+ {title: 'a', start: 0, duration: 1});
thread.sliceGroup.pushSlice(event);
- diagnostic.push(event);
+ diagnostic.add(event);
});
var span = tr.v.ui.createDiagnosticSpan(diagnostic);
assert.strictEqual('TR-V-UI-RELATED-EVENT-SET-SPAN', span.tagName);
this.addHTMLOutput(span);
- assert.strictEqual('1 event', span.textContent);
+ assert.strictEqual('a 1.000 ms', span.textContent);
});
test('instantiate_RelatedEventSet2', function() {
@@ -43,10 +44,10 @@ tr.b.unittest.testSuite(function() {
var thread = proc.getOrCreateThread(2);
var event = tr.c.TestUtils.newSliceEx({start: 0, duration: 1});
thread.sliceGroup.pushSlice(event);
- diagnostic.push(event);
+ diagnostic.add(event);
event = tr.c.TestUtils.newSliceEx({start: 1, duration: 1});
thread.sliceGroup.pushSlice(event);
- diagnostic.push(event);
+ diagnostic.add(event);
});
var span = tr.v.ui.createDiagnosticSpan(diagnostic);
assert.strictEqual('TR-V-UI-RELATED-EVENT-SET-SPAN', span.tagName);
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span.html
index c691c128c07..cfc46c8303d 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span.html
@@ -7,10 +7,12 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
-<polymer-element name="tr-v-ui-related-value-map-span">
+<dom-module id="tr-v-ui-related-value-map-span">
<script>
'use strict';
Polymer({
+ is: 'tr-v-ui-related-value-map-span',
+
ready: function() {
this.diagnostic_ = undefined;
},
@@ -25,14 +27,14 @@ found in the LICENSE file.
},
updateContents_: function() {
- this.textContent = '';
- this.diagnostic.iterItems(function(name, value) {
+ Polymer.dom(this).textContent = '';
+ for (var [name, value] of this.diagnostic) {
var link = document.createElement('tr-ui-a-analysis-link');
link.setSelectionAndContent(value, name);
- this.appendChild(link);
- this.appendChild(document.createElement('br'));
- }, this);
+ Polymer.dom(this).appendChild(link);
+ Polymer.dom(this).appendChild(document.createElement('br'));
+ }
}
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span_test.html
index c63ae6f1134..b57e3e4cbf5 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_map_span_test.html
@@ -6,16 +6,16 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/value/diagnostics/related_value_map.html">
+<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
-<link rel="import" href="/tracing/value/value.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
test('instantiate_RelatedValueMap', function() {
- var aValue = new tr.v.SkipValue('a');
- var bValue = new tr.v.SkipValue('b');
+ var aValue = new tr.v.Histogram('a', tr.b.Unit.byName.unitlessNumber);
+ var bValue = new tr.v.Histogram('b', tr.b.Unit.byName.unitlessNumber);
var diagnostic = new tr.v.d.RelatedValueMap();
diagnostic.set('foo', aValue);
diagnostic.set('bar', bValue);
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span.html
index 2edffb9df05..46417601c41 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span.html
@@ -7,10 +7,12 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
-<polymer-element name="tr-v-ui-related-value-set-span">
+<dom-module id="tr-v-ui-related-value-set-span">
<script>
'use strict';
Polymer({
+ is: 'tr-v-ui-related-value-set-span',
+
ready: function() {
this.diagnostic_ = undefined;
},
@@ -25,14 +27,14 @@ found in the LICENSE file.
},
updateContents_: function() {
- this.textContent = '';
- this.diagnostic.values.forEach(function(value) {
+ Polymer.dom(this).textContent = '';
+ for (var value of this.diagnostic) {
var link = document.createElement('tr-ui-a-analysis-link');
link.setSelectionAndContent(value, value.name);
- this.appendChild(link);
- this.appendChild(document.createElement('br'));
- }, this);
+ Polymer.dom(this).appendChild(link);
+ Polymer.dom(this).appendChild(document.createElement('br'));
+ }
}
});
</script>
-</polymer-element>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span_test.html
index 222dee57af6..05364e4c6c4 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/related_value_set_span_test.html
@@ -5,31 +5,21 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/diagnostics/composition.html">
<link rel="import" href="/tracing/value/diagnostics/related_value_set.html">
+<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
-<link rel="import" href="/tracing/value/value.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
test('instantiate_RelatedValueSet', function() {
- var aValue = new tr.v.SkipValue('a');
- var bValue = new tr.v.SkipValue('b');
+ var aValue = new tr.v.Histogram('a', tr.b.Unit.byName.unitlessNumber);
+ var bValue = new tr.v.Histogram('b', tr.b.Unit.byName.unitlessNumber);
var diagnostic = new tr.v.d.RelatedValueSet([aValue, bValue]);
var span = tr.v.ui.createDiagnosticSpan(diagnostic);
assert.strictEqual('TR-V-UI-RELATED-VALUE-SET-SPAN', span.tagName);
this.addHTMLOutput(span);
});
-
- test('instantiate_Composition', function() {
- var aValue = new tr.v.SkipValue('a');
- var bValue = new tr.v.SkipValue('b');
- var diagnostic = new tr.v.d.Composition([aValue, bValue]);
- var span = tr.v.ui.createDiagnosticSpan(diagnostic);
- assert.strictEqual('TR-V-UI-RELATED-VALUE-SET-SPAN', span.tagName);
- this.addHTMLOutput(span);
- });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller.html
new file mode 100644
index 00000000000..f99a4558be2
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller.html
@@ -0,0 +1,197 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/event.html">
+<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/base/range.html">
+
+<dom-module id='tr-v-ui-scalar-context-controller'>
+ <template></template>
+</dom-module>
+
+<!--
+@fileoverview Polymer element for controlling common context across scalar
+spans. To facilitate multiple separate contexts (e.g. a separate context for
+each table column), each scalar span has to specify which "context group"
+it belongs to:
+
+ +============ some container element (e.g. <div>) ============+
+ | |
+ | <tr-v-ui-scalar-context-controller> |
+ | ^ ^ |
+ | | | |
+ | v v |
+ | .... Context group 1 .... .... Context group 2 .... |
+ | : <tr-v-ui-scalar-span> : : <tr-v-ui-scalar-span> : |
+ | : <tr-v-ui-scalar-span> : : <tr-v-ui-scalar-span> : . . . |
+ | : . . . : : . . . : |
+ | :.......................: :.......................: |
+ +=============================================================+
+
+An element can find its enclosing context controller using the
+getScalarContextControllerForElement(node) defined in this file. Scalar spans
+can push their state to the controller using the following three methods:
+
+ 1. onScalarSpanAdded(contextGroup, span)
+ This method should be called when a span is attached to the DOM tree (or
+ afterwards when added to a context group).
+
+ 2. onScalarSpanRemoved(contextGroup, span)
+ This method should be called when a span is detached from the DOM tree (or
+ beforehand when removed from a context group).
+
+ 3. onScalarSpanUpdated(contextGroup, span)
+ This method should be called when a span's value changes.
+
+Note: If a span wants to change its context group, it should first call
+onScalarSpanRemoved with the old group and then onScalarSpanAdded with the new
+group.
+
+If one or more group contexts are modified (due to one of the three methods
+above), the controller will asynchronously (at the next RAF) update them and
+fire a 'context-updated' event. Scalar spans can listen for this event and
+update their UI accordingly.
+
+The context currently consists of the range of values of the associated spans.
+This allows automatic display of relative sizes using sparklines.
+
+The controller design is based on:
+https://docs.google.com/document/d/16ih8yYK8kF8MMlPnB-5KlyfS_AjjtbyAfi3pkxoZ8xs/edit?usp=sharing
+-->
+<script>
+'use strict';
+
+tr.exportTo('tr.v.ui', function() {
+
+ Polymer({
+ is: 'tr-v-ui-scalar-context-controller',
+
+ created: function() {
+ this.host_ = undefined;
+ this.groupToContext_ = new Map();
+ this.dirtyGroups_ = new Set();
+ },
+
+ attached: function() {
+ if (this.host_) {
+ throw new Error(
+ 'Scalar context controller is already attached to a host');
+ }
+
+ var host = findParentOrHost(this);
+ if (host.__scalarContextController) {
+ throw new Error(
+ 'Multiple scalar context controllers attached to this host');
+ }
+
+ host.__scalarContextController = this;
+ this.host_ = host;
+ },
+
+ detached: function() {
+ if (!this.host_)
+ throw new Error('Scalar context controller is not attached to a host');
+ if (this.host_.__scalarContextController !== this) {
+ throw new Error(
+ 'Scalar context controller is not attached to its host');
+ }
+
+ delete this.host_.__scalarContextController;
+ this.host_ = undefined;
+ },
+
+ getContext: function(group) {
+ return this.groupToContext_.get(group);
+ },
+
+ onScalarSpanAdded: function(group, span) {
+ var context = this.groupToContext_.get(group);
+ if (context === undefined) {
+ context = {
+ spans: new Set(),
+ range: new tr.b.Range()
+ };
+ this.groupToContext_.set(group, context);
+ }
+ if (context.spans.has(span))
+ throw new Error('Scalar span already registered with group: ' + group);
+ context.spans.add(span);
+ this._markGroupDirtyAndScheduleUpdate(group);
+ },
+
+ onScalarSpanRemoved: function(group, span) {
+ var context = this.groupToContext_.get(group);
+ if (!context.spans.has(span))
+ throw new Error('Scalar span not registered with group: ' + group);
+ context.spans.delete(span);
+ this._markGroupDirtyAndScheduleUpdate(group);
+ },
+
+ onScalarSpanUpdated: function(group, span) {
+ var context = this.groupToContext_.get(group);
+ if (!context.spans.has(span))
+ throw new Error('Scalar span not registered with group: ' + group);
+ this._markGroupDirtyAndScheduleUpdate(group);
+ },
+
+ _markGroupDirtyAndScheduleUpdate: function(group) {
+ var alreadyDirty = this.dirtyGroups_.size > 0;
+ this.dirtyGroups_.add(group);
+ if (!alreadyDirty) {
+ tr.b.requestAnimationFrameInThisFrameIfPossible(
+ this.updateContext, this);
+ }
+ },
+
+ updateContext: function() {
+ var groups = this.dirtyGroups_;
+ if (groups.size === 0)
+ return;
+ this.dirtyGroups_ = new Set();
+
+ for (var group of groups)
+ this.updateGroup_(group);
+
+ var event = new tr.b.Event('context-updated');
+ event.groups = groups;
+ this.dispatchEvent(event);
+ },
+
+ updateGroup_: function(group) {
+ var context = this.groupToContext_.get(group);
+ if (context.spans.size === 0) {
+ this.groupToContext_.delete(group);
+ return;
+ }
+ context.range.reset();
+ for (var span of context.spans)
+ context.range.addValue(span.value);
+ }
+ });
+
+ function getScalarContextControllerForElement(element) {
+ while (element) {
+ if (element.__scalarContextController)
+ return element.__scalarContextController;
+ element = findParentOrHost(element);
+ }
+ return undefined;
+ }
+
+ function findParentOrHost(node) {
+ if (node.parentElement)
+ return node.parentElement;
+ while (Polymer.dom(node).parentNode)
+ node = Polymer.dom(node).parentNode;
+ return node.host;
+ }
+
+ return {
+ getScalarContextControllerForElement: getScalarContextControllerForElement
+ };
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller_test.html
new file mode 100644
index 00000000000..dfee8fe6fc9
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_context_controller_test.html
@@ -0,0 +1,311 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/base/iteration_helpers.html">
+<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/value/ui/scalar_context_controller.html">
+
+<dom-module id='tr-v-ui-scalar-context-controller-mock-host'>
+ <template>
+ <tr-v-ui-scalar-context-controller id="controller">
+ </tr-v-ui-scalar-context-controller>
+ <content></content>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var getScalarContextControllerForElement =
+ tr.v.ui.getScalarContextControllerForElement;
+
+ Polymer({
+ is: 'tr-v-ui-scalar-context-controller-mock-host'
+ });
+
+ test('getScalarContextControllerForElement', function() {
+ var root = document.createElement('div');
+ Polymer.dom(document.body).appendChild(root);
+ try {
+ assert.isUndefined(getScalarContextControllerForElement(root));
+
+ // <div> root
+ // |__<div> host1
+ // |__<tr-v-ui-scalar-context-controller> c1
+ var host1 = document.createElement('div');
+ Polymer.dom(root).appendChild(host1);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1));
+ var c1 = document.createElement('tr-v-ui-scalar-context-controller');
+ Polymer.dom(host1).appendChild(c1);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+
+ // <div> root
+ // |__<div> host1
+ // | |__<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // :..<tr-v-ui-scalar-context-controller> c2
+ var host2 = document.createElement(
+ 'tr-v-ui-scalar-context-controller-mock-host');
+ var c2 = host2.$.controller;
+ Polymer.dom(root).appendChild(host2);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.strictEqual(getScalarContextControllerForElement(host2), c2);
+
+ // <div> root
+ // |__<div> host1
+ // | |__<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // | :..<tr-v-ui-scalar-context-controller> c2
+ // |__<div> divA
+ // |__<div> divB
+ var divA = document.createElement('div');
+ Polymer.dom(host2).appendChild(divA);
+ assert.strictEqual(getScalarContextControllerForElement(divA), c2);
+ var divB = document.createElement('div');
+ Polymer.dom(divA).appendChild(divB);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c2);
+
+ // <div> root
+ // |__<div> host1
+ // | |_<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // | :.-<tr-v-ui-scalar-context-controller> c2
+ // |__<div> divA
+ // |__<div> divB
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host3
+ // :..<tr-v-ui-scalar-context-controller> c3
+ var host3 = document.createElement(
+ 'tr-v-ui-scalar-context-controller-mock-host');
+ Polymer.dom(divB).appendChild(host3);
+ var c3 = host3.$.controller;
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.strictEqual(getScalarContextControllerForElement(host2), c2);
+ assert.strictEqual(getScalarContextControllerForElement(divA), c2);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c2);
+ assert.strictEqual(getScalarContextControllerForElement(host3), c3);
+
+ // <div> root
+ // |__<div> host1
+ // | |_<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // | :.-<tr-v-ui-scalar-context-controller> c2
+ // |__<div> divA
+ // | :.<tr-v-ui-scalar-context-controller> c4
+ // |__<div> divB
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host3
+ // :..<tr-v-ui-scalar-context-controller> c3
+ var c4 = document.createElement('tr-v-ui-scalar-context-controller');
+ Polymer.dom(divA).appendChild(c4);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.strictEqual(getScalarContextControllerForElement(host2), c2);
+ assert.strictEqual(getScalarContextControllerForElement(divA), c4);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c4);
+ assert.strictEqual(getScalarContextControllerForElement(host3), c3);
+
+ // <div> root
+ // |__<div> host1
+ // | |_<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // | :.-<tr-v-ui-scalar-context-controller> c2
+ // |__<div> divA
+ // | :.<tr-v-ui-scalar-context-controller> c4
+ // |__<div> divB
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host3
+ Polymer.dom(host3.root).removeChild(c3);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.strictEqual(getScalarContextControllerForElement(host2), c2);
+ assert.strictEqual(getScalarContextControllerForElement(divA), c4);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c4);
+ assert.strictEqual(getScalarContextControllerForElement(host3), c4);
+
+ // <div> root
+ // |__<div> host1
+ // | |_<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // |__<div> divA
+ // | :.<tr-v-ui-scalar-context-controller> c4
+ // |__<div> divB
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host3
+ Polymer.dom(host2.root).removeChild(c2);
+ assert.isUndefined(getScalarContextControllerForElement(root));
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.isUndefined(getScalarContextControllerForElement(host2));
+ assert.strictEqual(getScalarContextControllerForElement(divA), c4);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c4);
+ assert.strictEqual(getScalarContextControllerForElement(host3), c4);
+
+ // <div> root
+ // | :.<tr-v-ui-scalar-context-controller> c3
+ // |__<div> host1
+ // | |_<tr-v-ui-scalar-context-controller> c1
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host2
+ // |__<div> divA
+ // | :.<tr-v-ui-scalar-context-controller> c4
+ // |__<div> divB
+ // |__<tr-v-ui-scalar-context-controller-mock-host> host3
+ Polymer.dom(root).appendChild(c3);
+ assert.strictEqual(getScalarContextControllerForElement(root), c3);
+ assert.strictEqual(getScalarContextControllerForElement(host1), c1);
+ assert.strictEqual(getScalarContextControllerForElement(host2), c3);
+ assert.strictEqual(getScalarContextControllerForElement(divA), c4);
+ assert.strictEqual(getScalarContextControllerForElement(divB), c4);
+ assert.strictEqual(getScalarContextControllerForElement(host3), c4);
+ } finally {
+ Polymer.dom(document.body).removeChild(root);
+ }
+ });
+
+ function contextTest(name, testCallback) {
+ test('context_' + name, function() {
+ var root = document.createElement('div');
+ Polymer.dom(document.body).appendChild(root);
+ try {
+ var c = document.createElement('tr-v-ui-scalar-context-controller');
+ Polymer.dom(root).appendChild(c);
+
+ var updatedGroups = []; // Fail if event fires unexpectedly.
+ c.addEventListener('context-updated', function(e) {
+ if (updatedGroups)
+ assert.fail('Unexpected context-updated event fired.');
+ updatedGroups = tr.b.asArray(e.groups);
+ });
+
+ c.expectContextUpdatedEventForTesting =
+ function(expectedUpdatedGroups) {
+ updatedGroups = undefined;
+ tr.b.forceAllPendingTasksToRunForTest();
+ assert.sameMembers(updatedGroups, expectedUpdatedGroups);
+ };
+
+ testCallback.call(this, c);
+ } finally {
+ Polymer.dom(document.body).removeChild(root);
+ }
+ });
+ }
+
+ contextTest('singleGroup', function(c) {
+ assert.isUndefined(c.getContext('G'));
+
+ var s1 = {value: 10};
+ c.onScalarSpanAdded('G', s1);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(10, 10)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s1]);
+
+ var s2 = {value: 15};
+ c.onScalarSpanAdded('G', s2);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(10, 15)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s1, s2]);
+
+ s1.value = 5;
+ c.onScalarSpanUpdated('G', s1);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(5, 15)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s1, s2]);
+
+ c.onScalarSpanRemoved('G', s2);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(5, 5)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s1]);
+
+ var s3 = {value: 0};
+ c.onScalarSpanAdded('G', s3);
+ s2.value = 14;
+ c.onScalarSpanAdded('G', s2);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(0, 14)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s1, s2, s3]);
+
+ c.onScalarSpanRemoved('G', s1);
+ c.onScalarSpanRemoved('G', s2);
+ c.onScalarSpanRemoved('G', s3);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isUndefined(c.getContext('G'));
+
+ c.onScalarSpanAdded('G', s2);
+ c.expectContextUpdatedEventForTesting(['G']);
+ assert.isTrue(c.getContext('G').range.equals(
+ tr.b.Range.fromExplicitRange(14, 14)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G').spans), [s2]);
+ });
+
+ contextTest('multipleGroups', function(c) {
+ assert.isUndefined(c.getContext('G1'));
+ assert.isUndefined(c.getContext('G2'));
+
+ var s1 = {value: 0};
+ c.onScalarSpanAdded('G1', s1);
+ c.expectContextUpdatedEventForTesting(['G1']);
+ assert.isTrue(c.getContext('G1').range.equals(
+ tr.b.Range.fromExplicitRange(0, 0)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G1').spans), [s1]);
+
+ var s2 = {value: 1};
+ c.onScalarSpanAdded('G2', s2);
+ c.expectContextUpdatedEventForTesting(['G2']);
+ assert.isTrue(c.getContext('G2').range.equals(
+ tr.b.Range.fromExplicitRange(1, 1)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G2').spans), [s2]);
+
+ var s3 = {value: 2};
+ var s4 = {value: -1};
+ c.onScalarSpanAdded('G2', s3);
+ c.onScalarSpanAdded('G1', s4);
+ c.expectContextUpdatedEventForTesting(['G1', 'G2']);
+ assert.isTrue(c.getContext('G1').range.equals(
+ tr.b.Range.fromExplicitRange(-1, 0)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G1').spans), [s1, s4]);
+ assert.isTrue(c.getContext('G2').range.equals(
+ tr.b.Range.fromExplicitRange(1, 2)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G2').spans), [s2, s3]);
+
+ c.onScalarSpanRemoved('G2', s3);
+ c.onScalarSpanAdded('G1', s3);
+ c.expectContextUpdatedEventForTesting(['G1', 'G2']);
+ assert.isTrue(c.getContext('G1').range.equals(
+ tr.b.Range.fromExplicitRange(-1, 2)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G1').spans), [s1, s3, s4]);
+ assert.isTrue(c.getContext('G2').range.equals(
+ tr.b.Range.fromExplicitRange(1, 1)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G2').spans), [s2]);
+
+ s4.value = 3;
+ c.onScalarSpanUpdated('G1', s4);
+ s1.value = 1;
+ c.onScalarSpanUpdated('G1', s1);
+ c.expectContextUpdatedEventForTesting(['G1']);
+ assert.isTrue(c.getContext('G1').range.equals(
+ tr.b.Range.fromExplicitRange(1, 3)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G1').spans), [s1, s3, s4]);
+ assert.isTrue(c.getContext('G2').range.equals(
+ tr.b.Range.fromExplicitRange(1, 1)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G2').spans), [s2]);
+
+ c.onScalarSpanRemoved('G2', s2);
+ c.expectContextUpdatedEventForTesting(['G2']);
+ assert.isTrue(c.getContext('G1').range.equals(
+ tr.b.Range.fromExplicitRange(1, 3)));
+ assert.sameMembers(tr.b.asArray(c.getContext('G1').spans), [s1, s3, s4]);
+ assert.isUndefined(c.getContext('G2'));
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span.html
new file mode 100644
index 00000000000..e178d38276a
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/ui/scalar_span.html">
+
+<dom-module id="tr-v-ui-scalar-diagnostic-span">
+ <template>
+ <tr-v-ui-scalar-span id="scalar"></tr-v-ui-scalar-span>
+ </template>
+
+ <script>
+ 'use strict';
+ Polymer({
+ is: 'tr-v-ui-scalar-diagnostic-span',
+
+ ready: function() {
+ this.diagnostic_ = undefined;
+ },
+
+ get diagnostic() {
+ return this.diagnostic_;
+ },
+
+ set diagnostic(d) {
+ this.diagnostic_ = d;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ this.$.scalar.setValueAndUnit(this.diagnostic.value.value,
+ this.diagnostic.value.unit);
+ }
+ });
+ </script>
+</dom-module>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span_test.html
new file mode 100644
index 00000000000..69b055fcb92
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_diagnostic_span_test.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/diagnostics/scalar.html">
+<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('instantiate', function() {
+ var diagnostic = new tr.v.d.Scalar(new tr.v.ScalarNumeric(
+ tr.b.Unit.byName.timeDurationInMs, 123.456));
+ var span = tr.v.ui.createDiagnosticSpan(diagnostic);
+ assert.strictEqual('TR-V-UI-SCALAR-DIAGNOSTIC-SPAN', span.tagName);
+ this.addHTMLOutput(span);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table.html
new file mode 100644
index 00000000000..f303cb781dc
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/value/ui/scalar_span.html">
+
+<dom-module name="tr-v-ui-scalar-map-table">
+ <template>
+ <style>
+ </style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</dom-module>
+
+<script>
+'use strict';
+Polymer({
+ is: 'tr-v-ui-scalar-map-table',
+
+ created: function() {
+ /** @type {!Map.<string, !tr.v.ScalarNumeric>} */
+ this.scalarMap_ = new Map();
+
+ /** @type {!Map.<string, !tr.b.Statistics.Significance>} */
+ this.significance_ = new Map();
+ },
+
+ ready: function() {
+ this.$.table.showHeader = false;
+ this.$.table.tableColumns = [
+ {
+ value: function(row) {
+ return row.name;
+ }
+ },
+ {
+ align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT,
+ value: function(row) {
+ var span = tr.v.ui.createScalarSpan(row.value);
+ if (row.significance !== undefined) {
+ span.significance = row.significance;
+ } else if (row.anyRowsHaveSignificance) {
+ // Ensure vertical alignment.
+ span.style.marginRight = '14px';
+ }
+ span.style.whiteSpace = 'nowrap';
+ return span;
+ }
+ }
+ ];
+ },
+
+ get scalarMap() {
+ return this.scalarMap_;
+ },
+
+ /**
+ * @param {!Map.<string,!tr.v.ScalarNumeric>} map
+ */
+ set scalarMap(map) {
+ this.scalarMap_ = map;
+ this.updateContents_();
+ },
+
+ /**
+ * @param {string} key
+ * @param {!tr.b.Statistics.Significance} significance
+ */
+ setSignificanceForKey: function(key, significance) {
+ this.significance_.set(key, significance);
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var rows = [];
+ for (var [key, scalar] of this.scalarMap) {
+ rows.push({
+ name: key,
+ value: scalar,
+ significance: this.significance_.get(key),
+ anyRowsHaveSignificance: (this.significance_.size > 0)
+ });
+ }
+ this.$.table.tableRows = rows;
+ this.$.table.rebuild();
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table_test.html
new file mode 100644
index 00000000000..f43bbb9fd20
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_map_table_test.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/ui/scalar_map_table.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('instantiate', function() {
+ var span = document.createElement('tr-v-ui-scalar-map-table');
+
+ var histogram = new tr.v.Histogram('', tr.b.Unit.byName.energyInJoules);
+ for (var i = 0; i < 1e2; ++i) {
+ histogram.addSample(Math.random() * 1000);
+ }
+
+ histogram.addSample('foo');
+ histogram.customizeSummaryOptions({nans: true});
+
+ span.scalarMap = histogram.statisticsScalars;
+ this.addHTMLOutput(span);
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span.html
index 7588ee50d48..1ab5e864294 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span.html
@@ -5,18 +5,23 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/ui/base/deep_utils.html">
-<link rel="import" href="/tracing/ui/base/polymer_utils.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/ui/scalar_context_controller.html">
<script>
'use strict';
tr.exportTo('tr.v.ui', function() {
/**
- * @param {undefined|tr.v.NumericValue|tr.v.Numeric} value
+ * @param {undefined|tr.v.ScalarNumeric|tr.v.Histogram} value
* @param {Object=} opt_config
- * @return {string|Element}
+ * @param {!tr.b.Range=} opt_config.customContextRange
+ * @param {boolean=} opt_config.rightAlign
+ * @param {!tr.b.Unit=} opt_config.unit
+ * @param {tr.b.Statistics.Significance=} opt_config.significance
+ * @param {string=} opt_config.contextGroup
+ * @return {(string|!HTMLElement)}
*/
function createScalarSpan(value, opt_config) {
if (value === undefined)
@@ -27,17 +32,14 @@ tr.exportTo('tr.v.ui', function() {
var span = ownerDocument.createElement('tr-v-ui-scalar-span');
- if (value instanceof tr.v.NumericValue) {
- value = value.numeric;
- config.unit = value.unit;
- }
-
var numericValue;
if (value instanceof tr.v.ScalarNumeric) {
span.value = value;
numericValue = value.value;
- } else if (value instanceof tr.v.Numeric) {
+ } else if (value instanceof tr.v.Histogram) {
numericValue = value.average;
+ if (numericValue === undefined)
+ return '';
span.setValueAndUnit(numericValue, value.unit);
} else {
var unit = config.unit;
@@ -52,212 +54,533 @@ tr.exportTo('tr.v.ui', function() {
if (config.context)
span.context = config.context;
- if (config.total)
- span.percentage = numericValue / config.total;
+ if (config.customContextRange)
+ span.customContextRange = config.customContextRange;
if (config.rightAlign)
span.rightAlign = true;
+ if (config.significance !== undefined)
+ span.significance = config.significance;
+
+ if (config.contextGroup !== undefined)
+ span.contextGroup = config.contextGroup;
+
return span;
}
- tr.v.Unit.addEventListener('display-mode-changed', function(e) {
- var scalarSpanTagName = 'tr-v-ui-scalar-span';
- var subclassNames = tr.ui.b.getPolymerElementsThatSubclass(
- scalarSpanTagName);
- subclassNames.push(scalarSpanTagName);
- var isSubclass = {};
- subclassNames.forEach(function(n) {
- isSubclass[n.toUpperCase()] = true;
- });
-
- var m = tr.b.findDeepElementsMatchingPredicate(
- document.body,
- function(el) {
- return isSubclass[el.tagName];
- });
- m.forEach(function(el) {
- el.updateContent_();
- });
- });
-
return {
createScalarSpan: createScalarSpan
};
});
</script>
-<polymer-element name="tr-v-ui-scalar-span">
+<dom-module id='tr-v-ui-scalar-span'>
<template>
<style>
:host {
display: block;
position: relative;
+ /* Limit the sparkline's negative z-index to the span only. */
+ isolation: isolate;
}
- #content.right-align {
- text-align: right;
- position: relative;
- display: block;
- }
+
#sparkline {
width: 0%;
position: absolute;
bottom: 0;
- right: 0;
display: none;
height: 100%;
background-color: hsla(216, 100%, 94.5%, .75);
- border-left: 1px solid hsl(216, 100%, 89%);
+ border-color: hsl(216, 100%, 89%);
box-sizing: border-box;
+ z-index: -1;
+ }
+ #sparkline.positive {
+ border-right-style: solid;
+ /* The border width must be kept in sync with buildSparklineStyle_(). */
+ border-right-width: 1px;
+ }
+ #sparkline:not(.positive) {
+ border-left-style: solid;
+ /* The border width must be kept in sync with buildSparklineStyle_(). */
+ border-left-width: 1px;
+ }
+ #sparkline.better {
+ background-color: hsla(115, 100%, 93%, .75);
+ border-color: hsl(118, 60%, 80%);
+ }
+ #sparkline.worse {
+ background-color: hsla(0, 100%, 88%, .75);
+ border-color: hsl(0, 100%, 80%);
+ }
+
+ #content.right-align {
+ text-align: right;
+ position: relative;
+ display: block;
}
+ #content.better {
+ color: green;
+ }
+ #content.worse {
+ color: red;
+ }
+
+ #significance svg {
+ display: none;
+ height: 1em;
+ vertical-align: text-top;
+ stroke-width: 4;
+ fill: rgba(0, 0, 0, 0);
+ }
+ #significance #insignificant {
+ stroke: black;
+ }
+ #significance #significantly_better {
+ stroke: green;
+ }
+ #significance #significantly_worse {
+ stroke: red;
+ }
+
#warning {
+ display: none;
margin-left: 4px;
- font-size: 66%;
+ height: 1em;
+ vertical-align: text-top;
+ stroke-width: 0;
+ }
+ #warning path {
+ fill: rgb(255, 185, 185);
+ }
+ #warning rect {
+ fill: red;
}
</style>
+
<span id="sparkline"></span>
+
<span id="content"></span>
- <span id="warning" style="display:none">&#9888;</span>
+
+ <span id="significance">
+ <!-- Neutral face -->
+ <svg viewbox="0 0 128 128" id="insignificant">
+ <circle r="60" cx="64" cy="64"/>
+ <circle r="4" cx="44" cy="44"/>
+ <circle r="4" cx="84" cy="44"/>
+ <line x1="36" x2="92" y1="80" y2="80"/>
+ </svg>
+
+ <!-- Smiling face -->
+ <svg viewbox="0 0 128 128" id="significantly_better">
+ <circle r="60" cx="64" cy="64"/>
+ <circle r="4" cx="44" cy="44"/>
+ <circle r="4" cx="84" cy="44"/>
+ <path d="M 28 64 Q 64 128 100 64"/>
+ </svg>
+
+ <!-- Frowning face -->
+ <svg viewbox="0 0 128 128" id="significantly_worse">
+ <circle r="60" cx="64" cy="64"/>
+ <circle r="4" cx="44" cy="44"/>
+ <circle r="4" cx="84" cy="44"/>
+ <path d="M 36 96 Q 64 48 92 96"/>
+ </svg>
+ </span>
+
+ <svg viewbox="0 0 128 128" id="warning">
+ <path d="M 64 0 L 128 128 L 0 128 L 64 0"/>
+ <rect x="60" width="8" y="0" height="84"/>
+ <rect x="60" width="8" y="100" height="24"/>
+ </svg>
</template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.value_ = undefined;
- this.unit_ = undefined;
- this.context_ = undefined;
-
- this.warning_ = undefined;
- this.percentage_ = undefined;
- },
-
- set contentTextDecoration(deco) {
- this.$.content.style.textDecoration = deco;
- },
-
- get value() {
- return this.value_;
- },
-
- set value(value) {
- if (value instanceof tr.v.ScalarNumeric) {
- this.value_ = value.value;
- this.unit_ = value.unit;
- } else {
- this.value_ = value;
- }
- this.updateContent_();
- },
+</dom-module>
+<script>
+'use strict';
- get unit() {
- return this.unit_;
- },
+Polymer({
+ is: 'tr-v-ui-scalar-span',
+
+ properties: {
+ /**
+ * String identifier for grouping scalar spans with common context (e.g.
+ * all scalar spans in a single table column would typically share a common
+ * context and, thus, have the same context group identifier). If falsy,
+ * the scalar span will NOT be associated with any context.
+ */
+ contextGroup: {
+ type: String,
+ reflectToAttribute: true,
+ observer: 'contextGroupChanged_'
+ }
+ },
- set unit(unit) {
- this.unit_ = unit;
- this.updateContent_();
- },
+ created: function() {
+ this.value_ = undefined;
+ this.unit_ = undefined;
- get context() {
- return this.context_;
- },
+ // TODO(petrcermak): Merge this into the context controller.
+ this.context_ = undefined;
- set context(context) {
- this.context_ = context;
- this.updateContent_();
- },
+ this.warning_ = undefined;
+ this.significance_ = tr.b.Statistics.Significance.DONT_CARE;
- setValueAndUnit: function(value, unit) {
- this.value_ = value;
- this.unit_ = unit;
- this.updateContent_();
- },
+ // To avoid unnecessary DOM traversal, search for the context controller
+ // only when necessary (when the span is attached and has a context group).
+ this.shouldSearchForContextController_ = false;
+ this.lazyContextController_ = undefined;
+ this.onContextUpdated_ = this.onContextUpdated_.bind(this);
- get percentage() {
- return this.percentage_;
- },
+ // The span can specify a custom context range, which will override the
+ // values from the context controller.
+ this.customContextRange_ = undefined;
+ },
- set percentage(percentage) {
- this.percentage_ = percentage;
+ get significance() {
+ return this.significance_;
+ },
+
+ set significance(s) {
+ this.significance_ = s;
+ this.updateContents_();
+ },
+
+ set contentTextDecoration(deco) {
+ this.$.content.style.textDecoration = deco;
+ },
+
+ get value() {
+ return this.value_;
+ },
+
+ set value(value) {
+ if (value instanceof tr.v.ScalarNumeric) {
+ this.value_ = value.value;
+ this.unit_ = value.unit;
+ } else {
+ this.value_ = value;
+ }
+ this.updateContents_();
+ if (this.hasContext_(this.contextGroup))
+ this.contextController_.onScalarSpanUpdated(this.contextGroup, this);
+ else
this.updateSparkline_();
- },
-
- get rightAlign() {
- return this.$.content.classList.contains('right-align');
- },
-
- set rightAlign(rightAlign) {
- if (rightAlign)
- this.$.content.classList.add('right-align');
- else
- this.$.content.classList.remove('right-align');
- },
-
- updateSparkline_: function() {
- if (this.percentage_ === undefined) {
- this.$.sparkline.style.display = 'none';
- this.$.sparkline.style.width = '0';
- } else {
- this.$.sparkline.style.display = 'block';
- this.$.sparkline.style.width = (this.percentage_ * 100) + '%';
- }
- },
+ },
- updateContent_: function() {
- if (this.unit_ === undefined) {
- this.$.content.textContent = '';
- this.$.content.style.color = '';
- return;
- }
+ get contextController_() {
+ if (this.shouldSearchForContextController_) {
+ this.lazyContextController_ =
+ tr.v.ui.getScalarContextControllerForElement(this);
+ this.shouldSearchForContextController_ = false;
+ }
+ return this.lazyContextController_;
+ },
+
+ hasContext_: function(contextGroup) {
+ // The ordering here is important. It ensures that we avoid a DOM traversal
+ // when the span doesn't have a context group.
+ return !!(contextGroup && this.contextController_);
+ },
+
+ contextGroupChanged_: function(newContextGroup, oldContextGroup) {
+ this.detachFromContextControllerIfPossible_(oldContextGroup);
+ if (!this.attachToContextControllerIfPossible_(newContextGroup)) {
+ // If the span failed to attach to a controller, it won't receive a
+ // context-updated event, so we trigger it manually.
+ this.onContextUpdated_();
+ }
+ },
+
+ attachToContextControllerIfPossible_: function(contextGroup) {
+ if (!this.hasContext_(contextGroup))
+ return false;
+ this.contextController_.addEventListener(
+ 'context-updated', this.onContextUpdated_);
+ this.contextController_.onScalarSpanAdded(contextGroup, this);
+ return true;
+ },
+
+ detachFromContextControllerIfPossible_: function(contextGroup) {
+ if (!this.hasContext_(contextGroup))
+ return;
+ this.contextController_.removeEventListener(
+ 'context-updated', this.onContextUpdated_);
+ this.contextController_.onScalarSpanRemoved(contextGroup, this);
+ },
+
+ attached: function() {
+ tr.b.Unit.addEventListener(
+ 'display-mode-changed', this.updateContents_.bind(this));
+ this.shouldSearchForContextController_ = true;
+ this.attachToContextControllerIfPossible_(this.contextGroup);
+ },
+
+ detached: function() {
+ tr.b.Unit.removeEventListener(
+ 'display-mode-changed', this.updateContents_.bind(this));
+ this.detachFromContextControllerIfPossible_(this.contextGroup);
+ this.shouldSearchForContextController_ = false;
+ this.lazyContextController_ = undefined;
+ },
+
+ onContextUpdated_: function() {
+ this.updateSparkline_();
+ },
+
+ get context() {
+ return this.context_;
+ },
+
+ set context(context) {
+ this.context_ = context;
+ this.updateContents_();
+ },
+
+ get unit() {
+ return this.unit_;
+ },
+
+ set unit(unit) {
+ this.unit_ = unit;
+ this.updateContents_();
+ this.updateSparkline_();
+ },
+
+ setValueAndUnit: function(value, unit) {
+ this.value_ = value;
+ this.unit_ = unit;
+ this.updateContents_();
+ },
+
+ get customContextRange() {
+ return this.customContextRange_;
+ },
+
+ set customContextRange(customContextRange) {
+ this.customContextRange_ = customContextRange;
+ this.updateSparkline_();
+ },
+
+ get rightAlign() {
+ return Polymer.dom(this.$.content).classList.contains('right-align');
+ },
+
+ set rightAlign(rightAlign) {
+ if (rightAlign)
+ Polymer.dom(this.$.content).classList.add('right-align');
+ else
+ Polymer.dom(this.$.content).classList.remove('right-align');
+ },
+
+ updateSparkline_: function() {
+ Polymer.dom(this.$.sparkline).classList.remove('positive');
+ Polymer.dom(this.$.sparkline).classList.remove('better');
+ Polymer.dom(this.$.sparkline).classList.remove('worse');
+ Polymer.dom(this.$.sparkline).classList.remove('same');
+ this.$.sparkline.style.display = 'none';
+ this.$.sparkline.style.left = '0';
+ this.$.sparkline.style.width = '0';
+
+ // Custom context range takes precedence over controller context range.
+ var range = this.customContextRange_;
+ if (!range && this.hasContext_(this.contextGroup)) {
+ var context = this.contextController_.getContext(this.contextGroup);
+ if (context)
+ range = context.range;
+ }
+ if (!range || range.isEmpty)
+ return;
+
+ var leftPoint = Math.min(range.min, 0);
+ var rightPoint = Math.max(range.max, 0);
+ var pointDistance = rightPoint - leftPoint;
+ if (pointDistance === 0) {
+ // This can happen, for example, when all spans within the context have
+ // zero values (so |range| is [0, 0]).
+ return;
+ }
- this.$.content.textContent = this.unit_.format(this.value, this.context);
-
- var BIGGER_IS_BETTER = tr.v.ImprovementDirection.BIGGER_IS_BETTER;
- var SMALLER_IS_BETTER = tr.v.ImprovementDirection.SMALLER_IS_BETTER;
- var color = '';
- if (this.unit_.isDelta) {
- var improvementDirection = this.unit_.improvementDirection;
- if (this.value > 0) {
- // Positive delta.
- switch (improvementDirection) {
- case BIGGER_IS_BETTER:
- color = 'green';
- break;
- case SMALLER_IS_BETTER:
- color = 'red';
- break;
- }
- } else if (this.value < 0) {
- // Negative delta.
- switch (improvementDirection) {
- case BIGGER_IS_BETTER:
- color = 'red';
- break;
- case SMALLER_IS_BETTER:
- color = 'green';
- break;
- }
- }
- }
- this.$.content.style.color = color;
- },
-
- get warning() {
- return this.warning_;
- },
-
- set warning(warning) {
- this.warning_ = warning;
- var warningEl = this.$.warning;
- if (this.warning_) {
- warningEl.title = warning;
- warningEl.style.display = '';
- } else {
- warningEl.title = '';
- warningEl.style.display = 'none';
- }
+ // Draw the sparkline.
+ this.$.sparkline.style.display = 'block';
+ var left, width;
+ if (this.value > 0) {
+ width = Math.min(this.value, rightPoint);
+ left = -leftPoint;
+ Polymer.dom(this.$.sparkline).classList.add('positive');
+ } else if (this.value <= 0) {
+ width = -Math.max(this.value, leftPoint);
+ left = (-leftPoint) - width;
}
- });
- </script>
-</polymer-element>
+ this.$.sparkline.style.left = this.buildSparklineStyle_(
+ left / pointDistance, false);
+ this.$.sparkline.style.width = this.buildSparklineStyle_(
+ width / pointDistance, true);
+
+ // Set the sparkline color (if applicable).
+ var changeClass = this.changeClassName_;
+ if (changeClass)
+ Polymer.dom(this.$.sparkline).classList.add(changeClass);
+ },
+
+ buildSparklineStyle_: function(ratio, isWidth) {
+ // To avoid visual glitches around the zero value bar, we subtract 1 pixel
+ // from the width of the element and multiply the remainder (100% - 1px) by
+ // |ratio|. The extra pixel is used for the sparkline border. This allows
+ // us to align zero sparklines with both positive and negative values:
+ //
+ // ::::::::::| +10 MiB
+ // :::::| +5 MiB
+ // | 0 MiB
+ // |::::: -5 MiB
+ // |:::::::::: -10 MiB
+ //
+ var position = 'calc(' + ratio + ' * (100% - 1px)';
+ if (isWidth)
+ position += ' + 1px'; // Extra pixel for sparkline border.
+ position += ')';
+ return position;
+ },
+
+ updateContents_: function() {
+ Polymer.dom(this.$.content).textContent = '';
+ Polymer.dom(this.$.content).classList.remove('better');
+ Polymer.dom(this.$.content).classList.remove('worse');
+ Polymer.dom(this.$.content).classList.remove('same');
+ this.$.insignificant.style.display = '';
+ this.$.significantly_better.style.display = '';
+ this.$.significantly_worse.style.display = '';
+
+ if (this.unit_ === undefined)
+ return;
+
+ this.$.content.title = '';
+ Polymer.dom(this.$.content).textContent =
+ this.unit_.format(this.value, this.context);
+ this.updateDelta_();
+ },
+
+ updateDelta_: function() {
+ var changeClass = this.changeClassName_;
+ if (!changeClass) {
+ this.$.significance.style.display = 'none';
+ return; // Not a delta or we don't care.
+ }
+
+ this.$.significance.style.display = 'inline';
+
+ var title;
+ switch (changeClass) {
+ case 'better':
+ title = 'improvement';
+ break;
+
+ case 'worse':
+ title = 'regression';
+ break;
+
+ case 'same':
+ title = 'no change';
+ break;
+
+ default:
+ throw new Error('Unknown change class: ' + changeClass);
+ }
+
+ // Set the content class separately from the significance class so that
+ // the Neutral face is always a neutral color.
+ Polymer.dom(this.$.content).classList.add(changeClass);
+
+ switch (this.significance) {
+ case tr.b.Statistics.Significance.DONT_CARE:
+ break;
+
+ case tr.b.Statistics.Significance.INSIGNIFICANT:
+ if (changeClass !== 'same')
+ title = 'insignificant ' + title;
+ this.$.insignificant.style.display = 'inline';
+ changeClass = 'same';
+ break;
+
+ case tr.b.Statistics.Significance.SIGNIFICANT:
+ if (changeClass === 'same')
+ throw new Error('How can no change be significant?');
+ this.$['significantly_' + changeClass].style.display = 'inline';
+ title = 'significant ' + title;
+ break;
+
+ default:
+ throw new Error('Unknown significance ' + this.significance);
+ }
+
+ this.$.significance.title = title;
+ this.$.content.title = title;
+ },
+
+ get changeClassName_() {
+ if (!this.unit_ || !this.unit_.isDelta)
+ return undefined;
+
+ switch (this.unit_.improvementDirection) {
+ case tr.b.ImprovementDirection.DONT_CARE:
+ return undefined;
+
+ case tr.b.ImprovementDirection.BIGGER_IS_BETTER:
+ if (this.value === 0)
+ return 'same';
+ return this.value > 0 ? 'better' : 'worse';
+
+ case tr.b.ImprovementDirection.SMALLER_IS_BETTER:
+ if (this.value === 0)
+ return 'same';
+ return this.value < 0 ? 'better' : 'worse';
+
+ default:
+ throw new Error('Unknown improvement direction: ' +
+ this.unit_.improvementDirection);
+ }
+ },
+
+ get warning() {
+ return this.warning_;
+ },
+
+ set warning(warning) {
+ this.warning_ = warning;
+ var warningEl = this.$.warning;
+ if (this.warning_) {
+ warningEl.title = warning;
+ warningEl.style.display = 'inline';
+ } else {
+ warningEl.title = '';
+ warningEl.style.display = '';
+ }
+ },
+
+ // tr-v-ui-time-stamp-span property
+ get timestamp() {
+ return this.value;
+ },
+
+ set timestamp(timestamp) {
+ if (timestamp instanceof tr.b.u.TimeStamp) {
+ this.value = timestamp;
+ return;
+ }
+ this.setValueAndUnit(timestamp, tr.b.u.Units.timeStampInMs);
+ },
+
+ // tr-v-ui-time-duration-span property
+ get duration() {
+ return this.value;
+ },
+
+ set duration(duration) {
+ if (duration instanceof tr.b.u.TimeDuration) {
+ this.value = duration;
+ return;
+ }
+ this.setValueAndUnit(duration, tr.b.u.Units.timeDurationInMs);
+ }
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span_test.html
index 04c266cdc3a..fe92b1b248e 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/scalar_span_test.html
@@ -5,32 +5,228 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/time_display_mode.html">
+<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/time_display_modes.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/base/unit_scale.html">
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/ui/scalar_context_controller.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/unit_scale.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
var ScalarNumeric = tr.v.ScalarNumeric;
- var Unit = tr.v.Unit;
- var THIS_DOC = document._currentScript.ownerDocument;
-
- function checkScalarSpan(
- test, value, unit, expectedTextContent, opt_expectedColor) {
- var span = tr.v.ui.createScalarSpan(new tr.v.ScalarNumeric(unit, value));
- assert.strictEqual(span.$.content.textContent, expectedTextContent);
- assert.strictEqual(span.$.content.style.color, opt_expectedColor || '');
+ var Unit = tr.b.Unit;
+ var THIS_DOC = document.currentScript.ownerDocument;
+
+ function checkSignificance(span, expectedSignificance) {
+ assert.strictEqual(span.$.insignificant.style.display,
+ expectedSignificance === 'insignificant' ? 'inline' : '');
+ assert.strictEqual(span.$.significantly_better.style.display,
+ expectedSignificance === 'significantly_better' ? 'inline' : '');
+ assert.strictEqual(span.$.significantly_worse.style.display,
+ expectedSignificance === 'significantly_worse' ? 'inline' : '');
+ }
+
+ function checkScalarSpan(test, value, unit, expectedContent, opt_options) {
+ var options = opt_options || {};
+ var span = tr.v.ui.createScalarSpan(new tr.v.ScalarNumeric(unit, value),
+ {significance: options.significance});
+
test.addHTMLOutput(span);
+ assert.strictEqual(
+ Polymer.dom(span.$.content).textContent, expectedContent);
+ assert.strictEqual(window.getComputedStyle(span.$.content).color,
+ options.expectedColor || 'rgb(0, 0, 0)');
+
+ if (options.expectedTitle) {
+ assert.strictEqual(span.$.content.title, options.expectedTitle);
+ }
+
+ if (options.significance !== undefined) {
+ checkSignificance(span, options.expectedEmoji);
+ if (options.expectedTitle) {
+ assert.strictEqual(span.$.significance.title, options.expectedTitle);
+ }
+ }
}
+ test('instantiate_significance', function() {
+ var countD = Unit.byName.count.correspondingDeltaUnit;
+ var countSIBD = Unit.byName.count_smallerIsBetter.correspondingDeltaUnit;
+ var countBIBD = Unit.byName.count_biggerIsBetter.correspondingDeltaUnit;
+
+ var zero = String.fromCharCode(177) + '0';
+
+ checkScalarSpan(this, 0, countSIBD, zero, {
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedTitle: 'no change',
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 0, countSIBD, zero, {
+ expectedEmoji: 'insignificant',
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'no change'
+ });
+
+ assert.throws(() => checkScalarSpan(this, 0, countSIBD, zero,
+ {significance: tr.b.Statistics.Significance.SIGNIFICANT}));
+
+ checkScalarSpan(this, 0, countBIBD, zero, {
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedTitle: 'no change',
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 0, countBIBD, zero, {
+ expectedEmoji: 'insignificant',
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'no change'
+ });
+
+ assert.throws(() => checkScalarSpan(this, 0, countSIBD, zero,
+ {significance: tr.b.Statistics.Significance.SIGNIFICANT}));
+
+ checkScalarSpan(this, 1, countSIBD, '+1', {
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedColor: 'rgb(255, 0, 0)',
+ expectedTitle: 'regression',
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 1, countSIBD, '+1', {
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedColor: 'rgb(255, 0, 0)',
+ expectedEmoji: 'insignificant',
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'insignificant regression'
+ });
+
+ checkScalarSpan(this, 1, countSIBD, '+1', {
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedColor: 'rgb(255, 0, 0)',
+ expectedEmoji: 'significantly_worse',
+ expectedEmojiColor: 'rgb(255, 0, 0)',
+ expectedTitle: 'significant regression'
+ });
+
+ checkScalarSpan(this, 1, countBIBD, '+1', {
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedTitle: 'improvement',
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 1, countBIBD, '+1', {
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedEmoji: 'insignificant',
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'insignificant improvement'
+ });
+
+ checkScalarSpan(this, 1, countBIBD, '+1', {
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedEmoji: 'significantly_better',
+ expectedEmojiColor: 'rgb(0, 128, 0)',
+ expectedTitle: 'significant improvement'
+ });
+
+ checkScalarSpan(this, -1, countSIBD, '-1', {
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedEmoji: '',
+ expectedEmojiColor: '',
+ expectedTitle: 'improvement'
+ });
+
+ checkScalarSpan(this, -1, countSIBD, '-1', {
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedEmoji: 'insignificant',
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'insignificant improvement'
+ });
+
+ checkScalarSpan(this, -1, countSIBD, '-1', {
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedColor: 'rgb(0, 128, 0)',
+ expectedEmoji: 'significantly_better',
+ expectedEmojiColor: 'rgb(0, 128, 0)',
+ expectedTitle: 'significant improvement'
+ });
+
+ checkScalarSpan(this, -1, countBIBD, '-1', {
+ expectedColor: 'rgb(255, 0, 0)',
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, -1, countBIBD, '-1', {
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedColor: 'rgb(255, 0, 0)',
+ expectedEmoji: 'insignificant',
+ expectedEmojiColor: 'rgb(0, 0, 0)',
+ expectedTitle: 'insignificant regression'
+ });
+
+ checkScalarSpan(this, -1, countBIBD, '-1', {
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedColor: 'rgb(255, 0, 0)',
+ expectedEmoji: 'significantly_worse',
+ expectedEmojiColor: 'rgb(255, 0, 0)',
+ expectedTitle: 'significant regression'
+ });
+
+ checkScalarSpan(this, 1, countD, '+1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 1, countD, '+1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, 1, countD, '+1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, -1, countD, '-1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.DONT_CARE,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, -1, countD, '-1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.INSIGNIFICANT,
+ expectedEmoji: ''
+ });
+
+ checkScalarSpan(this, -1, countD, '-1', {
+ expectedColor: 'rgb(0, 0, 0)',
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ expectedEmoji: ''
+ });
+ });
+
test('instantiate', function() {
checkScalarSpan(this, 123.456789, Unit.byName.timeDurationInMs,
'123.457 ms');
checkScalarSpan(this, 0, Unit.byName.normalizedPercentage, '0.000%');
+ checkScalarSpan(this, 1, Unit.byName.normalizedPercentage, '100.000%');
checkScalarSpan(this, -2560, Unit.byName.sizeInBytes, '-2.5 KiB');
});
@@ -63,33 +259,36 @@ tr.b.unittest.testSuite(function() {
test('instantiate_delta_smallerIsBetter', function() {
checkScalarSpan(this, 45097156608,
- Unit.byName.sizeInBytesDelta_smallerIsBetter, '+42.0 GiB', 'red');
+ Unit.byName.sizeInBytesDelta_smallerIsBetter, '+42.0 GiB',
+ {expectedColor: 'rgb(255, 0, 0)'});
checkScalarSpan(this, 0, Unit.byName.energyInJoulesDelta_smallerIsBetter,
'\u00B10.000 J');
checkScalarSpan(this, -0.25,
- Unit.byName.unitlessNumberDelta_smallerIsBetter, '-0.250', 'green');
+ Unit.byName.unitlessNumberDelta_smallerIsBetter, '-0.250',
+ {expectedColor: 'rgb(0, 128, 0)'});
});
test('instantiate_delta_biggerIsBetter', function() {
checkScalarSpan(this, 0.07, Unit.byName.powerInWattsDelta_biggerIsBetter,
- '+0.070 W', 'green');
+ '+0.070 W', {expectedColor: 'rgb(0, 128, 0)'});
checkScalarSpan(this, 0, Unit.byName.timeStampInMsDelta_biggerIsBetter,
'\u00B10.000 ms');
checkScalarSpan(this, -0.00003,
- Unit.byName.normalizedPercentageDelta_biggerIsBetter, '-0.003%', 'red');
+ Unit.byName.normalizedPercentageDelta_biggerIsBetter, '-0.003%',
+ {expectedColor: 'rgb(255, 0, 0)'});
});
test('createScalarSpan', function() {
// No config.
var span = tr.v.ui.createScalarSpan(
new ScalarNumeric(Unit.byName.powerInWatts, 3.14));
- assert.strictEqual(span.$.content.textContent, '3.140 W');
+ assert.strictEqual(Polymer.dom(span.$.content).textContent, '3.140 W');
assert.strictEqual(span.ownerDocument, document);
assert.strictEqual(span.tagName, 'TR-V-UI-SCALAR-SPAN');
assert.strictEqual(span.value, 3.14);
assert.strictEqual(span.unit, Unit.byName.powerInWatts);
assert.isUndefined(span.context);
- assert.isUndefined(span.percentage);
+ assert.isUndefined(span.customContextRange);
assert.isUndefined(span.warning);
assert.isFalse(span.rightAlign);
this.addHTMLOutput(span);
@@ -98,27 +297,30 @@ tr.b.unittest.testSuite(function() {
var span = tr.v.ui.createScalarSpan(
new ScalarNumeric(Unit.byName.energyInJoules, 2.72),
{ ownerDocument: THIS_DOC, rightAlign: true });
- assert.strictEqual(span.$.content.textContent, '2.720 J');
+ assert.strictEqual(Polymer.dom(span.$.content).textContent, '2.720 J');
assert.strictEqual(span.ownerDocument, THIS_DOC);
assert.strictEqual(span.tagName, 'TR-V-UI-SCALAR-SPAN');
assert.strictEqual(span.value, 2.72);
assert.strictEqual(span.unit, Unit.byName.energyInJoules);
assert.isUndefined(span.context);
- assert.isUndefined(span.percentage);
+ assert.isUndefined(span.customContextRange);
assert.isUndefined(span.warning);
assert.isTrue(span.rightAlign);
this.addHTMLOutput(span);
// Unit and sparkline set via config.
- var span = tr.v.ui.createScalarSpan(1.62,
- { unit: Unit.byName.timeStampInMs, total: 3.24 });
- assert.strictEqual(span.$.content.textContent, '1.620 ms');
+ var span = tr.v.ui.createScalarSpan(1.62, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: tr.b.Range.fromExplicitRange(0, 3.24)
+ });
+ assert.strictEqual(Polymer.dom(span.$.content).textContent, '1.620 ms');
assert.strictEqual(span.ownerDocument, document);
assert.strictEqual(span.tagName, 'TR-V-UI-SCALAR-SPAN');
assert.strictEqual(span.value, 1.62);
assert.strictEqual(span.unit, Unit.byName.timeStampInMs);
assert.isUndefined(span.context);
- assert.strictEqual(span.percentage, 0.5);
+ assert.isTrue(tr.b.Range.fromExplicitRange(0, 3.24).equals(
+ span.customContextRange));
assert.isUndefined(span.warning);
assert.isFalse(span.rightAlign);
this.addHTMLOutput(span);
@@ -127,17 +329,18 @@ tr.b.unittest.testSuite(function() {
var span = tr.v.ui.createScalarSpan(
new ScalarNumeric(Unit.byName.sizeInBytesDelta_smallerIsBetter,
256 * 1024 * 1024), { context: {
- unitPrefix: tr.v.UnitScale.Binary.KIBI,
+ unitPrefix: tr.b.UnitScale.Binary.KIBI,
minimumFractionDigits: 2
} });
- assert.strictEqual(span.$.content.textContent, '+262,144.00 KiB');
+ assert.strictEqual(
+ Polymer.dom(span.$.content).textContent, '+262,144.00 KiB');
assert.strictEqual(span.ownerDocument, document);
assert.strictEqual(span.tagName, 'TR-V-UI-SCALAR-SPAN');
assert.strictEqual(span.value, 256 * 1024 * 1024);
assert.strictEqual(span.unit, Unit.byName.sizeInBytesDelta_smallerIsBetter);
assert.deepEqual(span.context,
- { unitPrefix: tr.v.UnitScale.Binary.KIBI, minimumFractionDigits: 2 });
- assert.isUndefined(span.percentage);
+ { unitPrefix: tr.b.UnitScale.Binary.KIBI, minimumFractionDigits: 2 });
+ assert.isUndefined(span.customContextRange);
assert.isUndefined(span.warning);
assert.isFalse(span.rightAlign);
this.addHTMLOutput(span);
@@ -151,10 +354,10 @@ tr.b.unittest.testSuite(function() {
this.addHTMLOutput(span);
});
- test('instantiate_withPercentage', function() {
+ test('instantiate_withCustomContextRange', function() {
var span = document.createElement('tr-v-ui-scalar-span');
- span.value = new ScalarNumeric(Unit.byName.unitlessNumber, 99);
- span.percentage = 0.66;
+ span.value = new ScalarNumeric(Unit.byName.unitlessNumber, 0.99);
+ span.customContextRange = tr.b.Range.fromExplicitRange(0, 3);
this.addHTMLOutput(span);
});
@@ -170,10 +373,57 @@ tr.b.unittest.testSuite(function() {
span.value = new ScalarNumeric(
Unit.byName.unitlessNumberDelta_smallerIsBetter, 42);
span.context = { maximumFractionDigits: 2 };
- assert.strictEqual(span.$.content.textContent, '+42.00');
+ assert.strictEqual(Polymer.dom(span.$.content).textContent, '+42.00');
this.addHTMLOutput(span);
});
+ test('deltaAndNonDeltaHaveSimilarHeights', function() {
+ var spanA = document.createElement('tr-v-ui-scalar-span');
+ spanA.setValueAndUnit(400, Unit.byName.timeDurationInMs);
+ checkSignificance(spanA, '');
+
+ var spanB = document.createElement('tr-v-ui-scalar-span');
+ spanB.setValueAndUnit(400, Unit.byName.timeDurationInMsDelta);
+ checkSignificance(spanB, '');
+
+ var spanC = document.createElement('tr-v-ui-scalar-span');
+ spanC.setValueAndUnit(
+ 400, Unit.byName.timeDurationInMsDelta_smallerIsBetter);
+ spanC.significance = tr.b.Statistics.Significance.SIGNIFICANT;
+ checkSignificance(spanC, 'significantly_worse');
+
+ var spanD = document.createElement('tr-v-ui-scalar-span');
+ spanD.setValueAndUnit(
+ 400, Unit.byName.timeDurationInMsDelta_biggerIsBetter);
+ spanD.significance = tr.b.Statistics.Significance.SIGNIFICANT;
+ checkSignificance(spanD, 'significantly_better');
+
+ var spanE = document.createElement('tr-v-ui-scalar-span');
+ spanE.setValueAndUnit(
+ 400, Unit.byName.timeDurationInMsDelta_smallerIsBetter);
+ spanE.significance = tr.b.Statistics.Significance.INSIGNIFICANT;
+ checkSignificance(spanE, 'insignificant');
+
+ var overall = document.createElement('div');
+ overall.style.display = 'flex';
+ // These spans must be on separate lines so that Chrome has the option of
+ // making their heights different. The point of the test is that Chrome
+ // shouldn't have to make their heights different even when it could.
+ overall.style.flexDirection = 'column';
+ Polymer.dom(overall).appendChild(spanA);
+ Polymer.dom(overall).appendChild(spanB);
+ Polymer.dom(overall).appendChild(spanC);
+ Polymer.dom(overall).appendChild(spanD);
+ Polymer.dom(overall).appendChild(spanE);
+ this.addHTMLOutput(overall);
+
+ var expectedHeight = spanA.getBoundingClientRect().height;
+ assert.strictEqual(expectedHeight, spanB.getBoundingClientRect().height);
+ assert.strictEqual(expectedHeight, spanC.getBoundingClientRect().height);
+ assert.strictEqual(expectedHeight, spanD.getBoundingClientRect().height);
+ assert.strictEqual(expectedHeight, spanE.getBoundingClientRect().height);
+ });
+
test('warningAndNonWarningHaveSimilarHeights', function() {
var spanA = document.createElement('tr-v-ui-scalar-span');
spanA.setValueAndUnit(400, Unit.byName.timeDurationInMs);
@@ -184,53 +434,555 @@ tr.b.unittest.testSuite(function() {
var overall = document.createElement('div');
overall.style.display = 'flex';
- overall.appendChild(spanA);
- spanB.style.marginLeft = '4px';
- overall.appendChild(spanB);
+ // These spans must be on separate lines so that Chrome has the option of
+ // making their heights different. The point of the test is that Chrome
+ // shouldn't have to make their heights different even when it could.
+ overall.style.flexDirection = 'column';
+ Polymer.dom(overall).appendChild(spanA);
+ Polymer.dom(overall).appendChild(spanB);
this.addHTMLOutput(overall);
+
+ var rectA = spanA.getBoundingClientRect();
+ var rectB = spanB.getBoundingClientRect();
+ assert.strictEqual(rectA.height, rectB.height);
});
test('respectCurrentDisplayUnit', function() {
try {
- Unit.currentTimeDisplayMode = tr.v.TimeDisplayModes.ns;
+ Unit.currentTimeDisplayMode = tr.b.TimeDisplayModes.ns;
var span = document.createElement('tr-v-ui-scalar-span');
span.setValueAndUnit(73, Unit.byName.timeStampInMs);
this.addHTMLOutput(span);
- assert.isTrue(span.$.content.textContent.indexOf('ns') > 0);
- Unit.currentTimeDisplayMode = tr.v.TimeDisplayModes.ms;
- assert.isTrue(span.$.content.textContent.indexOf('ms') > 0);
+ assert.isTrue(Polymer.dom(span.$.content).textContent.indexOf('ns') > 0);
+ Unit.currentTimeDisplayMode = tr.b.TimeDisplayModes.ms;
+ assert.isTrue(Polymer.dom(span.$.content).textContent.indexOf('ms') > 0);
} finally {
Unit.reset();
}
});
- test('displaySparkline', function() {
+ function checkSparkline(span, expectation) {
+ tr.b.forceAllPendingTasksToRunForTest();
+ var sparklineEl = span.$.sparkline;
+ var computedStyle = getComputedStyle(sparklineEl);
+
+ var expectedDisplay = expectation.display || 'block';
+ assert.strictEqual(computedStyle.display, expectedDisplay);
+ if (expectedDisplay === 'none') {
+ // Test expectation sanity check.
+ assert.notProperty(expectation, 'left');
+ assert.notProperty(expectation, 'width');
+ assert.notProperty(expectation, 'classList');
+ return;
+ }
+
+ assert.closeTo(parseFloat(computedStyle.left), expectation.left, 0.1);
+ assert.closeTo(parseFloat(computedStyle.width), expectation.width, 0.1);
+ assert.sameMembers(tr.b.asArray(sparklineEl.classList),
+ expectation.classList || []);
+ }
+
+ test('customContextRange', function() {
var div = document.createElement('div');
- div.style.width = '100px';
+ div.style.width = '101px'; // One extra pixel for sparkline border.
this.addHTMLOutput(div);
- function addAndCheckScalarSpan(percentage, expectedDisplay, expectedWidth) {
- var span = tr.v.ui.createScalarSpan(new ScalarNumeric(
- Unit.byName.timeDurationInMs, 10 * div.children.length));
- if (percentage !== null)
- span.percentage = percentage;
+ // No custom context range.
+ var span1 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.timeStampInMs
+ });
+ Polymer.dom(div).appendChild(span1);
+ checkSparkline(span1, {display: 'none'});
+ var span2 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: undefined
+ });
+ Polymer.dom(div).appendChild(span2);
+ checkSparkline(span2, {display: 'none'});
+ var span3 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: new tr.b.Range() // Empty range.
+ });
+ Polymer.dom(div).appendChild(span3);
+ checkSparkline(span3, {display: 'none'});
- div.appendChild(span);
+ var range = tr.b.Range.fromExplicitRange(-15, 15);
- var computedStyle = getComputedStyle(span.$.sparkline);
- assert.equal(computedStyle.display, expectedDisplay);
- assert.equal(parseInt(computedStyle.width), expectedWidth);
- }
+ // Values inside custom context range.
+ var span4 = tr.v.ui.createScalarSpan(-15, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span4);
+ checkSparkline(span4, {left: 0, width: 51});
+ var span5 = tr.v.ui.createScalarSpan(-14, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span5);
+ checkSparkline(span5, {left: 3.33, width: 47.67});
+ var span6 = tr.v.ui.createScalarSpan(-10, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span6);
+ checkSparkline(span6, {left: 16.67, width: 34.33});
+ var span7 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span7);
+ checkSparkline(span7, {left: 50, width: 1});
+ var span8 = tr.v.ui.createScalarSpan(10, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span8);
+ checkSparkline(span8, {left: 50, width: 34.33, classList: ['positive']});
+ var span9 = tr.v.ui.createScalarSpan(14, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span9);
+ checkSparkline(span9, {left: 50, width: 47.67, classList: ['positive']});
+ var span10 = tr.v.ui.createScalarSpan(15, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span10);
+ checkSparkline(span10, {left: 50, width: 51, classList: ['positive']});
+
+ // Values outside custom context range.
+ var span11 = tr.v.ui.createScalarSpan(-20, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span11);
+ checkSparkline(span11, {left: 0, width: 51});
+ var span12 = tr.v.ui.createScalarSpan(20, {
+ unit: Unit.byName.timeStampInMs,
+ customContextRange: range
+ });
+ Polymer.dom(div).appendChild(span12);
+ checkSparkline(span12, {left: 50, width: 51, classList: ['positive']});
+ });
+
+ test('emptyNumeric', function() {
+ assert.strictEqual(tr.v.ui.createScalarSpan(), '');
+ });
+
+ test('contextControllerChanges', function() {
+ var div = document.createElement('div');
+ div.style.width = '101px'; // One extra pixel for sparkline border.
+ this.addHTMLOutput(div);
+
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
+
+ var s1 = tr.v.ui.createScalarSpan(10, {
+ unit: Unit.byName.powerInWatts
+ });
+ Polymer.dom(div).appendChild(s1);
+ checkSparkline(s1, {display: 'none'});
+
+ var s2 = tr.v.ui.createScalarSpan(20, {
+ unit: Unit.byName.powerInWatts,
+ contextGroup: 'A'
+ });
+ Polymer.dom(div).appendChild(s2);
+ checkSparkline(s1, {display: 'none'});
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+
+ var s3 = tr.v.ui.createScalarSpan(30, {
+ unit: Unit.byName.powerInWatts,
+ contextGroup: 'A'
+ });
+ Polymer.dom(div).appendChild(s3);
+ checkSparkline(s1, {display: 'none'});
+ checkSparkline(s2, {left: 0, width: 67.67, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+
+ var s4 = tr.v.ui.createScalarSpan(40, {
+ unit: Unit.byName.powerInWatts,
+ contextGroup: 'B'
+ });
+ Polymer.dom(div).appendChild(s4);
+ checkSparkline(s1, {display: 'none'});
+ checkSparkline(s2, {left: 0, width: 67.67, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {left: 0, width: 101, classList: ['positive']});
+
+ s3.contextGroup = 'B';
+ checkSparkline(s1, {display: 'none'});
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 76, classList: ['positive']});
+ checkSparkline(s4, {left: 0, width: 101, classList: ['positive']});
+
+ s1.setAttribute('context-group', 'A');
+ checkSparkline(s1, {left: 0, width: 51, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 76, classList: ['positive']});
+ checkSparkline(s4, {left: 0, width: 101, classList: ['positive']});
+
+ s1.value = 50;
+ checkSparkline(s1, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 76, classList: ['positive']});
+ checkSparkline(s4, {left: 0, width: 101, classList: ['positive']});
+
+ s1.customContextRange = tr.b.Range.fromExplicitRange(0, 150);
+ checkSparkline(s1, {left: 0, width: 34.33, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 76, classList: ['positive']});
+ checkSparkline(s4, {left: 0, width: 101, classList: ['positive']});
+
+ s4.contextGroup = null;
+ checkSparkline(s1, {left: 0, width: 34.33, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+
+ s1.customContextRange = undefined;
+ checkSparkline(s1, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+
+ s4.value = 0;
+ checkSparkline(s1, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s2, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+
+ div.removeChild(s1);
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+
+ s1.contextGroup = 'B';
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+
+ div.appendChild(s1);
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 61, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+ checkSparkline(s1, {left: 0, width: 101, classList: ['positive']});
+
+ s1.removeAttribute('context-group');
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+ checkSparkline(s1, {display: 'none'});
+
+ s1.customContextRange = tr.b.Range.fromExplicitRange(0, 100);
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s4, {display: 'none'});
+ checkSparkline(s1, {left: 0, width: 51, classList: ['positive']});
+
+ s3.value = 0;
+ checkSparkline(s2, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(s3, {display: 'none'});
+ checkSparkline(s4, {display: 'none'});
+ checkSparkline(s1, {left: 0, width: 51, classList: ['positive']});
+ });
+
+ test('deltaSparkline_noImprovementDirection', function() {
+ var div = document.createElement('div');
+ div.style.width = '101px'; // One extra pixel for sparkline border.
+ this.addHTMLOutput(div);
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
+
+ var span1 = tr.v.ui.createScalarSpan(20971520, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span1);
+ var span2 = tr.v.ui.createScalarSpan(15728640, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span2);
+ var span3 = tr.v.ui.createScalarSpan(12582912, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span3);
+ var span4 = tr.v.ui.createScalarSpan(11534336, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span4);
+ var span5 = tr.v.ui.createScalarSpan(10485760, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span5);
+ var span6 = tr.v.ui.createScalarSpan(9437184, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span6);
+ var span7 = tr.v.ui.createScalarSpan(8388608, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span7);
+ var span8 = tr.v.ui.createScalarSpan(5242880, {
+ unit: Unit.byName.sizeInBytesDelta,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span8);
+
+ // We must check the sparklines *after* all spans are appended because new
+ // values can change the context range.
+ checkSparkline(span1, {left: 0, width: 101, classList: ['positive']});
+ checkSparkline(span2, {left: 0, width: 76, classList: ['positive']});
+ checkSparkline(span3, {left: 0, width: 61, classList: ['positive']});
+ checkSparkline(span4, {left: 0, width: 56, classList: ['positive']});
+ checkSparkline(span5, {left: 0, width: 51, classList: ['positive']});
+ checkSparkline(span6, {left: 0, width: 46, classList: ['positive']});
+ checkSparkline(span7, {left: 0, width: 41, classList: ['positive']});
+ checkSparkline(span8, {left: 0, width: 26, classList: ['positive']});
+ });
+
+ test('deltaSparkline_smallerIsBetter', function() {
+ var div = document.createElement('div');
+ div.style.width = '101px'; // One extra pixel for sparkline border.
+ this.addHTMLOutput(div);
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
+
+ var span1 = tr.v.ui.createScalarSpan(5242880, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span1);
+ var span2 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span2);
+ var span3 = tr.v.ui.createScalarSpan(-3145728, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span3);
+ var span4 = tr.v.ui.createScalarSpan(-4194304, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span4);
+ var span5 = tr.v.ui.createScalarSpan(-5242880, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span5);
+ var span6 = tr.v.ui.createScalarSpan(-6291456, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span6);
+ var span7 = tr.v.ui.createScalarSpan(-7340032, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span7);
+ var span8 = tr.v.ui.createScalarSpan(-15728640, {
+ unit: Unit.byName.sizeInBytesDelta_smallerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span8);
+
+ // We must check the sparklines *after* all spans are appended because new
+ // values can change the context range.
+ checkSparkline(span1,
+ {left: 75, width: 26, classList: ['positive', 'worse']});
+ checkSparkline(span2, {left: 75, width: 1, classList: ['same']});
+ checkSparkline(span3, {left: 60, width: 16, classList: ['better']});
+ checkSparkline(span4, {left: 55, width: 21, classList: ['better']});
+ checkSparkline(span5, {left: 50, width: 26, classList: ['better']});
+ checkSparkline(span6, {left: 45, width: 31, classList: ['better']});
+ checkSparkline(span7, {left: 40, width: 36, classList: ['better']});
+ checkSparkline(span8, {left: 0, width: 76, classList: ['better']});
+ });
+
+ test('deltaSparkline_biggerIsBetter', function() {
+ var div = document.createElement('div');
+ div.style.width = '101px'; // One extra pixel for sparkline border.
+ this.addHTMLOutput(div);
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
+
+ var span1 = tr.v.ui.createScalarSpan(0, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span1);
+ var span2 = tr.v.ui.createScalarSpan(-5242880, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span2);
+ var span3 = tr.v.ui.createScalarSpan(-8388608, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span3);
+ var span4 = tr.v.ui.createScalarSpan(-9437184, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span4);
+ var span5 = tr.v.ui.createScalarSpan(-10485760, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span5);
+ var span6 = tr.v.ui.createScalarSpan(-11534336, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span6);
+ var span7 = tr.v.ui.createScalarSpan(-12582912, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span7);
+ var span8 = tr.v.ui.createScalarSpan(-20971520, {
+ unit: Unit.byName.sizeInBytesDelta_biggerIsBetter,
+ contextGroup: 'test'
+ });
+ Polymer.dom(div).appendChild(span8);
+
+ // We must check the sparklines *after* all spans are appended because new
+ // values can change the context range.
+ checkSparkline(span1, {left: 100, width: 1, classList: ['same']});
+ checkSparkline(span2, {left: 75, width: 26, classList: ['worse']});
+ checkSparkline(span3, {left: 60, width: 41, classList: ['worse']});
+ checkSparkline(span4, {left: 55, width: 46, classList: ['worse']});
+ checkSparkline(span5, {left: 50, width: 51, classList: ['worse']});
+ checkSparkline(span6, {left: 45, width: 56, classList: ['worse']});
+ checkSparkline(span7, {left: 40, width: 61, classList: ['worse']});
+ checkSparkline(span8, {left: 0, width: 101, classList: ['worse']});
+ });
+
+ test('classListChanges', function() {
+ var div = document.createElement('div');
+ div.style.width = '200px';
+ this.addHTMLOutput(div);
+
+ var span = tr.v.ui.createScalarSpan(10, {
+ unit: Unit.byName.energyInJoulesDelta_smallerIsBetter,
+ significance: tr.b.Statistics.Significance.SIGNIFICANT,
+ customContextRange: tr.b.Range.fromExplicitRange(-20, 20)
+ });
+ Polymer.dom(div).appendChild(span);
+
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['worse']);
+ checkSignificance(span, 'significantly_worse');
+
+ span.significance = tr.b.Statistics.Significance.DONT_CARE;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList),
+ ['positive', 'worse']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['worse']);
+ checkSignificance(span, '');
+
+ span.value = -5;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList), ['better']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['better']);
+ checkSignificance(span, '');
+
+ span.unit = Unit.byName.energyInJoules;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList), []);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), []);
+ checkSignificance(span, '');
+
+ span.value = 20;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList), ['positive']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), []);
+ checkSignificance(span, '');
+
+ span.unit = Unit.byName.energyInJoulesDelta_biggerIsBetter;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList),
+ ['positive', 'better']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['better']);
+ checkSignificance(span, '');
+
+ span.significance = tr.b.Statistics.Significance.INSIGNIFICANT;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList),
+ ['positive', 'better']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['better']);
+ checkSignificance(span, 'insignificant');
+
+ span.unit = Unit.byName.energyInJoulesDelta_smallerIsBetter;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList),
+ ['positive', 'worse']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), ['worse']);
+ checkSignificance(span, 'insignificant');
+
+ span.unit = Unit.byName.energyInJoulesDelta;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList), ['positive']);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), []);
+ checkSignificance(span, '');
+
+ span.value = 0;
+ assert.sameMembers(tr.b.asArray(span.$.sparkline.classList), []);
+ assert.sameMembers(tr.b.asArray(span.$.content.classList), []);
+ checkSignificance(span, '');
+ });
+
+ test('sparkline_uncentered', function() {
+ var div = document.createElement('div');
+ this.addHTMLOutput(div);
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
+
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(-1, {
+ unit: Unit.byName.powerInWattsDelta,
+ contextGroup: 'test'
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(100, {
+ unit: Unit.byName.powerInWattsDelta,
+ contextGroup: 'test'
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(80, {
+ unit: Unit.byName.powerInWattsDelta,
+ contextGroup: 'test'
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(60, {
+ unit: Unit.byName.powerInWattsDelta,
+ contextGroup: 'test'
+ }));
+ });
+
+ test('sparkline_centered', function() {
+ var div = document.createElement('div');
+ this.addHTMLOutput(div);
+ div.appendChild(
+ document.createElement('tr-v-ui-scalar-context-controller'));
- addAndCheckScalarSpan(null /* no percentage set */, 'none', 0);
- addAndCheckScalarSpan(undefined, 'none', 0);
- addAndCheckScalarSpan(0, 'block', 1);
- addAndCheckScalarSpan(0.05, 'block', 5);
- addAndCheckScalarSpan(0.5, 'block', 50);
- addAndCheckScalarSpan(0.95, 'block', 95);
- addAndCheckScalarSpan(1, 'block', 100);
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(-1, {
+ unit: Unit.byName.powerInWattsDelta,
+ customContextRange: tr.b.Range.fromExplicitRange(-100, 100)
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(100, {
+ unit: Unit.byName.powerInWattsDelta,
+ customContextRange: tr.b.Range.fromExplicitRange(-100, 100)
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(80, {
+ unit: Unit.byName.powerInWattsDelta,
+ customContextRange: tr.b.Range.fromExplicitRange(-100, 100)
+ }));
+ Polymer.dom(div).appendChild(tr.v.ui.createScalarSpan(60, {
+ unit: Unit.byName.powerInWattsDelta,
+ customContextRange: tr.b.Range.fromExplicitRange(-100, 100)
+ }));
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table.html b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table.html
index e9388185408..7a1422c2f68 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table.html
@@ -6,57 +6,322 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/raf.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/ui/base/grouping_table_groupby_picker.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/value/ui/diagnostic_span.html">
<link rel="import" href="/tracing/value/ui/histogram_span.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
-<link rel="import" href="/tracing/value/ui/value_set_view.html">
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/value/value_set.html">
-<polymer-element name='tr-v-ui-value-set-table'>
+<dom-module id="tr-v-ui-value-set-table-cell">
<template>
<style>
:host {
display: flex;
+ flex-direction: row;
+ }
+
+ #missing, #empty, #unmergeable, #scalar {
+ flex-grow: 1;
+ }
+
+ svg {
+ height: 1em;
+ }
+
+ #open_histogram {
+ margin-left: 4px;
+ stroke-width: 0;
+ stroke: blue;
+ fill: blue;
+ }
+ :host(:hover) #open_histogram {
+ background: blue;
+ stroke: white;
+ fill: white;
+ }
+
+ #scalar {
+ flex-grow: 1;
+ white-space: nowrap;
+ }
+
+ #histogram {
+ flex-grow: 1;
+ }
+
+ #close_histogram line {
+ stroke-width: 18;
+ stroke: black;
+ }
+ #close_histogram:hover {
+ background: black;
+ }
+ #close_histogram:hover line {
+ stroke: white;
+ }
+ </style>
+
+ <span id="missing">(missing)</span>
+ <span id="empty">(empty)</span>
+ <span id="unmergeable">(unmergeable)</span>
+
+ <tr-v-ui-scalar-span id="scalar" on-click="openHistogram_"></tr-v-ui-scalar-span>
+
+ <svg viewbox="0 0 128 128" id="open_histogram" on-click="openHistogram_">
+ <rect x="16" y="24" width="32" height="16"/>
+ <rect x="16" y="56" width="96" height="16"/>
+ <rect x="16" y="88" width="64" height="16"/>
+ </svg>
+
+ <tr-v-ui-histogram-span id="histogram"></tr-v-ui-histogram-span>
+
+ <svg viewbox="0 0 128 128" id="close_histogram" on-click="closeHistogram_">
+ <line x1="28" y1="28" x2="100" y2="100"/>
+ <line x1="28" y1="100" x2="100" y2="28"/>
+ </svg>
+ </template>
+</dom-module>
+
+<dom-module id="tr-v-ui-value-set-table">
+ <template>
+ <style>
+ :host {
+ display: block;
+ }
+
+ #container {
flex-direction: column;
+ display: none;
}
+
table-container {
+ margin-top: 5px;
display: flex;
min-height: 0px;
overflow-y: auto;
}
- div#error {
- color: red;
- }
+
#histogram {
display: none;
}
+
+ #zero {
+ color: red;
+ /* value-set-table is used by both metrics-side-panel and results2.html.
+ * This font-size rule has no effect in results2.html, but improves
+ * legibility in the metrics-side-panel, which sets font-size in order to
+ * make this table denser.
+ */
+ font-size: initial;
+ }
+
+ #search {
+ max-width: 20em;
+ margin-right: 20px;
+ }
+
+ #controls {
+ white-space: nowrap;
+ }
+
+ #reference_column_container * {
+ margin-right: 20px;
+ }
</style>
- <div id="error"></div>
- <table-container>
- <tr-ui-b-table id="table"></tr-ui-b-table>
- </table-container>
- <tr-v-ui-histogram-span id="histogram"></tr-v-ui-histogram-span>
+ <div id="zero">zero values</div>
+
+ <div id="container">
+ <div id="controls">
+ <input id="search" placeholder="Find Histogram name" on-keyup="onSearch_">
+
+ <span id="reference_column_container"></span>
+
+ <input type="checkbox" id="show_all" on-change="onShowAllChange_" title="When unchecked, less important histograms are hidden.">
+ <label for="show_all" title="When unchecked, less important histograms are hidden.">Show all</label>
+ </div>
+
+ <tr-ui-b-grouping-table-groupby-picker id="picker">
+ </tr-ui-b-grouping-table-groupby-picker>
+
+ <table-container>
+ <tr-ui-b-table id="table"/>
+ </table-container>
+ </div>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
tr.exportTo('tr.ui', function() {
- Polymer('tr-v-ui-value-set-table', {
+ /**
+ * Returns a closure that gets a story grouping key label from a Histogram.
+ *
+ * @param {string} storyGroupingKey
+ * @return {!function(tr.v.Histogram):string}
+ */
+ function makeStoryGroupingKeyLabelGetter(storyGroupingKey) {
+ return v => tr.v.d.IterationInfo.getStoryGroupingKeyLabel(
+ v, storyGroupingKey);
+ }
+
+ var getDisplayLabel = tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL.callback;
+
+ var DEFAULT_POSSIBLE_GROUPS = [];
+ DEFAULT_POSSIBLE_GROUPS.push(new tr.v.HistogramGrouping(
+ tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key,
+ h => h.shortName || h.name));
+
+ tr.b.iterItems(tr.v.ValueSet.GROUPINGS, function(name, group) {
+ // DISPLAY_LABEL is used to define the columns, so don't allow grouping
+ // rows by it.
+ // Override HISTOGRAM_NAME so that we can display shortName.
+ if (group !== tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL &&
+ group !== tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME)
+ DEFAULT_POSSIBLE_GROUPS.push(group);
+ });
+
+ var SHOW_ALL_SETTINGS_KEY = 'tr-v-ui-value-set-table-show-all';
+
+ var UNMERGEABLE = '(unmergeable)';
+
+ Polymer({
+ is: 'tr-v-ui-value-set-table-cell',
+
+ created: function() {
+ this.histogram_ = undefined;
+ this.referenceHistogram_ = undefined;
+ },
+
+ ready: function() {
+ this.addEventListener('click', this.onClick_.bind(this));
+ },
+
+ onClick_: function(event) {
+ // Since the value-set-table's table doesn't support any kind of
+ // selection, clicking anywhere within a row that has subRows will
+ // expand/collapse that row, which can relayout the table and move things
+ // around. Prevent table relayout by preventing the tr-ui-b-table from
+ // receiving the click event.
+ event.stopPropagation();
+ },
+
+ get histogram() {
+ return this.histogram_;
+ },
+
/**
- * Return true if this view supports this ValueSet.
- * Value-set-table supports all possible metrics, so it always returns true.
- *
- * @param {!tr.v.ValueSet} values
- * @return {boolean}
+ * @param {undefined|string|!tr.v.Histogram} h
*/
- supportsValueSet: function(values) {
- return true;
+ set histogram(h) {
+ this.histogram_ = h;
+ this.updateContents_();
},
/**
+ * @param {undefined|string|!tr.v.Histogram} rh
+ */
+ set referenceHistogram(rh) {
+ this.referenceHistogram_ = rh;
+ this.updateContents_();
+ },
+
+ get referenceHistogram() {
+ return this.referenceHistogram_;
+ },
+
+ get isHistogramOpen() {
+ return this.$.histogram.style.display === 'block';
+ },
+
+ set isHistogramOpen(open) {
+ if (!this.histogram ||
+ this.histogram === UNMERGEABLE ||
+ !(this.histogram instanceof tr.v.Histogram) ||
+ (this.histogram.numValues === 0)) {
+ return;
+ }
+
+ // Unfortunately, we can't use a css attribute for this since this stuff
+ // is tied up in all the possible states of this.histogram. See
+ // updateContents_().
+
+ this.$.scalar.style.display = open ? 'none' : 'block';
+ this.$.open_histogram.style.display = open ? 'none' : 'block';
+
+ this.$.close_histogram.style.display = open ? 'block' : 'none';
+ this.$.histogram.style.display = open ? 'block' : 'none';
+
+ if (open) {
+ // Wait to pass the Histogram to the histogram-span until it's displayed
+ // so that it can size its BarChart appropriately.
+ this.$.histogram.referenceHistogram = this.referenceHistogram;
+ this.$.histogram.histogram = this.histogram;
+ }
+ },
+
+ openHistogram_: function() {
+ this.isHistogramOpen = true;
+ },
+
+ closeHistogram_: function() {
+ this.isHistogramOpen = false;
+ },
+
+ updateContents_: function() {
+ this.$.empty.style.display = 'none';
+ this.$.unmergeable.style.display = 'none';
+ this.$.scalar.style.display = 'none';
+ this.$.histogram.style.display = 'none';
+ this.$.close_histogram.style.display = 'none';
+ this.$.open_histogram.style.visibility = 'hidden';
+
+ if (!this.histogram) {
+ this.$.missing.style.display = 'block';
+ return;
+ }
+
+ this.$.missing.style.display = 'none';
+
+ if (this.histogram === UNMERGEABLE) {
+ this.$.unmergeable.style.display = 'block';
+ return;
+ }
+
+ if (!(this.histogram instanceof tr.v.Histogram)) {
+ throw new Error('Invalid Histogram: ' + this.histogram);
+ }
+
+ if (this.histogram.numValues === 0) {
+ this.$.empty.style.display = 'block';
+ return;
+ }
+
+ this.$.open_histogram.style.display = 'block';
+ this.$.open_histogram.style.visibility = 'visible';
+ this.$.scalar.style.display = 'block';
+
+ if ((this.referenceHistogram instanceof tr.v.Histogram) &&
+ (this.histogram.unit === this.referenceHistogram.unit) &&
+ (this.referenceHistogram.numValues > 0)) {
+ this.$.scalar.setValueAndUnit(
+ this.histogram.average - this.referenceHistogram.average,
+ this.histogram.unit.correspondingDeltaUnit);
+ this.$.scalar.significance = this.histogram.getDifferenceSignificance(
+ this.referenceHistogram);
+ } else {
+ this.$.scalar.setValueAndUnit(
+ this.histogram.average, this.histogram.unit);
+ }
+ }
+ });
+
+ Polymer({
+ is: 'tr-v-ui-value-set-table',
+
+ /**
* This can optionally depend on the ValueSet.
*
* @return {string}
@@ -65,79 +330,195 @@ tr.exportTo('tr.ui', function() {
return 'Table';
},
- ready: function() {
+ created: function() {
+ /** @type {undefined|!tr.v.ValueSet} */
this.values_ = undefined;
- this.summaryValues_ = {};
+
+ /** @type {undefined|!tr.v.ValueSet} */
+ this.sourceValues_ = undefined;
+
+ this.rows_ = undefined;
this.columns_ = undefined;
- this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.CELL;
- this.$.table.addEventListener('selection-changed',
- this.onSelectionChanged_.bind(this));
- },
-
- onSelectionChanged_: function() {
- var row = this.$.table.selectedTableRow;
- var col = this.$.table.selectedColumnIndex;
- var cell = undefined;
- if (row && col && this.columns_)
- cell = row[this.columns_[col].title];
-
- if ((cell instanceof tr.v.NumericValue) &&
- (cell.numeric instanceof tr.v.Numeric)) {
- this.$.histogram.style.display = 'block';
- this.$.histogram.histogram = cell.numeric;
- } else {
- this.$.histogram.style.display = 'none';
+
+ this.updatingContents_ = false;
+ this.displayLabels_ = undefined;
+ this.referenceDisplayLabel_ = undefined;
+ },
+
+ ready: function() {
+ this.$.table.zebra = true;
+ this.addEventListener('requestSelectionChange',
+ this.onRelatedValueSelected_.bind(this));
+ this.$.show_all.checked = tr.b.Settings.get(SHOW_ALL_SETTINGS_KEY, false);
+ this.$.picker.settingsKey = 'tr-v-ui-value-set-table-groupby-picker';
+
+ this.$.picker.possibleGroups = DEFAULT_POSSIBLE_GROUPS.slice();
+ this.$.picker.defaultGroupKeys = [
+ tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key,
+ tr.v.ValueSet.GROUPINGS.STORY_NAME.key];
+ this.$.picker.addEventListener('current-groups-changed',
+ this.currentGroupsChanged_.bind(this));
+ },
+
+ set groupingKeys(keys) {
+ this.$.picker.currentGroupKeys = keys;
+ },
+
+ get groupingKeys() {
+ return this.$.picker.currentGroupKeys;
+ },
+
+ get possibleGroupingKeys() {
+ return this.$.picker.possibleGroups.map(g => g.key);
+ },
+
+ currentGroupsChanged_: function() {
+ if (this.updatingContents_)
+ return;
+
+ if (this.$.picker.currentGroups.length === 0 &&
+ this.possibleGroupingKeys.length > 0) {
+ this.$.picker.currentGroupKeys = [this.$.picker.possibleGroups[0].key];
}
+ var expansionStates = undefined;
+ if (this.rows_)
+ expansionStates = this.getExpansionStates_();
+ this.updateContents_();
+ if (expansionStates)
+ this.setExpansionStates_(expansionStates);
+ },
+
+ onShowAllChange_: function() {
+ if (this.updatingContents_)
+ return;
+
+ tr.b.Settings.set(SHOW_ALL_SETTINGS_KEY, this.$.show_all.checked);
+ var expansionStates = this.getExpansionStates_();
+ this.updateContents_();
+ this.setExpansionStates_(expansionStates);
},
- handleFailureValues_: function() {
- this.values.map(function(value) {
- if (value instanceof tr.v.FailureValue) {
- this.$.error.textContent = value.description;
- this.$.table.style.display = 'none';
- this.style.width = '10em';
+ getExpansionStates_: function() {
+ var table = this.$.table;
+ function recurse(row) {
+ var rowStates = {
+ expanded: table.getExpandedForTableRow(row),
+ cells: new Map(),
+ subRows: new Map()
+ };
+
+ tr.b.iterItems(row.cells, function(displayLabel, cell) {
+ if (cell.isHistogramOpen) {
+ rowStates.cells.set(displayLabel, true);
+ }
+ });
+
+ if (rowStates.expanded) {
+ for (var i = 0; i < row.subRows.length; ++i) {
+ rowStates.subRows.set(i, recurse(row.subRows[i]));
+ }
}
- }, this);
+ return rowStates;
+ }
+
+ var states = new Map();
+ for (var i = 0; i < this.rows_.length; ++i) {
+ states.set(i, recurse(this.rows_[i]));
+ }
+ return states;
},
- addDiagnosticSubRows_: function(value, row, column) {
- value.diagnostics.forEach(function(name, diagnostic) {
- if (name === tr.v.SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME)
- return;
+ setExpansionStates_: function(states) {
+ var table = this.$.table;
+ function recurse(row, rowStates) {
+ if (rowStates.expanded) {
+ table.setExpandedForTableRow(row, true);
+ }
- // If a previous |value| had a diagnostic with the same name, then
- // there is already a subRow that should contain this diagnostic.
- for (var subRow of row.subRows) {
- if (subRow.name === name) {
- subRow[column] = diagnostic;
- return;
+ for (var [displayLabel, value] of rowStates.cells) {
+ var cell = row.cells[displayLabel];
+ if (cell) {
+ cell.isHistogramOpen = value;
}
}
+ for (var [key, value] of rowStates.subRows) {
+ var subRow = row.subRows[key];
+ recurse(subRow, value);
+ }
+ }
- // This is the first time that a diagnostic with this name has been
- // seen for Values whose name is |value.name|, so create a new subRow.
- var subRow = {name: name};
- subRow[column] = diagnostic;
- row.subRows.push(subRow);
- });
+ for (var i = 0; i < this.rows_.length; ++i) {
+ var rowStates = states.get(i);
+ if (rowStates === undefined) {
+ continue;
+ }
+ var row = this.rows_[i];
+ recurse(row, rowStates);
+ }
},
- get values() {
- return this.values_;
+ onSearch_: function() {
+ this.updateContents_();
+ },
+
+ rowMatchesSearch_: function(row) {
+ return row.name.indexOf(this.$.search.value) >= 0;
},
- findSummaryValues_: function() {
- this.summaryValues_ = {};
- this.values.map(function(value) {
- var summaryValueMap = value.diagnostics.get(
- tr.v.SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME);
- if (!(summaryValueMap instanceof tr.v.d.RelatedValueMap))
+ onRelatedValueSelected_: function(event) {
+ var value = event.selection;
+ if (!(value instanceof tr.v.Histogram))
+ return;
+
+ event.stopPropagation();
+
+ var displayLabel = getDisplayLabel(value);
+ var columnIndex = -1;
+ for (var i = 0; i < this.columns_.length; ++i) {
+ if (this.columns_[i].title === displayLabel) {
+ columnIndex = i;
+ break;
+ }
+ }
+ if (columnIndex < 0)
+ return;
+
+ var hierarchy = [];
+ var found = false;
+ function search(row) {
+ if (row.columns[displayLabel] === value) {
+ for (var hirow in hierarchy) {
+ this.$.table.setExpandedForTableRow(hirow, true);
+ }
+ found = true;
+ row.cells[displayLabel].isHistogramOpen = true;
+ return;
+ }
+ if (!row.subRows)
return;
+ hierarchy.push(row);
+ row.subRows.forEach(search, this);
+ hierarchy.pop(row);
+ }
+ this.rows_.forEach(search, this);
- summaryValueMap.values.forEach(function(summaryValue) {
- this.summaryValues_[summaryValue.guid] = summaryValue;
- }, this);
- }, this);
+ if (found || this.$.show_all.checked)
+ return;
+
+ // Search hidden values for |value|.
+ for (var test of this.values) {
+ if (test === value) {
+ found = true;
+ this.$.show_all.checked = true;
+ this.onShowAllChange_();
+ this.onRelatedValueSelected_(event);
+ break;
+ }
+ }
+ },
+
+ get values() {
+ return this.values_;
},
/**
@@ -145,171 +526,430 @@ tr.exportTo('tr.ui', function() {
*/
set values(values) {
this.values_ = values;
- this.style.width = '';
- this.$.table.style.display = '';
- this.$.error.textContent = '';
+ this.sourceValues_ = values ? values.sourceValues : new tr.v.ValueSet();
+ this.displayLabels_ = undefined;
+ this.referenceDisplayLabel_ = undefined;
+ this.maybeDisableShowAll_();
+ this.updateContents_();
+ },
- this.handleFailureValues_();
- if (this.$.error.textContent)
- return;
+ get referenceDisplayLabel() {
+ return this.referenceDisplayLabel_;
+ },
- this.findSummaryValues_();
+ set referenceDisplayLabel(reference) {
+ this.referenceDisplayLabel_ = reference;
- /* rows will look something like [
- {name: 'long tasks',
- displayLabelA: Value,
- displayLabelB: Value,
- subRows: [
- {name: 'iteration',
- displayLabelA: Diagnostic,
- displayLabelB: Diagnostic,
- }
- ]
- }
- ]
- TODO(benjhayden): After Values are summarized and merged, there will be
- more row tiers: value name > benchmark name > story name > benchmark
- start > storyset repeat > story repeat > diagnostics.
- */
- var rows = [];
+ if (this.updatingContents_)
+ return;
- // This will be used to sort the columns by start time.
- var startTimesForDisplayLabels = {};
+ this.$.table.selectedTableColumnIndex = this.referenceDisplayLabel ?
+ 1 + this.displayLabels.indexOf(this.referenceDisplayLabel) : undefined;
- tr.b.iterItems(values.organizedByName, function(name, vals) {
- var row = {name: name, subRows: []};
- var isEmptyRow = true;
+ // Force the table to rebuild the cell values without forgetting which
+ // rows were expanded.
+ var expansionStates = this.getExpansionStates_();
+ this.$.table.tableRows = this.rows_;
+ this.setExpansionStates_(expansionStates);
+ },
- vals.forEach(function(val) {
- if (this.summaryValues_[val.guid])
- return;
+ updateReferenceColumnSelector_: function() {
+ Polymer.dom(this.$.reference_column_container).textContent = '';
- if (!row.description && val.description)
- row.description = val.description;
+ if (this.displayLabels.length < 2)
+ return;
- var displayLabel = 'Value';
- var startMs = 0;
- var iteration = val.diagnostics.get(
- tr.v.ITERATION_INFO_DIAGNOSTIC_NAME);
- if (iteration instanceof tr.v.d.IterationInfo) {
- displayLabel = iteration.displayLabel;
- startMs = iteration.benchmarkStart.getTime();
- }
+ var options = [{value: '', label: 'Select a reference column'}];
+ for (var displayLabel of this.displayLabels)
+ options.push({value: displayLabel, label: displayLabel});
- this.addDiagnosticSubRows_(val, row, displayLabel);
+ var settingsKey =
+ 'tr-v-ui-value-set-table-reference-display-label';
+ Polymer.dom(this.$.reference_column_container).appendChild(
+ tr.ui.b.createSelector(
+ this, 'referenceDisplayLabel', settingsKey, '', options));
+ },
- startTimesForDisplayLabels[displayLabel] = Math.min(
- startTimesForDisplayLabels[displayLabel] || 0,
- startMs);
+ updateGroups_: function() {
+ var groups = DEFAULT_POSSIBLE_GROUPS.filter(function(group) {
+ // Remove groups for which there is only one value, except
+ // HISTOGRAM_NAME.
+ if (group.key === tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key)
+ return true;
+
+ var values = new Set();
+ for (var value of this.values_) {
+ value = group.callback(value);
+ if (!value)
+ continue;
+
+ values.add(value);
+ if (values.size > 1)
+ return true;
+ }
+ return false; // Prune this grouping.
+ }, this);
- if (row[displayLabel] !== undefined) {
- console.warn('Multiple Values with same name and displayLabel:',
- name, displayLabel, row[displayLabel], val,
- 'Sorry, only one will be displayed until summarization and ' +
- 'merging are implemented.');
- }
- row[displayLabel] = val;
- isEmptyRow = false;
- }, this);
+ // Add all storyGroupingKey groups for the current values.
+ for (var storyGroupingKey of this.storyGroupingKeys) {
+ groups.push(new tr.v.HistogramGrouping(
+ 'storyGroupingKey_' + storyGroupingKey,
+ makeStoryGroupingKeyLabelGetter(storyGroupingKey),
+ storyGroupingKey));
+ }
- if (isEmptyRow)
- return;
+ // Save and restore current grouping keys in order to let
+ // |set groupingKeys| filter out the keys that are no longer in
+ // possibleGroups.
+ var groupingKeys = this.groupingKeys;
+ this.$.picker.possibleGroups = groups;
+ this.$.picker.currentGroupKeys = groupingKeys;
- rows.push(row);
- }, this);
+ this.$.picker.style.display = (groups.length === 1) ? 'none' : '';
+ },
+
+ updateContents_: function() {
+ if (this.updatingContents_)
+ return;
- if (rows.length === 0) {
- this.$.error.textContent = 'zero values';
- this.$.table.style.display = 'none';
- this.style.width = '10em';
+ if (!this.values_ || (this.values_.length === 0)) {
+ this.$.container.style.display = '';
+ this.$.zero.style.display = '';
return;
}
- this.buildColumns_(startTimesForDisplayLabels);
+ this.updatingContents_ = true;
+
+ this.$.zero.style.display = 'none';
+ this.$.container.style.display = 'block';
+ this.$.table.style.display = '';
+ this.updateReferenceColumnSelector_();
+ this.updateGroups_();
+ this.buildRows_();
+ this.buildColumns_();
this.$.table.tableColumns = this.columns_;
- this.$.table.tableRows = rows;
+ this.$.table.tableRows = this.rows_;
this.$.table.sortColumnIndex = 0;
this.$.table.rebuild();
- this.$.table.selectedTableRow = rows[0];
- this.$.table.selectedColumnIndex = 1;
- tr.b.requestAnimationFrame(function() {
- this.style.width = this.$.table.getBoundingClientRect().width;
- }, this);
+ this.$.table.selectedTableColumnIndex = this.referenceDisplayLabel ?
+ 1 + this.displayLabels.indexOf(this.referenceDisplayLabel) : undefined;
+
+ this.updatingContents_ = false;
},
- buildColumns_: function(startTimesForDisplayLabels) {
- var displayLabels = Object.keys(startTimesForDisplayLabels);
- displayLabels.sort(function(a, b) {
- return startTimesForDisplayLabels[a] - startTimesForDisplayLabels[b];
- });
+ maybeDisableShowAll_: function() {
+ var allValuesAreSource = !this.values ||
+ (this.values.length === this.sourceValues_.length);
+
+ // Disable show_all if all values are sourceValues.
+ // Re-enable show_all if this changes.
+ this.$.show_all.disabled = allValuesAreSource;
+ // Check show_all if it is disabled.
+ // Do not automatically uncheck show_all.
+ if (this.$.show_all.disabled) {
+ this.$.show_all.checked = true;
+ }
+ },
+
+ /**
+ * Build table rows recursively from organized Values. The recursion stack
+ * of subRows is maintained in |hierarchy|.
+ *
+ * @param {!Object} organizedValues
+ * @param {!Array.<!Object>} hierarchy
+ */
+ buildRow_: function(organizedValues, hierarchy) {
+ for (var [name, values] of organizedValues) {
+ if (values instanceof Array) {
+ // This recursion base case corresponds to the recursion base case of
+ // groupHistogramsRecursively(). The last groupingCallback is always
+ // getDisplayLabel, which defines the columns of the table and is
+ // unskippable.
+ for (var value of values) {
+ // Merge Values up the grouping hierarchy.
+ for (var row of hierarchy) {
+ if (!row.description) {
+ row.description = value.description;
+ }
+
+ if (!row.columns[name]) {
+ row.columns[name] = value;
+ continue;
+ }
+ if (row.columns[name] === UNMERGEABLE) {
+ continue;
+ }
+ if (!row.columns[name].canAddHistogram(value)) {
+ row.columns[name] = UNMERGEABLE;
+ continue;
+ }
+
+ // Create a new Histogram with a new uuid instead of cloning
+ // either |value| or |row.columns[name]| so that we don't clone
+ // either Histogram's diagnostics.
+ // |value.name| might not necessarily equal |row.columns[name]|,
+ // but that shouldn't matter for this dom-module.
+ // TODO(eakuefner) When MergedFrom diagnostic lands, only create a
+ // new Histogram if |row.columns[name]| doesn't have it so that we
+ // don't create new Histograms unnecessarily.
+ var merged = value.cloneEmpty();
+ merged.addHistogram(row.columns[name]);
+ merged.addHistogram(value);
+ row.columns[name] = merged;
+ }
+ }
+ } else if (values instanceof Map) {
+ // |values| is actually a nested organizedValues.
+ var row = {name: name, subRows: [], columns: {}, cells: {}};
+ hierarchy.push(row);
+ this.buildRow_(values, hierarchy);
+ hierarchy.pop();
+
+ if (hierarchy.length === 0)
+ this.rows_.push(row);
+ else
+ hierarchy[hierarchy.length - 1].subRows.push(row);
+ }
+ }
+ },
+
+ get storyGroupingKeys() {
+ var keys = new Set();
+ for (var value of this.values) {
+ var iteration = tr.v.d.IterationInfo.getFromValue(value);
+ if (!(iteration instanceof tr.v.d.IterationInfo) ||
+ !iteration.storyGroupingKeys)
+ continue;
+
+ for (var key in iteration.storyGroupingKeys)
+ keys.add(key);
+ }
+ return [...keys.values()].sort();
+ },
+
+ /**
+ * A ValueSet is a flat set of Values. Value-set-table must present a
+ * hierarchical view. This method recursively groups this.values as an
+ * intermediate step towards building tableRows in buildRow_().
+ * {
+ * valueA: {
+ * benchmarkA: {
+ * storyA: {
+ * startA: {
+ * storysetRepeatCounterA: {
+ * storyRepeatCounterA: {
+ * displayLabelA: Value,
+ * displayLabelB: Value
+ * }
+ * }
+ * }
+ * }
+ * }
+ * }
+ * }
+ * @return {!Object}
+ */
+ get organizedValues_() {
+ var showingValueSet = this.$.show_all.checked ?
+ this.values : this.sourceValues_;
+
+ var groupings = this.$.picker.currentGroups.slice();
+ groupings.push(tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL);
+
+ function canSkipGrouping(grouping, groupedHistograms) {
+ // Never skip meaningful groupings.
+ if (groupedHistograms.size > 1)
+ return false;
+
+ // Never skip the zero-th grouping.
+ if (grouping.key === groupings[0].key)
+ return false;
+
+ // Never skip the grouping that defines the table columns.
+ if (grouping.key === tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL.key)
+ return false;
+
+ // Skip meaningless groupings.
+ return true;
+ }
+
+ return showingValueSet.groupHistogramsRecursively(
+ groupings, canSkipGrouping);
+ },
+
+ /* this.rows_ will look something like
+ * [
+ * {
+ * name: 'value name',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'benchmark name if multiple',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'story name if multiple',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'benchmark start if multiple',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'storyset repeat counter if multiple',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'story repeat counter if multiple',
+ * columns: {
+ * displayLabelA: Value,
+ * displayLabelB: Value,
+ * },
+ * subRows: [
+ * {
+ * name: 'diagnostic map key',
+ * columns: {
+ * displayLabelA: Diagnostic,
+ * displayLabelB: Diagnostic,
+ * },
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * ]
+ *
+ * Any of those layers may be missing except 'value name'.
+ */
+ buildRows_: function() {
+ this.rows_ = [];
+ var hierarchy = [];
+ var organizedValues = this.organizedValues_;
+ this.buildRow_(organizedValues, hierarchy);
+ this.rows_ = this.rows_.filter(this.rowMatchesSearch_.bind(this));
+ },
+
+ get startTimesForDisplayLabels() {
+ var startTimesForDisplayLabels = {};
+ for (var value of this.values) {
+ var displayLabel = getDisplayLabel(value);
+ startTimesForDisplayLabels[displayLabel] = Math.min(
+ startTimesForDisplayLabels[displayLabel] || 0,
+ tr.v.d.IterationInfo.getField(
+ value, 'benchmarkStart', new Date(0)).getTime());
+ }
+ return startTimesForDisplayLabels;
+ },
+
+ get displayLabels() {
+ if (this.displayLabels_ === undefined) {
+ var startTimesForDisplayLabels = this.startTimesForDisplayLabels;
+ this.displayLabels_ = Object.keys(startTimesForDisplayLabels);
+ this.displayLabels_.sort(function(a, b) {
+ return startTimesForDisplayLabels[a] - startTimesForDisplayLabels[b];
+ });
+ }
+ return this.displayLabels_;
+ },
+
+ buildColumn_: function(displayLabel) {
+ return {
+ title: displayLabel,
+ align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT,
+
+ value: row => {
+ var cell = document.createElement('tr-v-ui-value-set-table-cell');
+ cell.histogram = row.columns[displayLabel];
+ if (this.referenceDisplayLabel &&
+ this.referenceDisplayLabel !== displayLabel) {
+ cell.referenceHistogram = row.columns[this.referenceDisplayLabel];
+ }
+ row.cells[displayLabel] = cell;
+ return cell;
+ },
+
+ cmp: (rowA, rowB) => {
+ var cellA = rowA.columns[displayLabel];
+ var cellB = rowB.columns[displayLabel];
+ if (!(cellA instanceof tr.v.Histogram) ||
+ !(cellB instanceof tr.v.Histogram)) {
+ return undefined;
+ }
+
+ var valueA = cellA.average;
+ var valueB = cellB.average;
+
+ // If a reference column is selected, compare the absolute deltas
+ // between the two cells and their references.
+ if (this.referenceDisplayLabel &&
+ this.referenceDisplayLabel !== displayLabel) {
+ var referenceCellA = rowA.columns[this.referenceDisplayLabel];
+ var referenceCellB = rowB.columns[this.referenceDisplayLabel];
+ if (referenceCellA instanceof tr.v.Histogram &&
+ referenceCellB instanceof tr.v.Histogram &&
+ cellA.unit === referenceCellA.unit &&
+ cellB.unit === referenceCellB.unit) {
+ valueA -= referenceCellA.average;
+ valueB -= referenceCellB.average;
+ }
+ }
+
+ return valueA - valueB;
+ }
+ };
+ },
+
+ buildColumns_: function() {
this.columns_ = [
{
title: 'Name',
- align: tr.ui.b.TableFormat.ColumnAlignment.LEFT,
value: function(row) {
var nameEl = document.createElement('span');
- nameEl.textContent = row.name;
- if (row.description)
+ Polymer.dom(nameEl).textContent = row.name;
+ if (row.description) {
nameEl.title = row.description;
- nameEl.style.textOverflow = 'ellipsis';
+ }
+ nameEl.style.whiteSpace = 'nowrap';
return nameEl;
},
- cmp: function(rowA, rowB) {
- rowA = rowA ? rowA.name : '';
- rowB = rowB ? rowB.name : '';
- return rowA.localeCompare(rowB);
- },
+ cmp: (a, b) => a.name.localeCompare(b.name)
}
];
- displayLabels.forEach(function(displayLabel) {
- this.columns_.push({
- title: displayLabel,
- align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT,
- supportsCellSelection: true,
-
- value: function(row) {
- var cell = row[displayLabel];
- if (cell instanceof tr.v.d.Diagnostic) {
- return tr.v.ui.createDiagnosticSpan(cell);
- } else if (cell instanceof tr.v.NumericValue) {
- return tr.v.ui.createScalarSpan(cell);
- } else if (cell === undefined) {
- return '';
- } else {
- throw new Error('Invalid cell', cell);
- }
- },
-
- cmp: function(rowA, rowB) {
- var cellA = rowA[displayLabel];
- var cellB = rowB[displayLabel];
- if (!(cellA instanceof tr.v.NumericValue) ||
- !(cellB instanceof tr.v.NumericValue))
- return undefined;
-
- var numericA = cellA.numeric;
- var numericB = cellB.numeric;
-
- var valueA = (numericA instanceof tr.v.ScalarNumeric) ?
- numericA.value : numericA.average;
- var valueB = (numericB instanceof tr.v.ScalarNumeric) ?
- numericB.value : numericB.average;
-
- return valueA - valueB;
- }
- });
- }, this);
+ for (var displayLabel of this.displayLabels) {
+ this.columns_.push(this.buildColumn_(displayLabel));
+ }
}
});
- tr.ui.registerValueSetView('tr-v-ui-value-set-table');
-
return {};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table_test.html
index 5358e8442f3..1b27c8ab5f9 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_table_test.html
@@ -5,6 +5,9 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
+<link rel="import" href="/tracing/base/utils.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
+<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/ui/value_set_table.html">
<link rel="import" href="/tracing/value/value_set.html">
@@ -12,76 +15,530 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var TEST_NUMERIC_BUILDER = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 1000),
- 20);
+ var TEST_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 1e3, 20);
- test('instantiate', function() {
+ function getTableRowAtPath(table, path) {
+ var row = table.tableRows[0];
+ for (var index of path)
+ row = row.subRows[index];
+ return row;
+ }
+
+ test('requestSelectionChange', function() {
var table = document.createElement('tr-v-ui-value-set-table');
var values = new tr.v.ValueSet();
- assert.isTrue(table.supportsValueSet(values));
- var numeric0a = TEST_NUMERIC_BUILDER.build();
- for (var i = 0; i < 1e2; ++i) {
- numeric0a.add(Math.random() * 1000);
- }
- var fooA = new tr.v.NumericValue('foo', numeric0a, {
- description: 'they should have sent a poet'
- });
- values.addValue(fooA);
- fooA.diagnostics.add(
- tr.v.ITERATION_INFO_DIAGNOSTIC_NAME, new tr.v.d.IterationInfo({
- label: 'iteration A',
- benchmarkStartMs: new Date().getTime(),
- }));
-
- var numeric1a = TEST_NUMERIC_BUILDER.build();
- for (var i = 0; i < 1e2; ++i) {
- numeric1a.add(Math.random() * 1000);
- }
- var barA = new tr.v.NumericValue('bar', numeric1a, {
- description: 'indescribable'
- });
- values.addValue(barA);
- barA.diagnostics.add(
- tr.v.ITERATION_INFO_DIAGNOSTIC_NAME, new tr.v.d.IterationInfo({
- label: 'iteration A',
- benchmarkStartMs: new Date().getTime(),
- }));
-
- var numeric0b = TEST_NUMERIC_BUILDER.build();
- for (var i = 0; i < 1e2; ++i) {
- numeric0b.add(Math.random() * 1000);
- }
- var fooB = new tr.v.NumericValue('foo', numeric0b, {
- description: 'they should have sent a poet'
- });
- values.addValue(fooB);
- fooB.diagnostics.add(
- tr.v.ITERATION_INFO_DIAGNOSTIC_NAME, new tr.v.d.IterationInfo({
- label: 'iteration B',
- benchmarkStartMs: new Date().getTime(),
- }));
-
- var numeric1b = TEST_NUMERIC_BUILDER.build();
- for (var i = 0; i < 1e2; ++i) {
- numeric1b.add(Math.random() * 1000);
+ var barHist = new tr.v.Histogram('bar',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ barHist.addSample(1);
+
+ var fooHist = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ fooHist.addSample(1);
+ var breakdown = new tr.v.d.RelatedHistogramBreakdown();
+ breakdown.set('bar', barHist);
+
+ fooHist.diagnostics.set('breakdown', breakdown);
+ values.addHistogram(fooHist);
+ values.addHistogram(barHist);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ var fooCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === fooHist)));
+ assert.isDefined(fooCell);
+
+ var barCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === barHist)));
+ assert.isUndefined(barCell);
+
+ fooCell.isHistogramOpen = true;
+
+ var barLink = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.tagName === 'TR-UI-A-ANALYSIS-LINK');
+ assert.isDefined(barLink);
+ barLink.click();
+
+ barCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === barHist)));
+ assert.isDefined(barCell);
+ });
+
+ test('search', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var barHist = new tr.v.Histogram('bar',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ barHist.addSample(1);
+
+ var fooHist = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ fooHist.addSample(1);
+
+ values.addHistogram(fooHist);
+ values.addHistogram(barHist);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ var search = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.id === 'search');
+ search.value = 'bar';
+
+ var fooCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === fooHist)));
+ assert.isDefined(fooCell);
+
+ var barCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === barHist)));
+ assert.isDefined(barCell);
+
+ var search = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.id === 'search');
+
+ search.value = 'bar';
+ table.onSearch_();
+
+ fooCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === fooHist)));
+ assert.isUndefined(fooCell);
+
+ barCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === barHist)));
+ assert.isDefined(barCell);
+
+ search.value = 'foo';
+ table.onSearch_();
+
+ fooCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === fooHist)));
+ assert.isDefined(fooCell);
+
+ barCell = tr.b.findDeepElementMatchingPredicate(
+ table, elem => (
+ (elem.tagName === 'TR-V-UI-VALUE-SET-TABLE-CELL') &&
+ (elem.histogram === barHist)));
+ assert.isUndefined(barCell);
+ });
+
+ test('implicitUndefinedValues', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ this.addHTMLOutput(table);
+ assert.strictEqual('block', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'zero values')).display);
+ assert.strictEqual('none', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.id === 'container')).display);
+ });
+
+ test('explicitUndefinedValues', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ table.values = undefined;
+ this.addHTMLOutput(table);
+ assert.strictEqual('block', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'zero values')).display);
+ assert.strictEqual('none', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.id === 'container')).display);
+ });
+
+ test('emptyValues', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+ table.values = values;
+ this.addHTMLOutput(table);
+ assert.strictEqual('block', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'zero values')).display);
+ assert.strictEqual('none', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.id === 'container')).display);
+ });
+
+ test('shortName', function() {
+ // One value has |name|='long name' and |shortName|='short name',
+ // another value has |name|='short name' to demonstrate the fundamental
+ // ambiguity that arises when Values can have multiple different "names".
+
+ var now = new Date().getTime();
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var histA = new tr.v.Histogram('long name',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ histA.addSample(Math.random() * 1e3);
+ histA.shortName = 'short name';
+ new tr.v.d.IterationInfo({
+ label: 'iteration A',
+ benchmarkStartMs: now,
+ }).addToValue(histA);
+ values.addHistogram(histA);
+
+ var histB = new tr.v.Histogram('short name',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ histB.addSample(Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'iteration B',
+ benchmarkStartMs: now,
+ }).addToValue(histB);
+ values.addHistogram(histB);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ assert.strictEqual('none', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'zero values')).display);
+ assert.strictEqual('block', getComputedStyle(
+ tr.b.findDeepElementMatchingPredicate(
+ table, e => e.id === 'container')).display);
+ assert.isDefined(tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'short name'));
+ assert.isUndefined(tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === 'long name'));
+ });
+
+ test('emptyAndMissing', function() {
+ var now = new Date().getTime();
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var histA = new tr.v.Histogram('histogram A',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ histA.addSample(Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'iteration A',
+ benchmarkStartMs: now,
+ }).addToValue(histA);
+ values.addHistogram(histA);
+
+ var histB = new tr.v.Histogram('histogram B',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ histB.addSample(Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'iteration B',
+ benchmarkStartMs: now,
+ }).addToValue(histB);
+ values.addHistogram(histB);
+
+ var histC = new tr.v.Histogram('histogram A',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ new tr.v.d.IterationInfo({
+ label: 'iteration B',
+ benchmarkStartMs: now,
+ }).addToValue(histC);
+ values.addHistogram(histC);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ assert.isDefined(tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === '(empty)'));
+ assert.isDefined(tr.b.findDeepElementMatchingPredicate(
+ table, e => e.textContent === '(missing)'));
+ });
+
+ test('instantiate_1x1', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var hist = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ hist.addSample(Math.random() * 1e3);
+ values.addHistogram(hist);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ var baseTable = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.tagName === 'TR-UI-B-TABLE');
+ assert.strictEqual(baseTable.tableRows.length, 1);
+ });
+
+ test('merge_unmergeable', function() {
+ var now = new Date().getTime();
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var histA = new tr.v.Histogram('histogram A',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ histA.addSample(Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'Value',
+ benchmarkStartMs: now,
+ storyDisplayName: 'story A'
+ }).addToValue(histA);
+ values.addHistogram(histA);
+
+ var histB = new tr.v.Histogram('histogram B',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createExponential(1e-3, 1e3, 20));
+ for (var i = 0; i < 100; ++i)
+ histB.addSample(Math.random() * Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'Value',
+ benchmarkStartMs: now,
+ storyDisplayName: 'story A'
+ }).addToValue(histB);
+ values.addHistogram(histB);
+
+ var histC = new tr.v.Histogram('histogram C',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ tr.v.HistogramBinBoundaries.createExponential(1e-3, 1e3, 30));
+ for (var i = 0; i < 100; ++i)
+ histC.addSample(Math.random() * Math.random() * 1e3);
+ new tr.v.d.IterationInfo({
+ label: 'Value',
+ benchmarkStartMs: now,
+ storyDisplayName: 'story B'
+ }).addToValue(histC);
+ values.addHistogram(histC);
+
+ table.values = values;
+ table.groupingKeys = [tr.v.ValueSet.GROUPINGS.STORY_NAME.key];
+ this.addHTMLOutput(table);
+
+ var baseTable = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.tagName === 'TR-UI-B-TABLE');
+ assert.strictEqual(baseTable.tableRows.length, 2);
+ });
+
+ test('instantiate_2x2', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+
+ var numeric0a = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ numeric0a.addSample(Math.random() * 1e3);
+ values.addHistogram(numeric0a);
+ new tr.v.d.IterationInfo({
+ label: 'iteration A',
+ benchmarkStartMs: new Date().getTime(),
+ }).addToValue(numeric0a);
+
+ var numeric1a = new tr.v.Histogram('bar',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ numeric1a.addSample(Math.random() * 1e3);
+ values.addHistogram(numeric1a);
+ new tr.v.d.IterationInfo({
+ label: 'iteration A',
+ benchmarkStartMs: new Date().getTime(),
+ }).addToValue(numeric1a);
+
+ var numeric0b = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ numeric0b.addSample(Math.random() * 1e3);
+ values.addHistogram(numeric0b);
+ new tr.v.d.IterationInfo({
+ label: 'iteration B',
+ benchmarkStartMs: new Date().getTime(),
+ }).addToValue(numeric0b);
+
+ var numeric1b = new tr.v.Histogram('bar',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i)
+ numeric1b.addSample(Math.random() * 1e3);
+ values.addHistogram(numeric1b);
+ new tr.v.d.IterationInfo({
+ label: 'iteration B',
+ benchmarkStartMs: new Date().getTime(),
+ }).addToValue(numeric1b);
+
+ table.values = values;
+ this.addHTMLOutput(table);
+
+ var baseTable = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.tagName === 'TR-UI-B-TABLE');
+
+ assert.lengthOf(baseTable.tableColumns, 3);
+ assert.strictEqual('Name', baseTable.tableColumns[0].title);
+ assert.strictEqual('iteration A',
+ baseTable.tableColumns[1].title);
+ assert.strictEqual('iteration B',
+ baseTable.tableColumns[2].title);
+
+ table.referenceDisplayLabel = 'iteration A';
+ baseTable.rebuild();
+ assert.strictEqual(1, baseTable.selectedTableColumnIndex);
+ assert.strictEqual(table.rows_[0].cells['iteration B'].referenceHistogram,
+ table.rows_[0].cells['iteration A'].histogram);
+ assert.strictEqual(table.rows_[1].cells['iteration B'].referenceHistogram,
+ table.rows_[1].cells['iteration A'].histogram);
+
+ table.referenceDisplayLabel = 'iteration B';
+ baseTable.rebuild();
+ assert.strictEqual(2, baseTable.selectedTableColumnIndex);
+ assert.strictEqual(table.rows_[0].cells['iteration A'].referenceHistogram,
+ table.rows_[0].cells['iteration B'].histogram);
+ assert.strictEqual(table.rows_[1].cells['iteration A'].referenceHistogram,
+ table.rows_[1].cells['iteration B'].histogram);
+ });
+
+ test('instantiation_mergeNumerics', function() {
+ var table = document.createElement('tr-v-ui-value-set-table');
+ var values = new tr.v.ValueSet();
+ // Add 64 Histograms, all named 'foo', with different IterationInfos.
+ var benchmarkNames = ['bm A', 'bm B'];
+ var storyGroupingKeys0 = ['A', 'B'];
+ var storyGroupingKeys1 = ['C', 'D'];
+ var storyNames = ['story A', 'story B'];
+ var starts = [1439708400000, 1439794800000];
+ var labels = ['label A', 'label B'];
+
+ for (var benchmarkName of benchmarkNames) {
+ for (var storyGroupingKey0 of storyGroupingKeys0) {
+ for (var storyGroupingKey1 of storyGroupingKeys1) {
+ for (var storyName of storyNames) {
+ for (var startMs of starts) {
+ for (var storysetCounter = 0; storysetCounter < 2;
+ ++storysetCounter) {
+ for (var storyCounter = 0; storyCounter < 2; ++storyCounter) {
+ for (var label of labels) {
+ var numeric = new tr.v.Histogram('foo',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ TEST_BOUNDARIES);
+ for (var i = 0; i < 100; ++i) {
+ numeric.addSample(Math.random() * 1e3, {
+ sample_diagnostic: new tr.v.d.Generic(i)});
+ }
+
+ values.addHistogram(numeric);
+
+ new tr.v.d.IterationInfo({
+ storyGroupingKeys: {
+ storyGroupingKey0: storyGroupingKey0,
+ storyGroupingKey1: storyGroupingKey1
+ },
+ benchmarkName: benchmarkName,
+ storyDisplayName: storyName,
+ benchmarkStartMs: startMs,
+ storysetRepeatCounter: storysetCounter,
+ storyRepeatCounter: storyCounter,
+ label: label,
+ }).addToValue(numeric);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
- var barB = new tr.v.NumericValue('bar', numeric1b, {
- description: 'indescribable'
- });
- values.addValue(barB);
- barB.diagnostics.add(
- tr.v.ITERATION_INFO_DIAGNOSTIC_NAME, new tr.v.d.IterationInfo({
- label: 'iteration B',
- benchmarkStartMs: new Date().getTime(),
- }));
table.values = values;
+ table.groupingKeys = [
+ tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key,
+ tr.v.ValueSet.GROUPINGS.BENCHMARK_NAME.key,
+ 'storyGroupingKey_storyGroupingKey0',
+ 'storyGroupingKey_storyGroupingKey1',
+ tr.v.ValueSet.GROUPINGS.STORY_NAME.key,
+ tr.v.ValueSet.GROUPINGS.BENCHMARK_START.key,
+ tr.v.ValueSet.GROUPINGS.STORYSET_REPEAT.key,
+ tr.v.ValueSet.GROUPINGS.STORY_REPEAT.key,
+ ];
this.addHTMLOutput(table);
- // XXX test multi-col
- // XXX test selection
- // XXX test sorting by name, valueA, valueB
+ var baseTable = tr.b.findDeepElementMatchingPredicate(
+ table, elem => elem.tagName === 'TR-UI-B-TABLE');
+
+ assert.lengthOf(baseTable.tableColumns, 3);
+ assert.strictEqual('Name', baseTable.tableColumns[0].title);
+ assert.strictEqual('label A', baseTable.tableColumns[1].title);
+ assert.strictEqual('label B', baseTable.tableColumns[2].title);
+
+ assert.lengthOf(baseTable.tableRows, 1);
+ assert.strictEqual('foo', baseTable.tableRows[0].name);
+ assert.lengthOf(baseTable.tableRows[0].subRows, 2);
+
+ // assertions only report their arguments, which is not enough information
+ // to diagnose problems with nested structures like tableRows -- the path to
+ // the particular row is needed. This code would be a bit simpler if each
+ // row were given a named variable, but the path to each subRow would still
+ // need to be tracked in order to provide for diagnosing.
+ var subRowPath = [];
+ var getSubRow = () => getTableRowAtPath(baseTable, subRowPath);
+
+ for (var i = 0; i < benchmarkNames.length; ++i) {
+ subRowPath.push(i);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual(benchmarkNames[i], getSubRow().name, subRowPath);
+
+ for (var s = 0; s < storyGroupingKeys0.length; ++s) {
+ subRowPath.push(s);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual('storyGroupingKey0: ' + storyGroupingKeys0[s],
+ getSubRow().name, subRowPath);
+
+ for (var t = 0; t < storyGroupingKeys1.length; ++t) {
+ subRowPath.push(t);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual('storyGroupingKey1: ' + storyGroupingKeys1[t],
+ getSubRow().name, subRowPath);
+
+ for (var j = 0; j < storyNames.length; ++j) {
+ subRowPath.push(j);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual(storyNames[j], getSubRow().name, subRowPath);
+
+ for (var k = 0; k < starts.length; ++k) {
+ subRowPath.push(k);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual(tr.b.formatDate(new Date(starts[k])),
+ getSubRow().name, subRowPath);
+
+ for (var l = 0; l < 2; ++l) {
+ subRowPath.push(l);
+ assert.lengthOf(getSubRow().subRows, 2, subRowPath);
+ assert.strictEqual('storyset repeat ' + l, getSubRow().name,
+ subRowPath);
+
+ for (var m = 0; m < 2; ++m) {
+ subRowPath.push(m);
+ assert.lengthOf(getSubRow().subRows, 0, subRowPath);
+ assert.strictEqual('story repeat ' + m, getSubRow().name,
+ subRowPath);
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
+ subRowPath.pop();
+ }
});
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view.html b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view.html
index 9a773957e74..95cdbb76c30 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view.html
@@ -5,83 +5,205 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
-<link rel="import" href="/tracing/ui/base/polymer_utils.html">
<link rel="import" href="/tracing/ui/base/tab_view.html">
+<link rel="import" href="/tracing/ui/brushing_state_controller.html">
+<link rel="import" href="/tracing/value/ui/value_set_table.html">
-<polymer-element name='tr-v-ui-value-set-view'>
+<dom-module id="tr-v-ui-value-set-view">
<template>
- <tr-ui-a-tab-view id="container"></tr-ui-a-tab-view>
+ <style>
+ :host {
+ font-family: sans-serif;
+ };
+ </style>
+
+ <tr-v-ui-value-set-table id="valueSetTable"></tr-v-ui-value-set-table>
</template>
-</polymer-element>
+</dom-module>
<script>
'use strict';
-tr.exportTo('tr.ui', function() {
- var VALUE_SET_VIEW_ELEMENT_NAMES = [];
+tr.exportTo('tr.v.ui', function() {
+ function NullBrushingStateController() {
+ this.parentController = undefined;
+ }
- var SELECTED_TAB_SETTINGS_KEY = 'tr-v-ui-value-set-view-element-name';
+ NullBrushingStateController.prototype = {
+ __proto__: tr.c.BrushingStateController.prototype,
- Polymer('tr-v-ui-value-set-view', {
- ready: function() {
- this.$.container.addEventListener(
- 'selected-tab-change', this.onSelectedTabChange_.bind(this));
+ dispatchChangeEvent_: function() {
+ if (this.parentController)
+ this.parentController.dispatchChangeEvent_();
},
- onSelectedTabChange_: function() {
- if (!this.$.container.selectedTab)
- return;
+ get model() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.model;
+ },
- tr.b.Settings.set(
- SELECTED_TAB_SETTINGS_KEY,
- this.$.container.selectedTab.tagName.toLowerCase());
+ get trackView() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.trackView;
},
- /**
- * @param {!tr.v.ValueSet} values
- */
- set values(values) {
- this.$.container.textContent = '';
+ get viewport() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.viewport;
+ },
- var initialTabElementName = tr.b.Settings.get(
- SELECTED_TAB_SETTINGS_KEY, undefined);
+ get historyEnabled() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.historyEnabled;
+ },
+
+ set historyEnabled(historyEnabled) {
+ if (this.parentController)
+ this.parentController.historyEnabled = historyEnabled;
+ },
- VALUE_SET_VIEW_ELEMENT_NAMES.forEach(function(elementName, index) {
- var view = document.createElement(elementName);
- if (!view.supportsValueSet(values))
- return;
+ modelWillChange: function() {
+ if (this.parentController)
+ this.parentController.modelWillChange();
+ },
- view.values = values;
+ modelDidChange: function() {
+ if (this.parentController)
+ this.parentController.modelDidChange();
+ },
- if (elementName.toLowerCase() === initialTabElementName)
- view.setAttribute('selected', true);
+ onUserInitiatedSelectionChange_: function() {
+ if (this.parentController)
+ this.parentController.onUserInitiatedSelectionChange_();
+ },
- view.setAttribute('tab-label', view.tabLabel);
+ onPopState_: function(e) {
+ if (this.parentController)
+ this.parentController.onPopState_(e);
+ },
- this.$.container.appendChild(view);
- }, this);
+ get selection() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.selection;
+ },
- if (this.$.container.children.length === 1) {
- this.$.container.tabsHidden = true;
- } else if (this.$.container.selectedTab === undefined) {
- this.$.container.children[0].setAttribute('selected', true);
+ get findMatches() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.findMatches;
+ },
+
+ get selectionOfInterest() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.selectionOfInterest;
+ },
+
+ get currentBrushingState() {
+ if (!this.parentController)
+ return undefined;
+ return this.parentController.currentBrushingState;
+ },
+
+ set currentBrushingState(newBrushingState) {
+ if (this.parentController)
+ this.parentController.currentBrushingState = newBrushingState;
+ },
+
+ addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) {
+ if (this.parentController) {
+ this.parentController.addAllEventsMatchingFilterToSelectionAsTask(
+ filter, selection);
}
- }
- });
+ },
+
+ findTextChangedTo: function(allPossibleMatches) {
+ if (this.parentController)
+ this.parentController.findTextChangedTo(allPossibleMatches);
+ },
- /**
- * Register the name of a polymer element that supports displaying ValueSets.
- *
- * @param {string} elementName
- */
- function registerValueSetView(elementName) {
- if (!tr.ui.b.getPolymerElementNamed(elementName))
- throw new Error('Element not registered: ' + elementName);
+ findFocusChangedTo: function(currentFocus) {
+ if (this.parentController)
+ this.parentController.findFocusChangedTo(currentFocus);
+ },
- VALUE_SET_VIEW_ELEMENT_NAMES.push(elementName);
- }
+ findTextCleared: function() {
+ if (this.parentController)
+ this.parentController.findTextCleared();
+ },
- return {
- registerValueSetView: registerValueSetView
+ uiStateFromString: function(string) {
+ if (this.parentController)
+ this.parentController.uiStateFromString(string);
+ },
+
+ navToPosition: function(uiState, showNavLine) {
+ if (this.parentController)
+ this.parentController.navToPosition(uiState, showNavLine);
+ },
+
+ changeSelectionFromTimeline: function(selection) {
+ if (this.parentController)
+ this.parentController.changeSelectionFromTimeline(selection);
+ },
+
+ showScriptControlSelection: function(selection) {
+ if (this.parentController)
+ this.parentController.showScriptControlSelection(selection);
+ },
+
+ changeSelectionFromRequestSelectionChangeEvent: function(selection) {
+ if (this.parentController) {
+ this.parentController.changeSelectionFromRequestSelectionChangeEvent(
+ selection);
+ }
+ },
+
+ changeAnalysisViewRelatedEvents: function(eventSet) {
+ if (this.parentController && (eventSet instanceof tr.model.EventSet))
+ this.parentController.changeAnalysisViewRelatedEvents(eventSet);
+ },
+
+ changeAnalysisLinkHoveredEvents: function(eventSet) {
+ if (this.parentController && (eventSet instanceof tr.model.EventSet))
+ this.parentController.changeAnalysisLinkHoveredEvents(eventSet);
+ },
+
+ getViewSpecificBrushingState: function(viewId) {
+ if (this.parentController)
+ this.parentController.getViewSpecificBrushingState(viewId);
+ },
+
+ changeViewSpecificBrushingState: function(viewId, newState) {
+ if (this.parentController)
+ this.parentController.changeViewSpecificBrushingState(viewId, newState);
+ }
};
+
+ Polymer({
+ is: 'tr-v-ui-value-set-view',
+
+ ready: function() {
+ this.brushingStateController = new NullBrushingStateController();
+ },
+
+ attached: function() {
+ this.brushingStateController.parentController =
+ tr.c.BrushingStateController.getControllerForElement(this.parentNode);
+ },
+
+ /**
+ * @param {!tr.v.ValueSet} values
+ */
+ set values(values) {
+ this.$.valueSetTable.values = values;
+ }
+ });
+
+ return {};
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view_test.html
new file mode 100644
index 00000000000..a1c0301a018
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing/value/ui/value_set_view_test.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/value/histogram.html">
+<link rel="import" href="/tracing/value/ui/value_set_table.html">
+<link rel="import" href="/tracing/value/ui/value_set_view.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('instantiate0', function() {
+ var view = document.createElement('tr-v-ui-value-set-view');
+ var values = new tr.v.ValueSet();
+
+ var hist = new tr.v.Histogram('foo', tr.b.Unit.byName.normalizedPercentage);
+ for (var i = 0; i < 1e2; ++i)
+ hist.addSample(Math.random());
+ values.addHistogram(hist);
+
+ this.addHTMLOutput(view);
+ view.values = values;
+ });
+});
+</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/value.html b/chromium/third_party/catapult/tracing/tracing/value/value.html
deleted file mode 100644
index 9b9c79052fb..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/value/value.html
+++ /dev/null
@@ -1,232 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2015 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/guid.html">
-<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/base/utils.html">
-<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
-
-<script>
-'use strict';
-
-tr.exportTo('tr.v', function() {
- /** @constructor */
- function Value(name, opt_options) {
- if (typeof(name) !== 'string')
- throw new Error('name must be a string');
-
- this.name_ = name;
-
- // If this Value is being deserialized, then its guid will be set by
- // fromDict().
- // If this Value is being computed by a metric, then its guid will be
- // allocated the first time the guid is gotten by asDict().
- this.guid_ = undefined;
-
- this.diagnostics = new tr.v.d.DiagnosticMap();
-
- var options = opt_options || {};
- this.description = options.description;
- this.important = options.important !== undefined ?
- options.important : false;
- }
-
- Value.fromDict = function(d) {
- var value = undefined;
- switch (d.type) {
- case 'numeric':
- value = NumericValue.fromDict(d);
- break;
-
- case 'dict':
- value = DictValue.fromDict(d);
- break;
-
- case 'failure':
- value = FailureValue.fromDict(d);
- break;
-
- case 'skip':
- value = SkipValue.fromDict(d);
- break;
-
- default:
- throw new Error('Not implemented');
- }
-
- value.guid = d.guid;
- value.diagnostics.addDicts(d.diagnostics);
- return value;
- };
-
- Value.prototype = {
- get guid() {
- if (this.guid_ === undefined)
- this.guid_ = tr.b.GUID.allocateUUID4();
-
- return this.guid_;
- },
-
- set guid(guid) {
- if (this.guid_ !== undefined)
- throw new Error('Cannot reset guid');
-
- this.guid_ = guid;
- },
-
- get name() {
- return this.name_;
- },
-
- asDict: function() {
- return this.asJSON();
- },
-
- asJSON: function() {
- var d = {
- guid: this.guid,
- name: this.name_,
- description: this.description,
- important: this.important,
- diagnostics: this.diagnostics.asDict()
- };
-
- this.asDictInto_(d);
- if (d.type === undefined)
- throw new Error('asDictInto_ must set type field');
- return d;
- },
-
- asDictInto_: function(d) {
- throw new Error('Not implemented');
- }
- };
-
- /** @constructor */
- function NumericValue(name, numeric, opt_options) {
- if (!(numeric instanceof tr.v.NumericBase))
- throw new Error('Expected numeric to be instance of tr.v.NumericBase');
-
- Value.call(this, name, opt_options);
- this.numeric = numeric;
- }
-
- NumericValue.fromDict = function(d) {
- if (d.numeric === undefined)
- throw new Error('Expected numeric to be provided');
- var numeric = tr.v.NumericBase.fromDict(d.numeric);
- var value = new NumericValue(d.name, numeric, d);
- return value;
- };
-
- NumericValue.prototype = {
- __proto__: Value.prototype,
-
- asDictInto_: function(d) {
- d.type = 'numeric';
- d.numeric = this.numeric.asDict();
- }
- };
-
- /** @constructor */
- function DictValue(name, value, opt_options) {
- Value.call(this, name, opt_options);
- this.value = value;
- }
-
- DictValue.fromDict = function(d) {
- if (d.units !== undefined)
- throw new Error('Expected units to be undefined');
- if (d.value === undefined)
- throw new Error('Expected value to be provided');
- var value = new DictValue(d.name, d.value, d);
- return value;
- };
-
- DictValue.prototype = {
- __proto__: Value.prototype,
-
- asDictInto_: function(d) {
- d.type = 'dict';
- d.value = this.value;
- }
- };
-
- /** @constructor */
- function FailureValue(name, opt_options) {
- var options = opt_options || {};
-
- var stack;
- if (options.stack === undefined) {
- if (options.stack_str === undefined) {
- throw new Error('Expected stack_str or stack to be provided');
- } else {
- stack = options.stack_str;
- }
- } else {
- stack = options.stack;
- }
-
- if (typeof stack !== 'string')
- throw new Error('stack must be provided as a string');
-
- Value.call(this, name, options);
- this.stack = stack;
- }
-
- FailureValue.fromError = function(e) {
- var ex = tr.b.normalizeException(e);
- return new FailureValue(ex.typeName, {
- description: ex.message, stack: ex.stack});
- };
-
- FailureValue.fromDict = function(d) {
- if (d.units !== undefined)
- throw new Error('Expected units to be undefined');
- if (d.stack_str === undefined)
- throw new Error('Expected stack_str to be provided');
- return new FailureValue(d.name, d);
- };
-
- FailureValue.prototype = {
- __proto__: Value.prototype,
-
- asDictInto_: function(d) {
- d.type = 'failure';
- d.stack_str = this.stack;
- }
- };
-
- /** @constructor */
- function SkipValue(name, opt_options) {
- Value.call(this, name, opt_options);
- }
-
- SkipValue.fromDict = function(d) {
- if (d.units !== undefined)
- throw new Error('Expected units to be undefined');
- return new SkipValue(d.name, d);
- };
-
- SkipValue.prototype = {
- __proto__: Value.prototype,
-
- asDictInto_: function(d) {
- d.type = 'skip';
- }
- };
-
-
- return {
- Value: Value,
- NumericValue: NumericValue,
- DictValue: DictValue,
- FailureValue: FailureValue,
- SkipValue: SkipValue
- };
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/value_set.html b/chromium/third_party/catapult/tracing/tracing/value/value_set.html
index fe33b1fe898..c2874747f19 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/value_set.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/value_set.html
@@ -6,67 +6,66 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
+<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.v', function() {
- var SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME = 'summary values';
- var ITERATION_INFO_DIAGNOSTIC_NAME = 'iteration';
+ /*
+ * See ValueSet.groupHistogramsRecursively() and
+ * tr-ui-b-grouping-table-groupby-picker.
+ */
+ class HistogramGrouping {
+ /**
+ * @param {string} key
+ * @param {!function(!tr.v.Histogram):string} callback
+ * @param {string=} opt_label
+ */
+ constructor(key, callback, opt_label) {
+ this.key = key;
+ this.callback = callback;
+ this.label = opt_label || key;
+ }
+ }
- function ValueSet(opt_values) {
- this.values_ = {};
+ class ValueSet {
+ constructor(opt_values) {
+ this.values_ = new Map();
- if (opt_values !== undefined)
- opt_values.forEach(this.addValue, this);
- }
+ if (opt_values !== undefined)
+ for (var value of opt_values)
+ this.addHistogram(value);
+ }
- ValueSet.prototype = {
get valueDicts() {
- return this.map(function(v) {
- return v.asDict();
- });
- },
+ return this.map(v => v.asDict());
+ }
- lookup: function(guid) {
- return this.values_[guid];
- },
+ lookup(guid) {
+ return this.values_.get(guid);
+ }
- /**
- * @param {!function(!tr.v.Value):*} callback
- * @param {*=} opt_this
- */
- map: function(callback, opt_this) {
- return tr.b.dictionaryValues(this.values_).map(
- callback, opt_this || this);
- },
+ get length() {
+ return this.values_.size;
+ }
- get organizedByName() {
- return this.getValuesOrganizedByCallback(function(value) {
- return value.name;
- });
- },
+ toArray() {
+ return [...this];
+ }
+
+ *[Symbol.iterator]() {
+ for (var [guid, value] of this.values_)
+ yield value;
+ }
/**
- * @param {!function(!tr.v.Value):*} callback
+ * @param {!function(!tr.v.Histogram):*} callback
* @param {*=} opt_this
- * @return {!Object}
*/
- getValuesOrganizedByCallback: function(callback, opt_this) {
- var valuesByCallback = {};
- tr.b.iterItems(this.values_, function(guid, value) {
- var key = callback.call(opt_this || this, value);
- if (key === undefined)
- return;
- if (valuesByCallback[key] === undefined)
- valuesByCallback[key] = [];
- valuesByCallback[key].push(value);
- });
- return valuesByCallback;
- },
+ map(callback, opt_this) {
+ return this.toArray().map(callback, opt_this || this);
+ }
/**
* Convert Values from dicts and add them.
@@ -74,11 +73,9 @@ tr.exportTo('tr.v', function() {
*
* @param {Array.<Object>} dicts
*/
- addValuesFromDicts: function(dicts) {
- dicts.forEach(function(dict) {
- var value = tr.v.Value.fromDict(dict);
- this.addValue(value);
- }, this);
+ addValuesFromDicts(dicts) {
+ for (var dict of dicts)
+ this.addHistogram(tr.v.Histogram.fromDict(dict));
// Now resolve the RelatedValueSet references between values.
// This resolution process must wait until all new values are added in
@@ -88,81 +85,146 @@ tr.exportTo('tr.v', function() {
// The expected running time is this: for each value (hundreds to
// thousands?), for each diagnostic that is a RelatedValueSet (0-5?), for
// each ValueRef (0-10?), do a hash lookup (constant time?).
- tr.b.iterItems(this.values_, function(guid, value) {
- value.diagnostics.forEach(function(name, diagnostic) {
+ for (var value of this) {
+ for (var [name, diagnostic] of value.diagnostics) {
if ((diagnostic instanceof tr.v.d.RelatedValueSet) ||
- (diagnostic instanceof tr.v.d.RelatedValueMap))
+ (diagnostic instanceof tr.v.d.RelatedValueMap)) {
diagnostic.resolve(this);
- }, this);
- }, this);
- },
+ }
+ }
+
+ // In addition to Values, we must also look inside of Histogram samples.
+ for (var bin of value.allBins) {
+ for (var dm of bin.diagnosticMaps) {
+ for (var [name, diagnostic] of dm) {
+ if ((diagnostic instanceof tr.v.d.RelatedValueSet) ||
+ (diagnostic instanceof tr.v.d.RelatedValueMap)) {
+ diagnostic.resolve(this);
+ }
+ }
+ }
+ }
+ }
+ }
/**
* Find the Values that are not contained in any other Values'
* RelatedValueSet or RelatedValueMap diagnostics.
*
- * @return {!Array.<!tr.v.Value>}
+ * @return {!Array.<!tr.v.Histogram>}
*/
get sourceValues() {
- var sourceValues = tr.b.cloneDictionary(this.values_);
- // If a Value is in a RelatedValueSet or RelatedValueMap, then it is not a
- // source Value.
- this.map(function(value) {
- value.diagnostics.forEach(function(name, diagnostic) {
- if ((diagnostic instanceof tr.v.d.RelatedValueSet) ||
- (diagnostic instanceof tr.v.d.RelatedValueMap)) {
- diagnostic.values.forEach(function(relatedValue) {
- delete sourceValues[relatedValue.guid];
- });
+ var sourceValues = new Map(this.values_);
+ // If a Histogram is in a RelatedValueSet or RelatedValueMap, which can be
+ // owned either by Values or by numeric samples, then it is not a
+ // source Histogram.
+ function deleteSourceValues(diagnosticMap) {
+ for (var [name, diagnostic] of diagnosticMap) {
+ if (diagnostic instanceof tr.v.d.RelatedValueSet)
+ for (var relatedValue of diagnostic)
+ sourceValues.delete(relatedValue.guid);
+ else if (diagnostic instanceof tr.v.d.RelatedValueMap)
+ for (var [name, relatedValue] of diagnostic)
+ sourceValues.delete(relatedValue.guid);
+ }
+ }
+
+ for (var hist of this) {
+ deleteSourceValues(hist.diagnostics);
+ for (var b of hist.allBins) {
+ for (var dm of b.diagnosticMaps) {
+ deleteSourceValues(dm);
}
- }, this);
- }, this);
- return tr.b.dictionaryValues(sourceValues);
- },
-
- getValuesWithName: function(name) {
- return tr.b.dictionaryValues(this.values_).filter(function(value) {
- return value.name.indexOf(name) > -1;
- });
- },
-
- addValue: function(v) {
- if (this.values_[v.guid]) {
- var err = new Error('Tried to add same value twice');
- err.name = 'ValueError';
- throw err;
+ }
}
+ return new ValueSet([...sourceValues.values()]);
+ }
+
+ getValuesNamed(name) {
+ return this.toArray().filter(h => h.name === name);
+ }
+
+ /**
+ * @param {!tr.v.Histogram} h
+ */
+ addHistogram(h) {
+ if (this.values_.get(h.guid))
+ throw new Error('Cannot add same Histogram twice');
- this.values_[v.guid] = v;
+ this.values_.set(h.guid, h);
+ }
- if (v.numeric instanceof tr.v.Numeric) {
- ValueSet.computeSummaryValuesForNumericValue(v).forEach(function(s) {
- this.addValue(s);
- }, this);
+ /**
+ * Return a nested Map, whose keys are strings and leaf values are Arrays of
+ * Histograms.
+ * See GROUPINGS for example |groupings|.
+ * Groupings are skipped when |opt_skipGroupingCallback| is specified and
+ * returns true.
+ *
+ * @typedef {!Array.<tr.v.Histogram>} HistogramArray
+ * @typedef {!Map.<string,!(HistogramArray|HistogramArrayMap)>}
+ * HistogramArrayMap
+ * @typedef {!Map.<string,!HistogramArray>} LeafHistogramArrayMap
+ *
+ * @param {!Array.<!tr.v.HistogramGrouping>} groupings
+ * @param {!function(!Grouping, !LeafHistogramArrayMap):boolean=}
+ * opt_skipGroupingCallback
+ *
+ * @return {!(HistogramArray|HistogramArrayMap)}
+ */
+ groupHistogramsRecursively(groupings, opt_skipGroupingCallback) {
+ function recurse(histograms, level) {
+ if (level === groupings.length) {
+ return histograms; // recursion base case
+ }
+
+ var grouping = groupings[level]
+ var groupedHistograms = tr.b.groupIntoMap(
+ histograms, grouping.callback);
+
+ if (opt_skipGroupingCallback && opt_skipGroupingCallback(
+ grouping, groupedHistograms)) {
+ return recurse(histograms, level + 1);
+ }
+
+ for (var [key, group] of groupedHistograms) {
+ groupedHistograms.set(key, recurse(group, level + 1));
+ }
+
+ return groupedHistograms;
}
+
+ return recurse(this.toArray(), 0);
}
- };
+ }
+
+ // This does not contain storyGroupingKeys!
+ ValueSet.GROUPINGS = {
+ HISTOGRAM_NAME: new HistogramGrouping('name', h => h.name),
+
+ BENCHMARK_NAME: new HistogramGrouping('benchmark',
+ h => tr.v.d.IterationInfo.getField(h, 'benchmarkName', '')),
+
+ BENCHMARK_START: new HistogramGrouping('time',
+ h => tr.v.d.IterationInfo.getField(h, 'benchmarkStartString', '')),
+
+ STORYSET_REPEAT: new HistogramGrouping('storyset repeat',
+ h => tr.v.d.IterationInfo.getField(
+ h, 'storysetRepeatCounterLabel', 0)),
+
+ STORY_REPEAT: new HistogramGrouping('story repeat',
+ h => tr.v.d.IterationInfo.getField(
+ h, 'storyRepeatCounterLabel', 0)),
+
+ STORY_NAME: new HistogramGrouping('story',
+ h => tr.v.d.IterationInfo.getField(h, 'storyDisplayName', '')),
- ValueSet.computeSummaryValuesForNumericValue = function(value) {
- if (!(value instanceof tr.v.NumericValue &&
- value.numeric instanceof tr.v.Numeric))
- throw new Error('Tried to compute summary values for non-numeric');
-
- var summaryValueMap = new tr.v.d.RelatedValueMap();
- value.diagnostics.add(SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME, summaryValueMap);
- var options = {description: value.description};
- var stats = value.numeric.getSummarizedScalarNumericsWithNames();
- return stats.map(function(stat) {
- var summaryValue = new tr.v.NumericValue(
- value.name + '_' + stat.name, stat.scalar, options);
- summaryValueMap.set(stat.name, summaryValue);
- return summaryValue;
- });
+ DISPLAY_LABEL: new HistogramGrouping('label',
+ h => tr.v.d.IterationInfo.getField(h, 'displayLabel', 'Value'))
};
return {
- SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME: SUMMARY_VALUE_MAP_DIAGNOSTIC_NAME,
- ITERATION_INFO_DIAGNOSTIC_NAME: ITERATION_INFO_DIAGNOSTIC_NAME,
+ HistogramGrouping: HistogramGrouping,
ValueSet: ValueSet
};
});
diff --git a/chromium/third_party/catapult/tracing/tracing/value/value_set_test.html b/chromium/third_party/catapult/tracing/tracing/value/value_set_test.html
index a1b48e5e864..d958c77063d 100644
--- a/chromium/third_party/catapult/tracing/tracing/value/value_set_test.html
+++ b/chromium/third_party/catapult/tracing/tracing/value/value_set_test.html
@@ -6,87 +6,78 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/range.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
+<link rel="import" href="/tracing/base/unit.html">
+<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
+<link rel="import" href="/tracing/value/diagnostics/generic.html">
+<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/value_set.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- test('computeSummaryValuesForNumericValue', function() {
- var n = tr.v.NumericBuilder.createLinear(
- tr.v.Unit.byName.timeDurationInMs, tr.b.Range.fromExplicitRange(0, 100),
- 100).build();
-
- n.add(50);
- n.add(60);
- n.add(70);
-
- n.customizeSummaryOptions({
- count: true,
- min: true,
- max: true,
- sum: true,
- avg: true,
- std: true,
- percentile: [0.5, 1]
- });
-
- var results =
- tr.v.ValueSet.computeSummaryValuesForNumericValue(
- new tr.v.NumericValue('abc', n, { description: 'desc' }));
- var values = {};
- results.forEach(function(x) {
- values[x.name] = x.numeric;
- });
- assert.strictEqual(values.abc_count.value, 3);
- assert.strictEqual(values.abc_min.value, 50);
- assert.strictEqual(values.abc_max.value, 70);
- assert.strictEqual(values.abc_sum.value, 180);
- assert.strictEqual(values.abc_avg.value, 60);
- assert.strictEqual(values.abc_std.value, 10);
- assert.closeTo(values.abc_pct_050.value, 60, 1);
- assert.closeTo(values.abc_pct_100.value, 70, 1);
+ // TODO(benjhayden): Test groupHistogramsRecursively.
+
+ test('addValuesFromDicts', function() {
+ var n = new tr.v.Histogram('foo', tr.b.Unit.byName.unitlessNumber);
+ var values = new tr.v.ValueSet([n]);
+ var values2 = new tr.v.ValueSet();
+ values2.addValuesFromDicts(values.valueDicts);
+ assert.lengthOf(values2.getValuesNamed('foo'), 1);
+ });
+
+ test('addValueFromDictsWithSampleDiagnostic', function() {
+ var n = new tr.v.Histogram('foo', tr.b.Unit.byName.count);
+ n.addSample(10, {bar: new tr.v.d.Generic('baz')});
+
+ var values = new tr.v.ValueSet([n]);
+ var values2 = new tr.v.ValueSet();
+ values2.addValuesFromDicts(values.valueDicts);
+ assert.lengthOf(values2.getValuesNamed('foo'), 1);
+ var v = values2.getValuesNamed('foo')[0];
+ assert.lengthOf(v.getBinForValue(10).diagnosticMaps, 1);
+ var dm = v.getBinForValue(10).diagnosticMaps[0];
+ assert.strictEqual(dm.size, 1);
+ assert.instanceOf(dm.get('bar'), tr.v.d.Generic);
+ assert.strictEqual(dm.get('bar').value, 'baz');
});
test('relatedValueSetDiagnostic', function() {
- var unit = tr.v.Unit.byName.unitlessNumber;
- var a = new tr.v.NumericValue('a', new tr.v.ScalarNumeric(unit, 0));
- var b = new tr.v.NumericValue('b', new tr.v.ScalarNumeric(unit, 1));
- var c = new tr.v.NumericValue('c', new tr.v.ScalarNumeric(unit, 2));
- a.diagnostics.add('rvs', new tr.v.d.RelatedValueSet([b, c]));
+ var unit = tr.b.Unit.byName.unitlessNumber;
+ var a = new tr.v.Histogram('a', unit);
+ var b = new tr.v.Histogram('b', unit);
+ var c = new tr.v.Histogram('c', unit);
+ a.diagnostics.set('rvs', new tr.v.d.RelatedValueSet([b, c]));
// Don't serialize c just yet.
var values = new tr.v.ValueSet([a, b]);
var sourceValues = values.sourceValues;
- assert.lengthOf(sourceValues, 1);
- assert.strictEqual(sourceValues[0], a);
+ assert.strictEqual(tr.b.getOnlyElement(sourceValues), a);
var values2 = new tr.v.ValueSet();
values2.addValuesFromDicts(values.valueDicts);
- var a2 = values2.getValuesWithName('a');
+ var a2 = values2.getValuesNamed('a');
assert.lengthOf(a2, 1);
a2 = a2[0];
assert.strictEqual(a2.guid, a.guid);
- assert.instanceOf(a2, tr.v.Value);
+ assert.instanceOf(a2, tr.v.Histogram);
assert.notStrictEqual(a2, a);
- var b2 = values2.getValuesWithName('b');
+ var b2 = values2.getValuesNamed('b');
assert.lengthOf(b2, 1);
b2 = b2[0];
assert.strictEqual(b2.guid, b.guid);
- assert.instanceOf(b2, tr.v.Value);
+ assert.instanceOf(b2, tr.v.Histogram);
assert.notStrictEqual(b2, b);
var rvs2 = a2.diagnostics.get('rvs');
assert.instanceOf(rvs2, tr.v.d.RelatedValueSet);
- assert.lengthOf(rvs2.values, 2);
+ assert.lengthOf(rvs2, 2);
// Assert that b and c are in a2's RelatedValueSet.
- var rvs2vs = rvs2.values;
+ var rvs2vs = [...rvs2];
var rvs2guids = rvs2vs.map(v => v.guid);
var b2i = rvs2guids.indexOf(b.guid);
assert.strictEqual(rvs2vs[b2i], b2);
@@ -100,14 +91,14 @@ tr.b.unittest.testSuite(function() {
// Old values can refer to new values.
values2.addValuesFromDicts([c.asDict()]);
- var c2 = values2.getValuesWithName('c');
+ var c2 = values2.getValuesNamed('c');
assert.lengthOf(c2, 1);
c2 = c2[0];
assert.strictEqual(c2.guid, c.guid);
assert.notStrictEqual(c2, c);
// Now a real c2 Value should be in a2's RelatedValueSet.
- rvs2vs = rvs2.values;
+ rvs2vs = [...rvs2];
rvs2guids = rvs2vs.map(v => v.guid);
b2i = rvs2guids.indexOf(b.guid);
c2i = rvs2guids.indexOf(c.guid);
@@ -116,42 +107,41 @@ tr.b.unittest.testSuite(function() {
});
test('relatedValueMapDiagnostic', function() {
- var unit = tr.v.Unit.byName.unitlessNumber;
- var a = new tr.v.NumericValue('a', new tr.v.ScalarNumeric(unit, 0));
- var b = new tr.v.NumericValue('b', new tr.v.ScalarNumeric(unit, 1));
- var c = new tr.v.NumericValue('c', new tr.v.ScalarNumeric(unit, 2));
+ var unit = tr.b.Unit.byName.unitlessNumber;
+ var a = new tr.v.Histogram('a', unit);
+ var b = new tr.v.Histogram('b', unit);
+ var c = new tr.v.Histogram('c', unit);
var rvm = new tr.v.d.RelatedValueMap();
rvm.set('y', b);
rvm.set('z', c);
- a.diagnostics.add('rvm', rvm);
+ a.diagnostics.set('rvm', rvm);
// Don't serialize c just yet.
var values = new tr.v.ValueSet([a, b]);
var sourceValues = values.sourceValues;
- assert.lengthOf(sourceValues, 1);
- assert.strictEqual(sourceValues[0], a);
+ assert.strictEqual(tr.b.getOnlyElement(sourceValues), a);
var values2 = new tr.v.ValueSet();
values2.addValuesFromDicts(values.valueDicts);
- var a2 = values2.getValuesWithName('a');
+ var a2 = values2.getValuesNamed('a');
assert.lengthOf(a2, 1);
a2 = a2[0];
assert.strictEqual(a2.guid, a.guid);
- assert.instanceOf(a2, tr.v.Value);
+ assert.instanceOf(a2, tr.v.Histogram);
assert.notStrictEqual(a2, a);
- var b2 = values2.getValuesWithName('b');
+ var b2 = values2.getValuesNamed('b');
assert.lengthOf(b2, 1);
b2 = b2[0];
assert.strictEqual(b2.guid, b.guid);
- assert.instanceOf(b2, tr.v.Value);
+ assert.instanceOf(b2, tr.v.Histogram);
assert.notStrictEqual(b2, b);
var rvm2 = a2.diagnostics.get('rvm');
assert.instanceOf(rvm2, tr.v.d.RelatedValueMap);
- assert.lengthOf(rvm2.values, 2);
+ assert.lengthOf(rvm2, 2);
// Assert that b and c are in a2's RelatedValueMap.
// |c| should still be a ValueRef since it wasn't in values2.
@@ -163,11 +153,11 @@ tr.b.unittest.testSuite(function() {
// Old values can refer to new values.
values2.addValuesFromDicts([c.asDict()]);
- var c2 = values2.getValuesWithName('c');
+ var c2 = values2.getValuesNamed('c');
assert.lengthOf(c2, 1);
c2 = c2[0];
assert.strictEqual(c2.guid, c.guid);
- assert.instanceOf(c2, tr.v.Value);
+ assert.instanceOf(c2, tr.v.Histogram);
assert.notStrictEqual(c2, c);
// b2 should still be in a2's RelatedValueMap.
@@ -176,5 +166,17 @@ tr.b.unittest.testSuite(function() {
// Now a real c2 Value should be in a2's RelatedValueMap.
assert.strictEqual(rvm2.get('z'), c2);
});
+
+ test('sourceValuesWithSampleDiagnostic', function() {
+ var unit = tr.b.Unit.byName.unitlessNumber;
+ var aHist = new tr.v.Histogram('a', unit);
+ aHist.addSample(1);
+
+ var numeric = new tr.v.Histogram('b', tr.b.Unit.byName.unitlessNumber);
+ numeric.addSample(1, {rvs: new tr.v.d.RelatedValueSet([aHist])});
+
+ var values = new tr.v.ValueSet([aHist, numeric]);
+ assert.strictEqual(tr.b.getOnlyElement(values.sourceValues), numeric);
+ });
});
</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/value_test.html b/chromium/third_party/catapult/tracing/tracing/value/value_test.html
deleted file mode 100644
index 07e73b030ee..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/value/value_test.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/utils.html">
-<link rel="import" href="/tracing/value/numeric.html">
-<link rel="import" href="/tracing/value/unit.html">
-<link rel="import" href="/tracing/value/value.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- test('numericValueBasic', function() {
- var n = new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes, 314);
- var v = new tr.v.NumericValue('MyNumeric', n);
- assert.isDefined(v.guid);
- var d = v.asDict();
-
- var v2 = tr.v.Value.fromDict(d);
- assert.instanceOf(v2, tr.v.NumericValue);
- assert.equal(v.guid, v2.guid);
- assert.equal(v.name, v2.name);
- assert.equal(v.numeric.value, v2.numeric.value);
- });
-
- test('dictValueBasic', function() {
- var v = new tr.v.DictValue('MyDict', {my_key: 'my_value'});
- assert.isDefined(v.guid);
- var d = v.asDict();
-
- var v2 = tr.v.Value.fromDict(d);
- assert.instanceOf(v2, tr.v.DictValue);
- assert.equal(v.guid, v2.guid);
- assert.deepEqual(v.value, v2.value);
- });
-
- test('failureValueBasic', function() {
- var v = new tr.v.FailureValue(
- 'MyFailure',
- {description: 'Description', stack: tr.b.stackTraceAsString()});
- assert.isDefined(v.guid);
- var d = v.asDict();
-
- var v2 = tr.v.Value.fromDict(d);
- assert.instanceOf(v2, tr.v.FailureValue);
- assert.equal(v.guid, v2.guid);
- assert.equal(v.name, v2.name);
- assert.equal(v.description, v2.description);
- assert.equal(v.stack, v2.stack);
- });
-
- test('skipValueBasic', function() {
- var v = new tr.v.SkipValue('MySkip',
- {description: 'WhySkipped'});
- assert.isDefined(v.guid);
- var d = v.asDict();
-
- var v2 = tr.v.Value.fromDict(d);
- assert.equal(v.guid, v2.guid);
- assert.instanceOf(v2, tr.v.SkipValue);
- assert.equal(v.description, v2.description);
- });
-
- test('genericDiagnostic', function() {
- var skip = new tr.v.SkipValue('skip');
- skip.diagnostics.add('foo', new tr.v.d.Generic({
- t: true,
- f: false,
- z: 0,
- o: 1,
- ans: 0.42,
- s: 'string',
- a: [42.42, 'more string'],
- d: {a: {b: 'c'}}
- }));
- var skip2 = tr.v.Value.fromDict(skip.asDict());
- var foo2 = skip2.diagnostics.get('foo');
- assert.strictEqual(true, foo2.value.t);
- assert.strictEqual(false, foo2.value.f);
- assert.strictEqual(0, foo2.value.z);
- assert.strictEqual(1, foo2.value.o);
- assert.strictEqual(0.42, foo2.value.ans);
- assert.strictEqual('string', foo2.value.s);
- assert.deepEqual([42.42, 'more string'], foo2.value.a);
- assert.deepEqual({a: {b: 'c'}}, foo2.value.d);
- });
-});
-</script>
diff --git a/chromium/third_party/catapult/tracing/tracing/value/value_unittest.py b/chromium/third_party/catapult/tracing/tracing/value/value_unittest.py
deleted file mode 100644
index 88ffbc32382..00000000000
--- a/chromium/third_party/catapult/tracing/tracing/value/value_unittest.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-import unittest
-
-from tracing import value as value_module
-
-
-class ValueTests(unittest.TestCase):
-
- def testScalar(self):
- d = {
- 'canonical_url': '/a.json',
- 'type': 'scalar',
- 'name': 'MyScalarValue',
- 'important': False,
- 'value': {'a': 1, 'b': 'b'}
- }
- v = value_module.Value.FromDict(d)
- self.assertTrue(isinstance(v, value_module.ScalarValue))
- d2 = v.AsDict()
-
- self.assertEquals(d, d2)
-
- def testDict(self):
- d = {
- 'canonical_url': '/a.json',
- 'type': 'dict',
- 'name': 'MyDictValue',
- 'important': False,
- 'value': {'a': 1, 'b': 'b'}
- }
- v = value_module.Value.FromDict(d)
- self.assertTrue(isinstance(v, value_module.DictValue))
- d2 = v.AsDict()
-
- self.assertEquals(d, d2)
-
- def testFailure(self):
- d = {
- 'canonical_url': '/a.json',
- 'type': 'failure',
- 'name': 'Error',
- 'important': False,
- 'description': 'Some error message',
- 'stack_str': 'Some stack string'
- }
- v = value_module.Value.FromDict(d)
- self.assertTrue(isinstance(v, value_module.FailureValue))
- d2 = v.AsDict()
-
- self.assertEquals(d, d2)
diff --git a/chromium/third_party/catapult/tracing/tracing_build/check_common.py b/chromium/third_party/catapult/tracing/tracing_build/check_common.py
index b49513f6d61..41fd301f4a3 100644
--- a/chromium/third_party/catapult/tracing/tracing_build/check_common.py
+++ b/chromium/third_party/catapult/tracing/tracing_build/check_common.py
@@ -84,7 +84,7 @@ def CheckCommon(file_name, listed_files):
'\n\n'
' Note: only files actually used in about:tracing should\n'
' be listed in the build files. Try running \n'
- ' tracing/bin/update_gyp_and_gn\n'
+ ' tracing/bin/update_gypi\n'
' to update the files automatically.')
return error
diff --git a/chromium/third_party/catapult/tracing/tracing_build/html2trace.py b/chromium/third_party/catapult/tracing/tracing_build/html2trace.py
index 1acab58d5d6..85a451888af 100644
--- a/chromium/third_party/catapult/tracing/tracing_build/html2trace.py
+++ b/chromium/third_party/catapult/tracing/tracing_build/html2trace.py
@@ -3,7 +3,6 @@
# found in the LICENSE file.
import base64
-import codecs
import gzip
import json
import re
@@ -20,13 +19,23 @@ TRACE_DATA_START_LINE_RE = re.compile(
TRACE_DATA_END_LINE_RE = re.compile(r'^<\/\s*script>$')
-def CopyTraceDataFromHTMLFilePath(html_path, trace_path, gzipped_output=False):
+def IsHTMLTrace(trace_file_handle):
+ trace_file_handle.seek(0)
+ for line in trace_file_handle:
+ line = line.strip()
+ if not line:
+ continue
+ return line == '<!DOCTYPE html>'
+
+
+def CopyTraceDataFromHTMLFilePath(html_file_handle, trace_path,
+ gzipped_output=False):
"""Copies trace data from an existing HTML file into new trace file(s).
- If |html_path| doesn't contain any trace data blocks, this function throws an
- exception. If |html_path| contains more than one trace data block, the first
- block will be extracted into |trace_path| and the rest will be extracted
- into separate files |trace_path|.1, |trace_path|.2, etc.
+ If |html_file_handle| doesn't contain any trace data blocks, this function
+ throws an exception. If |html_file_handle| contains more than one trace data
+ block, the first block will be extracted into |trace_path| and the rest will
+ be extracted into separate files |trace_path|.1, |trace_path|.2, etc.
The contents of each trace data block is decoded and, if |gzipped_output| is
false, inflated before it's stored in a trace file.
@@ -34,7 +43,7 @@ def CopyTraceDataFromHTMLFilePath(html_path, trace_path, gzipped_output=False):
This function returns a list of paths of the saved trace files ([|trace_path|,
|trace_path|.1, |trace_path|.2, ...]).
"""
- trace_data_list = _ExtractTraceDataFromHTMLFile(html_path,
+ trace_data_list = _ExtractTraceDataFromHTMLFile(html_file_handle,
unzip_data=not gzipped_output)
saved_paths = []
for i, trace_data in enumerate(trace_data_list):
@@ -45,14 +54,15 @@ def CopyTraceDataFromHTMLFilePath(html_path, trace_path, gzipped_output=False):
return saved_paths
-def ReadTracesFromHTMLFilePath(html_path):
+def ReadTracesFromHTMLFilePath(html_file_handle):
"""Returns a list of inflated JSON traces extracted from an HTML file."""
- return map(json.load, _ExtractTraceDataFromHTMLFile(html_path))
+ return map(json.load, _ExtractTraceDataFromHTMLFile(html_file_handle))
-def _ExtractTraceDataFromHTMLFile(html_path, unzip_data=True):
- with codecs.open(html_path, mode='r', encoding='utf-8') as html_file:
- lines = html_file.readlines()
+def _ExtractTraceDataFromHTMLFile(html_file_handle, unzip_data=True):
+ assert IsHTMLTrace(html_file_handle)
+ html_file_handle.seek(0)
+ lines = html_file_handle.readlines()
start_indices = [i for i in xrange(len(lines))
if TRACE_DATA_START_LINE_RE.match(lines[i])]
diff --git a/chromium/third_party/catapult/tracing/tracing_build/merge_traces.py b/chromium/third_party/catapult/tracing/tracing_build/merge_traces.py
index b107253dcf8..5280f620b1c 100644
--- a/chromium/third_party/catapult/tracing/tracing_build/merge_traces.py
+++ b/chromium/third_party/catapult/tracing/tracing_build/merge_traces.py
@@ -27,6 +27,7 @@ METADATA_PHASE = 'M'
MEMORY_DUMP_PHASE = 'v'
BEGIN_PHASE = 'B'
END_PHASE = 'E'
+CLOCK_SYNC_EVENT_PHASE = 'c'
# Minimum gap between two consecutive merged traces in microseconds.
@@ -295,11 +296,7 @@ def LoadTrace(filename):
"""Load a trace from a (possibly gzipped) file and return its parsed JSON."""
logging.info('Loading trace %r...', filename)
if filename.endswith(HTML_FILENAME_SUFFIX):
- traces = html2trace.ReadTracesFromHTMLFilePath(filename)
- if len(traces) > 1:
- logging.warning('HTML trace contains multiple trace data blocks. Only '
- 'the first block will be merged.')
- return traces[0]
+ return LoadHTMLTrace(filename)
elif filename.endswith(GZIP_FILENAME_SUFFIX):
with gzip.open(filename, 'rb') as f:
return json.load(f)
@@ -308,6 +305,30 @@ def LoadTrace(filename):
return json.load(f)
+def LoadHTMLTrace(filename):
+ """Load a trace from a vulcanized HTML trace file."""
+ trace_components = collections.defaultdict(list)
+
+ for sub_trace in html2trace.ReadTracesFromHTMLFilePath(filename):
+ for name, component in TraceAsDict(sub_trace).iteritems():
+ trace_components[name].append(component)
+
+ trace = {}
+ for name, components in trace_components.iteritems():
+ if len(components) == 1:
+ trace[name] = components[0]
+ elif all(isinstance(component, list) for component in components):
+ trace[name] = [e for component in components for e in component]
+ else:
+ trace[name] = components[0]
+ logging.warning(
+ 'Values of repeated trace component %r in HTML trace %r are not '
+ 'lists. The first defined value of the component will be used.',
+ filename, name)
+
+ return trace
+
+
def SaveTrace(trace, filename):
"""Save a JSON trace to a (possibly gzipped) file."""
if filename is None:
@@ -326,6 +347,13 @@ def SaveTrace(trace, filename):
json.dump(trace, f)
+def TraceAsDict(trace):
+ """Ensure that a trace is a dictionary."""
+ if isinstance(trace, list):
+ return {'traceEvents': trace}
+ return trace
+
+
def MergeTraceFiles(input_trace_filenames, output_trace_filename):
"""Merge a collection of input trace files into an output trace file."""
logging.info('Loading %d input traces...', len(input_trace_filenames))
@@ -347,9 +375,7 @@ def MergeTraces(traces):
trace_components = collections.defaultdict(collections.OrderedDict)
for filename, trace in traces.iteritems():
- if isinstance(trace, list):
- trace = {'traceEvents': trace}
- for name, component in trace.iteritems():
+ for name, component in TraceAsDict(trace).iteritems():
trace_components[name][filename] = component
merged_trace = {}
@@ -372,14 +398,32 @@ def MergeComponents(component_name, components_by_filename):
def MergeTraceEvents(events_by_filename):
"""Merge trace events from multiple traces into a single list of events."""
+ # Remove strings from the list of trace events
+ # (https://github.com/catapult-project/catapult/issues/2497).
+ events_by_filename = collections.OrderedDict(
+ (filename, [e for e in events if not isinstance(e, basestring)])
+ for filename, events in events_by_filename.iteritems())
+
timestamp_range_by_filename = _AdjustTimestampRanges(events_by_filename)
process_map = _CreateProcessMapFromTraceEvents(events_by_filename)
merged_events = _CombineTraceEvents(events_by_filename, process_map)
+ _RemoveSurplusClockSyncEvents(merged_events)
merged_events.extend(
_BuildInjectedTraceMarkerEvents(timestamp_range_by_filename, process_map))
return merged_events
+def _RemoveSurplusClockSyncEvents(events):
+ """Remove all clock sync events except for the first one."""
+ # TODO(petrcermak): Figure out how to handle merging multiple clock sync
+ # events.
+ clock_sync_event_indices = [i for i, e in enumerate(events)
+ if e['ph'] == CLOCK_SYNC_EVENT_PHASE]
+ # The indices need to be traversed from largest to smallest (hence the -1).
+ for i in clock_sync_event_indices[:0:-1]:
+ del events[i]
+
+
def _AdjustTimestampRanges(events_by_filename):
logging.info('Adjusting timestamp ranges of traces...')
diff --git a/chromium/third_party/catapult/tracing/tracing_build/slim_trace.py b/chromium/third_party/catapult/tracing/tracing_build/slim_trace.py
new file mode 100644
index 00000000000..ac47c79d9b5
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing_build/slim_trace.py
@@ -0,0 +1,112 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import codecs
+import json
+import os
+import logging
+
+
+from tracing_build import html2trace
+from tracing_build import trace2html
+
+
+def GetFileSizeInMb(path):
+ return os.path.getsize(path) >> 20
+
+
+def Main(argv):
+ parser = argparse.ArgumentParser(
+ description='Slim a trace to a more managable size')
+ parser.add_argument('trace_path', metavar='TRACE_PATH', type=str,
+ help='trace file path (input).')
+ options = parser.parse_args(argv[1:])
+
+ trace_path = os.path.abspath(options.trace_path)
+
+ orignal_trace_name = os.path.splitext(os.path.basename(trace_path))[0]
+ slimmed_trace_path = os.path.join(
+ os.path.dirname(trace_path), 'slimmed_%s.html' % orignal_trace_name)
+
+ with codecs.open(trace_path, mode='r', encoding='utf-8') as f:
+ SlimTrace(f, slimmed_trace_path)
+
+ print 'Original trace %s (%s Mb)' % (
+ trace_path, GetFileSizeInMb(trace_path))
+ print 'Slimmed trace file://%s (%s Mb)' % (
+ slimmed_trace_path, GetFileSizeInMb(slimmed_trace_path))
+
+def SlimTraceEventsList(events_list):
+ filtered_events = []
+ # Filter out all events of phase complete that takes less than 20
+ # microseconds.
+ for e in events_list:
+ dur = e.get('dur', 0)
+ if e['ph'] != 'X' or dur >= 20:
+ filtered_events.append(e)
+ return filtered_events
+
+
+def SlimSingleTrace(trace_data):
+ if isinstance(trace_data, dict):
+ trace_data['traceEvents'] = SlimTraceEventsList(trace_data['traceEvents'])
+ elif isinstance(trace_data, list) and isinstance(trace_data[0], dict):
+ trace_data = SlimTraceEventsList(trace_data)
+ else:
+ logging.warning('Cannot slim trace %s...', trace_data[:10])
+ return trace_data
+
+
+class TraceExtractor(object):
+ def CanExtractFile(self, trace_file_handle):
+ raise NotImplementedError
+
+ def ExtractTracesFromFile(self, trace_file_handle):
+ raise NotImplementedError
+
+
+class HTMLTraceExtractor(TraceExtractor):
+ def CanExtractFile(self, trace_file_handle):
+ return html2trace.IsHTMLTrace(trace_file_handle)
+
+ def ExtractTracesFromFile(self, trace_file_handle):
+ return html2trace.ReadTracesFromHTMLFilePath(trace_file_handle)
+
+
+class JsonTraceExtractor(TraceExtractor):
+ def CanExtractFile(self, trace_file_handle):
+ trace_file_handle.seek(0)
+ begin_char = trace_file_handle.read(1)
+ trace_file_handle.seek(-1, 2)
+ end_char = trace_file_handle.read(1)
+ return ((begin_char == '{' and end_char == '}') or
+ (begin_char == '[' and end_char == ']'))
+
+ def ExtractTracesFromFile(self, trace_file_handle):
+ trace_file_handle.seek(0)
+ return [json.load(trace_file_handle)]
+
+
+ALL_TRACE_EXTRACTORS = [
+ HTMLTraceExtractor(),
+ JsonTraceExtractor()
+]
+
+
+def SlimTrace(trace_file_handle, slimmed_trace_path):
+ traces = None
+ for extractor in ALL_TRACE_EXTRACTORS:
+ if extractor.CanExtractFile(trace_file_handle):
+ traces = extractor.ExtractTracesFromFile(trace_file_handle)
+ break
+
+ if traces == None:
+ raise Exception('Cannot extrac trace from %s' % trace_file_handle.name)
+
+ slimmed_traces = map(SlimSingleTrace, traces)
+
+ with codecs.open(slimmed_trace_path, mode='w', encoding='utf-8') as f:
+ trace2html.WriteHTMLForTraceDataToFile(
+ slimmed_traces, title='', output_file=f)
diff --git a/chromium/third_party/catapult/tracing/tracing_build/strip_memory_infra_trace.py b/chromium/third_party/catapult/tracing/tracing_build/strip_memory_infra_trace.py
new file mode 100755
index 00000000000..5db429f8c6b
--- /dev/null
+++ b/chromium/third_party/catapult/tracing/tracing_build/strip_memory_infra_trace.py
@@ -0,0 +1,100 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Filters a big trace keeping only the last memory-infra dumps."""
+
+import collections
+import gzip
+import json
+
+
+def FormatBytes(value):
+ units = ['B', 'KiB', 'MiB', 'GiB']
+ while abs(value) >= 1024 and len(units) > 1:
+ value /= 1024
+ units = units.pop(0)
+ return '%3.1f %s' % (value, units[0])
+
+
+def Main(argv):
+ if len(argv) < 2:
+ print 'Usage: %s trace.json[.gz]' % argv[0]
+ return 1
+
+ in_path = argv[1]
+ if in_path.lower().endswith('.gz'):
+ fin = gzip.open(in_path, 'rb')
+ else:
+ fin = open(in_path, 'r')
+ with fin:
+ print 'Loading trace (can take 1 min on a z620 for a 1GB trace)...'
+ trace = json.load(fin)
+ print 'Done. Read ' + FormatBytes(fin.tell())
+
+ print 'Filtering events'
+ phase_count = collections.defaultdict(int)
+ out_events = []
+ global_dumps = collections.OrderedDict()
+ if isinstance(trace, dict):
+ in_events = trace.get('traceEvents', [])
+ elif isinstance(trace, list) and isinstance(trace[0], dict):
+ in_events = trace
+
+ for evt in in_events:
+ phase = evt.get('ph', '?')
+ phase_count[phase] += 1
+
+ # Drop all diagnostic events for memory-infra debugging.
+ if phase not in ('v', 'V') and evt.get('cat', '').endswith('memory-infra'):
+ continue
+
+ # pass-through all the other non-memory-infra events
+ if phase != 'v':
+ out_events.append(evt)
+ continue
+
+ # Recreate the global dump groups
+ event_id = evt['id']
+ global_dumps.setdefault(event_id, [])
+ global_dumps[event_id].append(evt)
+
+
+ print 'Detected %d memory-infra global dumps' % len(global_dumps)
+ if global_dumps:
+ max_procs = max(len(x) for x in global_dumps.itervalues())
+ print 'Max number of processes seen: %d' % max_procs
+
+ ndumps = 2
+ print 'Preserving the last %d memory-infra dumps' % ndumps
+ detailed_dumps = []
+ non_detailed_dumps = []
+ for global_dump in global_dumps.itervalues():
+ try:
+ level_of_detail = global_dump[0]['args']['dumps']['level_of_detail']
+ except KeyError:
+ level_of_detail = None
+ if level_of_detail == 'detailed':
+ detailed_dumps.append(global_dump)
+ else:
+ non_detailed_dumps.append(global_dump)
+
+ dumps_to_preserve = detailed_dumps[-ndumps:]
+ ndumps -= len(dumps_to_preserve)
+ if ndumps:
+ dumps_to_preserve += non_detailed_dumps[-ndumps:]
+
+ for global_dump in dumps_to_preserve:
+ out_events += global_dump
+
+ print '\nEvents histogram for the original trace (count by phase)'
+ print '--------------------------------------------------------'
+ for phase, count in sorted(phase_count.items(), key=lambda x: x[1]):
+ print '%s %d' % (phase, count)
+
+ out_path = in_path.split('.json')[0] + '-filtered.json'
+ print '\nWriting filtered trace to ' + out_path,
+ with open(out_path, 'w') as fout:
+ json.dump({'traceEvents': out_events}, fout)
+ num_bytes_written = fout.tell()
+ print ' (%s written)' % FormatBytes(num_bytes_written)
diff --git a/chromium/third_party/catapult/tracing/tracing_build/trace2html.py b/chromium/third_party/catapult/tracing/tracing_build/trace2html.py
index 82682d065a8..96006b247cf 100644
--- a/chromium/third_party/catapult/tracing/tracing_build/trace2html.py
+++ b/chromium/third_party/catapult/tracing/tracing_build/trace2html.py
@@ -82,10 +82,8 @@ def WriteHTMLForTraceDataToFile(trace_data_list,
modules = [
'tracing.trace2html',
- 'tracing.extras.importer.gzip_importer', # Must have for all configs.
- project.GetModuleNameForConfigName(config_name)
+ project.GetModuleNameForConfigName(config_name),
]
-
vulcanizer = project.CreateVulcanizer()
load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(modules)
diff --git a/chromium/third_party/catapult/tracing/tracing_project.py b/chromium/third_party/catapult/tracing/tracing_project.py
index e3ddaa9fee6..6aa0a779162 100644
--- a/chromium/third_party/catapult/tracing/tracing_project.py
+++ b/chromium/third_party/catapult/tracing/tracing_project.py
@@ -58,11 +58,13 @@ class TracingProject(object):
os.path.join(os.path.dirname(__file__), os.path.pardir))
tracing_root_path = os.path.join(catapult_path, 'tracing')
+ trace_processor_root_path = os.path.join(catapult_path, 'trace_processor')
tracing_src_path = os.path.join(tracing_root_path, 'tracing')
extras_path = os.path.join(tracing_src_path, 'extras')
ui_extras_path = os.path.join(tracing_src_path, 'ui', 'extras')
catapult_third_party_path = os.path.join(catapult_path, 'third_party')
+ polymer_path = os.path.join(catapult_third_party_path, 'polymer')
tracing_third_party_path = os.path.join(tracing_root_path, 'third_party')
py_vulcanize_path = os.path.join(catapult_third_party_path, 'py_vulcanize')
@@ -81,7 +83,7 @@ class TracingProject(object):
chai_path = os.path.join(tracing_third_party_path, 'chai')
mocha_path = os.path.join(tracing_third_party_path, 'mocha')
- mre_path = os.path.join(catapult_path, 'perf_insights')
+ mre_path = os.path.join(tracing_src_path, 'mre')
metrics_path = os.path.join(tracing_src_path, 'metrics')
@@ -99,6 +101,7 @@ class TracingProject(object):
def __init__(self):
self.source_paths = []
self.source_paths.append(self.tracing_root_path)
+ self.source_paths.append(self.polymer_path)
self.source_paths.append(self.tracing_third_party_path)
self.source_paths.append(self.mre_path)
self.source_paths.append(self.jszip_path)